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: mpi_integer, mpi_max, neko_comm, neko_error
37 use num_types, only: rp
38 use, intrinsic :: iso_fortran_env, only: error_unit
39 use rhs_maker, only : rhs_maker_bdf_t, rhs_maker_ext_t, rhs_maker_oifs_t, &
40 rhs_maker_ext_fctry, rhs_maker_bdf_fctry, rhs_maker_oifs_fctry
42 use field, only : field_t
43 use bc_list, only : bc_list_t
44 use mesh, only : mesh_t
45 use checkpoint, only : chkp_t
46 use coefs, only : coef_t
47 use device, only : host_to_device, device_memcpy
48 use gather_scatter, only : gs_t, gs_op_add
49 use scalar_residual, only : scalar_residual_t, scalar_residual_factory
50 use ax_product, only : ax_t, ax_helm_factory
51 use field_series, only: field_series_t
52 use facet_normal, only : facet_normal_t
53 use krylov, only : ksp_monitor_t
54 use device_math, only : device_add2s2, device_col2
55 use scalar_aux, only : scalar_step_info
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
61 use advection_adjoint_fctry, only: advection_adjoint_factory
62 use profiler, only : profiler_start_region, profiler_end_region
63 use json_utils, only : json_get, json_get_or_default, json_extract_item
64 use json_module, only : json_file, json_core, json_value
65 use user_intf, only : user_t
66 use neko_config, only : neko_bcknd_device
67 use zero_dirichlet, only : zero_dirichlet_t
68 use time_step_controller, only : time_step_controller_t
69 use scratch_registry, only : neko_scratch_registry
70 use bc, only : bc_t
71 implicit none
72 private
73
74
76
78 type(field_t) :: s_adj_res
79
81 type(field_t) :: ds_adj
82
84 class(ax_t), allocatable :: ax
85
87 type(projection_t) :: proj_s
88
92 type(zero_dirichlet_t) :: bc_res
93
96 type(bc_list_t) :: bclst_ds
97
99 class(advection_adjoint_t), allocatable :: adv
100
101 ! Time interpolation scheme
102 logical :: oifs
103
104 ! Lag arrays for the RHS.
105 type(field_t) :: abx1, abx2
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
166 subroutine adjoint_scalar_pnpn_init(this, msh, coef, gs, params, user, &
167 ulag, vlag, wlag, time_scheme, rho)
168 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
169 type(mesh_t), target, intent(in) :: msh
170 type(coef_t), target, intent(in) :: coef
171 type(gs_t), target, intent(inout) :: gs
172 type(json_file), target, intent(inout) :: params
173 type(user_t), target, intent(in) :: user
174 type(field_series_t), target, intent(in) :: ulag, vlag, wlag
175 type(time_scheme_controller_t), target, intent(in) :: time_scheme
176 type(field_t), target, intent(in) :: rho
177 integer :: i
178 class(bc_t), pointer :: bc_i
179 character(len=15), parameter :: scheme = 'Modular (Pn/Pn)'
180
181 call this%free()
182
183 ! Initiliaze base type.
184 call this%scheme_init(msh, coef, gs, params, scheme, user, rho)
185
186 ! Setup backend dependent Ax routines
187 call ax_helm_factory(this%ax, full_formulation = .false.)
188
189 ! Setup backend dependent scalar residual routines
190 call scalar_residual_factory(this%res)
191
192 ! Setup backend dependent summation of extrapolation scheme
193 call rhs_maker_ext_fctry(this%makeext)
194
195 ! Setup backend dependent contributions to F from lagged BD terms
196 call rhs_maker_bdf_fctry(this%makebdf)
197
198 ! Setup backend dependent contributions of the OIFS scheme
199 call rhs_maker_oifs_fctry(this%makeoifs)
200
201 ! Initialize variables specific to this plan
202 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
203 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
204
205 call this%s_adj_res%init(dm_xh, "s_adj_res")
206
207 call this%abx1%init(dm_xh, "abx1")
208
209 call this%abx2%init(dm_xh, "abx2")
210
211 call this%advs%init(dm_xh, "advs")
212
213 call this%ds_adj%init(dm_xh, 'ds_adj')
214
215 end associate
216
217 ! Set up boundary conditions
218 call this%setup_bcs_(user)
219
220 ! Initialize dirichlet bcs for scalar residual
221 call this%bc_res%init(this%c_Xh, params)
222 do i = 1, this%bcs%size()
223 if (this%bcs%strong(i)) then
224 bc_i => this%bcs%get(i)
225 call this%bc_res%mark_facets(bc_i%marked_facet)
226 end if
227 end do
228
229! call this%bc_res%mark_zones_from_list('d_s', this%bc_labels)
230 call this%bc_res%finalize()
231
232 call this%bclst_ds%init()
233 call this%bclst_ds%append(this%bc_res)
234
235
236 ! Initialize projection space
237 call this%proj_s%init(this%dm_Xh%size(), this%projection_dim, &
238 this%projection_activ_step)
239
240 ! Add lagged term to checkpoint
241 ! @todo Init chkp object, note, adding 3 slags
242 ! call this%chkp%add_lag(this%s_adj_lag, this%s_adj_lag, this%s_adj_lag)
243
244 ! Determine the time-interpolation scheme
245 call json_get_or_default(params, 'case.numerics.oifs', this%oifs, .false.)
246
247 ! Initialize advection factory
248 ! call json_get_or_default(params, 'case.scalar.advection', advection, &
249 ! .true.)
250 ! call advection_adjoint_factory(this%adv, params, this%c_Xh, &
251 ! ulag, vlag, wlag, this%chkp%dtlag, &
252 ! this%chkp%tlag, time_scheme, .not. advection, &
253 ! this%s_adj_lag)
254 ! @todo NOTE:
255 ! This is changed a fair amount and I suspect it's due oifs
256 call advection_adjoint_factory(this%adv, params, this%c_Xh)
257 end subroutine adjoint_scalar_pnpn_init
258
260 subroutine adjoint_scalar_pnpn_restart(this, dtlag, tlag)
261 class(adjoint_scalar_pnpn_t), target, intent(inout) :: this
262 real(kind=rp) :: dtlag(10), tlag(10)
263 integer :: n
264
265
266 n = this%s_adj%dof%size()
267
268 call col2(this%s_adj%x, this%c_Xh%mult, n)
269 call col2(this%s_adj_lag%lf(1)%x, this%c_Xh%mult, n)
270 call col2(this%s_adj_lag%lf(2)%x, this%c_Xh%mult, n)
271 if (neko_bcknd_device .eq. 1) then
272 call device_memcpy(this%s_adj%x, this%s_adj%x_d, &
273 n, host_to_device, sync = .false.)
274 call device_memcpy(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x_d, &
275 n, host_to_device, sync = .false.)
276 call device_memcpy(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x_d, &
277 n, host_to_device, sync = .false.)
278 call device_memcpy(this%abx1%x, this%abx1%x_d, &
279 n, host_to_device, sync = .false.)
280 call device_memcpy(this%abx2%x, this%abx2%x_d, &
281 n, host_to_device, sync = .false.)
282 call device_memcpy(this%advs%x, this%advs%x_d, &
283 n, host_to_device, sync = .false.)
284 end if
285
286 call this%gs_Xh%op(this%s_adj, gs_op_add)
287 call this%gs_Xh%op(this%s_adj_lag%lf(1), gs_op_add)
288 call this%gs_Xh%op(this%s_adj_lag%lf(2), gs_op_add)
289
290 end subroutine adjoint_scalar_pnpn_restart
291
292 subroutine adjoint_scalar_pnpn_free(this)
293 class(adjoint_scalar_pnpn_t), intent(inout) :: this
294
295 !Deallocate scalar field
296 call this%scheme_free()
297
298 call this%bclst_ds%free()
299 call this%proj_s%free()
300
301 call this%s_adj_res%free()
302
303 call this%ds_adj%free()
304
305 call this%abx1%free()
306 call this%abx2%free()
307
308 call this%advs%free()
309
310 if (allocated(this%Ax)) then
311 deallocate(this%Ax)
312 end if
313
314 if (allocated(this%res)) then
315 deallocate(this%res)
316 end if
317
318 if (allocated(this%makeext)) then
319 deallocate(this%makeext)
320 end if
321
322 if (allocated(this%makebdf)) then
323 deallocate(this%makebdf)
324 end if
325
326 if (allocated(this%makeoifs)) then
327 deallocate(this%makeoifs)
328 end if
329
330 end subroutine adjoint_scalar_pnpn_free
331
332 subroutine adjoint_scalar_pnpn_step(this, t, tstep, dt, ext_bdf, &
333 dt_controller)
334 class(adjoint_scalar_pnpn_t), intent(inout) :: this
335 real(kind=rp), intent(in) :: t
336 integer, intent(in) :: tstep
337 real(kind=rp), intent(in) :: dt
338 type(time_scheme_controller_t), intent(in) :: ext_bdf
339 type(time_step_controller_t), intent(in) :: dt_controller
340 ! Number of degrees of freedom
341 integer :: n
342 ! Linear solver results monitor
343 type(ksp_monitor_t) :: ksp_results(1)
344
345 n = this%dm_Xh%size()
346
347 call profiler_start_region('Scalar', 2)
348 associate(u => this%u, v => this%v, w => this%w, s_adj => this%s_adj, &
349 cp => this%cp, rho => this%rho, &
350 ds_adj => this%ds_adj, &
351 s_adj_res => this%s_adj_res, &
352 ax => this%Ax, f_xh => this%f_Xh, xh => this%Xh, &
353 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
354 s_adj_lag => this%s_adj_lag, oifs => this%oifs, &
355 lambda_field => this%lambda, &
356 projection_dim => this%projection_dim, &
357 msh => this%msh, res => this%res, makeoifs => this%makeoifs, &
358 makeext => this%makeext, makebdf => this%makebdf, &
359 if_variable_dt => dt_controller%if_variable_dt, &
360 dt_last_change => dt_controller%dt_last_change)
361
362 ! Logs extra information the log level is NEKO_LOG_DEBUG or above.
363 call print_debug(this)
364 ! Compute the source terms
365 call this%source_term%compute(t, tstep)
366
367 ! Compute the grandient jump penalty term
368 if (this%if_gradient_jump_penalty .eqv. .true.) then
369 call neko_error("gradient jump not implemented for adjoint scalar")
370 ! call this%gradient_jump_penalty%compute(u, v, w, s_adj)
371 ! call this%gradient_jump_penalty%perform(f_Xh)
372 end if
373
374 ! Apply weak boundary conditions, that contribute to the source terms.
375 call this%bcs%apply_scalar(this%f_Xh%x, dm_xh%size(), t, tstep, .false.)
376
377 ! if (oifs) then
378 ! call neko_error("oifs not implemented for adjoint scalar")
379 ! ! Add the advection operators to the right-hans-side.
380 ! call this%adv%compute_scalar(u, v, w, s_adj, this%advs, &
381 ! Xh, this%c_Xh, dm_Xh%size())
382
383 ! call makeext%compute_scalar(this%abx1, this%abx2, f_Xh%x, rho, &
384 ! ext_bdf%advection_coeffs, n)
385
386 ! call makeoifs%compute_scalar(this%advs%x, f_Xh%x, rho, dt, n)
387 ! else
388 ! Add the advection operators to the right-hans-side.
389 call this%adv%compute_adjoint_scalar(u, v, w, s_adj, f_xh, &
390 xh, this%c_Xh, dm_xh%size())
391
392 ! At this point the RHS contains the sum of the advection operator,
393 ! Neumann boundary sources and additional source terms, evaluated using
394 ! the scalar field from the previous time-step.
395 ! Now, this value is used in the explicit time scheme to advance these
396 ! terms in time.
397 call makeext%compute_scalar(this%abx1, this%abx2, f_xh%x, rho%x(1,1,1,1), &
398 ext_bdf%advection_coeffs, n)
399
400 ! Add the RHS contributions coming from the BDF scheme.
401 call makebdf%compute_scalar(s_adj_lag, f_xh%x, s_adj, c_xh%B, rho%x(1,1,1,1), &
402 dt, ext_bdf%diffusion_coeffs, ext_bdf%ndiff, n)
403 ! end if
404
405 call s_adj_lag%update()
406
408 call this%bcs%apply_scalar(this%s_adj%x, this%dm_Xh%size(), t, tstep, &
409 .true.)
410
411 ! Update material properties if necessary
412 call this%update_material_properties(t, tstep)
413
414 ! Compute scalar residual.
415 call profiler_start_region('Adjoint_scalar_residual', 20)
416 call res%compute(ax, s_adj, s_adj_res, f_xh, c_xh, msh, xh, &
417 lambda_field, rho%x(1,1,1,1)*cp%x(1,1,1,1), ext_bdf%diffusion_coeffs(1), dt, dm_xh%size())
418
419 call gs_xh%op(s_adj_res, gs_op_add)
420
421
422 ! Apply a 0-valued Dirichlet boundary conditions on the ds_adj.
423 call this%bclst_ds%apply_scalar(s_adj_res%x, dm_xh%size())
424
425 call profiler_end_region('Adjoint_scalar_residual', 20)
426
427 call this%proj_s%pre_solving(s_adj_res%x, tstep, c_xh, n, dt_controller)
428
429 call this%pc%update()
430 call profiler_start_region('Adjoint_scalar_solve', 21)
431 ksp_results(1) = this%ksp%solve(ax, ds_adj, s_adj_res%x, n, &
432 c_xh, this%bclst_ds, gs_xh)
433 call profiler_end_region('Adjoint_scalar_solve', 21)
434
435 call this%proj_s%post_solving(ds_adj%x, ax, c_xh, this%bclst_ds, gs_xh, &
436 n, tstep, dt_controller)
437
438 ! Update the solution
439 if (neko_bcknd_device .eq. 1) then
440 call device_add2s2(s_adj%x_d, ds_adj%x_d, 1.0_rp, n)
441 else
442 call add2s2(s_adj%x, ds_adj%x, 1.0_rp, n)
443 end if
444
445 call scalar_step_info(tstep, t, dt, ksp_results)
446
447 end associate
448 call profiler_end_region('Scalar', 2)
449 end subroutine adjoint_scalar_pnpn_step
450
451 subroutine print_debug(this)
452 class(adjoint_scalar_pnpn_t), intent(inout) :: this
453 integer :: n
454
455 n = this%dm_Xh%size()
456 ! TODO come back to this
457 !write(log_buf,'(A,A,E15.7,A,E15.7,A,E15.7)') 'Adjoint scalar debug', &
458 ! ' l2norm s_adj', glsc2(this%s_adj%x, this%s_adj%x, n), &
459 ! ' slag1', glsc2(this%s_adj_lag%lf(1)%x, this%s_adj_lag%lf(1)%x, n), &
460 ! ' slag2', glsc2(this%s_adj_lag%lf(2)%x, this%s_adj_lag%lf(2)%x, n)
461 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
462 !write(log_buf,'(A,A,E15.7,A,E15.7)') 'Adjoint scalar debug2', &
463 ! ' l2norm abx1', glsc2(this%abx1%x, this%abx1%x, n), &
464 ! ' abx2', glsc2(this%abx2%x, this%abx2%x, n)
465 !call neko_log%message(log_buf, lvl=NEKO_LOG_DEBUG)
466 end subroutine print_debug
467
471 subroutine adjoint_scalar_pnpn_setup_bcs_(this, user)
472 class(adjoint_scalar_pnpn_t), intent(inout) :: this
473 type(user_t), target, intent(in) :: user
474 integer :: i, j, n_bcs, zone_size, global_zone_size, ierr
475 type(json_core) :: core
476 type(json_value), pointer :: bc_object
477 type(json_file) :: bc_subdict
478 class(bc_t), pointer :: bc_i
479 logical :: found
480 ! Monitor which boundary zones have been marked
481 logical, allocatable :: marked_zones(:)
482 integer, allocatable :: zone_indices(:)
483
484
485 if (this%params%valid_path('case.adjoint_scalar.boundary_conditions')) then
486 call this%params%info('case.adjoint_scalar.boundary_conditions', &
487 n_children = n_bcs)
488 call this%params%get_core(core)
489 call this%params%get('case.adjoint_scalar.boundary_conditions', &
490 bc_object, found)
491
492 call this%bcs%init(n_bcs)
493
494 allocate(marked_zones(size(this%msh%labeled_zones)))
495 marked_zones = .false.
496
497 do i = 1, n_bcs
498 ! Create a new json containing just the subdict for this bc
499 call json_extract_item(core, bc_object, i, bc_subdict)
500
501 ! Check that we are not trying to assing a bc to zone, for which one
502 ! has already been assigned and that the zone has more than 0 size
503 ! in the mesh.
504 call json_get(bc_subdict, "zone_indices", zone_indices)
505
506 do j = 1, size(zone_indices)
507 zone_size = this%msh%labeled_zones(zone_indices(j))%size
508 call mpi_allreduce(zone_size, global_zone_size, 1, &
509 mpi_integer, mpi_max, neko_comm, ierr)
510
511 if (global_zone_size .eq. 0) then
512 write(error_unit, '(A, A, I0, A, A, I0, A)') "*** ERROR ***: ",&
513 "Zone index ", zone_indices(j), &
514 " is invalid as this zone has 0 size, meaning it ", &
515 "does not in the mesh. Check adjoint scalar BC ", &
516 i, "."
517 error stop
518 end if
519
520 if (marked_zones(zone_indices(j)) .eqv. .true.) then
521 write(error_unit, '(A, A, I0, A, A, A, A)') "*** ERROR ***: ", &
522 "Zone with index ", zone_indices(j), &
523 " has already been assigned a boundary condition. ", &
524 "Please check your boundary_conditions entry for the ", &
525 "adjoint scalar and make sure that each zone index ", &
526 "appears only in a single boundary condition."
527 error stop
528 else
529 marked_zones(zone_indices(j)) = .true.
530 end if
531 end do
532
533 bc_i => null()
534
535 call adjoint_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
536 call this%bcs%append(bc_i)
537 end do
538
539 ! Make sure all labeled zones with non-zero size have been marked
540 do i = 1, size(this%msh%labeled_zones)
541 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
542 (marked_zones(i) .eqv. .false.)) then
543 write(error_unit, '(A, A, I0)') "*** ERROR ***: ", &
544 "No adjoint scalar boundary condition assigned to zone ", i
545 error stop
546 end if
547 end do
548 end if
549 end subroutine adjoint_scalar_pnpn_setup_bcs_
550
551end 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.
Contains the factory routine for advection_t children.
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.