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 bc_list, only : bc_list_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_factory
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
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
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
102 type(bc_list_t) :: bclst_ds
103
105 class(advection_adjoint_t), allocatable :: adv
106
107 ! Time interpolation scheme
108 logical :: oifs
109
110 ! Advection terms for the oifs method
111 type(field_t) :: advs
112
114 class(scalar_residual_t), allocatable :: res
115
117 class(rhs_maker_ext_t), allocatable :: makeext
118
120 class(rhs_maker_bdf_t), allocatable :: makebdf
121
123 class(rhs_maker_oifs_t), allocatable :: makeoifs
124
125 contains
127 procedure, pass(this) :: init => adjoint_scalar_pnpn_init
129 procedure, pass(this) :: restart => adjoint_scalar_pnpn_restart
131 procedure, pass(this) :: free => adjoint_scalar_pnpn_free
133 procedure, pass(this) :: step => adjoint_scalar_pnpn_step
135 procedure, pass(this) :: setup_bcs_ => adjoint_scalar_pnpn_setup_bcs_
136 end type adjoint_scalar_pnpn_t
137
145 module subroutine adjoint_bc_factory(object, scheme, json, coef, user)
146 class(bc_t), pointer, intent(inout) :: object
147 type(adjoint_scalar_pnpn_t), intent(in) :: scheme
148 type(json_file), intent(inout) :: json
149 type(coef_t), intent(in) :: coef
150 type(user_t), intent(in) :: user
151 end subroutine adjoint_bc_factory
152 end interface adjoint_bc_factory
153
154contains
155
172 subroutine adjoint_scalar_pnpn_init(this, msh, coef, gs, params_adjoint, &
173 params_primal, numerics_params, user, chkp, ulag, vlag, wlag, &
174 time_scheme, rho)
175 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
176 type(mesh_t), target, intent(in) :: msh
177 type(coef_t), target, intent(in) :: coef
178 type(gs_t), target, intent(inout) :: gs
179 type(json_file), target, intent(inout) :: params_adjoint
180 type(json_file), target, intent(inout) :: params_primal
181 type(json_file), target, intent(inout) :: numerics_params
182 type(user_t), target, intent(in) :: user
183 type(chkp_t), target, intent(inout) :: chkp
184 type(field_series_t), target, intent(in) :: ulag, vlag, wlag
185 type(time_scheme_controller_t), target, intent(in) :: time_scheme
186 type(field_t), target, intent(in) :: rho
187 integer :: i
188 class(bc_t), pointer :: bc_i
189 character(len=15), parameter :: scheme = 'Modular (Pn/Pn)'
190 logical :: advection
191
192 call this%free()
193
194 ! Initiliaze base type.
195 call this%scheme_init(msh, coef, gs, params_adjoint, params_primal, &
196 scheme, user, rho)
197
198 ! Setup backend dependent Ax routines
199 call ax_helm_factory(this%ax, full_formulation = .false.)
200
201 ! Setup backend dependent scalar residual routines
202 call scalar_residual_factory(this%res)
203
204 ! Setup backend dependent summation of extrapolation scheme
205 call rhs_maker_ext_fctry(this%makeext)
206
207 ! Setup backend dependent contributions to F from lagged BD terms
208 call rhs_maker_bdf_fctry(this%makebdf)
209
210 ! Setup backend dependent contributions of the OIFS scheme
211 call rhs_maker_oifs_fctry(this%makeoifs)
212
213 ! Initialize variables specific to this plan
214 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
215 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
216
217 call this%s_adj_res%init(dm_xh, "s_adj_res")
218
219 call this%abx1%init(dm_xh, "abx1")
220
221 call this%abx2%init(dm_xh, "abx2")
222
223 call this%advs%init(dm_xh, "advs")
224
225 call this%ds_adj%init(dm_xh, 'ds_adj')
226
227 end associate
228
229 ! Set up boundary conditions
230 call this%setup_bcs_(user)
231
232 ! Initialize dirichlet bcs for scalar residual
233 call this%bc_res%init(this%c_Xh, params_adjoint)
234 do i = 1, this%bcs%size()
235 if (this%bcs%strong(i)) then
236 bc_i => this%bcs%get(i)
237 call this%bc_res%mark_facets(bc_i%marked_facet)
238 end if
239 end do
240
241! call this%bc_res%mark_zones_from_list('d_s', this%bc_labels)
242 call this%bc_res%finalize()
243
244 call this%bclst_ds%init()
245 call this%bclst_ds%append(this%bc_res)
246
247
248 ! Initialize projection space
249 call this%proj_s%init(this%dm_Xh%size(), this%projection_dim, &
250 this%projection_activ_step)
251
252 ! Determine the time-interpolation scheme
253 call json_get_or_default(numerics_params, 'oifs', this%oifs, .false.)
254
255 ! Point to case checkpoint
256 this%chkp => chkp
257
258 ! Initialize advection factory
259 call json_get_or_default(params_adjoint, 'advection', advection, .true.)
260
261 call advection_adjoint_factory(this%adv, numerics_params, this%c_Xh, &
262 ulag, vlag, wlag, this%chkp%dtlag, &
263 this%chkp%tlag, time_scheme, .not. advection, &
264 this%s_adj_lag)
265 ! Add lagged term to checkpoint
266 ! @todo Init chkp object, note, adding 3 slags
267
268 ! Add scalar info to checkpoint
269 ! call this%chkp%add_scalar(this%s)
270 ! this%chkp%abs1 => this%abx1
271 ! this%chkp%abs2 => this%abx2
272 ! this%chkp%slag => this%slag
273
274 end subroutine adjoint_scalar_pnpn_init
275
277 subroutine adjoint_scalar_pnpn_restart(this, chkp)
278 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
279 type(chkp_t), intent(inout) :: chkp
280 real(kind=rp) :: dtlag(10), tlag(10)
281 integer :: n
282 dtlag = chkp%dtlag
283 tlag = chkp%tlag
284
285 n = this%s_adj%dof%size()
286
287 call col2(this%s_adj%x, this%c_Xh%mult, n)
288 call col2(this%s_adj_lag%lf(1)%x, this%c_Xh%mult, n)
289 call col2(this%s_adj_lag%lf(2)%x, this%c_Xh%mult, n)
290 if (neko_bcknd_device .eq. 1) then
291 call device_memcpy(this%s_adj%x, this%s_adj%x_d, &
292 n, host_to_device, sync = .false.)
293 call device_memcpy(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x_d, &
294 n, host_to_device, sync = .false.)
295 call device_memcpy(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x_d, &
296 n, host_to_device, sync = .false.)
297 call device_memcpy(this%abx1%x, this%abx1%x_d, &
298 n, host_to_device, sync = .false.)
299 call device_memcpy(this%abx2%x, this%abx2%x_d, &
300 n, host_to_device, sync = .false.)
301 call device_memcpy(this%advs%x, this%advs%x_d, &
302 n, host_to_device, sync = .false.)
303 end if
304
305 call this%gs_Xh%op(this%s_adj, gs_op_add)
306 call this%gs_Xh%op(this%s_adj_lag%lf(1), gs_op_add)
307 call this%gs_Xh%op(this%s_adj_lag%lf(2), gs_op_add)
308
309 end subroutine adjoint_scalar_pnpn_restart
310
311 subroutine adjoint_scalar_pnpn_free(this)
312 class(adjoint_scalar_pnpn_t), intent(inout) :: this
313
314 !Deallocate scalar field
315 call this%scheme_free()
316
317 call this%bclst_ds%free()
318 call this%bc_res%free()
319 call this%proj_s%free()
320
321 call this%s_adj_res%free()
322
323 call this%ds_adj%free()
324
325 call this%abx1%free()
326 call this%abx2%free()
327
328 call this%advs%free()
329
330 if (allocated(this%Ax)) then
331 deallocate(this%Ax)
332 end if
333
334 if (allocated(this%res)) then
335 deallocate(this%res)
336 end if
337
338 if (allocated(this%makeext)) then
339 deallocate(this%makeext)
340 end if
341
342 if (allocated(this%makebdf)) then
343 deallocate(this%makebdf)
344 end if
345
346 if (allocated(this%makeoifs)) then
347 deallocate(this%makeoifs)
348 end if
349
350 end subroutine adjoint_scalar_pnpn_free
351
352 subroutine adjoint_scalar_pnpn_step(this, time, ext_bdf, dt_controller, &
353 ksp_results)
354 class(adjoint_scalar_pnpn_t), intent(inout) :: this
355 type(time_state_t), intent(in) :: time
356 type(time_scheme_controller_t), intent(in) :: ext_bdf
357 type(time_step_controller_t), intent(in) :: dt_controller
358 type(ksp_monitor_t), intent(inout) :: ksp_results
359 type(field_t), pointer :: rho_cp
360 integer :: rho_cp_index
361 ! Number of degrees of freedom
362 integer :: n
363
364 if (this%freeze) return
365
366 n = this%dm_Xh%size()
367 call neko_scratch_registry%request_field(rho_cp, rho_cp_index, .false.)
368
369 call profiler_start_region('Adjoint Scalar')
370 associate(u => this%u, v => this%v, w => this%w, s_adj => this%s_adj, &
371 cp => this%cp, rho => this%rho, lambda => this%lambda, &
372 ds_adj => this%ds_adj, &
373 s_adj_res => this%s_adj_res, &
374 ax => this%Ax, f_xh => this%f_Xh, xh => this%Xh, &
375 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
376 s_adj_lag => this%s_adj_lag, oifs => this%oifs, &
377 projection_dim => this%projection_dim, &
378 msh => this%msh, res => this%res, makeoifs => this%makeoifs, &
379 makeext => this%makeext, makebdf => this%makebdf, &
380 t => time%t, tstep => time%tstep, dt => time%dt)
381
382 ! Logs extra information the log level is NEKO_LOG_DEBUG or above.
383 call print_debug(this)
384 ! Compute the source terms
385 call this%source_term%compute(time)
386
387 ! Apply weak boundary conditions, that contribute to the source terms.
388 call this%bcs%apply_scalar(this%f_Xh%x, dm_xh%size(), time, .false.)
389
390 ! if (oifs) then
391 ! call neko_error("oifs not implemented for adjoint scalar")
392 ! ! Add the advection operators to the right-hans-side.
393 ! call this%adv%compute_scalar(u, v, w, s_adj, this%advs, &
394 ! Xh, this%c_Xh, dm_Xh%size())
395
396 ! call makeext%compute_scalar(this%abx1, this%abx2, f_Xh%x, rho, &
397 ! ext_bdf%advection_coeffs, n)
398
399 ! call makeoifs%compute_scalar(this%advs%x, f_Xh%x, rho, dt, n)
400 ! else
401 ! Add the advection operators to the right-hans-side.
402 call this%adv%compute_adjoint_scalar(u, v, w, s_adj, f_xh, &
403 xh, this%c_Xh, dm_xh%size())
404
405 ! At this point the RHS contains the sum of the advection operator,
406 ! Neumann boundary sources and additional source terms, evaluated using
407 ! the scalar field from the previous time-step.
408 ! Now, this value is used in the explicit time scheme to advance these
409 ! terms in time.
410 call makeext%compute_scalar(this%abx1, this%abx2, f_xh%x, &
411 ext_bdf%advection_coeffs%x, n)
412
413 ! Add the RHS contributions coming from the BDF scheme.
414 call makebdf%compute_scalar(s_adj_lag, f_xh%x, s_adj, c_xh%B, &
415 rho_cp, dt, ext_bdf%diffusion_coeffs%x, ext_bdf%ndiff, n)
416 ! end if
417
418 call s_adj_lag%update()
419
421 call this%bcs%apply_scalar(this%s_adj%x, this%dm_Xh%size(), time, &
422 .true.)
423
424 ! Update material properties if necessary
425 call this%update_material_properties(time)
426 call field_col3(rho_cp, rho, cp)
427
428 ! Compute scalar residual.
429 call profiler_start_region('Adjoint_scalar_residual')
430 call res%compute(ax, s_adj, s_adj_res, f_xh, c_xh, msh, xh, &
431 lambda, rho_cp, ext_bdf%diffusion_coeffs%x(1), &
432 dt, dm_xh%size())
433
434 call gs_xh%op(s_adj_res, gs_op_add)
435
436
437 ! Apply a 0-valued Dirichlet boundary conditions on the ds_adj.
438 call this%bclst_ds%apply_scalar(s_adj_res%x, dm_xh%size())
439
440 call profiler_end_region('Adjoint_scalar_residual')
441
442 call this%proj_s%pre_solving(s_adj_res%x, tstep, c_xh, n, dt_controller)
443
444 call this%pc%update()
445 call profiler_start_region('Adjoint_scalar_solve')
446 ksp_results = this%ksp%solve(ax, ds_adj, s_adj_res%x, n, &
447 c_xh, this%bclst_ds, gs_xh)
448 call profiler_end_region('Adjoint_scalar_solve')
449
450 ksp_results%name = 'Adjoint Scalar'
451
452 call this%proj_s%post_solving(ds_adj%x, ax, c_xh, this%bclst_ds, gs_xh, &
453 n, tstep, dt_controller)
454
455 ! Update the solution
456 if (neko_bcknd_device .eq. 1) then
457 call device_add2s2(s_adj%x_d, ds_adj%x_d, 1.0_rp, n)
458 else
459 call add2s2(s_adj%x, ds_adj%x, 1.0_rp, n)
460 end if
461
462 end associate
463 call neko_scratch_registry%relinquish_field(rho_cp_index)
464 call profiler_end_region('Adjoint Scalar')
465 end subroutine adjoint_scalar_pnpn_step
466
467 subroutine print_debug(this)
468 class(adjoint_scalar_pnpn_t), intent(inout) :: this
469 ! character(len=LOG_SIZE) :: log_buf
470 integer :: n
471
472 n = this%dm_Xh%size()
473 ! TODO come back to this
474 !write(log_buf,'(A,A,E15.7,A,E15.7,A,E15.7)') 'Adjoint scalar debug', &
475 ! ' l2norm s_adj', glsc2(this%s_adj%x, this%s_adj%x, n), &
476 ! ' slag1', glsc2(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x, n), &
477 ! ' slag2', glsc2(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x, n)
478 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
479 !write(log_buf,'(A,A,E15.7,A,E15.7)') 'Adjoint scalar debug2', &
480 ! ' l2norm abx1', glsc2(this%abx1%x, this%abx1%x, n), &
481 ! ' abx2', glsc2(this%abx2%x, this%abx2%x, n)
482 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
483 end subroutine print_debug
484
488 subroutine adjoint_scalar_pnpn_setup_bcs_(this, user)
489 class(adjoint_scalar_pnpn_t), intent(inout) :: this
490 type(user_t), target, intent(in) :: user
491 integer :: i, j, n_bcs, zone_size, global_zone_size, ierr
492 type(json_core) :: core
493 type(json_value), pointer :: bc_object
494 type(json_file) :: bc_subdict
495 class(bc_t), pointer :: bc_i
496 logical :: found
497 ! Monitor which boundary zones have been marked
498 logical, allocatable :: marked_zones(:)
499 integer, allocatable :: zone_indices(:)
500
501 if (this%params%valid_path('boundary_conditions')) then
502 call this%params%info('boundary_conditions', &
503 n_children = n_bcs)
504 call this%params%get_core(core)
505 call this%params%get('boundary_conditions', bc_object, found)
506
507 call this%bcs%init(n_bcs)
508
509 allocate(marked_zones(size(this%msh%labeled_zones)))
510 marked_zones = .false.
511
512 do i = 1, n_bcs
513 ! Create a new json containing just the subdict for this bc
514 call json_extract_item(core, bc_object, i, bc_subdict)
515
516 ! Check that we are not trying to assing a bc to zone, for which one
517 ! has already been assigned and that the zone has more than 0 size
518 ! in the mesh.
519 call json_get(bc_subdict, "zone_indices", zone_indices)
520
521 do j = 1, size(zone_indices)
522 zone_size = this%msh%labeled_zones(zone_indices(j))%size
523 call mpi_allreduce(zone_size, global_zone_size, 1, &
524 mpi_integer, mpi_max, neko_comm, ierr)
525
526 if (global_zone_size .eq. 0) then
527 write(error_unit, '(A, A, I0, A, A, I0, A)') "*** ERROR ***: ",&
528 "Zone index ", zone_indices(j), &
529 " is invalid as this zone has 0 size, meaning it ", &
530 "does not exist in the mesh. Check adjoint scalar BC ", &
531 i, "."
532 error stop
533 end if
534
535 if (marked_zones(zone_indices(j)) .eqv. .true.) then
536 write(error_unit, '(A, A, I0, A, A, A, A)') "*** ERROR ***: ", &
537 "Zone with index ", zone_indices(j), &
538 " has already been assigned a boundary condition. ", &
539 "Please check your boundary_conditions entry for the ", &
540 "adjoint scalar and make sure that each zone index ", &
541 "appears only in a single boundary condition."
542 error stop
543 else
544 marked_zones(zone_indices(j)) = .true.
545 end if
546 end do
547
548 bc_i => null()
549
550 call adjoint_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
551 call this%bcs%append(bc_i)
552 end do
553
554 ! Make sure all labeled zones with non-zero size have been marked
555 do i = 1, size(this%msh%labeled_zones)
556 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
557 (marked_zones(i) .eqv. .false.)) then
558 write(error_unit, '(A, A, I0)') "*** ERROR ***: ", &
559 "No adjoint scalar boundary condition assigned to zone ", i
560 error stop
561 end if
562 end do
563 else
564 ! Check that there are no labeled zones, i.e. all are periodic.
565 do i = 1, size(this%msh%labeled_zones)
566 if (this%msh%labeled_zones(i)%size .gt. 0) then
567 write(error_unit, '(A, A, A)') "*** ERROR ***: ", &
568 "No boundary_conditions entry in the case file for " // &
569 " adjoint scalar ", &
570 this%s%name
571 error stop
572 end if
573 end do
574 end if
575 end subroutine adjoint_scalar_pnpn_setup_bcs_
576
577end 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.