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