Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_scalar_scheme.f90
Go to the documentation of this file.
1
34!
36
38 use gather_scatter, only : gs_t
39 use checkpoint, only : chkp_t
40 use checkpoint_payload, only : checkpoint_payload_t
41 use num_types, only: rp
42 use field, only : field_t
43 use field_list, only: field_list_t
44 use space, only : space_t
45 use dofmap, only : dofmap_t
46 use krylov, only : ksp_t, krylov_solver_factory, ksp_max_iter, ksp_monitor_t
47 use coefs, only : coef_t
48 use bc, only : bc_t
49 use bc_list, only : bc_list_t
50 use precon, only : pc_t, precon_factory
51 use field_dirichlet, only: field_dirichlet_t, field_dirichlet_update
52 use mesh, only : mesh_t, neko_msh_max_zlbls, neko_msh_max_zlbl_len
53 use facet_zone, only : facet_zone_t
54 use time_scheme_controller, only : time_scheme_controller_t
55 use logger, only : neko_log, log_size, neko_log_verbose
56 use registry, only : neko_registry
57 use json_utils, only : json_get, json_get_or_default, json_extract_item
58 use json_module, only : json_file
59 use user_intf, only : user_t, dummy_user_material_properties, &
60 user_material_properties_intf
61 use utils, only : neko_error, neko_warning
62 use comm, only: neko_comm
63 use scalar_source_term, only : scalar_source_term_t
64 use field_series, only : field_series_t
65 use math, only : cfill, add2s2
66 use field_math, only : field_cmult, field_col3, field_cfill, field_add2, &
67 field_col2
68 use device_math, only : device_cfill, device_add2s2
69 use neko_config, only : neko_bcknd_device
70 use field_series, only : field_series_t
71 use time_step_controller, only : time_step_controller_t
72 use json_utils_ext, only: json_key_fallback
73 use scalar_scheme, only: scalar_scheme_precon_factory, &
74 scalar_scheme_solver_factory
75 use scratch_registry, only : neko_scratch_registry
76 use time_state, only : time_state_t
77 use device, only : device_memcpy, device_to_host
78 use field_math, only : field_col3, field_cmult2, field_add2, field_cfill
79 use mpi_f08, only: mpi_integer, mpi_sum
80 implicit none
81
83 type, abstract :: adjoint_scalar_scheme_t
85 character(len=:), allocatable :: name
87 character(len=:), allocatable :: primal_name
89 type(field_t), pointer :: u
91 type(field_t), pointer :: v
93 type(field_t), pointer :: w
95 type(field_t), pointer :: s
97 type(field_t), pointer :: s_adj
99 type(field_series_t) :: s_adj_lag
101 type(space_t), pointer :: xh
103 type(dofmap_t), pointer :: dm_xh
105 type(gs_t), pointer :: gs_xh
107 type(coef_t), pointer :: c_xh
109 type(field_t), pointer :: f_xh => null()
111 type(scalar_source_term_t) :: source_term
113 class(ksp_t), allocatable :: ksp
115 integer :: ksp_maxiter
117 integer :: projection_dim
118
119 integer :: projection_activ_step
121 class(pc_t), allocatable :: pc
123 type(bc_list_t) :: bcs
125 type(json_file), pointer :: params
127 type(mesh_t), pointer :: msh => null()
129 type(chkp_t), pointer :: chkp => null()
131 character(len=:), allocatable :: nut_field_name
133 type(field_t), pointer :: rho => null()
135 type(field_t) :: lambda
137 type(field_t) :: cp
139 real(kind=rp) :: pr_turb
141 type(field_list_t) :: material_properties
143 logical :: variable_material_properties = .false.
144 ! Lag arrays for the RHS.
145 type(field_t) :: abx1, abx2
146 procedure(user_material_properties_intf), nopass, pointer :: &
147 user_material_properties => null()
149 logical :: freeze = .false.
150 contains
152 procedure, pass(this) :: scheme_init => adjoint_scalar_scheme_init
154 procedure, pass(this) :: scheme_free => adjoint_scalar_scheme_free
156 procedure, pass(this) :: validate => adjoint_scalar_scheme_validate
158 procedure, pass(this) :: set_material_properties => &
161 procedure, pass(this) :: update_material_properties => &
164 procedure, pass(this) :: register_checkpoint => &
167 procedure(adjoint_scalar_scheme_init_intrf), pass(this), deferred :: init
169 procedure(adjoint_scalar_scheme_free_intrf), pass(this), deferred :: free
171 procedure(adjoint_scalar_scheme_step_intrf), pass(this), deferred :: step
173 procedure(adjoint_scalar_scheme_restart_intrf), pass(this), deferred :: &
174 restart
176
178 abstract interface
179 subroutine adjoint_scalar_scheme_init_intrf(this, msh, coef, gs, &
180 params_adjoint, params_primal, numerics_params, user, chkp, ulag, &
181 vlag, wlag, time_scheme, rho)
183 import json_file
184 import coef_t
185 import gs_t
186 import mesh_t
187 import user_t
188 import field_series_t, field_t
189 import time_scheme_controller_t
190 import rp
191 import chkp_t
192 class(adjoint_scalar_scheme_t), target, intent(inout) :: this
193 type(mesh_t), target, intent(in) :: msh
194 type(coef_t), target, intent(in) :: coef
195 type(gs_t), target, intent(inout) :: gs
196 type(json_file), target, intent(inout) :: params_adjoint
197 type(json_file), target, intent(inout) :: params_primal
198 type(json_file), target, intent(inout) :: numerics_params
199 type(user_t), target, intent(in) :: user
200 type(chkp_t), target, intent(inout) :: chkp
201 type(field_series_t), target, intent(in) :: ulag, vlag, wlag
202 type(time_scheme_controller_t), target, intent(in) :: time_scheme
203 type(field_t), target, intent(in) :: rho
205 end interface
206
208 abstract interface
211 import chkp_t
212 import rp
213 class(adjoint_scalar_scheme_t), target, intent(inout) :: this
214 type(chkp_t), intent(inout) :: chkp
216 end interface
217
219 abstract interface
222 class(adjoint_scalar_scheme_t), intent(inout) :: this
224 end interface
225
227 abstract interface
228 subroutine adjoint_scalar_scheme_step_intrf(this, time, ext_bdf, &
229 dt_controller, ksp_results)
231 import time_state_t
232 import time_scheme_controller_t
233 import time_step_controller_t
234 import ksp_monitor_t
235 class(adjoint_scalar_scheme_t), intent(inout) :: this
236 type(time_state_t), intent(in) :: time
237 type(time_scheme_controller_t), intent(in) :: ext_bdf
238 type(time_step_controller_t), intent(in) :: dt_controller
239 type(ksp_monitor_t), intent(inout) :: ksp_results
241 end interface
242
243contains
244
255 subroutine adjoint_scalar_scheme_init(this, msh, c_Xh, gs_Xh, &
256 params_adjoint, params_primal, scheme, user, rho)
257 class(adjoint_scalar_scheme_t), target, intent(inout) :: this
258 type(mesh_t), target, intent(in) :: msh
259 type(coef_t), target, intent(in) :: c_Xh
260 type(gs_t), target, intent(inout) :: gs_Xh
261 type(json_file), target, intent(inout) :: params_primal, params_adjoint
262 character(len=*), intent(in) :: scheme
263 type(user_t), target, intent(in) :: user
264 type(field_t), target, intent(in) :: rho
265 type(json_file), pointer :: params_selected
266 ! IO buffer for log output
267 character(len=LOG_SIZE) :: log_buf
268 ! Variables for retrieving json parameters
269 logical :: logical_val
270 real(kind=rp) :: solver_abstol
271 integer :: integer_val
272 character(len=:), allocatable :: solver_type, solver_precon
273 type(json_file) :: precon_params
274
275 this%u => neko_registry%get_field('u')
276 this%v => neko_registry%get_field('v')
277 this%w => neko_registry%get_field('w')
278 this%rho => rho
279
280 ! get the primal adjoint's name
281 call json_get_or_default(params_adjoint, 'primal_name', this%primal_name, &
282 's')
283 ! Assign a name
284 call json_get_or_default(params_adjoint, 'name', this%name, &
285 this%primal_name // '_adj')
286
287 call neko_log%section('Adjoint scalar')
288 params_selected => json_key_fallback(params_adjoint, params_primal, &
289 'solver.type')
290 call json_get(params_selected, 'solver.type', solver_type)
291
292 params_selected => json_key_fallback(params_adjoint, params_primal, &
293 'solver.preconditioner.type')
294 call json_get(params_selected, 'solver.preconditioner.type', solver_precon)
295
296 params_selected => json_key_fallback(params_adjoint, params_primal, &
297 'solver.preconditioner')
298 call json_get(params_selected, 'solver.preconditioner', &
299 precon_params)
300
301 params_selected => json_key_fallback(params_adjoint, params_primal, &
302 'solver.absolute_tolerance')
303 call json_get(params_selected, 'solver.absolute_tolerance', &
304 solver_abstol)
305
306 params_selected => json_key_fallback(params_adjoint, params_primal, &
307 'solver.projection_space_size')
308 call json_get_or_default(params_selected, &
309 'solver.projection_space_size', &
310 this%projection_dim, 0)
311
312 params_selected => json_key_fallback(params_adjoint, params_primal, &
313 'solver.projection_hold_steps')
314 call json_get_or_default(params_selected, &
315 'solver.projection_hold_steps', &
316 this%projection_activ_step, 5)
317
318
319 write(log_buf, '(A, A)') 'Type : ', trim(scheme)
320 call neko_log%message(log_buf)
321 write(log_buf, '(A, A)') 'Name : ', trim(this%name)
322 call neko_log%message(log_buf)
323 call neko_log%message('Ksp adjoint scalar : ('// trim(solver_type) // &
324 ', ' // trim(solver_precon) // ')')
325 write(log_buf, '(A,ES13.6)') ' `-abs tol :', solver_abstol
326 call neko_log%message(log_buf)
327
328 this%Xh => this%u%Xh
329 this%dm_Xh => this%u%dof
330 this%params => params_adjoint
331 this%msh => msh
332
333 if (.not. neko_registry%field_exists(this%name)) then
334 call neko_registry%add_field(this%dm_Xh, this%name)
335 end if
336
337 this%s_adj => neko_registry%get_field(this%name)
338
339 call this%s_adj_lag%init(this%s_adj, 2)
340
341 this%s => neko_registry%get_field(this%primal_name)
342
343 this%gs_Xh => gs_xh
344 this%c_Xh => c_xh
345
346 !
347 ! Material properties
348 !
349 call this%set_material_properties(params_primal, user)
350
351
352 !
353 ! Turbulence modelling and variable material properties
354 !
355 params_selected => json_key_fallback(params_adjoint, params_primal, &
356 'variable_material_properties')
357 if (params_selected%valid_path('variable_material_properties')) then
358 call neko_error('variable material properties no supported for adjoint')
359 end if
360
361 write(log_buf, '(A,L1)') 'LES : ', this%variable_material_properties
362 call neko_log%message(log_buf)
363
364 !
365 ! Setup right-hand side field.
366 !
367 allocate(this%f_Xh)
368 call this%f_Xh%init(this%dm_Xh, fld_name = "adjoint_scalar_rhs")
369
370 ! Initialize the source term
371 call this%source_term%init(this%f_Xh, this%c_Xh, user, this%name)
372 ! We should ONLY read the adjoint
373 call this%source_term%add(params_primal, 'source_terms')
374
375 ! todo parameter file ksp tol should be added
376 params_selected => json_key_fallback(params_adjoint, params_primal, &
377 'solver.max_iterations')
378 call json_get_or_default(params_selected, &
379 'solver.max_iterations', &
380 integer_val, ksp_max_iter)
381 params_selected => json_key_fallback(params_adjoint, params_primal, &
382 'solver.monitor')
383 call json_get_or_default(params_selected, &
384 'solver.monitor', &
385 logical_val, .false.)
386 call adjoint_scalar_scheme_solver_factory(this%ksp, this%dm_Xh%size(), &
387 solver_type, integer_val, solver_abstol, logical_val)
388 call scalar_scheme_precon_factory(this%pc, this%ksp, &
389 this%c_Xh, this%bcs, &
390 solver_precon, precon_params)
391
392 call neko_log%end_section()
393
394 end subroutine adjoint_scalar_scheme_init
395
400 class(adjoint_scalar_scheme_t), target, intent(inout) :: this
401 type(chkp_t), intent(inout) :: chkp
402 type(checkpoint_payload_t), pointer :: payload
403
404 payload => chkp%add_payload("adjoint_scalars/" // trim(this%name))
405 call payload%add_field(this%s_adj)
406 call payload%add_series(this%s_adj_lag)
407
409
412 class(adjoint_scalar_scheme_t), intent(inout) :: this
413 class(bc_t), pointer :: bc
414 integer :: i
415
416 bc => null()
417
418 nullify(this%Xh)
419 nullify(this%dm_Xh)
420 nullify(this%gs_Xh)
421 nullify(this%c_Xh)
422 nullify(this%params)
423
424 if (allocated(this%ksp)) then
425 call this%ksp%free()
426 deallocate(this%ksp)
427 end if
428
429 if (allocated(this%pc)) then
430 call this%pc%free()
431 deallocate(this%pc)
432 end if
433
434 call this%source_term%free()
435
436 if (associated(this%f_Xh)) then
437 call this%f_Xh%free()
438 deallocate(this%f_Xh)
439 nullify(this%f_Xh)
440 end if
441
442 do i = 1, this%bcs%size()
443 bc => this%bcs%get(i)
444 if (associated(bc)) then
445 call bc%free()
446 deallocate(bc)
447 end if
448 end do
449
450 call this%bcs%free()
451
452 call this%cp%free()
453 call this%lambda%free()
454 call this%s_adj_lag%free()
455
456 nullify(bc)
457
458 end subroutine adjoint_scalar_scheme_free
459
463 class(adjoint_scalar_scheme_t), target, intent(inout) :: this
464
465 if ( (.not. allocated(this%u%x)) .or. &
466 (.not. allocated(this%v%x)) .or. &
467 (.not. allocated(this%w%x)) .or. &
468 (.not. allocated(this%s%x)) .or. &
469 (.not. allocated(this%s_adj%x))) then
470 call neko_error('Fields are not allocated')
471 end if
472
473 if (.not. allocated(this%ksp)) then
474 call neko_error('No Krylov solver for velocity defined')
475 end if
476
477 if (.not. associated(this%Xh)) then
478 call neko_error('No function space defined')
479 end if
480
481 if (.not. associated(this%dm_Xh)) then
482 call neko_error('No dofmap defined')
483 end if
484
485 if (.not. associated(this%c_Xh)) then
486 call neko_error('No coefficients defined')
487 end if
488
489 if (.not. associated(this%f_Xh)) then
490 call neko_error('No rhs allocated')
491 end if
492
493 if (.not. associated(this%params)) then
494 call neko_error('No parameters defined')
495 end if
496
497 if (.not. associated(this%rho)) then
498 call neko_error('No density field defined')
499 end if
500
501 end subroutine adjoint_scalar_scheme_validate
502
505 subroutine adjoint_scalar_scheme_solver_factory(ksp, n, solver, max_iter, &
506 abstol, monitor)
507 class(ksp_t), allocatable, target, intent(inout) :: ksp
508 integer, intent(in), value :: n
509 integer, intent(in) :: max_iter
510 character(len=*), intent(in) :: solver
511 real(kind=rp) :: abstol
512 logical, intent(in) :: monitor
513
514 call krylov_solver_factory(ksp, n, solver, max_iter, &
515 abstol, monitor = monitor)
516
518
520 subroutine adjoint_scalar_scheme_precon_factory(pc, ksp, coef, &
521 bclst, pctype, json)
522 class(pc_t), allocatable, target, intent(inout) :: pc
523 class(ksp_t), target, intent(inout) :: ksp
524 type(coef_t), target, intent(in) :: coef
525 type(bc_list_t), target, intent(inout) :: bclst
526 character(len=*) :: pctype
527 type(json_file), intent(inout) :: json
528
529 call precon_factory(pc, pctype, coef, bclst, json)
530 call ksp%set_pc(pc)
531
533
539 class(adjoint_scalar_scheme_t), intent(inout) :: this
540 type(time_state_t), intent(in) :: time
541 type(field_t), pointer :: nut
542 integer :: index
543 ! Factor to transform nu_t to lambda_t
544 type(field_t), pointer :: lambda_factor
545
546 call this%user_material_properties(this%name, this%material_properties, &
547 time)
548
549 ! factor = rho * cp / pr_turb
550 if (this%variable_material_properties .and. &
551 len(trim(this%nut_field_name)) > 0) then
552 nut => neko_registry%get_field(this%nut_field_name)
553
554 ! lambda = lambda + rho * cp * nut / pr_turb
555 call neko_scratch_registry%request_field(lambda_factor, index, .false.)
556
557 call field_col3(lambda_factor, this%cp, this%rho)
558 call field_col2(lambda_factor, nut)
559 call field_cmult(lambda_factor, 1.0_rp / this%pr_turb)
560 call field_add2(this%lambda, lambda_factor)
561 call neko_scratch_registry%relinquish_field(index)
562 end if
563
564 ! Since cp is a fields and we use the %x(1,1,1,1) of the
565 ! host array data to pass constant material properties
566 ! to some routines, we need to make sure that the host
567 ! values are also filled
568 if (neko_bcknd_device .eq. 1) then
569 call device_memcpy(this%cp%x, this%cp%x_d, this%cp%size(), &
570 device_to_host, sync=.false.)
571 end if
572
574
580 params_primal, user)
581 class(adjoint_scalar_scheme_t), intent(inout) :: this
582 type(json_file), intent(inout) :: params_primal
583 type(user_t), target, intent(in) :: user
584 character(len=LOG_SIZE) :: log_buf
585 ! A local pointer that is needed to make Intel happy
586 procedure(user_material_properties_intf), pointer :: dummy_mp_ptr
587 real(kind=rp) :: const_cp, const_lambda
588 ! Dummy time state set to 0
589 type(time_state_t) :: time
590
591 dummy_mp_ptr => dummy_user_material_properties
592
593 ! Fill lambda field with the physical value
594 call this%lambda%init(this%dm_Xh, "lambda")
595 call this%cp%init(this%dm_Xh, "cp")
596
597 call this%material_properties%init(2)
598 call this%material_properties%assign_to_field(1, this%cp)
599 call this%material_properties%assign_to_field(2, this%lambda)
600
601 if (.not. associated(user%material_properties, dummy_mp_ptr)) then
602
603 write(log_buf, '(A)') "Material properties must be set in the user " // &
604 "file!"
605 call neko_log%message(log_buf)
606 this%user_material_properties => user%material_properties
607 call user%material_properties(this%name, this%material_properties, time)
608 else
609 this%user_material_properties => dummy_user_material_properties
610 if (params_primal%valid_path('Pe') .and. &
611 (params_primal%valid_path('lambda') .or. &
612 params_primal%valid_path('cp'))) then
613 call neko_error("To set the material properties for the scalar, " // &
614 "either provide Pe OR lambda and cp in the case file.")
615 ! Non-dimensional case
616 else if (params_primal%valid_path('Pe')) then
617 write(log_buf, '(A)') 'Non-dimensional scalar material properties' //&
618 ' input.'
619 call neko_log%message(log_buf, lvl = neko_log_verbose)
620 write(log_buf, '(A)') 'Specific heat capacity will be set to 1,'
621 call neko_log%message(log_buf, lvl = neko_log_verbose)
622 write(log_buf, '(A)') 'conductivity to 1/Pe. Assumes density is 1.'
623 call neko_log%message(log_buf, lvl = neko_log_verbose)
624
625 ! Read Pe into lambda for further manipulation.
626 call json_get(params_primal, 'Pe', const_lambda)
627 write(log_buf, '(A,ES13.6)') 'Pe :', const_lambda
628 call neko_log%message(log_buf)
629
630 ! Set cp and rho to 1 since the setup is non-dimensional.
631 const_cp = 1.0_rp
632 ! Invert the Pe to get conductivity
633 const_lambda = 1.0_rp/const_lambda
634 ! Dimensional case
635 else
636 call json_get(params_primal, 'lambda', const_lambda)
637 call json_get(params_primal, 'cp', const_cp)
638 end if
639 end if
640 ! We need to fill the fields based on the parsed const values
641 ! if the user routine is not used.
642 if (associated(user%material_properties, dummy_mp_ptr)) then
643 ! Fill mu and rho field with the physical value
644 call field_cfill(this%lambda, const_lambda)
645 call field_cfill(this%cp, const_cp)
646
647 write(log_buf, '(A,ES13.6)') 'lambda :', const_lambda
648 call neko_log%message(log_buf)
649 write(log_buf, '(A,ES13.6)') 'cp :', const_cp
650 call neko_log%message(log_buf)
651 end if
652
653 ! Since cp is a field and we use the %x(1,1,1,1) of the
654 ! host array data to pass constant material properties
655 ! to some routines, we need to make sure that the host
656 ! values are also filled
657 if (neko_bcknd_device .eq. 1) then
658 call device_memcpy(this%cp%x, this%cp%x_d, this%cp%size(), &
659 device_to_host, sync=.false.)
660 end if
662
663end module adjoint_scalar_scheme
Abstract interface to dealocate a scalar formulation.
Abstract interface to initialize a scalar formulation.
Abstract interface to restart a scalar formulation.
Contains the adjoint_scalar_scheme_t type.
subroutine adjoint_scalar_scheme_register_checkpoint(this, chkp)
Register this scalar scheme with the checkpoint.
subroutine adjoint_scalar_scheme_set_material_properties(this, params_primal, user)
Set lamdba and cp.
subroutine adjoint_scalar_scheme_init(this, msh, c_xh, gs_xh, params_adjoint, params_primal, scheme, user, rho)
Initialize all related components of the current scheme.
subroutine adjoint_scalar_scheme_solver_factory(ksp, n, solver, max_iter, abstol, monitor)
Initialize a linear solver.
subroutine adjoint_scalar_scheme_precon_factory(pc, ksp, coef, bclst, pctype, json)
Initialize a Krylov preconditioner.
subroutine adjoint_scalar_scheme_update_material_properties(this, time)
Call user material properties routine and update the values of lambda if necessary.
subroutine adjoint_scalar_scheme_free(this)
Deallocate a scalar formulation.
subroutine adjoint_scalar_scheme_validate(this)
Validate that all fields, solvers etc necessary for performing time-stepping are defined.
Base type for a scalar advection-diffusion solver.