Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_fluid_pnpn.f90
1! Copyright (c) 2025, 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!
35 use, intrinsic :: iso_fortran_env, only: error_unit
36 use coefs, only: coef_t
37 use symmetry, only: symmetry_t
38 use field_registry, only: neko_field_registry
39 use logger, only: neko_log, log_size, neko_log_debug
40 use num_types, only: rp
41 use krylov, only: ksp_monitor_t
42 use pnpn_residual, only: pnpn_prs_res_t, pnpn_vel_res_t, &
43 pnpn_prs_res_factory, pnpn_vel_res_factory, &
44 pnpn_prs_res_stress_factory, pnpn_vel_res_stress_factory
45 use rhs_maker, only: rhs_maker_sumab_t, rhs_maker_bdf_t, rhs_maker_ext_t, &
46 rhs_maker_oifs_t, rhs_maker_sumab_fctry, rhs_maker_bdf_fctry, &
47 rhs_maker_ext_fctry, rhs_maker_oifs_fctry
48 use adjoint_fluid_scheme, only: adjoint_fluid_scheme_t
51 use device_mathops, only: device_opcolv, device_opadd2cm
52 use fluid_aux, only: fluid_step_info
53 use time_scheme_controller, only: time_scheme_controller_t
54 use projection, only: projection_t
55 use projection_vel, only: projection_vel_t
56 use device, only: device_memcpy, host_to_device, device_event_sync, &
57 glb_cmd_event
58 use advection_adjoint, only: advection_adjoint_t, advection_adjoint_factory
59 use profiler, only: profiler_start_region, profiler_end_region
60 use json_module, only: json_file, json_core, json_value
61 use json_utils, only: json_get, json_get_or_default, json_extract_item
62 use json_module, only: json_file
63 use ax_product, only: ax_t, ax_helm_factory
64 use field, only: field_t
65 use dirichlet, only: dirichlet_t
66 use shear_stress, only: shear_stress_t
67 use wall_model_bc, only: wall_model_bc_t
68 use facet_normal, only: facet_normal_t
69 use non_normal, only: non_normal_t
70 use checkpoint, only: chkp_t
71 use mesh, only: mesh_t
72 use user_intf, only: user_t
73 use time_step_controller, only: time_step_controller_t
74 use gs_ops, only: gs_op_add
75 use neko_config, only: neko_bcknd_device
76 use mathops, only: opadd2cm, opcolv
77 use bc_list, only: bc_list_t
78 use zero_dirichlet, only: zero_dirichlet_t
79 use utils, only: neko_error, neko_type_error
80 use field_math, only: field_add2, field_copy
81 use bc, only: bc_t
82 use file, only: file_t
83 use operators, only: ortho
84 use inflow, only: inflow_t
85 use field_dirichlet, only: field_dirichlet_t
86 use blasius, only: blasius_t
87 use field_dirichlet_vector, only: field_dirichlet_vector_t
88 use dong_outflow, only: dong_outflow_t
89 use time_state, only: time_state_t
90 use vector, only: vector_t
91 use device_math, only: device_vlsc3, device_cmult
92 use math, only: vlsc3, cmult
93 use json_utils_ext, only: json_key_fallback
94 use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr, c_associated
95 use comm, only: neko_comm, mpi_real_precision
96 use mpi_f08, only: mpi_sum, mpi_max, mpi_allreduce, mpi_comm_world, &
97 mpi_integer, mpi_logical, mpi_lor
98
99 implicit none
100 private
101
103
105 type(field_t) :: p_res, u_res, v_res, w_res
106
109 type(field_t) :: dp, du, dv, dw
110
111 !
112 ! Implicit operators, i.e. the left-hand-side of the Helmholz problem.
113 !
114
115 ! Coupled Helmholz operator for velocity
116 class(ax_t), allocatable :: ax_vel
117 ! Helmholz operator for pressure
118 class(ax_t), allocatable :: ax_prs
119
120 !
121 ! Projections for solver speed-up
122 !
123
125 type(projection_t) :: proj_prs
126 type(projection_vel_t) :: proj_vel
127
128 !
129 ! Special Karniadakis scheme boundary conditions in the pressure equation
130 !
131
133 type(facet_normal_t) :: bc_prs_surface
134
136 type(facet_normal_t) :: bc_sym_surface
137
138 !
139 ! Boundary conditions and lists for residuals and solution increments
140 !
141
143 type(zero_dirichlet_t) :: bc_vel_res
145 type(zero_dirichlet_t) :: bc_du
147 type(zero_dirichlet_t) :: bc_dv
149 type(zero_dirichlet_t) :: bc_dw
151 type(zero_dirichlet_t) :: bc_dp
152
154 type(bc_list_t) :: bclst_vel_res
155 type(bc_list_t) :: bclst_du
156 type(bc_list_t) :: bclst_dv
157 type(bc_list_t) :: bclst_dw
158 type(bc_list_t) :: bclst_dp
159
160
161 ! Checker for wether we have a strong pressure bc. If not, the pressure
162 ! is demeaned at every time step.
163 logical :: prs_dirichlet = .false.
164
165
166 ! The advection operator.
167 class(advection_adjoint_t), allocatable :: adv
168
169 ! Time OIFS interpolation scheme for advection.
170 logical :: oifs
171
172 ! Time variables
173 type(field_t) :: abx1, aby1, abz1
174 type(field_t) :: abx2, aby2, abz2
175
176 ! Advection terms for the oifs method
177 type(field_t) :: advx, advy, advz
178
180 class(pnpn_prs_res_t), allocatable :: prs_res
181
183 class(pnpn_vel_res_t), allocatable :: vel_res
184
186 class(rhs_maker_sumab_t), allocatable :: sumab
187
189 class(rhs_maker_ext_t), allocatable :: makeabf
190
192 class(rhs_maker_bdf_t), allocatable :: makebdf
193
195 class(rhs_maker_oifs_t), allocatable :: makeoifs
196
197 ! !> Adjust flow volume
198 ! type(fluid_volflow_t) :: vol_flow
199
201 logical :: full_stress_formulation = .false.
202
203 ! ======================================================================= !
204 ! Addressable attributes
205
206 real(kind=rp) :: norm_scaling
207 real(kind=rp) :: norm_target
208 real(kind=rp) :: norm_tolerance
209
210 ! ======================================================================= !
211 ! Definition of shorthands and local variables
212
214 real(kind=rp) :: norm_l2_base
215
217 real(kind=rp) :: norm_l2_upper
219 real(kind=rp) :: norm_l2_lower
220
222 type(file_t) :: file_output
223
224 contains
226 procedure, pass(this) :: init => adjoint_fluid_pnpn_init
228 procedure, pass(this) :: free => adjoint_fluid_pnpn_free
230 procedure, pass(this) :: step => adjoint_fluid_pnpn_step
232 procedure, pass(this) :: restart => adjoint_fluid_pnpn_restart
234 procedure, pass(this) :: setup_bcs => adjoint_fluid_pnpn_setup_bcs
236 procedure, pass(this) :: write_boundary_conditions => &
237 adjoint_fluid_pnpn_write_boundary_conditions
238
240 procedure, public, pass(this) :: pw_compute_ => power_iterations_compute
241
242 end type adjoint_fluid_pnpn_t
243
252 module subroutine pressure_bc_factory(object, scheme, json, coef, user)
253 class(bc_t), pointer, intent(inout) :: object
254 type(adjoint_fluid_pnpn_t), intent(in) :: scheme
255 type(json_file), intent(inout) :: json
256 type(coef_t), intent(in) :: coef
257 type(user_t), intent(in) :: user
258 end subroutine pressure_bc_factory
259 end interface pressure_bc_factory
260
268 interface velocity_bc_factory
269 module subroutine velocity_bc_factory(object, scheme, json, coef, user)
270 class(bc_t), pointer, intent(inout) :: object
271 type(adjoint_fluid_pnpn_t), intent(in) :: scheme
272 type(json_file), intent(inout) :: json
273 type(coef_t), intent(in) :: coef
274 type(user_t), intent(in) :: user
275 end subroutine velocity_bc_factory
276 end interface velocity_bc_factory
277
278contains
279
280 subroutine adjoint_fluid_pnpn_init(this, msh, lx, params, user, chkp)
281 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
282 type(mesh_t), target, intent(inout) :: msh
283 integer, intent(in) :: lx
284 type(json_file), target, intent(inout) :: params
285 type(user_t), target, intent(in) :: user
286 type(chkp_t), target, intent(inout) :: chkp
287 character(len=15), parameter :: scheme = 'Adjoint (Pn/Pn)'
288 real(kind=rp) :: abs_tol
289 character(len=LOG_SIZE) :: log_buf
290 integer :: integer_val, solver_maxiter
291 character(len=:), allocatable :: solver_type, precon_type
292 logical :: monitor, found
293 logical :: advection
294 type(json_file) :: numerics_params, precon_params
295
296 ! Temporary field pointers
297 character(len=:), allocatable :: file_name
298 character(len=256) :: header_line
299
300 call this%free()
301
302 ! Initialize base class
303 call this%init_base(msh, lx, params, scheme, user, .true.)
304
305 ! Add pressure field to the registry. For this scheme it is in the same
306 ! Xh as the velocity
307 call neko_field_registry%add_field(this%dm_Xh, 'p_adj')
308 this%p_adj => neko_field_registry%get_field('p_adj')
309
310 !
311 ! Select governing equations via associated residual and Ax types
312 !
313
314 call json_get(params, 'case.numerics.time_order', integer_val)
315 allocate(this%ext_bdf)
316 call this%ext_bdf%init(integer_val)
317
318 call json_get_or_default(params, "case.fluid.full_stress_formulation", &
319 this%full_stress_formulation, .false.)
320
321 if (this%full_stress_formulation .eqv. .true.) then
322 call neko_error( &
323 "Full stress formulation is not supported in the adjoint module.")
324 ! ! Setup backend dependent Ax routines
325 ! call ax_helm_factory(this%Ax_vel, full_formulation = .true.)
326
327 ! ! Setup backend dependent prs residual routines
328 ! call pnpn_prs_res_stress_factory(this%prs_res)
329
330 ! ! Setup backend dependent vel residual routines
331 ! call pnpn_vel_res_stress_factory(this%vel_res)
332 else
333 ! Setup backend dependent Ax routines
334 call ax_helm_factory(this%Ax_vel, full_formulation = .false.)
335
336 ! Setup backend dependent prs residual routines
337 call pnpn_prs_res_factory(this%prs_res)
338
339 ! Setup backend dependent vel residual routines
340 call pnpn_vel_res_factory(this%vel_res)
341 end if
342
343 if (params%valid_path('case.fluid.nut_field')) then
344 if (this%full_stress_formulation .eqv. .false.) then
345 call neko_error("You need to set full_stress_formulation to " // &
346 "true for the fluid to have a spatially varying " // &
347 "viscocity field.")
348 end if
349 call json_get(params, 'case.fluid.nut_field', this%nut_field_name)
350 else
351 this%nut_field_name = ""
352 end if
353
354 ! Setup Ax for the pressure
355 call ax_helm_factory(this%Ax_prs, full_formulation = .false.)
356
357
358 ! Setup backend dependent summation of AB/BDF
359 call rhs_maker_sumab_fctry(this%sumab)
360
361 ! Setup backend dependent summation of extrapolation scheme
362 call rhs_maker_ext_fctry(this%makeabf)
363
364 ! Setup backend depenent contributions to F from lagged BD terms
365 call rhs_maker_bdf_fctry(this%makebdf)
366
367 ! Setup backend dependent summations of the OIFS method
368 call rhs_maker_oifs_fctry(this%makeoifs)
369
370 ! Initialize variables specific to this plan
371 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
372 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
373
374 call this%p_res%init(dm_xh, "p_res")
375 call this%u_res%init(dm_xh, "u_res")
376 call this%v_res%init(dm_xh, "v_res")
377 call this%w_res%init(dm_xh, "w_res")
378 call this%abx1%init(dm_xh, "abx1")
379 call this%aby1%init(dm_xh, "aby1")
380 call this%abz1%init(dm_xh, "abz1")
381 call this%abx2%init(dm_xh, "abx2")
382 call this%aby2%init(dm_xh, "aby2")
383 call this%abz2%init(dm_xh, "abz2")
384 call this%advx%init(dm_xh, "advx")
385 call this%advy%init(dm_xh, "advy")
386 call this%advz%init(dm_xh, "advz")
387 end associate
388
389 call this%du%init(this%dm_Xh, 'du')
390 call this%dv%init(this%dm_Xh, 'dv')
391 call this%dw%init(this%dm_Xh, 'dw')
392 call this%dp%init(this%dm_Xh, 'dp')
393
394 ! Set up boundary conditions
395 call this%setup_bcs(user, params)
396
397 ! Check if we need to output boundaries
398 call json_get_or_default(params, 'case.output_boundary', found, .false.)
399 if (found) call this%write_boundary_conditions()
400
401 call this%proj_prs%init(this%dm_Xh%size(), this%pr_projection_dim, &
402 this%pr_projection_activ_step)
403
404 call this%proj_vel%init(this%dm_Xh%size(), this%vel_projection_dim, &
405 this%vel_projection_activ_step)
406
407 ! Determine the time-interpolation scheme
408 call json_get_or_default(params, 'case.numerics.oifs', this%oifs, .false.)
409 if (params%valid_path('case.fluid.flow_rate_force')) then
410 call neko_error("Flow rate forcing not available for adjoint_fluid_pnpn")
411 end if
412
413 ! Setup pressure solver
414 call neko_log%section("Pressure solver")
415
416 call json_get_or_default(params, &
417 'case.fluid.pressure_solver.max_iterations', &
418 solver_maxiter, 800)
419 call json_get(params, 'case.fluid.pressure_solver.type', solver_type)
420 call json_get(params, 'case.fluid.pressure_solver.preconditioner.type', &
421 precon_type)
422 call json_get(params, &
423 'case.fluid.pressure_solver.preconditioner', precon_params)
424 call json_get(params, 'case.fluid.pressure_solver.absolute_tolerance', &
425 abs_tol)
426 call json_get_or_default(params, 'case.fluid.pressure_solver.monitor', &
427 monitor, .false.)
428 call neko_log%message('Type : ('// trim(solver_type) // &
429 ', ' // trim(precon_type) // ')')
430 write(log_buf, '(A,ES13.6)') 'Abs tol :', abs_tol
431 call neko_log%message(log_buf)
432
433 call this%solver_factory(this%ksp_prs, this%dm_Xh%size(), &
434 solver_type, solver_maxiter, abs_tol, monitor)
435 call this%precon_factory_(this%pc_prs, this%ksp_prs, &
436 this%c_Xh, this%dm_Xh, this%gs_Xh, this%bcs_prs, &
437 precon_type, precon_params)
438 call neko_log%end_section()
439
440 ! Initialize the advection factory
441 call neko_log%section("Advection factory")
442 call json_get_or_default(params, 'case.fluid.advection', advection, .true.)
443 call json_get(params, 'case.numerics', numerics_params)
444 call advection_adjoint_factory(this%adv, numerics_params, this%c_Xh, &
445 this%ulag, this%vlag, this%wlag, &
446 chkp%dtlag, chkp%tlag, this%ext_bdf, &
447 .not. advection)
448 ! Should be in init_base maybe?
449 this%chkp => chkp
450 ! This is probably scheme specific
451 ! Should not be init really, but more like, add fluid or something...
452 call this%chkp%init(this%u_adj, this%v_adj, this%w_adj, this%p_adj)
453
454 this%chkp%abx1 => this%abx1
455 this%chkp%abx2 => this%abx2
456 this%chkp%aby1 => this%aby1
457 this%chkp%aby2 => this%aby2
458 this%chkp%abz1 => this%abz1
459 this%chkp%abz2 => this%abz2
460 call this%chkp%add_lag(this%ulag, this%vlag, this%wlag)
461
462 call neko_log%end_section()
463
464 ! ------------------------------------------------------------------------ !
465 ! Handling the rescaling and baseflow
466
467 ! Read the norm scaling from the json file
468 call json_get_or_default(params, 'norm_scaling', &
469 this%norm_scaling, 0.5_rp)
470
471 ! The baseflow is the solution to the forward.
472 ! Userdefined baseflows can be invoked via setting initial conditions
473 ! call neko_field_registry%add_field(this%dm_Xh, 'u')
474 ! call neko_field_registry%add_field(this%dm_Xh, 'v')
475 ! call neko_field_registry%add_field(this%dm_Xh, 'w')
476 ! call neko_field_registry%add_field(this%dm_Xh, 'p')
477 this%u_b => neko_field_registry%get_field('u')
478 this%v_b => neko_field_registry%get_field('v')
479 this%w_b => neko_field_registry%get_field('w')
480 this%p_b => neko_field_registry%get_field('p')
481
482 ! Read the json file
483 call json_get_or_default(params, 'norm_target', &
484 this%norm_target, -1.0_rp)
485 call json_get_or_default(params, 'norm_tolerance', &
486 this%norm_tolerance, 10.0_rp)
487
488 ! Build the header
489 call json_get_or_default(params, 'output_file', &
490 file_name, 'power_iterations.csv')
491 call this%file_output%init(trim(file_name))
492 write(header_line, '(A)') 'Time, Norm, Scaling'
493 call this%file_output%set_header(header_line)
494
495 end subroutine adjoint_fluid_pnpn_init
496
497 subroutine adjoint_fluid_pnpn_restart(this, chkp)
498 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
499 type(chkp_t), intent(inout) :: chkp
500 real(kind=rp) :: dtlag(10), tlag(10)
501 integer :: i, j, n
502
503 dtlag = chkp%dtlag
504 tlag = chkp%tlag
505
506 n = this%u_adj%dof%size()
507 if (allocated(this%chkp%previous_mesh%elements) .or. &
508 chkp%previous_Xh%lx .ne. this%Xh%lx) then
509 associate(u => this%u_adj, v => this%v_adj, w => this%w_adj, &
510 p => this%p_adj, c_xh => this%c_Xh, ulag => this%ulag, &
511 vlag => this%vlag, wlag => this%wlag)
512 do concurrent(j = 1:n)
513 u%x(j,1,1,1) = u%x(j,1,1,1) * c_xh%mult(j,1,1,1)
514 v%x(j,1,1,1) = v%x(j,1,1,1) * c_xh%mult(j,1,1,1)
515 w%x(j,1,1,1) = w%x(j,1,1,1) * c_xh%mult(j,1,1,1)
516 p%x(j,1,1,1) = p%x(j,1,1,1) * c_xh%mult(j,1,1,1)
517 end do
518 do i = 1, this%ulag%size()
519 do concurrent(j = 1:n)
520 ulag%lf(i)%x(j,1,1,1) = ulag%lf(i)%x(j,1,1,1) &
521 * c_xh%mult(j,1,1,1)
522 vlag%lf(i)%x(j,1,1,1) = vlag%lf(i)%x(j,1,1,1) &
523 * c_xh%mult(j,1,1,1)
524 wlag%lf(i)%x(j,1,1,1) = wlag%lf(i)%x(j,1,1,1) &
525 * c_xh%mult(j,1,1,1)
526 end do
527 end do
528 end associate
529 end if
530
531 if (neko_bcknd_device .eq. 1) then
532 associate(u => this%u_adj, v => this%v_adj, w => this%w_adj, &
533 ulag => this%ulag, vlag => this%vlag, wlag => this%wlag,&
534 p => this%p_adj)
535 call device_memcpy(u%x, u%x_d, u%dof%size(), &
536 host_to_device, sync = .false.)
537 call device_memcpy(v%x, v%x_d, v%dof%size(), &
538 host_to_device, sync = .false.)
539 call device_memcpy(w%x, w%x_d, w%dof%size(), &
540 host_to_device, sync = .false.)
541 call device_memcpy(p%x, p%x_d, p%dof%size(), &
542 host_to_device, sync = .false.)
543 call device_memcpy(ulag%lf(1)%x, ulag%lf(1)%x_d, &
544 u%dof%size(), host_to_device, sync = .false.)
545 call device_memcpy(ulag%lf(2)%x, ulag%lf(2)%x_d, &
546 u%dof%size(), host_to_device, sync = .false.)
547
548 call device_memcpy(vlag%lf(1)%x, vlag%lf(1)%x_d, &
549 v%dof%size(), host_to_device, sync = .false.)
550 call device_memcpy(vlag%lf(2)%x, vlag%lf(2)%x_d, &
551 v%dof%size(), host_to_device, sync = .false.)
552
553 call device_memcpy(wlag%lf(1)%x, wlag%lf(1)%x_d, &
554 w%dof%size(), host_to_device, sync = .false.)
555 call device_memcpy(wlag%lf(2)%x, wlag%lf(2)%x_d, &
556 w%dof%size(), host_to_device, sync = .false.)
557 call device_memcpy(this%abx1%x, this%abx1%x_d, &
558 w%dof%size(), host_to_device, sync = .false.)
559 call device_memcpy(this%abx2%x, this%abx2%x_d, &
560 w%dof%size(), host_to_device, sync = .false.)
561 call device_memcpy(this%aby1%x, this%aby1%x_d, &
562 w%dof%size(), host_to_device, sync = .false.)
563 call device_memcpy(this%aby2%x, this%aby2%x_d, &
564 w%dof%size(), host_to_device, sync = .false.)
565 call device_memcpy(this%abz1%x, this%abz1%x_d, &
566 w%dof%size(), host_to_device, sync = .false.)
567 call device_memcpy(this%abz2%x, this%abz2%x_d, &
568 w%dof%size(), host_to_device, sync = .false.)
569 call device_memcpy(this%advx%x, this%advx%x_d, &
570 w%dof%size(), host_to_device, sync = .false.)
571 call device_memcpy(this%advy%x, this%advy%x_d, &
572 w%dof%size(), host_to_device, sync = .false.)
573 call device_memcpy(this%advz%x, this%advz%x_d, &
574 w%dof%size(), host_to_device, sync = .false.)
575 end associate
576 end if
577 ! Make sure that continuity is maintained (important for interpolation)
578 ! Do not do this for lagged rhs
579 ! (derivatives are not necessairly coninous across elements)
580
581 if (allocated(this%chkp%previous_mesh%elements) &
582 .or. this%chkp%previous_Xh%lx .ne. this%Xh%lx) then
583 call this%gs_Xh%op(this%u_adj, gs_op_add)
584 call this%gs_Xh%op(this%v_adj, gs_op_add)
585 call this%gs_Xh%op(this%w_adj, gs_op_add)
586 call this%gs_Xh%op(this%p_adj, gs_op_add)
587
588 do i = 1, this%ulag%size()
589 call this%gs_Xh%op(this%ulag%lf(i), gs_op_add)
590 call this%gs_Xh%op(this%vlag%lf(i), gs_op_add)
591 call this%gs_Xh%op(this%wlag%lf(i), gs_op_add)
592 end do
593 end if
594
595 end subroutine adjoint_fluid_pnpn_restart
596
597 subroutine adjoint_fluid_pnpn_free(this)
598 class(adjoint_fluid_pnpn_t), intent(inout) :: this
599
600 !Deallocate velocity and pressure fields
601 call this%scheme_free()
602
603 call this%bc_prs_surface%free()
604 call this%bc_sym_surface%free()
605 call this%bclst_vel_res%free()
606 call this%bclst_dp%free()
607 call this%proj_prs%free()
608 call this%proj_vel%free()
609
610 call this%p_res%free()
611 call this%u_res%free()
612 call this%v_res%free()
613 call this%w_res%free()
614
615 call this%du%free()
616 call this%dv%free()
617 call this%dw%free()
618 call this%dp%free()
619
620 call this%abx1%free()
621 call this%aby1%free()
622 call this%abz1%free()
623
624 call this%abx2%free()
625 call this%aby2%free()
626 call this%abz2%free()
627
628 call this%advx%free()
629 call this%advy%free()
630 call this%advz%free()
631
632 if (allocated(this%Ax_vel)) then
633 deallocate(this%Ax_vel)
634 end if
635
636 if (allocated(this%Ax_prs)) then
637 deallocate(this%Ax_prs)
638 end if
639
640 if (allocated(this%prs_res)) then
641 deallocate(this%prs_res)
642 end if
643
644 if (allocated(this%vel_res)) then
645 deallocate(this%vel_res)
646 end if
647
648 if (allocated(this%sumab)) then
649 deallocate(this%sumab)
650 end if
651
652 if (allocated(this%makeabf)) then
653 deallocate(this%makeabf)
654 end if
655
656 if (allocated(this%makebdf)) then
657 deallocate(this%makebdf)
658 end if
659
660 if (allocated(this%makeoifs)) then
661 deallocate(this%makeoifs)
662 end if
663
664 if (allocated(this%ext_bdf)) then
665 deallocate(this%ext_bdf)
666 end if
667
668 ! call this%vol_flow%free()
669
670 end subroutine adjoint_fluid_pnpn_free
671
676 subroutine adjoint_fluid_pnpn_step(this, time, dt_controller)
677 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
678 type(time_state_t), intent(in) :: time
679 type(time_step_controller_t), intent(in) :: dt_controller
680 ! number of degrees of freedom
681 integer :: n
682 ! Solver results monitors (pressure + 3 velocity)
683 type(ksp_monitor_t) :: ksp_results(4)
684
685 if (this%freeze) return
686
687 n = this%dm_Xh%size()
688
689 call profiler_start_region('Adjoint')
690 associate(u => this%u_adj, v => this%v_adj, w => this%w_adj, &
691 p => this%p_adj, &
692 u_e => this%u_adj_e, v_e => this%v_adj_e, w_e => this%w_adj_e, &
693 du => this%du, dv => this%dv, dw => this%dw, dp => this%dp, &
694 u_b => this%u_b, v_b => this%v_b, w_b => this%w_b, &
695 u_res => this%u_res, v_res => this%v_res, w_res => this%w_res, &
696 p_res => this%p_res, ax_vel => this%Ax_vel, ax_prs => this%Ax_prs, &
697 xh => this%Xh, &
698 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
699 ulag => this%ulag, vlag => this%vlag, wlag => this%wlag, &
700 msh => this%msh, prs_res => this%prs_res, &
701 source_term => this%source_term, vel_res => this%vel_res, &
702 sumab => this%sumab, &
703 makeabf => this%makeabf, makebdf => this%makebdf, &
704 vel_projection_dim => this%vel_projection_dim, &
705 pr_projection_dim => this%pr_projection_dim, &
706 oifs => this%oifs, &
707 rho => this%rho, mu => this%mu, &
708 f_x => this%f_adj_x, f_y => this%f_adj_y, f_z => this%f_adj_z, &
709 t => time%t, tstep => time%tstep, dt => time%dt, &
710 ext_bdf => this%ext_bdf, event => glb_cmd_event)
711
712 ! Extrapolate the velocity if it's not done in nut_field estimation
713 call sumab%compute_fluid(u_e, v_e, w_e, u, v, w, &
714 ulag, vlag, wlag, ext_bdf%advection_coeffs, ext_bdf%nadv)
715
716 ! Compute the source terms
717 call this%source_term%compute(time)
718
719 ! Add Neumann bc contributions to the RHS
720 call this%bcs_vel%apply_vector(f_x%x, f_y%x, f_z%x, &
721 this%dm_Xh%size(), time, strong = .false.)
722
723 if (oifs) then
724 call neko_error("OIFS not implemented for adjoint")
725
726 else
727 ! Add the advection operators to the right-hand-side.
728 call this%adv%compute_adjoint(u, v, w, u_b, v_b, w_b, &
729 f_x, f_y, f_z, &
730 xh, this%c_Xh, dm_xh%size())
731
732 ! At this point the RHS contains the sum of the advection operator and
733 ! additional source terms, evaluated using the velocity field from the
734 ! previous time-step. Now, this value is used in the explicit time
735 ! scheme to advance both terms in time.
736 call makeabf%compute_fluid(this%abx1, this%aby1, this%abz1,&
737 this%abx2, this%aby2, this%abz2, &
738 f_x%x, f_y%x, f_z%x, &
739 rho%x(1,1,1,1), ext_bdf%advection_coeffs, n)
740
741 ! Add the RHS contributions coming from the BDF scheme.
742 call makebdf%compute_fluid(ulag, vlag, wlag, f_x%x, f_y%x, f_z%x, &
743 u, v, w, c_xh%B, rho%x(1,1,1,1), dt, &
744 ext_bdf%diffusion_coeffs, ext_bdf%ndiff, n)
745 end if
746
747 call ulag%update()
748 call vlag%update()
749 call wlag%update()
750
751 call this%bc_apply_vel(time, strong = .true.)
752 call this%bc_apply_prs(time)
753
754 ! Update material properties if necessary
755 call this%update_material_properties(time)
756
757 ! Compute pressure residual.
758 call profiler_start_region('Adjoint_pressure_residual')
759
760 call prs_res%compute(p, p_res, &
761 u, v, w, &
762 u_e, v_e, w_e, &
763 f_x, f_y, f_z, &
764 c_xh, gs_xh, &
765 this%bc_prs_surface, this%bc_sym_surface, &
766 ax_prs, ext_bdf%diffusion_coeffs(1), dt, &
767 mu, rho, event)
768
769 ! De-mean the pressure residual when no strong pressure boundaries present
770 if (.not. this%prs_dirichlet) call ortho(p_res%x, this%glb_n_points, n)
771
772 call gs_xh%op(p_res, gs_op_add, event)
773 call device_event_sync(event)
774
775 ! Set the residual to zero at strong pressure boundaries.
776 call this%bclst_dp%apply_scalar(p_res%x, p%dof%size(), time)
777
778
779 call profiler_end_region('Adjoint_pressure_residual')
780
781
782 call this%proj_prs%pre_solving(p_res%x, tstep, c_xh, n, dt_controller, &
783 'Pressure')
784
785 call this%pc_prs%update()
786
787 call profiler_start_region('Adjoint_pressure_solve')
788
789 ! Solve for the pressure increment.
790 ksp_results(1) = &
791 this%ksp_prs%solve(ax_prs, dp, p_res%x, n, c_xh, &
792 this%bclst_dp, gs_xh)
793
794
795 call profiler_end_region('Adjoint_pressure_solve')
796
797 call this%proj_prs%post_solving(dp%x, ax_prs, c_xh, &
798 this%bclst_dp, gs_xh, n, tstep, dt_controller)
799
800 ! Update the pressure with the increment. Demean if necessary.
801 call field_add2(p, dp, n)
802 if (.not. this%prs_dirichlet) call ortho(p%x, this%glb_n_points, n)
803
804 ! Compute velocity residual.
805 call profiler_start_region('Adjoint_velocity_residual')
806 call vel_res%compute(ax_vel, u, v, w, &
807 u_res, v_res, w_res, &
808 p, &
809 f_x, f_y, f_z, &
810 c_xh, msh, xh, &
811 mu, rho, ext_bdf%diffusion_coeffs(1), &
812 dt, dm_xh%size())
813
814 call gs_xh%op(u_res, gs_op_add, event)
815 call device_event_sync(event)
816 call gs_xh%op(v_res, gs_op_add, event)
817 call device_event_sync(event)
818 call gs_xh%op(w_res, gs_op_add, event)
819 call device_event_sync(event)
820
821 ! Set residual to zero at strong velocity boundaries.
822 call this%bclst_vel_res%apply(u_res, v_res, w_res, time)
823
824
825 call profiler_end_region('Adjoint_velocity_residual')
826
827 call this%proj_vel%pre_solving(u_res%x, v_res%x, w_res%x, &
828 tstep, c_xh, n, dt_controller, 'Velocity')
829
830 call this%pc_vel%update()
831
832 call profiler_start_region("Adjoint_velocity_solve")
833 ksp_results(2:4) = this%ksp_vel%solve_coupled(ax_vel, du, dv, dw, &
834 u_res%x, v_res%x, w_res%x, n, c_xh, &
835 this%bclst_du, this%bclst_dv, this%bclst_dw, gs_xh, &
836 this%ksp_vel%max_iter)
837 call profiler_end_region("Adjoint_velocity_solve")
838
839 ksp_results(1)%name = 'Adjoint Pressure'
840 ksp_results(2)%name = 'Adjoint Velocity U'
841 ksp_results(3)%name = 'Adjoint Velocity V'
842 ksp_results(4)%name = 'Adjoint Velocity W'
843
844 call this%proj_vel%post_solving(du%x, dv%x, dw%x, ax_vel, c_xh, &
845 this%bclst_du, this%bclst_dv, this%bclst_dw, gs_xh, n, tstep, &
846 dt_controller)
847
848 if (neko_bcknd_device .eq. 1) then
849 call device_opadd2cm(u%x_d, v%x_d, w%x_d, &
850 du%x_d, dv%x_d, dw%x_d, 1.0_rp, n, msh%gdim)
851 else
852 call opadd2cm(u%x, v%x, w%x, du%x, dv%x, dw%x, 1.0_rp, n, msh%gdim)
853 end if
854
855 if (this%forced_flow_rate) then
856 call neko_error('Forced flow rate is not implemented for the adjoint')
857
858 end if
859
860 call fluid_step_info(time, ksp_results, &
861 this%full_stress_formulation, this%strict_convergence)
862
863 end associate
864 call profiler_end_region('Adjoint')
865
866 end subroutine adjoint_fluid_pnpn_step
867
872 subroutine adjoint_fluid_pnpn_setup_bcs(this, user, params)
873 use mpi_f08, only: mpi_in_place
874 class(adjoint_fluid_pnpn_t), intent(inout) :: this
875 type(user_t), target, intent(in) :: user
876 type(json_file), intent(inout) :: params
877 integer :: i, n_bcs, j, zone_size, global_zone_size, ierr
878 class(bc_t), pointer :: bc_i
879 type(json_core) :: core
880 type(json_value), pointer :: bc_object
881 type(json_file) :: bc_subdict
882 logical :: found
883 ! Monitor which boundary zones have been marked
884 logical, allocatable :: marked_zones(:)
885 integer, allocatable :: zone_indices(:)
886 character(len=:), allocatable :: json_key
887
888 ! Lists for the residuals and solution increments
889 call this%bclst_vel_res%init()
890 call this%bclst_du%init()
891 call this%bclst_dv%init()
892 call this%bclst_dw%init()
893 call this%bclst_dp%init()
894
895 call this%bc_vel_res%init_from_components(this%c_Xh)
896 call this%bc_du%init_from_components(this%c_Xh)
897 call this%bc_dv%init_from_components(this%c_Xh)
898 call this%bc_dw%init_from_components(this%c_Xh)
899 call this%bc_dp%init_from_components(this%c_Xh)
900
901 ! Special PnPn boundary conditions for pressure
902 call this%bc_prs_surface%init_from_components(this%c_Xh)
903 call this%bc_sym_surface%init_from_components(this%c_Xh)
904
905 json_key = 'case.adjoint_fluid.boundary_conditions'
906
907 ! Populate bcs_vel and bcs_prs based on the case file
908 if (params%valid_path(json_key)) then
909 call params%info(json_key, n_children = n_bcs)
910 call params%get_core(core)
911 call params%get(json_key, bc_object, found)
912
913 !
914 ! Velocity bcs
915 !
916 call this%bcs_vel%init(n_bcs)
917
918 allocate(marked_zones(size(this%msh%labeled_zones)))
919 marked_zones = .false.
920
921 do i = 1, n_bcs
922 ! Create a new json containing just the subdict for this bc
923 call json_extract_item(core, bc_object, i, bc_subdict)
924
925 call json_get(bc_subdict, "zone_indices", zone_indices)
926
927 ! Check that we are not trying to assing a bc to zone, for which one
928 ! has already been assigned and that the zone has more than 0 size
929 ! in the mesh.
930 do j = 1, size(zone_indices)
931 zone_size = this%msh%labeled_zones(zone_indices(j))%size
932 call mpi_allreduce(zone_size, global_zone_size, 1, &
933 mpi_integer, mpi_max, neko_comm, ierr)
934
935 if (global_zone_size .eq. 0) then
936 write(error_unit, '(A, A, I0, A, A, I0, A)') "*** ERROR ***: ",&
937 "Zone index ", zone_indices(j), &
938 " is invalid as this zone has 0 size, meaning it does ", &
939 "not in the mesh. Check adjoint boundary condition ", &
940 i, "."
941 error stop
942 end if
943
944 if (marked_zones(zone_indices(j)) .eqv. .true.) then
945 write(error_unit, '(A, A, I0, A, A, A, A)') "*** ERROR ***: ", &
946 "Zone with index ", zone_indices(j), &
947 " has already been assigned a boundary condition. ", &
948 "Please check your boundary_conditions entry for the ", &
949 "adjoint and make sure that each zone index appears ", &
950 "only in a single boundary condition."
951 error stop
952 else
953 marked_zones(zone_indices(j)) = .true.
954 end if
955 end do
956
957 bc_i => null()
958 call velocity_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
959
960 ! Not all bcs require an allocation for velocity in particular,
961 ! so we check.
962 if (associated(bc_i)) then
963
964 ! We need to treat mixed bcs separately because they are by
965 ! convention marked weak and currently contain nested
966 ! bcs, some of which are strong.
967 select type (bc_i)
968 type is (symmetry_t)
969 ! Symmetry has 3 internal bcs, but only one actually contains
970 ! markings.
971 ! Symmetry's apply_scalar doesn't do anything, so we need to
972 ! mark individual nested bcs to the du,dv,dw, whereas the
973 ! vel_res can just get symmetry as a whole, because on this
974 ! list we call apply_vector.
975 ! Additionally we have to mark the special surface bc for p.
976 call this%bclst_vel_res%append(bc_i)
977 call this%bc_du%mark_facets(bc_i%bc_x%marked_facet)
978 call this%bc_dv%mark_facets(bc_i%bc_y%marked_facet)
979 call this%bc_dw%mark_facets(bc_i%bc_z%marked_facet)
980
981 call this%bcs_vel%append(bc_i)
982
983 call this%bc_sym_surface%mark_facets(bc_i%marked_facet)
984 type is (non_normal_t)
985 ! This is a bc for the residuals and increments, not the
986 ! velocity itself. So, don't append to bcs_vel
987 call this%bclst_vel_res%append(bc_i)
988 call this%bc_du%mark_facets(bc_i%bc_x%marked_facet)
989 call this%bc_dv%mark_facets(bc_i%bc_y%marked_facet)
990 call this%bc_dw%mark_facets(bc_i%bc_z%marked_facet)
991 type is (shear_stress_t)
992 ! Same as symmetry
993 call this%bclst_vel_res%append(bc_i%symmetry)
994 call this%bclst_du%append(bc_i%symmetry%bc_x)
995 call this%bclst_dv%append(bc_i%symmetry%bc_y)
996 call this%bclst_dw%append(bc_i%symmetry%bc_z)
997
998 call this%bcs_vel%append(bc_i)
999 type is (wall_model_bc_t)
1000 ! Same as symmetry
1001 call this%bclst_vel_res%append(bc_i%symmetry)
1002 call this%bclst_du%append(bc_i%symmetry%bc_x)
1003 call this%bclst_dv%append(bc_i%symmetry%bc_y)
1004 call this%bclst_dw%append(bc_i%symmetry%bc_z)
1005
1006 call this%bcs_vel%append(bc_i)
1007 class default
1008
1009 ! For the default case we use our dummy zero_dirichlet bcs to
1010 ! mark the same faces as in ordinary velocity dirichlet
1011 ! conditions.
1012 ! Additionally we mark the special PnPn pressure bc.
1013 if (bc_i%strong .eqv. .true.) then
1014 call this%bc_vel_res%mark_facets(bc_i%marked_facet)
1015 call this%bc_du%mark_facets(bc_i%marked_facet)
1016 call this%bc_dv%mark_facets(bc_i%marked_facet)
1017 call this%bc_dw%mark_facets(bc_i%marked_facet)
1018
1019 call this%bc_prs_surface%mark_facets(bc_i%marked_facet)
1020 end if
1021
1022 call this%bcs_vel%append(bc_i)
1023 end select
1024 end if
1025 end do
1026
1027 ! Make sure all labeled zones with non-zero size have been marked
1028 do i = 1, size(this%msh%labeled_zones)
1029 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
1030 (marked_zones(i) .eqv. .false.)) then
1031 write(error_unit, '(A, A, I0)') "*** ERROR ***: ", &
1032 "No adjoint boundary condition assigned to zone ", i
1033 error stop
1034 end if
1035 end do
1036
1037 !
1038 ! Pressure bcs
1039 !
1040 call this%bcs_prs%init(n_bcs)
1041
1042 do i = 1, n_bcs
1043 ! Create a new json containing just the subdict for this bc
1044 call json_extract_item(core, bc_object, i, bc_subdict)
1045 bc_i => null()
1046 call pressure_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
1047
1048 ! Not all bcs require an allocation for pressure in particular,
1049 ! so we check.
1050 if (associated(bc_i)) then
1051 call this%bcs_prs%append(bc_i)
1052
1053 ! Mark strong bcs in the dummy dp bc to force zero change.
1054 if (bc_i%strong .eqv. .true.) then
1055 call this%bc_dp%mark_facets(bc_i%marked_facet)
1056 end if
1057
1058 end if
1059
1060 end do
1061 else
1062 ! Check that there are no labeled zones, i.e. all are periodic.
1063 do i = 1, size(this%msh%labeled_zones)
1064 if (this%msh%labeled_zones(i)%size .gt. 0) then
1065 call neko_error("No boundary_conditions entry in the case file!")
1066 end if
1067 end do
1068
1069 end if
1070
1071 call this%bc_prs_surface%finalize()
1072 call this%bc_sym_surface%finalize()
1073
1074 call this%bc_vel_res%finalize()
1075 call this%bc_du%finalize()
1076 call this%bc_dv%finalize()
1077 call this%bc_dw%finalize()
1078 call this%bc_dp%finalize()
1079
1080 call this%bclst_vel_res%append(this%bc_vel_res)
1081 call this%bclst_du%append(this%bc_du)
1082 call this%bclst_dv%append(this%bc_dv)
1083 call this%bclst_dw%append(this%bc_dw)
1084 call this%bclst_dp%append(this%bc_dp)
1085
1086 ! If we have no strong pressure bcs, we will demean the pressure
1087 this%prs_dirichlet = .not. this%bclst_dp%is_empty()
1088 call mpi_allreduce(mpi_in_place, this%prs_dirichlet, 1, &
1089 mpi_logical, mpi_lor, neko_comm)
1090
1091 end subroutine adjoint_fluid_pnpn_setup_bcs
1092
1094 subroutine adjoint_fluid_pnpn_write_boundary_conditions(this)
1095 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
1096 type(dirichlet_t) :: bdry_mask
1097 type(field_t), pointer :: bdry_field
1098 type(file_t) :: bdry_file
1099 integer :: temp_index, i
1100 class(bc_t), pointer :: bci
1101 character(len=LOG_SIZE) :: log_buf
1102
1103 call neko_log%section("Adjoint boundary conditions")
1104 write(log_buf, '(A)') &
1105 'Marking using integer keys in boundary_adjoint0.f00000'
1106 call neko_log%message(log_buf)
1107 write(log_buf, '(A)') 'Condition-value pairs: '
1108 call neko_log%message(log_buf)
1109 write(log_buf, '(A)') ' no_slip = 1'
1110 call neko_log%message(log_buf)
1111 write(log_buf, '(A)') ' velocity_value = 2'
1112 call neko_log%message(log_buf)
1113 write(log_buf, '(A)') ' outflow, normal_outflow (+dong) = 3'
1114 call neko_log%message(log_buf)
1115 write(log_buf, '(A)') ' symmetry = 4'
1116 call neko_log%message(log_buf)
1117 write(log_buf, '(A)') ' user_velocity_pointwise = 5'
1118 call neko_log%message(log_buf)
1119 write(log_buf, '(A)') ' periodic = 6'
1120 call neko_log%message(log_buf)
1121 write(log_buf, '(A)') ' user_velocity = 7'
1122 call neko_log%message(log_buf)
1123 write(log_buf, '(A)') ' user_pressure = 8'
1124 call neko_log%message(log_buf)
1125 write(log_buf, '(A)') ' shear_stress = 9'
1126 call neko_log%message(log_buf)
1127 write(log_buf, '(A)') ' wall_modelling = 10'
1128 call neko_log%message(log_buf)
1129 write(log_buf, '(A)') ' blasius_profile = 11'
1130 call neko_log%message(log_buf)
1131 call neko_log%end_section()
1132
1133 call this%scratch%request_field(bdry_field, temp_index)
1134 bdry_field = 0.0_rp
1135
1136
1137
1138 call bdry_mask%init_from_components(this%c_Xh, 6.0_rp)
1139 call bdry_mask%mark_zone(this%msh%periodic)
1140 call bdry_mask%finalize()
1141 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1142 call bdry_mask%free()
1143
1144 do i = 1, this%bcs_prs%size()
1145 bci => this%bcs_prs%get(i)
1146 select type (bc => bci)
1147 type is (zero_dirichlet_t)
1148 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1149 call bdry_mask%mark_facets(bci%marked_facet)
1150 call bdry_mask%finalize()
1151 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1152 call bdry_mask%free()
1153 type is (dong_outflow_t)
1154 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1155 call bdry_mask%mark_facets(bci%marked_facet)
1156 call bdry_mask%finalize()
1157 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1158 call bdry_mask%free()
1159 type is (field_dirichlet_t)
1160 call bdry_mask%init_from_components(this%c_Xh, 8.0_rp)
1161 call bdry_mask%mark_facets(bci%marked_facet)
1162 call bdry_mask%finalize()
1163 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1164 call bdry_mask%free()
1165 end select
1166 end do
1167
1168 do i = 1, this%bcs_vel%size()
1169 bci => this%bcs_vel%get(i)
1170 select type (bc => bci)
1171 type is (zero_dirichlet_t)
1172 call bdry_mask%init_from_components(this%c_Xh, 1.0_rp)
1173 call bdry_mask%mark_facets(bci%marked_facet)
1174 call bdry_mask%finalize()
1175 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1176 call bdry_mask%free()
1177 type is (inflow_t)
1178 call bdry_mask%init_from_components(this%c_Xh, 2.0_rp)
1179 call bdry_mask%mark_facets(bci%marked_facet)
1180 call bdry_mask%finalize()
1181 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1182 call bdry_mask%free()
1183 type is (symmetry_t)
1184 call bdry_mask%init_from_components(this%c_Xh, 4.0_rp)
1185 call bdry_mask%mark_facets(bci%marked_facet)
1186 call bdry_mask%finalize()
1187 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1188 call bdry_mask%free()
1189 type is (field_dirichlet_vector_t)
1190 call bdry_mask%init_from_components(this%c_Xh, 7.0_rp)
1191 call bdry_mask%mark_facets(bci%marked_facet)
1192 call bdry_mask%finalize()
1193 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1194 call bdry_mask%free()
1195 type is (shear_stress_t)
1196 call bdry_mask%init_from_components(this%c_Xh, 9.0_rp)
1197 call bdry_mask%mark_facets(bci%marked_facet)
1198 call bdry_mask%finalize()
1199 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1200 call bdry_mask%free()
1201 type is (wall_model_bc_t)
1202 call bdry_mask%init_from_components(this%c_Xh, 10.0_rp)
1203 call bdry_mask%mark_facets(bci%marked_facet)
1204 call bdry_mask%finalize()
1205 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1206 call bdry_mask%free()
1207 type is (blasius_t)
1208 call bdry_mask%init_from_components(this%c_Xh, 11.0_rp)
1209 call bdry_mask%mark_facets(bci%marked_facet)
1210 call bdry_mask%finalize()
1211 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1212 call bdry_mask%free()
1213 end select
1214 end do
1215
1216
1217 call bdry_file%init('boundary_adjoint.fld')
1218 call bdry_file%write(bdry_field)
1219
1220 call this%scratch%relinquish_field(temp_index)
1221 end subroutine adjoint_fluid_pnpn_write_boundary_conditions
1222
1223 ! End of section to verify
1224 ! ========================================================================== !
1225
1226 subroutine rescale_fluid(fluid_data, scale)
1227
1228 class(adjoint_fluid_pnpn_t), intent(inout) :: fluid_data
1230 real(kind=rp), intent(in) :: scale
1231
1232 ! Local variables
1233 integer :: i
1234
1235 ! Scale the velocity fields
1236 if (neko_bcknd_device .eq. 1) then
1237 call device_cmult(fluid_data%u_adj%x_d, scale, fluid_data%u_adj%size())
1238 call device_cmult(fluid_data%v_adj%x_d, scale, fluid_data%v_adj%size())
1239 call device_cmult(fluid_data%w_adj%x_d, scale, fluid_data%w_adj%size())
1240 else
1241 call cmult(fluid_data%u_adj%x, scale, fluid_data%u_adj%size())
1242 call cmult(fluid_data%v_adj%x, scale, fluid_data%v_adj%size())
1243 call cmult(fluid_data%w_adj%x, scale, fluid_data%w_adj%size())
1244 end if
1245
1246 ! Scale the right hand sides
1247 if (neko_bcknd_device .eq. 1) then
1248 call device_cmult(fluid_data%f_adj_x%x_d, scale, &
1249 fluid_data%f_adj_x%size())
1250 call device_cmult(fluid_data%f_adj_y%x_d, scale, &
1251 fluid_data%f_adj_y%size())
1252 call device_cmult(fluid_data%f_adj_z%x_d, scale, &
1253 fluid_data%f_adj_z%size())
1254 ! HARRY
1255 ! maybe the abx's too
1256 call device_cmult(fluid_data%abx1%x_d, scale, fluid_data%abx1%size())
1257 call device_cmult(fluid_data%aby1%x_d, scale, fluid_data%aby1%size())
1258 call device_cmult(fluid_data%abz1%x_d, scale, fluid_data%abz1%size())
1259 call device_cmult(fluid_data%abx2%x_d, scale, fluid_data%abx2%size())
1260 call device_cmult(fluid_data%aby2%x_d, scale, fluid_data%aby2%size())
1261 call device_cmult(fluid_data%abz2%x_d, scale, fluid_data%abz2%size())
1262
1263 else
1264 call cmult(fluid_data%f_adj_x%x, scale, fluid_data%f_adj_x%size())
1265 call cmult(fluid_data%f_adj_y%x, scale, fluid_data%f_adj_y%size())
1266 call cmult(fluid_data%f_adj_z%x, scale, fluid_data%f_adj_z%size())
1267
1268 call cmult(fluid_data%abx1%x, scale, fluid_data%abx1%size())
1269 call cmult(fluid_data%aby1%x, scale, fluid_data%aby1%size())
1270 call cmult(fluid_data%abz1%x, scale, fluid_data%abz1%size())
1271
1272 call cmult(fluid_data%abx2%x, scale, fluid_data%abx2%size())
1273 call cmult(fluid_data%aby2%x, scale, fluid_data%aby2%size())
1274 call cmult(fluid_data%abz2%x, scale, fluid_data%abz2%size())
1275 end if
1276
1277 ! Scale the lag terms
1278 if (neko_bcknd_device .eq. 1) then
1279 do i = 1, fluid_data%ulag%size()
1280 call device_cmult(fluid_data%ulag%lf(i)%x_d, &
1281 scale, fluid_data%ulag%lf(i)%size())
1282 end do
1283
1284 do i = 1, fluid_data%vlag%size()
1285 call device_cmult(fluid_data%vlag%lf(i)%x_d, &
1286 scale, fluid_data%vlag%lf(i)%size())
1287 end do
1288
1289 do i = 1, fluid_data%wlag%size()
1290 call device_cmult(fluid_data%wlag%lf(i)%x_d, &
1291 scale, fluid_data%wlag%lf(i)%size())
1292 end do
1293 else
1294 do i = 1, fluid_data%ulag%size()
1295 call cmult(fluid_data%ulag%lf(i)%x, &
1296 scale, fluid_data%ulag%lf(i)%size())
1297 end do
1298
1299 do i = 1, fluid_data%vlag%size()
1300 call cmult(fluid_data%vlag%lf(i)%x, &
1301 scale, fluid_data%vlag%lf(i)%size())
1302 end do
1303
1304 do i = 1, fluid_data%wlag%size()
1305 call cmult(fluid_data%wlag%lf(i)%x, &
1306 scale, fluid_data%wlag%lf(i)%size())
1307 end do
1308 end if
1309
1310 end subroutine rescale_fluid
1311
1312 function norm(x, y, z, B, volume, n)
1313 use mpi_f08, only: mpi_in_place
1314
1315 integer, intent(in) :: n
1316 real(kind=rp), dimension(n), intent(in) :: x, y, z
1317 real(kind=rp), dimension(n), intent(in) :: b
1318 real(kind=rp), intent(in) :: volume
1319
1320 real(kind=rp) :: norm
1321
1322 norm = vlsc3(x, x, b, n) + vlsc3(y, y, b, n) + vlsc3(z, z, b, n)
1323
1324 call mpi_allreduce(mpi_in_place, norm, 1, &
1325 mpi_real_precision, mpi_sum, mpi_comm_world)
1326
1327 norm = sqrt(norm / volume)
1328 end function norm
1329
1330 function device_norm(x_d, y_d, z_d, B_d, volume, n)
1331 use mpi_f08, only: mpi_in_place
1332
1333 type(c_ptr), intent(in) :: x_d, y_d, z_d
1334 type(c_ptr), intent(in) :: B_d
1335 real(kind=rp), intent(in) :: volume
1336 integer, intent(in) :: n
1337
1338 real(kind=rp) :: device_norm
1339
1340 device_norm = device_vlsc3(x_d, x_d, b_d, n) + &
1341 device_vlsc3(y_d, y_d, b_d, n) + &
1342 device_vlsc3(z_d, z_d, b_d, n)
1343
1344 call mpi_allreduce(mpi_in_place, device_norm, 1, &
1345 mpi_real_precision, mpi_sum, mpi_comm_world)
1346
1347 device_norm = sqrt(device_norm / volume)
1348
1349 end function device_norm
1350
1355 subroutine power_iterations_compute(this, t, tstep)
1356 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
1357 real(kind=rp), intent(in) :: t
1358 integer, intent(in) :: tstep
1359
1360 ! Local variables
1361 real(kind=rp) :: scaling_factor
1362 real(kind=rp) :: norm_l2, norm_l2_base
1363 character(len=256) :: log_message
1364 type(vector_t) :: data_line
1365 integer :: n
1366
1367 n = this%c_Xh%dof%size()
1368 if (tstep .eq. 1) then
1369 if (neko_bcknd_device .eq. 1) then
1370 norm_l2_base = device_norm(this%u_adj%x_d, this%v_adj%x_d, &
1371 this%w_adj%x_d, &
1372 this%c_Xh%B_d, this%c_Xh%volume, n)
1373 else
1374 norm_l2_base = this%norm_scaling * norm(this%u_adj%x, this%v_adj%x, &
1375 this%w_adj%x, &
1376 this%c_Xh%B, this%c_Xh%volume, n)
1377 end if
1378 if (this%norm_target .lt. 0.0_rp) then
1379 this%norm_target = norm_l2_base
1380 end if
1381
1382 this%norm_l2_upper = this%norm_tolerance * this%norm_target
1383 this%norm_l2_lower = this%norm_target / this%norm_tolerance
1384
1385 end if
1386
1387 ! Compute the norm of the velocity field and eigenvalue estimate
1388 if (neko_bcknd_device .eq. 1) then
1389 norm_l2 = device_norm(this%u_adj%x_d, this%v_adj%x_d, this%w_adj%x_d, &
1390 this%c_Xh%B_d, this%c_Xh%volume, n)
1391 else
1392 norm_l2 = norm(this%u_adj%x, this%v_adj%x, this%w_adj%x, &
1393 this%c_Xh%B, this%c_Xh%volume, n)
1394 end if
1395 norm_l2 = sqrt(this%norm_scaling) * norm_l2
1396 scaling_factor = 1.0_rp
1397
1398 ! Rescale the flow if necessary
1399 if (norm_l2 .gt. this%norm_l2_upper &
1400 .or. norm_l2 .lt. this%norm_l2_lower) then
1401 scaling_factor = this%norm_target / norm_l2
1402 call rescale_fluid(this, scaling_factor)
1403 norm_l2 = this%norm_target
1404
1405 if (tstep .eq. 1) then
1406 scaling_factor = 1.0_rp
1407 end if
1408 end if
1409
1410 ! Log the results
1411 !call neko_log%section('Power Iterations', lvl = NEKO_LOG_DEBUG)
1412 call neko_log%section('Power Iterations')
1413
1414 write (log_message, '(A7,E20.14)') 'Norm: ', norm_l2
1415 call neko_log%message(log_message, lvl = neko_log_debug)
1416 write (log_message, '(A7,E20.14)') 'Scaling: ', scaling_factor
1417 call neko_log%message(log_message, lvl = neko_log_debug)
1418
1419 ! Save to file
1420 call data_line%init(2)
1421 data_line%x = [norm_l2, scaling_factor]
1422 call this%file_output%write(data_line, t)
1423
1424 !call neko_log%end_section('Power Iterations', lvl = NEKO_LOG_DEBUG)
1425 call neko_log%end_section('Power Iterations')
1426 end subroutine power_iterations_compute
1427
1428
1429end module adjoint_fluid_pnpn
Boundary condition factory for pressure.
Adjoint Pn/Pn formulation.
Subroutines to add advection terms to the RHS of a transport equation.
Base abstract type for computing the advection operator.