Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_scalar_pnpn.f90
1! Copyright (c) 2022-2024, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
34
36 use comm, only: neko_comm
37 use utils, only: neko_error
38 use num_types, only: rp
39 use, intrinsic :: iso_fortran_env, only: error_unit
40 use rhs_maker, only : rhs_maker_bdf_t, rhs_maker_ext_t, rhs_maker_oifs_t, &
41 rhs_maker_ext_fctry, rhs_maker_bdf_fctry, rhs_maker_oifs_fctry
43 use checkpoint, only : chkp_t
44 use field, only : field_t
45 use bc_list, only : bc_list_t
46 use mesh, only : mesh_t
47 use coefs, only : coef_t
48 use device, only : host_to_device, device_memcpy
49 use gather_scatter, only : gs_t, gs_op_add
50 use scalar_residual, only : scalar_residual_t, scalar_residual_factory
51 use ax_product, only : ax_t, ax_helm_factory
52 use field_series, only: field_series_t
53 use facet_normal, only : facet_normal_t
54 use krylov, only : ksp_monitor_t
55 use device_math, only : device_add2s2, device_col2
56 use time_scheme_controller, only : time_scheme_controller_t
57 use projection, only : projection_t
58 use math, only : glsc2, col2, add2s2
59 use logger, only : neko_log, log_size, neko_log_debug
60 use advection_adjoint, only : advection_adjoint_t, advection_adjoint_factory
61 use profiler, only : profiler_start_region, profiler_end_region
62 use json_utils, only : json_get, json_get_or_default, json_extract_item
63 use json_module, only : json_file, json_core, json_value
64 use user_intf, only : user_t
65 use neko_config, only : neko_bcknd_device
66 use zero_dirichlet, only : zero_dirichlet_t
67 use time_step_controller, only : time_step_controller_t
68 use scratch_registry, only : neko_scratch_registry
69 use time_state, only : time_state_t
70 use bc, only : bc_t
71 use mpi_f08, only: mpi_integer, mpi_sum, mpi_max
72 implicit none
73 private
74
75
77
79 type(field_t) :: s_adj_res
80
82 type(field_t) :: ds_adj
83
85 class(ax_t), allocatable :: ax
86
88 type(projection_t) :: proj_s
89
93 type(zero_dirichlet_t) :: bc_res
94
99 type(bc_list_t) :: bclst_ds
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), intent(in) :: coef
147 type(user_t), 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_factory(this%ax, full_formulation = .false.)
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%strong(i)) 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
241 call this%bclst_ds%init()
242 call this%bclst_ds%append(this%bc_res)
243
244
245 ! Initialize projection space
246 call this%proj_s%init(this%dm_Xh%size(), this%projection_dim, &
247 this%projection_activ_step)
248
249 ! Determine the time-interpolation scheme
250 call json_get_or_default(numerics_params, 'oifs', this%oifs, .false.)
251
252 ! Point to case checkpoint
253 this%chkp => chkp
254
255 ! Initialize advection factory
256 call json_get_or_default(params_adjoint, 'advection', advection, .true.)
257
258 call advection_adjoint_factory(this%adv, numerics_params, this%c_Xh, &
259 ulag, vlag, wlag, this%chkp%dtlag, &
260 this%chkp%tlag, time_scheme, .not. advection, &
261 this%s_adj_lag)
262 ! Add lagged term to checkpoint
263 ! @todo Init chkp object, note, adding 3 slags
264
265 ! Add scalar info to checkpoint
266 ! call this%chkp%add_scalar(this%s)
267 ! this%chkp%abs1 => this%abx1
268 ! this%chkp%abs2 => this%abx2
269 ! this%chkp%slag => this%slag
270
271 end subroutine adjoint_scalar_pnpn_init
272
274 subroutine adjoint_scalar_pnpn_restart(this, chkp)
275 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
276 type(chkp_t), intent(inout) :: chkp
277 real(kind=rp) :: dtlag(10), tlag(10)
278 integer :: n
279 dtlag = chkp%dtlag
280 tlag = chkp%tlag
281
282 n = this%s_adj%dof%size()
283
284 call col2(this%s_adj%x, this%c_Xh%mult, n)
285 call col2(this%s_adj_lag%lf(1)%x, this%c_Xh%mult, n)
286 call col2(this%s_adj_lag%lf(2)%x, this%c_Xh%mult, n)
287 if (neko_bcknd_device .eq. 1) then
288 call device_memcpy(this%s_adj%x, this%s_adj%x_d, &
289 n, host_to_device, sync = .false.)
290 call device_memcpy(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x_d, &
291 n, host_to_device, sync = .false.)
292 call device_memcpy(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x_d, &
293 n, host_to_device, sync = .false.)
294 call device_memcpy(this%abx1%x, this%abx1%x_d, &
295 n, host_to_device, sync = .false.)
296 call device_memcpy(this%abx2%x, this%abx2%x_d, &
297 n, host_to_device, sync = .false.)
298 call device_memcpy(this%advs%x, this%advs%x_d, &
299 n, host_to_device, sync = .false.)
300 end if
301
302 call this%gs_Xh%op(this%s_adj, gs_op_add)
303 call this%gs_Xh%op(this%s_adj_lag%lf(1), gs_op_add)
304 call this%gs_Xh%op(this%s_adj_lag%lf(2), gs_op_add)
305
306 end subroutine adjoint_scalar_pnpn_restart
307
308 subroutine adjoint_scalar_pnpn_free(this)
309 class(adjoint_scalar_pnpn_t), intent(inout) :: this
310
311 !Deallocate scalar field
312 call this%scheme_free()
313
314 call this%bclst_ds%free()
315 call this%proj_s%free()
316
317 call this%s_adj_res%free()
318
319 call this%ds_adj%free()
320
321 call this%abx1%free()
322 call this%abx2%free()
323
324 call this%advs%free()
325
326 if (allocated(this%Ax)) then
327 deallocate(this%Ax)
328 end if
329
330 if (allocated(this%res)) then
331 deallocate(this%res)
332 end if
333
334 if (allocated(this%makeext)) then
335 deallocate(this%makeext)
336 end if
337
338 if (allocated(this%makebdf)) then
339 deallocate(this%makebdf)
340 end if
341
342 if (allocated(this%makeoifs)) then
343 deallocate(this%makeoifs)
344 end if
345
346 end subroutine adjoint_scalar_pnpn_free
347
348 subroutine adjoint_scalar_pnpn_step(this, time, ext_bdf, dt_controller, &
349 ksp_results)
350 class(adjoint_scalar_pnpn_t), intent(inout) :: this
351 type(time_state_t), intent(in) :: time
352 type(time_scheme_controller_t), intent(in) :: ext_bdf
353 type(time_step_controller_t), intent(in) :: dt_controller
354 type(ksp_monitor_t), intent(inout) :: ksp_results
355 ! Number of degrees of freedom
356 integer :: n
357
358 if (this%freeze) return
359
360 n = this%dm_Xh%size()
361
362 call profiler_start_region('Adjoint Scalar')
363 associate(u => this%u, v => this%v, w => this%w, s_adj => this%s_adj, &
364 cp => this%cp, rho => this%rho, lambda => this%lambda, &
365 ds_adj => this%ds_adj, &
366 s_adj_res => this%s_adj_res, &
367 ax => this%Ax, f_xh => this%f_Xh, xh => this%Xh, &
368 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
369 s_adj_lag => this%s_adj_lag, oifs => this%oifs, &
370 projection_dim => this%projection_dim, &
371 msh => this%msh, res => this%res, makeoifs => this%makeoifs, &
372 makeext => this%makeext, makebdf => this%makebdf, &
373 t => time%t, tstep => time%tstep, dt => time%dt)
374
375 ! Logs extra information the log level is NEKO_LOG_DEBUG or above.
376 call print_debug(this)
377 ! Compute the source terms
378 call this%source_term%compute(time)
379
380 ! Apply weak boundary conditions, that contribute to the source terms.
381 call this%bcs%apply_scalar(this%f_Xh%x, dm_xh%size(), time, .false.)
382
383 ! if (oifs) then
384 ! call neko_error("oifs not implemented for adjoint scalar")
385 ! ! Add the advection operators to the right-hans-side.
386 ! call this%adv%compute_scalar(u, v, w, s_adj, this%advs, &
387 ! Xh, this%c_Xh, dm_Xh%size())
388
389 ! call makeext%compute_scalar(this%abx1, this%abx2, f_Xh%x, rho, &
390 ! ext_bdf%advection_coeffs, n)
391
392 ! call makeoifs%compute_scalar(this%advs%x, f_Xh%x, rho, dt, n)
393 ! else
394 ! Add the advection operators to the right-hans-side.
395 call this%adv%compute_adjoint_scalar(u, v, w, s_adj, f_xh, &
396 xh, this%c_Xh, dm_xh%size())
397
398 ! At this point the RHS contains the sum of the advection operator,
399 ! Neumann boundary sources and additional source terms, evaluated using
400 ! the scalar field from the previous time-step.
401 ! Now, this value is used in the explicit time scheme to advance these
402 ! terms in time.
403 call makeext%compute_scalar(this%abx1, this%abx2, f_xh%x, &
404 rho%x(1,1,1,1), ext_bdf%advection_coeffs, n)
405
406 ! Add the RHS contributions coming from the BDF scheme.
407 call makebdf%compute_scalar(s_adj_lag, f_xh%x, s_adj, c_xh%B, &
408 rho%x(1,1,1,1), dt, ext_bdf%diffusion_coeffs, ext_bdf%ndiff, n)
409 ! end if
410
411 call s_adj_lag%update()
412
414 call this%bcs%apply_scalar(this%s_adj%x, this%dm_Xh%size(), time, &
415 .true.)
416
417 ! Update material properties if necessary
418 call this%update_material_properties(time)
419
420 ! Compute scalar residual.
421 call profiler_start_region('Adjoint_scalar_residual')
422 call res%compute(ax, s_adj, s_adj_res, f_xh, c_xh, msh, xh, &
423 lambda, rho%x(1,1,1,1)*cp%x(1,1,1,1), ext_bdf%diffusion_coeffs(1), &
424 dt, dm_xh%size())
425
426 call gs_xh%op(s_adj_res, gs_op_add)
427
428
429 ! Apply a 0-valued Dirichlet boundary conditions on the ds_adj.
430 call this%bclst_ds%apply_scalar(s_adj_res%x, dm_xh%size())
431
432 call profiler_end_region('Adjoint_scalar_residual')
433
434 call this%proj_s%pre_solving(s_adj_res%x, tstep, c_xh, n, dt_controller)
435
436 call this%pc%update()
437 call profiler_start_region('Adjoint_scalar_solve')
438 ksp_results = this%ksp%solve(ax, ds_adj, s_adj_res%x, n, &
439 c_xh, this%bclst_ds, gs_xh)
440 call profiler_end_region('Adjoint_scalar_solve')
441
442 ksp_results%name = 'Adjoint Scalar'
443
444 call this%proj_s%post_solving(ds_adj%x, ax, c_xh, this%bclst_ds, gs_xh, &
445 n, tstep, dt_controller)
446
447 ! Update the solution
448 if (neko_bcknd_device .eq. 1) then
449 call device_add2s2(s_adj%x_d, ds_adj%x_d, 1.0_rp, n)
450 else
451 call add2s2(s_adj%x, ds_adj%x, 1.0_rp, n)
452 end if
453
454 end associate
455 call profiler_end_region('Adjoint Scalar')
456 end subroutine adjoint_scalar_pnpn_step
457
458 subroutine print_debug(this)
459 class(adjoint_scalar_pnpn_t), intent(inout) :: this
460 ! character(len=LOG_SIZE) :: log_buf
461 integer :: n
462
463 n = this%dm_Xh%size()
464 ! TODO come back to this
465 !write(log_buf,'(A,A,E15.7,A,E15.7,A,E15.7)') 'Adjoint scalar debug', &
466 ! ' l2norm s_adj', glsc2(this%s_adj%x, this%s_adj%x, n), &
467 ! ' slag1', glsc2(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x, n), &
468 ! ' slag2', glsc2(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x, n)
469 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
470 !write(log_buf,'(A,A,E15.7,A,E15.7)') 'Adjoint scalar debug2', &
471 ! ' l2norm abx1', glsc2(this%abx1%x, this%abx1%x, n), &
472 ! ' abx2', glsc2(this%abx2%x, this%abx2%x, n)
473 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
474 end subroutine print_debug
475
479 subroutine adjoint_scalar_pnpn_setup_bcs_(this, user)
480 class(adjoint_scalar_pnpn_t), intent(inout) :: this
481 type(user_t), target, intent(in) :: user
482 integer :: i, j, n_bcs, zone_size, global_zone_size, ierr
483 type(json_core) :: core
484 type(json_value), pointer :: bc_object
485 type(json_file) :: bc_subdict
486 class(bc_t), pointer :: bc_i
487 logical :: found
488 ! Monitor which boundary zones have been marked
489 logical, allocatable :: marked_zones(:)
490 integer, allocatable :: zone_indices(:)
491
492 if (this%params%valid_path('boundary_conditions')) then
493 call this%params%info('boundary_conditions', &
494 n_children = n_bcs)
495 call this%params%get_core(core)
496 call this%params%get('boundary_conditions', bc_object, found)
497
498 call this%bcs%init(n_bcs)
499
500 allocate(marked_zones(size(this%msh%labeled_zones)))
501 marked_zones = .false.
502
503 do i = 1, n_bcs
504 ! Create a new json containing just the subdict for this bc
505 call json_extract_item(core, bc_object, i, bc_subdict)
506
507 ! Check that we are not trying to assing a bc to zone, for which one
508 ! has already been assigned and that the zone has more than 0 size
509 ! in the mesh.
510 call json_get(bc_subdict, "zone_indices", zone_indices)
511
512 do j = 1, size(zone_indices)
513 zone_size = this%msh%labeled_zones(zone_indices(j))%size
514 call mpi_allreduce(zone_size, global_zone_size, 1, &
515 mpi_integer, mpi_max, neko_comm, ierr)
516
517 if (global_zone_size .eq. 0) then
518 write(error_unit, '(A, A, I0, A, A, I0, A)') "*** ERROR ***: ",&
519 "Zone index ", zone_indices(j), &
520 " is invalid as this zone has 0 size, meaning it ", &
521 "does not exist in the mesh. Check adjoint scalar BC ", &
522 i, "."
523 error stop
524 end if
525
526 if (marked_zones(zone_indices(j)) .eqv. .true.) then
527 write(error_unit, '(A, A, I0, A, A, A, A)') "*** ERROR ***: ", &
528 "Zone with index ", zone_indices(j), &
529 " has already been assigned a boundary condition. ", &
530 "Please check your boundary_conditions entry for the ", &
531 "adjoint scalar and make sure that each zone index ", &
532 "appears only in a single boundary condition."
533 error stop
534 else
535 marked_zones(zone_indices(j)) = .true.
536 end if
537 end do
538
539 bc_i => null()
540
541 call adjoint_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
542 call this%bcs%append(bc_i)
543 end do
544
545 ! Make sure all labeled zones with non-zero size have been marked
546 do i = 1, size(this%msh%labeled_zones)
547 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
548 (marked_zones(i) .eqv. .false.)) then
549 write(error_unit, '(A, A, I0)') "*** ERROR ***: ", &
550 "No adjoint scalar boundary condition assigned to zone ", i
551 error stop
552 end if
553 end do
554 else
555 ! Check that there are no labeled zones, i.e. all are periodic.
556 do i = 1, size(this%msh%labeled_zones)
557 if (this%msh%labeled_zones(i)%size .gt. 0) then
558 write(error_unit, '(A, A, A)') "*** ERROR ***: ", &
559 "No boundary_conditions entry in the case file for " // &
560 " adjoint scalar ", &
561 this%s%name
562 error stop
563 end if
564 end do
565 end if
566 end subroutine adjoint_scalar_pnpn_setup_bcs_
567
568end 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.