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 fld_file_output, only: fld_file_output_t
43 use field_list, only: field_list_t
44 use json_utils, only: json_get, json_extract_item, json_get_or_default
45 use json_module, only: json_file
46 use coefs, only: coef_t
47 use user_intf, only: user_t
48 use field_math, only: field_rzero, field_copy
49 use math, only: col2
50 use device_math, only: device_col2
51 use scratch_registry, only: neko_scratch_registry
52 use utils, only: neko_warning, neko_error
53 use vector, only:vector_t
55 use gather_scatter, only : gs_op_add
56 implicit none
57 private
58
65 type, public :: mapping_handler_t
69 class(mapping_wrapper_t), allocatable :: mapping_cascade(:)
71 type(coef_t), pointer :: coef
73 type(fld_file_output_t) :: design_output
75 type(fld_file_output_t) :: sensitivity_output
77 type(field_t), pointer :: design_out => null()
78 type(field_t), pointer :: sensitivity_out => null()
80 type(field_t), allocatable :: sensitivity_stages(:)
82 logical :: output_fields_set = .false.
83 logical :: outputs_initialized = .false.
85 logical :: verbose_design = .false.
87 logical :: verbose_sensitivity = .false.
89 integer :: output_precision = sp
90
91 contains
93 procedure, pass(this) :: init_base => mapping_handler_init_base
95 procedure, pass(this) :: free => mapping_handler_free
97 generic :: apply_forward => mapping_handler_apply_forward_field, &
98 mapping_handler_apply_forward_vector
99 procedure, pass(this) :: mapping_handler_apply_forward_field
100 procedure, pass(this) :: mapping_handler_apply_forward_vector
103 generic :: apply_backward => mapping_handler_apply_backward_field, &
104 mapping_handler_apply_backward_vector
105 procedure, pass(this) :: mapping_handler_apply_backward_field
106 procedure, pass(this) :: mapping_handler_apply_backward_vector
108 generic :: add => add_mapping, add_json_mappings
110 procedure, pass(this) :: add_mapping => &
111 mapping_handler_add_mapping
113 procedure, pass(this) :: add_json_mappings => &
114 mapping_handler_add_json_mappings
116 procedure, pass(this) :: make_cts => mapping_handler_make_cts
118 procedure, pass(this) :: init_output_fields => &
119 mapping_handler_init_output_fields
121 procedure, pass(this) :: write_design => mapping_handler_write_design
123 procedure, pass(this) :: write_sensitivity => &
124 mapping_handler_write_sensitivity
125 end type mapping_handler_t
126
127contains
128
132 class(mapping_handler_t), intent(inout) :: this
133 integer :: i, n_mappings, n_fields
134
135 if (.not. this%output_fields_set) then
136 call neko_error('Mapping output fields have not been configured')
137 end if
138 if (.not. associated(this%coef)) then
139 call neko_error('Mapping handler coefficients are not initialized')
140 end if
141 if (.not. associated(this%design_out)) then
142 call neko_error('Mapped design output field is not associated')
143 end if
144 if (.not. associated(this%sensitivity_out)) then
145 call neko_error('Sensitivity output field is not associated')
146 end if
147
148 call this%design_output%free()
149 call this%sensitivity_output%free()
150
151 if (allocated(this%sensitivity_stages)) then
152 do i = 1, size(this%sensitivity_stages)
153 call this%sensitivity_stages(i)%free()
154 end do
155 deallocate(this%sensitivity_stages)
156 end if
157
158 n_mappings = 0
159 if (allocated(this%mapping_cascade)) n_mappings = size(this%mapping_cascade)
160
161 if (this%verbose_design) then
162 ! all mapping inputs + mapped output
163 n_fields = n_mappings + 1
164 if (n_fields .le. 0) n_fields = 1
165 else
166 ! only first unmapped stage and mapped output
167 if (n_mappings .gt. 0) then
168 n_fields = 2
169 else
170 n_fields = 1
171 end if
172 end if
173
174 call this%design_output%init(this%output_precision, 'design', n_fields)
175 if (this%verbose_design .and. n_mappings .gt. 0) then
176 do i = 1, n_mappings
177 call this%design_output%fields%assign_to_field(i, &
178 this%mapping_cascade(i)%mapping%X_in)
179 end do
180 call this%design_output%fields%assign_to_field(n_fields, this%design_out)
181 else if (n_mappings .gt. 0) then
182 call this%design_output%fields%assign_to_field(1, &
183 this%mapping_cascade(1)%mapping%X_in)
184 call this%design_output%fields%assign_to_field(2, this%design_out)
185 else
186 call this%design_output%fields%assign_to_field(1, this%design_out)
187 end if
188
189 if (this%verbose_sensitivity) then
190 ! sensitivity_in + chain-rule stages + final sensitivity
191 n_fields = n_mappings + 2
192 allocate(this%sensitivity_stages(n_mappings + 1))
193 do i = 1, n_mappings + 1
194 call this%sensitivity_stages(i)%init(this%coef%dof)
195 end do
196
197 call this%sensitivity_output%init(this%output_precision, &
198 'sensitivity', n_fields)
199 do i = 1, n_mappings + 1
200 call this%sensitivity_output%fields%assign_to_field(i, &
201 this%sensitivity_stages(i))
202 end do
203 call this%sensitivity_output%fields%assign_to_field(n_fields, &
204 this%sensitivity_out)
205 else
206 call this%sensitivity_output%init(this%output_precision, &
207 'sensitivity', 1)
208 call this%sensitivity_output%fields%assign_to_field(1, &
209 this%sensitivity_out)
210 end if
211
212 this%outputs_initialized = .true.
213
214 end subroutine mapping_handler_setup_outputs
215
217 subroutine mapping_handler_init_base(this, coef)
218 class(mapping_handler_t), intent(inout) :: this
219 type(coef_t), target, intent(in) :: coef
220
221 call this%free()
222
223 this%coef => coef
224
225 end subroutine mapping_handler_init_base
226
227
229 subroutine mapping_handler_free(this)
230 class(mapping_handler_t), intent(inout) :: this
231 integer :: i
232
233 if (allocated(this%mapping_cascade)) then
234 do i = 1, size(this%mapping_cascade)
235 call this%mapping_cascade(i)%free()
236 end do
237 deallocate(this%mapping_cascade)
238 end if
239 if (allocated(this%sensitivity_stages)) then
240 do i = 1, size(this%sensitivity_stages)
241 call this%sensitivity_stages(i)%free()
242 end do
243 deallocate(this%sensitivity_stages)
244 end if
245 if (this%outputs_initialized) then
246 call this%design_output%free()
247 call this%sensitivity_output%free()
248 end if
249 this%outputs_initialized = .false.
250 this%output_fields_set = .false.
251 this%output_precision = sp
252 if (associated(this%design_out)) nullify(this%design_out)
253 if (associated(this%sensitivity_out)) nullify(this%sensitivity_out)
254 if (associated(this%coef)) nullify(this%coef)
255
256 end subroutine mapping_handler_free
257
262 subroutine mapping_handler_apply_forward_field(this, X_out, X_in)
263 class(mapping_handler_t), intent(inout) :: this
264 type(field_t), intent(in) :: X_in
265 type(field_t), intent(inout) :: X_out
266 integer :: i
267 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
268 integer :: temp_indices(2)
269
270 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
271 .false.)
272 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
273 .false.)
274
275 ! Start by copying the first X_in into the tmp_fld_out to begin the
276 ! cascade.
277 call field_copy(tmp_fld_out, x_in)
278
279 ! enforce continuity in the field
280 call this%make_cts(tmp_fld_out)
281
282 ! We enter the cascade
283 if (allocated(this%mapping_cascade)) then
284 do i = 1, size(this%mapping_cascade)
285 ! the output from one mapping becomes the input for the next.
286 call field_copy(tmp_fld_in, tmp_fld_out)
287 ! apply the mapping on temp_fld
288 call this%mapping_cascade(i)%mapping%apply_forward(tmp_fld_out, &
289 tmp_fld_in)
290
291 end do
292
293 end if
294
295 ! our final mapping should now live in tmp_fld_out
296 call field_copy(x_out, tmp_fld_out)
297
298 ! free the scratch.
299 call neko_scratch_registry%relinquish_field(temp_indices)
300
301 end subroutine mapping_handler_apply_forward_field
302
307 subroutine mapping_handler_apply_forward_vector(this, X_out, X_in)
308 class(mapping_handler_t), intent(inout) :: this
309 type(vector_t), intent(in) :: X_in
310 type(vector_t), intent(inout) :: X_out
311 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
312 integer :: temp_indices(2)
313
314 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
315 .false.)
316 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
317 .false.)
318
319 call vector_to_field(tmp_fld_in, x_in)
320 call mapping_handler_apply_forward_field(this, tmp_fld_out, tmp_fld_in)
321 call field_to_vector(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_vector
327
334 subroutine mapping_handler_apply_backward_field(this, sens_out, sens_in)
335 class(mapping_handler_t), intent(inout) :: this
336 type(field_t), intent(inout) :: sens_out
337 type(field_t), intent(in) :: sens_in
338 integer :: i
339 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
340 integer :: temp_indices(2)
341
342 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
343 .false.)
344 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
345 .false.)
346
347 ! Start by copying the first sens_in into the tmp_fld_out to begin the
348 ! cascade.
349 call field_copy(tmp_fld_out, sens_in)
350 if (allocated(this%sensitivity_stages)) then
351 call field_copy(this%sensitivity_stages(1), sens_in)
352 end if
353
354 ! enforce continuity in the field
355 call this%make_cts(tmp_fld_out)
356
357 ! We enter the cascade
358 if (allocated(this%mapping_cascade)) then
359 do i = size(this%mapping_cascade), 1, -1
360 ! the output from one mapping becomes the input for the next.
361 call field_copy(tmp_fld_in, tmp_fld_out)
362 ! apply the mapping on temp_fld
363 ! NOTE
364 ! all the X_in that is required to map backward should be held
365 ! internally by each mapping
366 call this%mapping_cascade(i)%mapping%apply_backward(tmp_fld_out, &
367 tmp_fld_in)
368 if (allocated(this%sensitivity_stages)) then
369 call field_copy(this%sensitivity_stages( &
370 size(this%mapping_cascade) - i + 2), tmp_fld_out)
371 end if
372
373 end do
374
375 end if
376
377 ! post-multiply by mass matrix
378 if (neko_bcknd_device .eq. 1) then
379 call device_col2(tmp_fld_out%x_d, this%coef%B_d, tmp_fld_out%size())
380 else
381 call col2(tmp_fld_out%x, this%coef%B, tmp_fld_out%size())
382 end if
383
384 ! our final mapping should now live in tmp_fld_out
385 call field_copy(sens_out, tmp_fld_out)
386
387 ! free the scratch.
388 call neko_scratch_registry%relinquish_field(temp_indices)
389
390
391 end subroutine mapping_handler_apply_backward_field
392
399 subroutine mapping_handler_apply_backward_vector(this, X_out, X_in)
400 class(mapping_handler_t), intent(inout) :: this
401 type(vector_t), intent(in) :: X_in
402 type(vector_t), intent(inout) :: X_out
403 type(field_t), pointer :: tmp_fld_in, tmp_fld_out
404 integer :: temp_indices(2)
405
406 call neko_scratch_registry%request_field(tmp_fld_in, temp_indices(1), &
407 .false.)
408 call neko_scratch_registry%request_field(tmp_fld_out, temp_indices(2), &
409 .false.)
410
411 call vector_to_field(tmp_fld_in, x_in)
412 call mapping_handler_apply_backward_field(this, tmp_fld_out, tmp_fld_in)
413 call field_to_vector(x_out, tmp_fld_out)
414
415 ! free the scratch.
416 call neko_scratch_registry%relinquish_field(temp_indices)
417
418 end subroutine mapping_handler_apply_backward_vector
419
421 subroutine mapping_handler_add_json_mappings(this, json, name)
422 class(mapping_handler_t), intent(inout) :: this
423 type(json_file), intent(inout) :: json
424 character(len=*), intent(in) :: name
425
426 class(mapping_wrapper_t), dimension(:), allocatable :: temp
427
428 ! A single mapping as its own json_file.
429 type(json_file) :: mapping_subdict
430 integer :: n_mappings, i, i0
431
432 if (json%valid_path(name)) then
433 ! Get the number of mapping_cascade.
434 call json%info(name, n_children = n_mappings)
435
436 if (allocated(this%mapping_cascade)) then
437 i0 = size(this%mapping_cascade)
438 call move_alloc(this%mapping_cascade, temp)
439 allocate(this%mapping_cascade(i0 + n_mappings))
440 if (allocated(temp)) then
441 do i = 1, i0
442 call move_alloc(temp(i)%mapping, &
443 this%mapping_cascade(i)%mapping)
444 end do
445 end if
446 else
447 i0 = 0
448 allocate(this%mapping_cascade(n_mappings))
449 end if
450
451 do i = 1, n_mappings
452 ! Create a new json containing just the subdict for this mapping.
453 call json_extract_item(json, name, i, mapping_subdict)
454 call mapping_factory(this%mapping_cascade(i + i0)%mapping, &
455 mapping_subdict, this%coef)
456 end do
457 if (this%output_fields_set) call mapping_handler_setup_outputs(this)
458 else
459 ! I was considering an error, but maybe a warning is more appropriate
460 call neko_warning("No mappings selected")
461 end if
462
463 end subroutine mapping_handler_add_json_mappings
464
468 subroutine mapping_handler_add_mapping(this, mapping)
469 class(mapping_handler_t), intent(inout) :: this
470 class(mapping_t), intent(in) :: mapping
471 class(mapping_wrapper_t), dimension(:), allocatable :: temp
472
473 integer :: n_mappings, i
474
475 if (allocated(this%mapping_cascade)) then
476 n_mappings = size(this%mapping_cascade)
477 else
478 n_mappings = 0
479 end if
480
481 call move_alloc(this%mapping_cascade, temp)
482 allocate(this%mapping_cascade(n_mappings + 1))
483
484 if (allocated(temp)) then
485 do i = 1, n_mappings
486 call move_alloc(temp(i)%mapping, this%mapping_cascade(i)%mapping)
487 end do
488 end if
489
490 this%mapping_cascade(n_mappings + 1)%mapping = mapping
491 if (this%output_fields_set) call mapping_handler_setup_outputs(this)
492
493 end subroutine mapping_handler_add_mapping
494
502 subroutine mapping_handler_init_output_fields(this, design_out, &
503 sensitivity_out, verbose_design, verbose_sensitivity, output_precision)
504 class(mapping_handler_t), intent(inout) :: this
505 type(field_t), target, intent(inout) :: design_out
506 type(field_t), target, intent(inout) :: sensitivity_out
507 logical, intent(in), optional :: verbose_design
508 logical, intent(in), optional :: verbose_sensitivity
509 integer, intent(in), optional :: output_precision
510
511 this%design_out => design_out
512 this%sensitivity_out => sensitivity_out
513 if (present(verbose_design)) this%verbose_design = verbose_design
514 if (present(verbose_sensitivity)) this%verbose_sensitivity = &
515 verbose_sensitivity
516 if (present(output_precision)) then
517 if (output_precision .ne. sp .and. output_precision .ne. dp) then
518 call neko_error('output_precision must be either sp or dp')
519 end if
520 this%output_precision = output_precision
521 end if
522 this%output_fields_set = .true.
523
525
526 end subroutine mapping_handler_init_output_fields
527
531 subroutine mapping_handler_write_design(this, idx)
532 class(mapping_handler_t), intent(inout) :: this
533 integer, intent(in) :: idx
534
535 if (.not. this%outputs_initialized) then
536 call neko_error('Mapping design output is not initialized')
537 end if
538 call this%design_output%sample(real(idx, kind=rp))
539
540 end subroutine mapping_handler_write_design
541
545 subroutine mapping_handler_write_sensitivity(this, idx)
546 class(mapping_handler_t), intent(inout) :: this
547 integer, intent(in) :: idx
548
549 if (.not. this%outputs_initialized) then
550 call neko_error('Mapping sensitivity output is not initialized')
551 end if
552 call this%sensitivity_output%sample(real(idx, kind=rp))
553
554 end subroutine mapping_handler_write_sensitivity
555
560 subroutine mapping_handler_make_cts(this, fld)
561 class(mapping_handler_t), intent(inout) :: this
562 type(field_t), intent(inout) :: fld
563
564 call this%coef%gs_h%op(fld, gs_op_add)
565 if (neko_bcknd_device .eq. 1) then
566 call device_col2(fld%x_d, this%coef%mult_d, fld%size())
567 else
568 call col2(fld%x, this%coef%mult, fld%size())
569 end if
570
571 end subroutine mapping_handler_make_cts
572end module mapping_handler
mapping factory. Both constructs and initializes the object.
Definition mapping.f90:138
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:406
subroutine, public vector_to_field(field, vector)
Vector to field.
Definition neko_ext.f90:382
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:73
Abstract class for handling mapping_cascade.