Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
mapping_handler.f90
Go to the documentation of this file.
1
34!
37 use neko_config, only: neko_bcknd_device
38 use num_types, only: rp, sp, dp
41 use field, only: field_t
42 use field_output, only: field_output_t
43 use json_utils, only: json_extract_item
44 use json_module, only: json_file
45 use coefs, only: coef_t
46 use field_math, only: field_copy
47 use math, only: col2
48 use device_math, only: device_col2
49 use scratch_registry, only: neko_scratch_registry
50 use utils, only: neko_warning, neko_error
51 use vector, only:vector_t
53 use gather_scatter, only : gs_op_add
54 implicit none
55 private
56
63 type, public :: mapping_handler_t
67 class(mapping_wrapper_t), allocatable :: mapping_cascade(:)
69 type(coef_t), pointer :: coef
71 type(field_output_t) :: design_output
73 type(field_output_t) :: sensitivity_output
75 type(field_t), pointer :: design_in => null()
76 type(field_t), pointer :: design_out => null()
77 type(field_t), pointer :: sensitivity_out => null()
79 type(field_t), allocatable :: sensitivity_stages(:)
81 logical :: output_fields_set = .false.
82 logical :: outputs_initialized = .false.
84 logical :: verbose_design = .false.
86 logical :: verbose_sensitivity = .false.
88 integer :: output_precision = sp
90 character(len=32) :: output_format = 'fld'
92 character(len=80) :: forward_file_name = ''
94 character(len=80) :: sensitivity_file_name = ''
95
96 contains
98 procedure, pass(this) :: init_base => mapping_handler_init_base
100 procedure, pass(this) :: free => mapping_handler_free
102 generic :: apply_forward => mapping_handler_apply_forward_field, &
103 mapping_handler_apply_forward_vector
104 procedure, pass(this) :: mapping_handler_apply_forward_field
105 procedure, pass(this) :: mapping_handler_apply_forward_vector
108 generic :: apply_backward => mapping_handler_apply_backward_field, &
109 mapping_handler_apply_backward_vector
110 procedure, pass(this) :: mapping_handler_apply_backward_field
111 procedure, pass(this) :: mapping_handler_apply_backward_vector
113 generic :: add => add_mapping, add_json_mappings
115 procedure, pass(this) :: add_mapping => &
116 mapping_handler_add_mapping
118 procedure, pass(this) :: add_json_mappings => &
119 mapping_handler_add_json_mappings
121 procedure, pass(this) :: set_stage_names => &
122 mapping_handler_set_stage_names
124 procedure, pass(this) :: make_cts => mapping_handler_make_cts
126 procedure, pass(this) :: init_output_fields => &
127 mapping_handler_init_output_fields
129 procedure, pass(this) :: write_design => mapping_handler_write_design
131 procedure, pass(this) :: write_sensitivity => &
132 mapping_handler_write_sensitivity
134 procedure, pass(this) :: set_output_counter => &
135 mapping_handler_set_output_counter
136 end type mapping_handler_t
137
138contains
139
143 class(mapping_handler_t), intent(inout) :: this
144 integer :: i, n_mappings, n_fields
145
146 if (.not. this%output_fields_set) then
147 call neko_error('Mapping output fields have not been configured')
148 end if
149 if (.not. associated(this%coef)) then
150 call neko_error('Mapping handler coefficients are not initialized')
151 end if
152 if (.not. associated(this%design_out)) then
153 call neko_error('Mapped design output field is not associated')
154 end if
155 if (.not. associated(this%design_in)) then
156 call neko_error('Unmapped design input field is not associated')
157 end if
158 if (.not. associated(this%sensitivity_out)) then
159 call neko_error('Sensitivity output field is not associated')
160 end if
161
162 n_mappings = 0
163 if (allocated(this%mapping_cascade)) n_mappings = size(this%mapping_cascade)
164
165 if (this%verbose_design) then
166 ! all mapping inputs + mapped output
167 n_fields = n_mappings + 1
168 if (n_fields .le. 0) n_fields = 1
169 else
170 ! only first unmapped stage and mapped output
171 if (n_mappings .gt. 0) then
172 n_fields = 2
173 else
174 n_fields = 1
175 end if
176 end if
177
178 call this%set_stage_names()
179
180 call this%design_output%init(trim(this%forward_file_name), n_fields, &
181 precision = this%output_precision, &
182 format = trim(this%output_format))
183
184 if (this%verbose_design) then
185 do i = 1, n_mappings
186 call this%design_output%fields%assign_to_field(i, &
187 this%mapping_cascade(i)%mapping%X_in)
188 end do
189 call this%design_output%fields%assign_to_field(n_fields, this%design_out)
190 else if (n_mappings .eq. 0) then
191 call this%design_output%fields%assign_to_field(1, this%design_out)
192 else
193 call this%design_output%fields%assign_to_field(1, &
194 this%mapping_cascade(1)%mapping%X_in)
195 call this%design_output%fields%assign_to_field(2, this%design_out)
196 end if
197
198 if (this%verbose_sensitivity) then
199 ! sensitivity_in + chain-rule stages + final sensitivity
200 n_fields = n_mappings + 2
201 allocate(this%sensitivity_stages(n_mappings + 1))
202 do i = 1, n_mappings + 1
203 call this%sensitivity_stages(i)%init(this%coef%dof)
204 end do
205 call this%sensitivity_output%init( &
206 trim(this%sensitivity_file_name), n_fields, &
207 precision = this%output_precision, &
208 format = trim(this%output_format))
209 do i = 1, n_mappings + 1
210 call this%sensitivity_output%fields%assign_to_field(i, &
211 this%sensitivity_stages(i))
212 end do
213 call this%sensitivity_output%fields%assign_to_field(n_fields, &
214 this%sensitivity_out)
215 else
216 call this%sensitivity_output%init( &
217 trim(this%sensitivity_file_name), 1, &
218 precision = this%output_precision, &
219 format = trim(this%output_format))
220 call this%sensitivity_output%fields%assign_to_field(1, &
221 this%sensitivity_out)
222 end if
223
224 this%outputs_initialized = .true.
225
226 end subroutine mapping_handler_setup_outputs
227
229 subroutine mapping_handler_init_base(this, coef)
230 class(mapping_handler_t), intent(inout) :: this
231 type(coef_t), target, intent(in) :: coef
232
233 call this%free()
234
235 this%coef => coef
236
237 end subroutine mapping_handler_init_base
238
239
241 subroutine mapping_handler_free(this)
242 class(mapping_handler_t), intent(inout) :: this
243 integer :: i
244
245 if (allocated(this%mapping_cascade)) then
246 do i = 1, size(this%mapping_cascade)
247 call this%mapping_cascade(i)%free()
248 end do
249 deallocate(this%mapping_cascade)
250 end if
251 if (allocated(this%sensitivity_stages)) then
252 do i = 1, size(this%sensitivity_stages)
253 call this%sensitivity_stages(i)%free()
254 end do
255 deallocate(this%sensitivity_stages)
256 end if
257
258 call this%design_output%free()
259 call this%sensitivity_output%free()
260
261 this%outputs_initialized = .false.
262 this%output_fields_set = .false.
263 this%output_precision = sp
264 this%output_format = 'fld'
265 this%forward_file_name = ''
266 this%sensitivity_file_name = ''
267 if (associated(this%design_in)) nullify(this%design_in)
268 if (associated(this%design_out)) nullify(this%design_out)
269 if (associated(this%sensitivity_out)) nullify(this%sensitivity_out)
270 if (associated(this%coef)) nullify(this%coef)
271
272 end subroutine mapping_handler_free
273
278 subroutine mapping_handler_apply_forward_field(this, X_out, X_in)
279 class(mapping_handler_t), intent(inout) :: this
280 type(field_t), intent(in) :: X_in
281 type(field_t), intent(inout) :: X_out
282 integer :: i
283 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
284 integer :: temp_indices(2)
285
286 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
287 .false.)
288 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
289 .false.)
290
291 ! Start by copying the first X_in into the tmp_fld_out to begin the
292 ! cascade.
293 call field_copy(tmp_fld_out, x_in)
294
295 ! enforce continuity in the field
296 call this%make_cts(tmp_fld_out)
297
298 ! We enter the cascade
299 if (allocated(this%mapping_cascade)) then
300 do i = 1, size(this%mapping_cascade)
301 ! the output from one mapping becomes the input for the next.
302 call field_copy(tmp_fld_in, tmp_fld_out)
303 ! apply the mapping on temp_fld
304 call this%mapping_cascade(i)%mapping%apply_forward(tmp_fld_out, &
305 tmp_fld_in)
306
307 end do
308
309 end if
310
311 ! our final mapping should now live in tmp_fld_out
312 call field_copy(x_out, tmp_fld_out)
313
314 ! free the scratch.
315 call neko_scratch_registry%relinquish_field(temp_indices)
316
317 end subroutine mapping_handler_apply_forward_field
318
323 subroutine mapping_handler_apply_forward_vector(this, X_out, X_in)
324 class(mapping_handler_t), intent(inout) :: this
325 type(vector_t), intent(in) :: X_in
326 type(vector_t), intent(inout) :: X_out
327 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
328 integer :: temp_indices(2)
329
330 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
331 .false.)
332 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
333 .false.)
334
335 call vector_to_field(tmp_fld_in, x_in)
336 call mapping_handler_apply_forward_field(this, tmp_fld_out, tmp_fld_in)
337 call field_to_vector(x_out, tmp_fld_out)
338
339 ! free the scratch.
340 call neko_scratch_registry%relinquish_field(temp_indices)
341
342 end subroutine mapping_handler_apply_forward_vector
343
350 subroutine mapping_handler_apply_backward_field(this, sens_out, sens_in)
351 class(mapping_handler_t), intent(inout) :: this
352 type(field_t), intent(inout) :: sens_out
353 type(field_t), intent(in) :: sens_in
354 integer :: i
355 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
356 integer :: temp_indices(2)
357
358 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
359 .false.)
360 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
361 .false.)
362
363 ! Start by copying the first sens_in into the tmp_fld_out to begin the
364 ! cascade.
365 call field_copy(tmp_fld_out, sens_in)
366 if (allocated(this%sensitivity_stages)) then
367 call field_copy(this%sensitivity_stages(1), sens_in)
368 end if
369
370 ! enforce continuity in the field
371 call this%make_cts(tmp_fld_out)
372
373 ! We enter the cascade
374 if (allocated(this%mapping_cascade)) then
375 do i = size(this%mapping_cascade), 1, -1
376 ! the output from one mapping becomes the input for the next.
377 call field_copy(tmp_fld_in, tmp_fld_out)
378 ! apply the mapping on temp_fld
379 ! NOTE
380 ! all the X_in that is required to map backward should be held
381 ! internally by each mapping
382 call this%mapping_cascade(i)%mapping%apply_backward(tmp_fld_out, &
383 tmp_fld_in)
384 if (allocated(this%sensitivity_stages)) then
385 call field_copy(this%sensitivity_stages( &
386 size(this%mapping_cascade) - i + 2), tmp_fld_out)
387 end if
388
389 end do
390
391 end if
392
393 ! our final mapping should now live in tmp_fld_out
394 call field_copy(sens_out, tmp_fld_out)
395
396 ! free the scratch.
397 call neko_scratch_registry%relinquish_field(temp_indices)
398
399
400 end subroutine mapping_handler_apply_backward_field
401
408 subroutine mapping_handler_apply_backward_vector(this, X_out, X_in)
409 class(mapping_handler_t), intent(inout) :: this
410 type(vector_t), intent(in) :: X_in
411 type(vector_t), intent(inout) :: X_out
412 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
413 integer :: temp_indices(2)
414
415 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
416 .false.)
417 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
418 .false.)
419
420 call vector_to_field(tmp_fld_in, x_in)
421 call mapping_handler_apply_backward_field(this, tmp_fld_out, tmp_fld_in)
422 call field_to_vector(x_out, tmp_fld_out)
423
424 ! free the scratch.
425 call neko_scratch_registry%relinquish_field(temp_indices)
426
427 end subroutine mapping_handler_apply_backward_vector
428
430 subroutine mapping_handler_add_json_mappings(this, json, name)
431 class(mapping_handler_t), intent(inout) :: this
432 type(json_file), intent(inout) :: json
433 character(len=*), intent(in) :: name
434
435 class(mapping_wrapper_t), dimension(:), allocatable :: temp
436
437 ! A single mapping as its own json_file.
438 type(json_file) :: mapping_subdict
439 integer :: n_mappings, i, i0
440
441 if (json%valid_path(name)) then
442 ! Get the number of mapping_cascade.
443 call json%info(name, n_children = n_mappings)
444
445 if (allocated(this%mapping_cascade)) then
446 i0 = size(this%mapping_cascade)
447 call move_alloc(this%mapping_cascade, temp)
448 allocate(this%mapping_cascade(i0 + n_mappings))
449 if (allocated(temp)) then
450 do i = 1, i0
451 call move_alloc(temp(i)%mapping, &
452 this%mapping_cascade(i)%mapping)
453 end do
454 end if
455 else
456 i0 = 0
457 allocate(this%mapping_cascade(n_mappings))
458 end if
459
460 do i = 1, n_mappings
461 ! Create a new json containing just the subdict for this mapping.
462 call json_extract_item(json, name, i, mapping_subdict)
463 call mapping_factory(this%mapping_cascade(i + i0)%mapping, &
464 mapping_subdict, this%coef)
465 end do
466 if (this%output_fields_set) call mapping_handler_setup_outputs(this)
467 else
468 ! I was considering an error, but maybe a warning is more appropriate
469 call neko_warning("No mappings selected")
470 end if
471
472 end subroutine mapping_handler_add_json_mappings
473
477 subroutine mapping_handler_add_mapping(this, mapping)
478 class(mapping_handler_t), intent(inout) :: this
479 class(mapping_t), intent(in) :: mapping
480 class(mapping_wrapper_t), dimension(:), allocatable :: temp
481
482 integer :: n_mappings, i
483
484 if (allocated(this%mapping_cascade)) then
485 n_mappings = size(this%mapping_cascade)
486 else
487 n_mappings = 0
488 end if
489
490 call move_alloc(this%mapping_cascade, temp)
491 allocate(this%mapping_cascade(n_mappings + 1))
492
493 if (allocated(temp)) then
494 do i = 1, n_mappings
495 call move_alloc(temp(i)%mapping, this%mapping_cascade(i)%mapping)
496 end do
497 end if
498
499 this%mapping_cascade(n_mappings + 1)%mapping = mapping
500 if (this%output_fields_set) call mapping_handler_setup_outputs(this)
501
502 end subroutine mapping_handler_add_mapping
503
505 pure function mapping_handler_derivative_name(field_name) result(name)
506 character(len=*), intent(in) :: field_name
507 character(len=80) :: name
508
509 name = 'dFd_' // trim(field_name)
510
511 end function mapping_handler_derivative_name
512
515 subroutine mapping_handler_set_stage_names(this)
516 class(mapping_handler_t), intent(inout) :: this
517 integer :: i, j
518 character(len=80) :: previous_name, current_name
519
520 ! Since each mapping stores their unmapped field (for chain rule purposes)
521 ! and stores the name for the mapped field, we need to loop through and
522 ! name them correctly
523 previous_name = trim(this%design_in%name)
524 if (allocated(this%mapping_cascade)) then
525 do i = 1, size(this%mapping_cascade)
526 current_name = trim(this%mapping_cascade(i)%mapping%fld_name)
527 this%mapping_cascade(i)%mapping%X_in%name = trim(previous_name)
528 previous_name = trim(current_name)
529 end do
530 end if
531
532 ! same thing for sensitivities
533 this%sensitivity_out%name = mapping_handler_derivative_name( &
534 this%design_in%name)
535 if (allocated(this%sensitivity_stages)) then
536 this%sensitivity_stages(1)%name = mapping_handler_derivative_name( &
537 this%design_out%name)
538 if (allocated(this%mapping_cascade)) then
539 do i = size(this%mapping_cascade), 1, -1
540 j = size(this%mapping_cascade) - i + 2
541 this%sensitivity_stages(j)%name = &
542 mapping_handler_derivative_name( &
543 this%mapping_cascade(i)%mapping%X_in%name)
544 end do
545 end if
546 end if
547
548 end subroutine mapping_handler_set_stage_names
549
561 subroutine mapping_handler_init_output_fields(this, design_in, design_out, &
562 sensitivity_out, verbose_design, verbose_sensitivity, &
563 output_precision, output_format, forward_file_name, &
564 sensitivity_file_name)
565 class(mapping_handler_t), intent(inout) :: this
566 type(field_t), target, intent(inout) :: design_in
567 type(field_t), target, intent(inout) :: design_out
568 type(field_t), target, intent(inout) :: sensitivity_out
569 logical, intent(in) :: verbose_design
570 logical, intent(in) :: verbose_sensitivity
571 integer, intent(in) :: output_precision
572 character(len=*), intent(in) :: output_format
573 character(len=*), intent(in) :: forward_file_name
574 character(len=*), intent(in) :: sensitivity_file_name
575
576 this%design_in => design_in
577 this%design_out => design_out
578 this%sensitivity_out => sensitivity_out
579 this%verbose_design = verbose_design
580 this%verbose_sensitivity = verbose_sensitivity
581 if (output_precision .ne. sp .and. output_precision .ne. dp) then
582 call neko_error('output_precision must be either sp or dp')
583 end if
584 this%output_precision = output_precision
585 this%output_format = trim(output_format)
586 this%forward_file_name = trim(forward_file_name)
587 this%sensitivity_file_name = trim(sensitivity_file_name)
588 this%output_fields_set = .true.
589
591
592 end subroutine mapping_handler_init_output_fields
593
597 subroutine mapping_handler_write_design(this, idx)
598 class(mapping_handler_t), intent(inout) :: this
599 integer, intent(in) :: idx
600
601 if (.not. this%outputs_initialized) then
602 call neko_error('Mapping design output is not initialized')
603 end if
604 call this%design_output%sample(real(idx, kind=rp))
605
606 end subroutine mapping_handler_write_design
607
611 subroutine mapping_handler_write_sensitivity(this, idx)
612 class(mapping_handler_t), intent(inout) :: this
613 integer, intent(in) :: idx
614
615 if (.not. this%outputs_initialized) then
616 call neko_error('Mapping sensitivity output is not initialized')
617 end if
618 call this%sensitivity_output%sample(real(idx, kind=rp))
619
620 end subroutine mapping_handler_write_sensitivity
621
625 subroutine mapping_handler_set_output_counter(this, idx)
626 class(mapping_handler_t), intent(inout) :: this
627 integer, intent(in) :: idx
628
629 if (.not. this%outputs_initialized) return
630
631 call this%design_output%set_counter(idx)
632 call this%sensitivity_output%set_counter(idx)
633
634 end subroutine mapping_handler_set_output_counter
635
640 subroutine mapping_handler_make_cts(this, fld)
641 class(mapping_handler_t), intent(inout) :: this
642 type(field_t), intent(inout) :: fld
643
644 call this%coef%gs_h%op(fld, gs_op_add)
645 if (neko_bcknd_device .eq. 1) then
646 call device_col2(fld%x_d, this%coef%mult_d, fld%size())
647 else
648 call col2(fld%x, this%coef%mult, fld%size())
649 end if
650
651 end subroutine mapping_handler_make_cts
652end module mapping_handler
mapping factory. Both constructs and initializes the object.
Definition mapping.f90:141
Implements the mapping_handler_t type.
subroutine mapping_handler_setup_outputs(this)
Setup output objects after mappings are known.
Mappings to be applied to a scalar field.
Definition mapping.f90:36
Contains extensions to the neko library required to run the topology optimization code.
Definition neko_ext.f90:42
subroutine, public field_to_vector(vector, field)
Field to vector.
Definition neko_ext.f90:409
subroutine, public vector_to_field(field, vector)
Vector to field.
Definition neko_ext.f90:385
Base abstract class for mapping.
Definition mapping.f90:47
A helper type that is needed to have an array of polymorphic objects.
Definition mapping.f90:76
Abstract class for handling mapping_cascade.