Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_scalar_pnpn.f90
Go to the documentation of this file.
1
34!
36
38 use comm, only: neko_comm
39 use utils, only: neko_error
40 use num_types, only: rp
41 use, intrinsic :: iso_fortran_env, only: error_unit
42 use rhs_maker, only : rhs_maker_bdf_t, rhs_maker_ext_t, rhs_maker_oifs_t, &
43 rhs_maker_ext_fctry, rhs_maker_bdf_fctry, rhs_maker_oifs_fctry
45 use checkpoint, only : chkp_t
46 use field, only : field_t
47 use scalar_bc_projector, only : scalar_bc_projector_t
48 use mesh, only : mesh_t
49 use coefs, only : coef_t
50 use device, only : host_to_device, device_memcpy
51 use gather_scatter, only : gs_t, gs_op_add
52 use scalar_residual, only : scalar_residual_t, scalar_residual_factory
53 use ax_product, only : ax_t, ax_helm_allocator
54 use field_series, only: field_series_t
55 use facet_normal, only : facet_normal_t
56 use krylov, only : ksp_monitor_t
57 use device_math, only : device_add2s2, device_col2
58 use time_scheme_controller, only : time_scheme_controller_t
59 use projection, only : projection_t
60 use math, only : glsc2, col2, add2s2
61 use field_math, only : field_col3, field_col2
62 use logger, only : neko_log, log_size, neko_log_debug
63 use advection_adjoint, only : advection_adjoint_t, advection_adjoint_factory
64 use profiler, only : profiler_start_region, profiler_end_region
65 use json_utils, only : json_get, json_get_or_default, json_extract_item
66 use json_module, only : json_file, json_core, json_value
67 use user_intf, only : user_t
68 use neko_config, only : neko_bcknd_device
69 use zero_dirichlet, only : zero_dirichlet_t
70 use time_step_controller, only : time_step_controller_t
71 use scratch_registry, only : neko_scratch_registry
72 use time_state, only : time_state_t
73 use bc, only : bc_t, bc_dirichlet
74 use mpi_f08, only: mpi_integer, mpi_sum, mpi_max
75 implicit none
76 private
77
78
80
82 type(field_t) :: s_adj_res
83
85 type(field_t) :: ds_adj
86
88 class(ax_t), allocatable :: ax
89
91 type(projection_t) :: proj_s
92
96 type(zero_dirichlet_t) :: bc_res
97
99 type(scalar_bc_projector_t) :: bc_projector
100
102 class(advection_adjoint_t), allocatable :: adv
103
104 ! Time interpolation scheme
105 logical :: oifs
106
107 ! Advection terms for the oifs method
108 type(field_t) :: advs
109
111 class(scalar_residual_t), allocatable :: res
112
114 class(rhs_maker_ext_t), allocatable :: makeext
115
117 class(rhs_maker_bdf_t), allocatable :: makebdf
118
120 class(rhs_maker_oifs_t), allocatable :: makeoifs
121
122 contains
124 procedure, pass(this) :: init => adjoint_scalar_pnpn_init
126 procedure, pass(this) :: restart => adjoint_scalar_pnpn_restart
128 procedure, pass(this) :: free => adjoint_scalar_pnpn_free
130 procedure, pass(this) :: step => adjoint_scalar_pnpn_step
132 procedure, pass(this) :: setup_bcs_ => adjoint_scalar_pnpn_setup_bcs_
133 end type adjoint_scalar_pnpn_t
134
142 module subroutine adjoint_bc_factory(object, scheme, json, coef, user)
143 class(bc_t), pointer, intent(inout) :: object
144 type(adjoint_scalar_pnpn_t), intent(in) :: scheme
145 type(json_file), intent(inout) :: json
146 type(coef_t), target, intent(in) :: coef
147 type(user_t), target, intent(in) :: user
148 end subroutine adjoint_bc_factory
149 end interface adjoint_bc_factory
150
151contains
152
169 subroutine adjoint_scalar_pnpn_init(this, msh, coef, gs, params_adjoint, &
170 params_primal, numerics_params, user, chkp, ulag, vlag, wlag, &
171 time_scheme, rho)
172 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
173 type(mesh_t), target, intent(in) :: msh
174 type(coef_t), target, intent(in) :: coef
175 type(gs_t), target, intent(inout) :: gs
176 type(json_file), target, intent(inout) :: params_adjoint
177 type(json_file), target, intent(inout) :: params_primal
178 type(json_file), target, intent(inout) :: numerics_params
179 type(user_t), target, intent(in) :: user
180 type(chkp_t), target, intent(inout) :: chkp
181 type(field_series_t), target, intent(in) :: ulag, vlag, wlag
182 type(time_scheme_controller_t), target, intent(in) :: time_scheme
183 type(field_t), target, intent(in) :: rho
184 integer :: i
185 class(bc_t), pointer :: bc_i
186 character(len=15), parameter :: scheme = 'Modular (Pn/Pn)'
187 logical :: advection
188
189 call this%free()
190
191 ! Initiliaze base type.
192 call this%scheme_init(msh, coef, gs, params_adjoint, params_primal, &
193 scheme, user, rho)
194
195 ! Setup backend dependent Ax routines
196 call ax_helm_allocator(this%ax, type_name = "standard")
197
198 ! Setup backend dependent scalar residual routines
199 call scalar_residual_factory(this%res)
200
201 ! Setup backend dependent summation of extrapolation scheme
202 call rhs_maker_ext_fctry(this%makeext)
203
204 ! Setup backend dependent contributions to F from lagged BD terms
205 call rhs_maker_bdf_fctry(this%makebdf)
206
207 ! Setup backend dependent contributions of the OIFS scheme
208 call rhs_maker_oifs_fctry(this%makeoifs)
209
210 ! Initialize variables specific to this plan
211 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
212 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
213
214 call this%s_adj_res%init(dm_xh, "s_adj_res")
215
216 call this%abx1%init(dm_xh, "abx1")
217
218 call this%abx2%init(dm_xh, "abx2")
219
220 call this%advs%init(dm_xh, "advs")
221
222 call this%ds_adj%init(dm_xh, 'ds_adj')
223
224 end associate
225
226 ! Set up boundary conditions
227 call this%setup_bcs_(user)
228
229 ! Initialize dirichlet bcs for scalar residual
230 call this%bc_res%init(this%c_Xh, params_adjoint)
231 do i = 1, this%bcs%size()
232 if (this%bcs%bc_type(i) .eq. bc_dirichlet) then
233 bc_i => this%bcs%get(i)
234 call this%bc_res%mark_facets(bc_i%marked_facet)
235 end if
236 end do
237
238! call this%bc_res%mark_zones_from_list('d_s', this%bc_labels)
239 call this%bc_res%finalize()
240 call this%bc_projector%mark(this%bc_res)
241
242
243 ! Initialize projection space
244 call this%proj_s%init(this%dm_Xh%size(), this%projection_dim, &
245 this%projection_activ_step)
246
247 ! Determine the time-interpolation scheme
248 call json_get_or_default(numerics_params, 'oifs', this%oifs, .false.)
249
250 ! Point to case checkpoint
251 this%chkp => chkp
252
253 ! Initialize advection factory
254 call json_get_or_default(params_adjoint, 'advection', advection, .true.)
255
256 call advection_adjoint_factory(this%adv, numerics_params, this%c_Xh, &
257 ulag, vlag, wlag, this%chkp%dtlag, &
258 this%chkp%tlag, time_scheme, .not. advection, &
259 this%s_adj_lag)
260 ! Add lagged term to checkpoint
261 ! @todo Init chkp object, note, adding 3 slags
262
263 ! Add scalar info to checkpoint
264 ! call this%chkp%add_scalar(this%s)
265 ! this%chkp%abs1 => this%abx1
266 ! this%chkp%abs2 => this%abx2
267 ! this%chkp%slag => this%slag
268
269 end subroutine adjoint_scalar_pnpn_init
270
272 subroutine adjoint_scalar_pnpn_restart(this, chkp)
273 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
274 type(chkp_t), intent(inout) :: chkp
275 real(kind=rp) :: dtlag(10), tlag(10)
276 integer :: n
277 dtlag = chkp%dtlag
278 tlag = chkp%tlag
279
280 n = this%s_adj%dof%size()
281
282 call col2(this%s_adj%x, this%c_Xh%mult, n)
283 call col2(this%s_adj_lag%lf(1)%x, this%c_Xh%mult, n)
284 call col2(this%s_adj_lag%lf(2)%x, this%c_Xh%mult, n)
285 if (neko_bcknd_device .eq. 1) then
286 call device_memcpy(this%s_adj%x, this%s_adj%x_d, &
287 n, host_to_device, sync = .false.)
288 call device_memcpy(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x_d, &
289 n, host_to_device, sync = .false.)
290 call device_memcpy(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x_d, &
291 n, host_to_device, sync = .false.)
292 call device_memcpy(this%abx1%x, this%abx1%x_d, &
293 n, host_to_device, sync = .false.)
294 call device_memcpy(this%abx2%x, this%abx2%x_d, &
295 n, host_to_device, sync = .false.)
296 call device_memcpy(this%advs%x, this%advs%x_d, &
297 n, host_to_device, sync = .false.)
298 end if
299
300 call this%gs_Xh%op(this%s_adj, gs_op_add)
301 call this%gs_Xh%op(this%s_adj_lag%lf(1), gs_op_add)
302 call this%gs_Xh%op(this%s_adj_lag%lf(2), gs_op_add)
303
304 end subroutine adjoint_scalar_pnpn_restart
305
306 subroutine adjoint_scalar_pnpn_free(this)
307 class(adjoint_scalar_pnpn_t), intent(inout) :: this
308
309 !Deallocate scalar field
310 call this%scheme_free()
311
312 call this%bc_projector%free()
313 call this%bc_res%free()
314 call this%proj_s%free()
315
316 call this%s_adj_res%free()
317
318 call this%ds_adj%free()
319
320 call this%abx1%free()
321 call this%abx2%free()
322
323 call this%advs%free()
324
325 if (allocated(this%Ax)) then
326 deallocate(this%Ax)
327 end if
328
329 if (allocated(this%res)) then
330 deallocate(this%res)
331 end if
332
333 if (allocated(this%makeext)) then
334 deallocate(this%makeext)
335 end if
336
337 if (allocated(this%makebdf)) then
338 deallocate(this%makebdf)
339 end if
340
341 if (allocated(this%makeoifs)) then
342 deallocate(this%makeoifs)
343 end if
344
345 end subroutine adjoint_scalar_pnpn_free
346
347 subroutine adjoint_scalar_pnpn_step(this, time, ext_bdf, dt_controller, &
348 ksp_results)
349 class(adjoint_scalar_pnpn_t), intent(inout) :: this
350 type(time_state_t), intent(in) :: time
351 type(time_scheme_controller_t), intent(in) :: ext_bdf
352 type(time_step_controller_t), intent(in) :: dt_controller
353 type(ksp_monitor_t), intent(inout) :: ksp_results
354 type(field_t), pointer :: rho_cp
355 integer :: rho_cp_index
356 ! Number of degrees of freedom
357 integer :: n
358
359 if (this%freeze) return
360
361 n = this%dm_Xh%size()
362 call neko_scratch_registry%request_field(rho_cp, rho_cp_index, .false.)
363
364 call profiler_start_region('Adjoint Scalar')
365 associate(u => this%u, v => this%v, w => this%w, s_adj => this%s_adj, &
366 cp => this%cp, rho => this%rho, lambda => this%lambda, &
367 ds_adj => this%ds_adj, &
368 s_adj_res => this%s_adj_res, &
369 ax => this%Ax, f_xh => this%f_Xh, xh => this%Xh, &
370 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
371 s_adj_lag => this%s_adj_lag, oifs => this%oifs, &
372 projection_dim => this%projection_dim, &
373 msh => this%msh, res => this%res, makeoifs => this%makeoifs, &
374 makeext => this%makeext, makebdf => this%makebdf, &
375 t => time%t, tstep => time%tstep, dt => time%dt)
376
377 ! Logs extra information the log level is NEKO_LOG_DEBUG or above.
378 call print_debug(this)
379
380 ! Update material properties and their pointwise product.
381 ! This MUST happen before rho_cp is used below (by makebdf and by the
382 ! source/advection scaling). It used to sit after those uses, which left
383 ! makebdf reading an uninitialised scratch field while res%compute used
384 ! the correct value -- so the BDF mass terms could not cancel at steady
385 ! state and the converged adjoint scalar came out proportional to dt.
386 ! Mirrors the ordering in Neko's forward scalar_pnpn.
387 call this%update_material_properties(time)
388 call field_col3(rho_cp, rho, cp)
389
390 ! Compute the source terms
391 call this%source_term%compute(time)
392
393 ! if (oifs) then
394 ! call neko_error("oifs not implemented for adjoint scalar")
395 ! ! Add the advection operators to the right-hans-side.
396 ! call this%adv%compute_scalar(u, v, w, s_adj, this%advs, &
397 ! Xh, this%c_Xh, dm_Xh%size())
398
399 ! call makeext%compute_scalar(this%abx1, this%abx2, f_Xh%x, rho, &
400 ! ext_bdf%advection_coeffs, n)
401
402 ! call makeoifs%compute_scalar(this%advs%x, f_Xh%x, rho, dt, n)
403 ! else
404 ! Add the advection operators to the right-hans-side.
405 call this%adv%compute_adjoint_scalar(u, v, w, s_adj, f_xh, &
406 xh, this%c_Xh, dm_xh%size())
407
408 ! Scale the volumetric source and advection terms by rho * cp, then add
409 ! the weak boundary fluxes without that scaling -- same split as the
410 ! forward scalar. (The weak BC application was previously done before
411 ! the advection term and never scaled, so it could not follow this
412 ! convention.)
413 call field_col2(f_xh, rho_cp)
414
415 ! Apply weak boundary conditions, that contribute to the source terms.
416 call this%bcs%apply_scalar(this%f_Xh%x, dm_xh%size(), time, .false.)
417
418 ! At this point the RHS contains the sum of the advection operator,
419 ! Neumann boundary sources and additional source terms, evaluated using
420 ! the scalar field from the previous time-step.
421 ! Now, this value is used in the explicit time scheme to advance these
422 ! terms in time.
423 call makeext%compute_scalar(this%abx1, this%abx2, f_xh%x, &
424 ext_bdf%advection_coeffs%x, n)
425
426 ! Add the RHS contributions coming from the BDF scheme.
427 call makebdf%compute_scalar(s_adj_lag, f_xh%x, s_adj, c_xh%B, &
428 rho_cp, dt, ext_bdf%diffusion_coeffs%x, ext_bdf%ndiff, n)
429 ! end if
430
431 call s_adj_lag%update()
432
434 call this%bcs%apply_scalar(this%s_adj%x, this%dm_Xh%size(), time, &
435 .true.)
436
437 ! Compute scalar residual.
438 call profiler_start_region('Adjoint_scalar_residual')
439 call res%compute(ax, s_adj, s_adj_res, f_xh, c_xh, msh, xh, &
440 lambda, rho_cp, ext_bdf%diffusion_coeffs%x(1), &
441 dt, dm_xh%size())
442
443 call gs_xh%op(s_adj_res, gs_op_add)
444
445
446 ! Apply a 0-valued Dirichlet boundary conditions on the ds_adj.
447 call this%bc_projector%apply(s_adj_res%x, dm_xh%size())
448
449 call profiler_end_region('Adjoint_scalar_residual')
450
451 call this%proj_s%pre_solving(s_adj_res%x, tstep, c_xh, n, dt_controller)
452
453 call this%pc%update()
454 call profiler_start_region('Adjoint_scalar_solve')
455 ksp_results = this%ksp%solve(ax, ds_adj, s_adj_res%x, n, &
456 c_xh, this%bc_projector, gs_xh)
457 call profiler_end_region('Adjoint_scalar_solve')
458
459 ksp_results%name = 'Adjoint Scalar'
460
461 call this%proj_s%post_solving(ds_adj%x, ax, c_xh, this%bc_projector, &
462 gs_xh, n, tstep, dt_controller)
463
464 ! Update the solution
465 if (neko_bcknd_device .eq. 1) then
466 call device_add2s2(s_adj%x_d, ds_adj%x_d, 1.0_rp, n)
467 else
468 call add2s2(s_adj%x, ds_adj%x, 1.0_rp, n)
469 end if
470
471 end associate
472 call neko_scratch_registry%relinquish_field(rho_cp_index)
473 call profiler_end_region('Adjoint Scalar')
474 end subroutine adjoint_scalar_pnpn_step
475
476 subroutine print_debug(this)
477 class(adjoint_scalar_pnpn_t), intent(inout) :: this
478 ! character(len=LOG_SIZE) :: log_buf
479 integer :: n
480
481 n = this%dm_Xh%size()
482 ! TODO come back to this
483 !write(log_buf,'(A,A,E15.7,A,E15.7,A,E15.7)') 'Adjoint scalar debug', &
484 ! ' l2norm s_adj', glsc2(this%s_adj%x, this%s_adj%x, n), &
485 ! ' slag1', glsc2(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x, n), &
486 ! ' slag2', glsc2(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x, n)
487 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
488 !write(log_buf,'(A,A,E15.7,A,E15.7)') 'Adjoint scalar debug2', &
489 ! ' l2norm abx1', glsc2(this%abx1%x, this%abx1%x, n), &
490 ! ' abx2', glsc2(this%abx2%x, this%abx2%x, n)
491 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
492 end subroutine print_debug
493
497 subroutine adjoint_scalar_pnpn_setup_bcs_(this, user)
498 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
499 type(user_t), target, intent(in) :: user
500 integer :: i, j, n_bcs, zone_size, global_zone_size, ierr
501 type(json_core) :: core
502 type(json_value), pointer :: bc_object
503 type(json_file) :: bc_subdict
504 class(bc_t), pointer :: bc_i
505 logical :: found
506 ! Monitor which boundary zones have been marked
507 logical, allocatable :: marked_zones(:)
508 integer, allocatable :: zone_indices(:)
509
510 if (this%params%valid_path('boundary_conditions')) then
511 call this%params%info('boundary_conditions', &
512 n_children = n_bcs)
513 call this%params%get_core(core)
514 call this%params%get('boundary_conditions', bc_object, found)
515
516 call this%bcs%init(n_bcs)
517
518 allocate(marked_zones(size(this%msh%labeled_zones)))
519 marked_zones = .false.
520
521 do i = 1, n_bcs
522 ! Create a new json containing just the subdict for this bc
523 call json_extract_item(core, bc_object, i, bc_subdict)
524
525 ! Check that we are not trying to assing a bc to zone, for which one
526 ! has already been assigned and that the zone has more than 0 size
527 ! in the mesh.
528 call json_get(bc_subdict, "zone_indices", zone_indices)
529
530 do j = 1, size(zone_indices)
531 zone_size = this%msh%labeled_zones(zone_indices(j))%size
532 call mpi_allreduce(zone_size, global_zone_size, 1, &
533 mpi_integer, mpi_max, neko_comm, ierr)
534
535 if (global_zone_size .eq. 0) then
536 write(error_unit, '(A, A, I0, A, A, I0, A)') "*** ERROR ***: ",&
537 "Zone index ", zone_indices(j), &
538 " is invalid as this zone has 0 size, meaning it ", &
539 "does not exist in the mesh. Check adjoint scalar BC ", &
540 i, "."
541 error stop
542 end if
543
544 if (marked_zones(zone_indices(j)) .eqv. .true.) then
545 write(error_unit, '(A, A, I0, A, A, A, A)') "*** ERROR ***: ", &
546 "Zone with index ", zone_indices(j), &
547 " has already been assigned a boundary condition. ", &
548 "Please check your boundary_conditions entry for the ", &
549 "adjoint scalar and make sure that each zone index ", &
550 "appears only in a single boundary condition."
551 error stop
552 else
553 marked_zones(zone_indices(j)) = .true.
554 end if
555 end do
556
557 bc_i => null()
558
559 call adjoint_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
560 call this%bcs%append(bc_i)
561 end do
562
563 ! Make sure all labeled zones with non-zero size have been marked
564 do i = 1, size(this%msh%labeled_zones)
565 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
566 (marked_zones(i) .eqv. .false.)) then
567 write(error_unit, '(A, A, I0)') "*** ERROR ***: ", &
568 "No adjoint scalar boundary condition assigned to zone ", i
569 error stop
570 end if
571 end do
572 else
573 ! Check that there are no labeled zones, i.e. all are periodic.
574 do i = 1, size(this%msh%labeled_zones)
575 if (this%msh%labeled_zones(i)%size .gt. 0) then
576 write(error_unit, '(A, A, A)') "*** ERROR ***: ", &
577 "No boundary_conditions entry in the case file for " // &
578 " adjoint scalar ", &
579 this%s%name
580 error stop
581 end if
582 end do
583 end if
584 end subroutine adjoint_scalar_pnpn_setup_bcs_
585
586end module adjoint_scalar_pnpn
Boundary condition factory. Both constructs and initializes the object.
Contains the adjoint_scalar_pnpn_t type.
Contains the adjoint_scalar_scheme_t type.
Subroutines to add advection terms to the RHS of a transport equation.
Base type for a scalar advection-diffusion solver.
Base abstract type for computing the advection operator.