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