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 call this%design_output%free()
163 call this%sensitivity_output%free()
164
165 if (allocated(this%sensitivity_stages)) then
166 do i = 1, size(this%sensitivity_stages)
167 call this%sensitivity_stages(i)%free()
168 end do
169 deallocate(this%sensitivity_stages)
170 end if
171
172 n_mappings = 0
173 if (allocated(this%mapping_cascade)) n_mappings = size(this%mapping_cascade)
174
175 if (this%verbose_design) then
176 ! all mapping inputs + mapped output
177 n_fields = n_mappings + 1
178 if (n_fields .le. 0) n_fields = 1
179 else
180 ! only first unmapped stage and mapped output
181 if (n_mappings .gt. 0) then
182 n_fields = 2
183 else
184 n_fields = 1
185 end if
186 end if
187
188 call this%design_output%init(trim(this%forward_file_name), n_fields, &
189 precision = this%output_precision, &
190 format = trim(this%output_format))
191 if (this%verbose_design .and. n_mappings .gt. 0) then
192 do i = 1, n_mappings
193 call this%design_output%fields%assign_to_field(i, &
194 this%mapping_cascade(i)%mapping%X_in)
195 end do
196 call this%design_output%fields%assign_to_field(n_fields, this%design_out)
197 else if (n_mappings .gt. 0) then
198 call this%design_output%fields%assign_to_field(1, &
199 this%mapping_cascade(1)%mapping%X_in)
200 call this%design_output%fields%assign_to_field(2, this%design_out)
201 else
202 call this%design_output%fields%assign_to_field(1, this%design_out)
203 end if
204
205 if (this%verbose_sensitivity) then
206 ! sensitivity_in + chain-rule stages + final sensitivity
207 n_fields = n_mappings + 2
208 allocate(this%sensitivity_stages(n_mappings + 1))
209 do i = 1, n_mappings + 1
210 call this%sensitivity_stages(i)%init(this%coef%dof)
211 end do
212 call this%set_stage_names()
213 call this%sensitivity_output%init( &
214 trim(this%sensitivity_file_name), n_fields, &
215 precision = this%output_precision, &
216 format = trim(this%output_format))
217 do i = 1, n_mappings + 1
218 call this%sensitivity_output%fields%assign_to_field(i, &
219 this%sensitivity_stages(i))
220 end do
221 call this%sensitivity_output%fields%assign_to_field(n_fields, &
222 this%sensitivity_out)
223 else
224 call this%set_stage_names()
225 call this%sensitivity_output%init( &
226 trim(this%sensitivity_file_name), 1, &
227 precision = this%output_precision, &
228 format = trim(this%output_format))
229 call this%sensitivity_output%fields%assign_to_field(1, &
230 this%sensitivity_out)
231 end if
232
233 this%outputs_initialized = .true.
234
235 end subroutine mapping_handler_setup_outputs
236
238 subroutine mapping_handler_init_base(this, coef)
239 class(mapping_handler_t), intent(inout) :: this
240 type(coef_t), target, intent(in) :: coef
241
242 call this%free()
243
244 this%coef => coef
245
246 end subroutine mapping_handler_init_base
247
248
250 subroutine mapping_handler_free(this)
251 class(mapping_handler_t), intent(inout) :: this
252 integer :: i
253
254 if (allocated(this%mapping_cascade)) then
255 do i = 1, size(this%mapping_cascade)
256 call this%mapping_cascade(i)%free()
257 end do
258 deallocate(this%mapping_cascade)
259 end if
260 if (allocated(this%sensitivity_stages)) then
261 do i = 1, size(this%sensitivity_stages)
262 call this%sensitivity_stages(i)%free()
263 end do
264 deallocate(this%sensitivity_stages)
265 end if
266 if (this%outputs_initialized) then
267 call this%design_output%free()
268 call this%sensitivity_output%free()
269 end if
270 this%outputs_initialized = .false.
271 this%output_fields_set = .false.
272 this%output_precision = sp
273 this%output_format = 'fld'
274 this%forward_file_name = ''
275 this%sensitivity_file_name = ''
276 if (associated(this%design_in)) nullify(this%design_in)
277 if (associated(this%design_out)) nullify(this%design_out)
278 if (associated(this%sensitivity_out)) nullify(this%sensitivity_out)
279 if (associated(this%coef)) nullify(this%coef)
280
281 end subroutine mapping_handler_free
282
287 subroutine mapping_handler_apply_forward_field(this, X_out, X_in)
288 class(mapping_handler_t), intent(inout) :: this
289 type(field_t), intent(in) :: X_in
290 type(field_t), intent(inout) :: X_out
291 integer :: i
292 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
293 integer :: temp_indices(2)
294
295 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
296 .false.)
297 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
298 .false.)
299
300 ! Start by copying the first X_in into the tmp_fld_out to begin the
301 ! cascade.
302 call field_copy(tmp_fld_out, x_in)
303
304 ! enforce continuity in the field
305 call this%make_cts(tmp_fld_out)
306
307 ! We enter the cascade
308 if (allocated(this%mapping_cascade)) then
309 do i = 1, size(this%mapping_cascade)
310 ! the output from one mapping becomes the input for the next.
311 call field_copy(tmp_fld_in, tmp_fld_out)
312 ! apply the mapping on temp_fld
313 call this%mapping_cascade(i)%mapping%apply_forward(tmp_fld_out, &
314 tmp_fld_in)
315
316 end do
317
318 end if
319
320 ! our final mapping should now live in tmp_fld_out
321 call field_copy(x_out, tmp_fld_out)
322
323 ! free the scratch.
324 call neko_scratch_registry%relinquish_field(temp_indices)
325
326 end subroutine mapping_handler_apply_forward_field
327
332 subroutine mapping_handler_apply_forward_vector(this, X_out, X_in)
333 class(mapping_handler_t), intent(inout) :: this
334 type(vector_t), intent(in) :: X_in
335 type(vector_t), intent(inout) :: X_out
336 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
337 integer :: temp_indices(2)
338
339 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
340 .false.)
341 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
342 .false.)
343
344 call vector_to_field(tmp_fld_in, x_in)
345 call mapping_handler_apply_forward_field(this, tmp_fld_out, tmp_fld_in)
346 call field_to_vector(x_out, tmp_fld_out)
347
348 ! free the scratch.
349 call neko_scratch_registry%relinquish_field(temp_indices)
350
351 end subroutine mapping_handler_apply_forward_vector
352
359 subroutine mapping_handler_apply_backward_field(this, sens_out, sens_in)
360 class(mapping_handler_t), intent(inout) :: this
361 type(field_t), intent(inout) :: sens_out
362 type(field_t), intent(in) :: sens_in
363 integer :: i
364 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
365 integer :: temp_indices(2)
366
367 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
368 .false.)
369 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
370 .false.)
371
372 ! Start by copying the first sens_in into the tmp_fld_out to begin the
373 ! cascade.
374 call field_copy(tmp_fld_out, sens_in)
375 if (allocated(this%sensitivity_stages)) then
376 call field_copy(this%sensitivity_stages(1), sens_in)
377 end if
378
379 ! enforce continuity in the field
380 call this%make_cts(tmp_fld_out)
381
382 ! We enter the cascade
383 if (allocated(this%mapping_cascade)) then
384 do i = size(this%mapping_cascade), 1, -1
385 ! the output from one mapping becomes the input for the next.
386 call field_copy(tmp_fld_in, tmp_fld_out)
387 ! apply the mapping on temp_fld
388 ! NOTE
389 ! all the X_in that is required to map backward should be held
390 ! internally by each mapping
391 call this%mapping_cascade(i)%mapping%apply_backward(tmp_fld_out, &
392 tmp_fld_in)
393 if (allocated(this%sensitivity_stages)) then
394 call field_copy(this%sensitivity_stages( &
395 size(this%mapping_cascade) - i + 2), tmp_fld_out)
396 end if
397
398 end do
399
400 end if
401
402 ! our final mapping should now live in tmp_fld_out
403 call field_copy(sens_out, tmp_fld_out)
404
405 ! free the scratch.
406 call neko_scratch_registry%relinquish_field(temp_indices)
407
408
409 end subroutine mapping_handler_apply_backward_field
410
417 subroutine mapping_handler_apply_backward_vector(this, X_out, X_in)
418 class(mapping_handler_t), intent(inout) :: this
419 type(vector_t), intent(in) :: X_in
420 type(vector_t), intent(inout) :: X_out
421 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
422 integer :: temp_indices(2)
423
424 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
425 .false.)
426 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
427 .false.)
428
429 call vector_to_field(tmp_fld_in, x_in)
430 call mapping_handler_apply_backward_field(this, tmp_fld_out, tmp_fld_in)
431 call field_to_vector(x_out, tmp_fld_out)
432
433 ! free the scratch.
434 call neko_scratch_registry%relinquish_field(temp_indices)
435
436 end subroutine mapping_handler_apply_backward_vector
437
439 subroutine mapping_handler_add_json_mappings(this, json, name)
440 class(mapping_handler_t), intent(inout) :: this
441 type(json_file), intent(inout) :: json
442 character(len=*), intent(in) :: name
443
444 class(mapping_wrapper_t), dimension(:), allocatable :: temp
445
446 ! A single mapping as its own json_file.
447 type(json_file) :: mapping_subdict
448 integer :: n_mappings, i, i0
449
450 if (json%valid_path(name)) then
451 ! Get the number of mapping_cascade.
452 call json%info(name, n_children = n_mappings)
453
454 if (allocated(this%mapping_cascade)) then
455 i0 = size(this%mapping_cascade)
456 call move_alloc(this%mapping_cascade, temp)
457 allocate(this%mapping_cascade(i0 + n_mappings))
458 if (allocated(temp)) then
459 do i = 1, i0
460 call move_alloc(temp(i)%mapping, &
461 this%mapping_cascade(i)%mapping)
462 end do
463 end if
464 else
465 i0 = 0
466 allocate(this%mapping_cascade(n_mappings))
467 end if
468
469 do i = 1, n_mappings
470 ! Create a new json containing just the subdict for this mapping.
471 call json_extract_item(json, name, i, mapping_subdict)
472 call mapping_factory(this%mapping_cascade(i + i0)%mapping, &
473 mapping_subdict, this%coef)
474 end do
475 if (this%output_fields_set) call mapping_handler_setup_outputs(this)
476 else
477 ! I was considering an error, but maybe a warning is more appropriate
478 call neko_warning("No mappings selected")
479 end if
480
481 end subroutine mapping_handler_add_json_mappings
482
486 subroutine mapping_handler_add_mapping(this, mapping)
487 class(mapping_handler_t), intent(inout) :: this
488 class(mapping_t), intent(in) :: mapping
489 class(mapping_wrapper_t), dimension(:), allocatable :: temp
490
491 integer :: n_mappings, i
492
493 if (allocated(this%mapping_cascade)) then
494 n_mappings = size(this%mapping_cascade)
495 else
496 n_mappings = 0
497 end if
498
499 call move_alloc(this%mapping_cascade, temp)
500 allocate(this%mapping_cascade(n_mappings + 1))
501
502 if (allocated(temp)) then
503 do i = 1, n_mappings
504 call move_alloc(temp(i)%mapping, this%mapping_cascade(i)%mapping)
505 end do
506 end if
507
508 this%mapping_cascade(n_mappings + 1)%mapping = mapping
509 if (this%output_fields_set) call mapping_handler_setup_outputs(this)
510
511 end subroutine mapping_handler_add_mapping
512
514 pure function mapping_handler_derivative_name(field_name) result(name)
515 character(len=*), intent(in) :: field_name
516 character(len=80) :: name
517
518 name = 'dFd_' // trim(field_name)
519
520 end function mapping_handler_derivative_name
521
524 subroutine mapping_handler_set_stage_names(this)
525 class(mapping_handler_t), intent(inout) :: this
526 integer :: i, j
527 character(len=80) :: previous_name
528
529 ! Since each mapping stores their unmapped field (for chain rule purposes)
530 ! and stores the name for the mapped field, we need to loop through and
531 ! name them correctly
532 previous_name = trim(this%design_in%name)
533 if (allocated(this%mapping_cascade)) then
534 do i = 1, size(this%mapping_cascade)
535 this%mapping_cascade(i)%mapping%X_in%name = trim(previous_name)
536 previous_name = trim(this%mapping_cascade(i)%mapping%fld_name)
537 end do
538 end if
539
540 ! same thing for sensitivities
541 this%sensitivity_out%name = mapping_handler_derivative_name( &
542 this%design_in%name)
543 if (allocated(this%sensitivity_stages)) then
544 this%sensitivity_stages(1)%name = mapping_handler_derivative_name( &
545 this%design_out%name)
546 if (allocated(this%mapping_cascade)) then
547 do i = size(this%mapping_cascade), 1, -1
548 j = size(this%mapping_cascade) - i + 2
549 this%sensitivity_stages(j)%name = &
550 mapping_handler_derivative_name( &
551 this%mapping_cascade(i)%mapping%X_in%name)
552 end do
553 end if
554 end if
555
556 end subroutine mapping_handler_set_stage_names
557
569 subroutine mapping_handler_init_output_fields(this, design_in, design_out, &
570 sensitivity_out, verbose_design, verbose_sensitivity, &
571 output_precision, output_format, forward_file_name, &
572 sensitivity_file_name)
573 class(mapping_handler_t), intent(inout) :: this
574 type(field_t), target, intent(inout) :: design_in
575 type(field_t), target, intent(inout) :: design_out
576 type(field_t), target, intent(inout) :: sensitivity_out
577 logical, intent(in) :: verbose_design
578 logical, intent(in) :: verbose_sensitivity
579 integer, intent(in) :: output_precision
580 character(len=*), intent(in) :: output_format
581 character(len=*), intent(in) :: forward_file_name
582 character(len=*), intent(in) :: sensitivity_file_name
583
584 this%design_in => design_in
585 this%design_out => design_out
586 this%sensitivity_out => sensitivity_out
587 this%verbose_design = verbose_design
588 this%verbose_sensitivity = verbose_sensitivity
589 if (output_precision .ne. sp .and. output_precision .ne. dp) then
590 call neko_error('output_precision must be either sp or dp')
591 end if
592 this%output_precision = output_precision
593 this%output_format = trim(output_format)
594 this%forward_file_name = trim(forward_file_name)
595 this%sensitivity_file_name = trim(sensitivity_file_name)
596 this%output_fields_set = .true.
597
599
600 end subroutine mapping_handler_init_output_fields
601
605 subroutine mapping_handler_write_design(this, idx)
606 class(mapping_handler_t), intent(inout) :: this
607 integer, intent(in) :: idx
608
609 if (.not. this%outputs_initialized) then
610 call neko_error('Mapping design output is not initialized')
611 end if
612 call this%design_output%sample(real(idx, kind=rp))
613
614 end subroutine mapping_handler_write_design
615
619 subroutine mapping_handler_write_sensitivity(this, idx)
620 class(mapping_handler_t), intent(inout) :: this
621 integer, intent(in) :: idx
622
623 if (.not. this%outputs_initialized) then
624 call neko_error('Mapping sensitivity output is not initialized')
625 end if
626 call this%sensitivity_output%sample(real(idx, kind=rp))
627
628 end subroutine mapping_handler_write_sensitivity
629
633 subroutine mapping_handler_set_output_counter(this, idx)
634 class(mapping_handler_t), intent(inout) :: this
635 integer, intent(in) :: idx
636
637 if (.not. this%outputs_initialized) return
638
639 call this%design_output%set_counter(idx)
640 call this%sensitivity_output%set_counter(idx)
641
642 end subroutine mapping_handler_set_output_counter
643
648 subroutine mapping_handler_make_cts(this, fld)
649 class(mapping_handler_t), intent(inout) :: this
650 type(field_t), intent(inout) :: fld
651
652 call this%coef%gs_h%op(fld, gs_op_add)
653 if (neko_bcknd_device .eq. 1) then
654 call device_col2(fld%x_d, this%coef%mult_d, fld%size())
655 else
656 call col2(fld%x, this%coef%mult, fld%size())
657 end if
658
659 end subroutine mapping_handler_make_cts
660end module mapping_handler
mapping factory. Both constructs and initializes the object.
Definition mapping.f90:140
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:46
A helper type that is needed to have an array of polymorphic objects.
Definition mapping.f90:75
Abstract class for handling mapping_cascade.