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