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 time_state, only: time_state_t
86 use vector, only: vector_t
87 use device_math, only: device_vlsc3, device_cmult
88 use math, only: vlsc3, cmult
89 use json_utils_ext, only: json_key_fallback
90 use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr, c_associated
91 use comm, only: neko_comm, mpi_real_precision
92 use mpi_f08, only: mpi_sum, mpi_max, mpi_allreduce, mpi_comm_world, &
93 mpi_integer, mpi_logical, mpi_lor
94
95 implicit none
96 private
97
99
101 type(field_t) :: p_res, u_res, v_res, w_res
102
105 type(field_t) :: dp, du, dv, dw
106
107 type(field_t), pointer :: u_b => null()
108 type(field_t), pointer :: v_b => null()
109 type(field_t), pointer :: w_b => null()
110 type(field_t), pointer :: p_b => null()
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(t, tstep)
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(), t, tstep, 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(t, tstep, strong = .true.)
753 call this%bc_apply_prs(t, tstep)
754
755 ! Update material properties if necessary
756 call this%update_material_properties(t, tstep)
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(), t, tstep)
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, t, tstep)
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 call this%proj_vel%post_solving(du%x, dv%x, dw%x, ax_vel, c_xh, &
841 this%bclst_du, this%bclst_dv, this%bclst_dw, gs_xh, n, tstep, &
842 dt_controller)
843
844 if (neko_bcknd_device .eq. 1) then
845 call device_opadd2cm(u%x_d, v%x_d, w%x_d, &
846 du%x_d, dv%x_d, dw%x_d, 1.0_rp, n, msh%gdim)
847 else
848 call opadd2cm(u%x, v%x, w%x, du%x, dv%x, dw%x, 1.0_rp, n, msh%gdim)
849 end if
850
851 if (this%forced_flow_rate) then
852 call neko_error('Forced flow rate is not implemented for the adjoint')
853
854 end if
855
856 call fluid_step_info(time, ksp_results, &
857 this%full_stress_formulation, this%strict_convergence)
858
859 end associate
860 call profiler_end_region('Adjoint', 13)
861
862 end subroutine adjoint_fluid_pnpn_step
863
868 subroutine adjoint_fluid_pnpn_setup_bcs(this, user, params)
869 use mpi_f08, only: mpi_in_place
870 class(adjoint_fluid_pnpn_t), intent(inout) :: this
871 type(user_t), target, intent(in) :: user
872 type(json_file), intent(inout) :: params
873 integer :: i, n_bcs, j, zone_size, global_zone_size, ierr
874 class(bc_t), pointer :: bc_i
875 type(json_core) :: core
876 type(json_value), pointer :: bc_object
877 type(json_file) :: bc_subdict
878 logical :: found
879 ! Monitor which boundary zones have been marked
880 logical, allocatable :: marked_zones(:)
881 integer, allocatable :: zone_indices(:)
882 character(len=:), allocatable :: json_key
883
884 ! Lists for the residuals and solution increments
885 call this%bclst_vel_res%init()
886 call this%bclst_du%init()
887 call this%bclst_dv%init()
888 call this%bclst_dw%init()
889 call this%bclst_dp%init()
890
891 call this%bc_vel_res%init_from_components(this%c_Xh)
892 call this%bc_du%init_from_components(this%c_Xh)
893 call this%bc_dv%init_from_components(this%c_Xh)
894 call this%bc_dw%init_from_components(this%c_Xh)
895 call this%bc_dp%init_from_components(this%c_Xh)
896
897 ! Special PnPn boundary conditions for pressure
898 call this%bc_prs_surface%init_from_components(this%c_Xh)
899 call this%bc_sym_surface%init_from_components(this%c_Xh)
900
901 json_key = 'case.adjoint_fluid.boundary_conditions'
902
903 ! Populate bcs_vel and bcs_prs based on the case file
904 if (params%valid_path(json_key)) then
905 call params%info(json_key, n_children = n_bcs)
906 call params%get_core(core)
907 call params%get(json_key, bc_object, found)
908
909 !
910 ! Velocity bcs
911 !
912 call this%bcs_vel%init(n_bcs)
913
914 allocate(marked_zones(size(this%msh%labeled_zones)))
915 marked_zones = .false.
916
917 do i = 1, n_bcs
918 ! Create a new json containing just the subdict for this bc
919 call json_extract_item(core, bc_object, i, bc_subdict)
920
921 call json_get(bc_subdict, "zone_indices", zone_indices)
922
923 ! Check that we are not trying to assing a bc to zone, for which one
924 ! has already been assigned and that the zone has more than 0 size
925 ! in the mesh.
926 do j = 1, size(zone_indices)
927 zone_size = this%msh%labeled_zones(zone_indices(j))%size
928 call mpi_allreduce(zone_size, global_zone_size, 1, &
929 mpi_integer, mpi_max, neko_comm, ierr)
930
931 if (global_zone_size .eq. 0) then
932 write(error_unit, '(A, A, I0, A, A, I0, A)') "*** ERROR ***: ",&
933 "Zone index ", zone_indices(j), &
934 " is invalid as this zone has 0 size, meaning it does ", &
935 "not in the mesh. Check adjoint boundary condition ", &
936 i, "."
937 error stop
938 end if
939
940 if (marked_zones(zone_indices(j)) .eqv. .true.) then
941 write(error_unit, '(A, A, I0, A, A, A, A)') "*** ERROR ***: ", &
942 "Zone with index ", zone_indices(j), &
943 " has already been assigned a boundary condition. ", &
944 "Please check your boundary_conditions entry for the ", &
945 "adjoint and make sure that each zone index appears ", &
946 "only in a single boundary condition."
947 error stop
948 else
949 marked_zones(zone_indices(j)) = .true.
950 end if
951 end do
952
953 bc_i => null()
954 call velocity_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
955
956 ! Not all bcs require an allocation for velocity in particular,
957 ! so we check.
958 if (associated(bc_i)) then
959
960 ! We need to treat mixed bcs separately because they are by
961 ! convention marked weak and currently contain nested
962 ! bcs, some of which are strong.
963 select type (bc_i)
964 type is (symmetry_t)
965 ! Symmetry has 3 internal bcs, but only one actually contains
966 ! markings.
967 ! Symmetry's apply_scalar doesn't do anything, so we need to
968 ! mark individual nested bcs to the du,dv,dw, whereas the
969 ! vel_res can just get symmetry as a whole, because on this
970 ! list we call apply_vector.
971 ! Additionally we have to mark the special surface bc for p.
972 call this%bclst_vel_res%append(bc_i)
973 call this%bc_du%mark_facets(bc_i%bc_x%marked_facet)
974 call this%bc_dv%mark_facets(bc_i%bc_y%marked_facet)
975 call this%bc_dw%mark_facets(bc_i%bc_z%marked_facet)
976
977 call this%bcs_vel%append(bc_i)
978
979 call this%bc_sym_surface%mark_facets(bc_i%marked_facet)
980 type is (non_normal_t)
981 ! This is a bc for the residuals and increments, not the
982 ! velocity itself. So, don't append to bcs_vel
983 call this%bclst_vel_res%append(bc_i)
984 call this%bc_du%mark_facets(bc_i%bc_x%marked_facet)
985 call this%bc_dv%mark_facets(bc_i%bc_y%marked_facet)
986 call this%bc_dw%mark_facets(bc_i%bc_z%marked_facet)
987 type is (shear_stress_t)
988 ! Same as symmetry
989 call this%bclst_vel_res%append(bc_i%symmetry)
990 call this%bclst_du%append(bc_i%symmetry%bc_x)
991 call this%bclst_dv%append(bc_i%symmetry%bc_y)
992 call this%bclst_dw%append(bc_i%symmetry%bc_z)
993
994 call this%bcs_vel%append(bc_i)
995 type is (wall_model_bc_t)
996 ! Same as symmetry
997 call this%bclst_vel_res%append(bc_i%symmetry)
998 call this%bclst_du%append(bc_i%symmetry%bc_x)
999 call this%bclst_dv%append(bc_i%symmetry%bc_y)
1000 call this%bclst_dw%append(bc_i%symmetry%bc_z)
1001
1002 call this%bcs_vel%append(bc_i)
1003 class default
1004
1005 ! For the default case we use our dummy zero_dirichlet bcs to
1006 ! mark the same faces as in ordinary velocity dirichlet
1007 ! conditions.
1008 ! Additionally we mark the special PnPn pressure bc.
1009 if (bc_i%strong .eqv. .true.) then
1010 call this%bc_vel_res%mark_facets(bc_i%marked_facet)
1011 call this%bc_du%mark_facets(bc_i%marked_facet)
1012 call this%bc_dv%mark_facets(bc_i%marked_facet)
1013 call this%bc_dw%mark_facets(bc_i%marked_facet)
1014
1015 call this%bc_prs_surface%mark_facets(bc_i%marked_facet)
1016 end if
1017
1018 call this%bcs_vel%append(bc_i)
1019 end select
1020 end if
1021 end do
1022
1023 ! Make sure all labeled zones with non-zero size have been marked
1024 do i = 1, size(this%msh%labeled_zones)
1025 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
1026 (marked_zones(i) .eqv. .false.)) then
1027 write(error_unit, '(A, A, I0)') "*** ERROR ***: ", &
1028 "No adjoint boundary condition assigned to zone ", i
1029 error stop
1030 end if
1031 end do
1032
1033 !
1034 ! Pressure bcs
1035 !
1036 call this%bcs_prs%init(n_bcs)
1037
1038 do i = 1, n_bcs
1039 ! Create a new json containing just the subdict for this bc
1040 call json_extract_item(core, bc_object, i, bc_subdict)
1041 bc_i => null()
1042 call pressure_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
1043
1044 ! Not all bcs require an allocation for pressure in particular,
1045 ! so we check.
1046 if (associated(bc_i)) then
1047 call this%bcs_prs%append(bc_i)
1048
1049 ! Mark strong bcs in the dummy dp bc to force zero change.
1050 if (bc_i%strong .eqv. .true.) then
1051 call this%bc_dp%mark_facets(bc_i%marked_facet)
1052 end if
1053
1054 end if
1055
1056 end do
1057 else
1058 ! Check that there are no labeled zones, i.e. all are periodic.
1059 do i = 1, size(this%msh%labeled_zones)
1060 if (this%msh%labeled_zones(i)%size .gt. 0) then
1061 call neko_error("No boundary_conditions entry in the case file!")
1062 end if
1063 end do
1064
1065 end if
1066
1067 call this%bc_prs_surface%finalize()
1068 call this%bc_sym_surface%finalize()
1069
1070 call this%bc_vel_res%finalize()
1071 call this%bc_du%finalize()
1072 call this%bc_dv%finalize()
1073 call this%bc_dw%finalize()
1074 call this%bc_dp%finalize()
1075
1076 call this%bclst_vel_res%append(this%bc_vel_res)
1077 call this%bclst_du%append(this%bc_du)
1078 call this%bclst_dv%append(this%bc_dv)
1079 call this%bclst_dw%append(this%bc_dw)
1080 call this%bclst_dp%append(this%bc_dp)
1081
1082 ! If we have no strong pressure bcs, we will demean the pressure
1083 this%prs_dirichlet = .not. this%bclst_dp%is_empty()
1084 call mpi_allreduce(mpi_in_place, this%prs_dirichlet, 1, &
1085 mpi_logical, mpi_lor, neko_comm)
1086
1087 end subroutine adjoint_fluid_pnpn_setup_bcs
1088
1090 subroutine adjoint_fluid_pnpn_write_boundary_conditions(this)
1091 use inflow, only: inflow_t
1092 use field_dirichlet, only: field_dirichlet_t
1093 use blasius, only: blasius_t
1094 use field_dirichlet_vector, only: field_dirichlet_vector_t
1095 use usr_inflow, only: usr_inflow_t
1096 use dong_outflow, only: dong_outflow_t
1097 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
1098 type(dirichlet_t) :: bdry_mask
1099 type(field_t), pointer :: bdry_field
1100 type(file_t) :: bdry_file
1101 integer :: temp_index, i
1102 class(bc_t), pointer :: bci
1103 character(len=LOG_SIZE) :: log_buf
1104
1105 call neko_log%section("Adjoint boundary conditions")
1106 write(log_buf, '(A)') &
1107 'Marking using integer keys in boundary_adjoint0.f00000'
1108 call neko_log%message(log_buf)
1109 write(log_buf, '(A)') 'Condition-value pairs: '
1110 call neko_log%message(log_buf)
1111 write(log_buf, '(A)') ' no_slip = 1'
1112 call neko_log%message(log_buf)
1113 write(log_buf, '(A)') ' velocity_value = 2'
1114 call neko_log%message(log_buf)
1115 write(log_buf, '(A)') ' outflow, normal_outflow (+dong) = 3'
1116 call neko_log%message(log_buf)
1117 write(log_buf, '(A)') ' symmetry = 4'
1118 call neko_log%message(log_buf)
1119 write(log_buf, '(A)') ' user_velocity_pointwise = 5'
1120 call neko_log%message(log_buf)
1121 write(log_buf, '(A)') ' periodic = 6'
1122 call neko_log%message(log_buf)
1123 write(log_buf, '(A)') ' user_velocity = 7'
1124 call neko_log%message(log_buf)
1125 write(log_buf, '(A)') ' user_pressure = 8'
1126 call neko_log%message(log_buf)
1127 write(log_buf, '(A)') ' shear_stress = 9'
1128 call neko_log%message(log_buf)
1129 write(log_buf, '(A)') ' wall_modelling = 10'
1130 call neko_log%message(log_buf)
1131 write(log_buf, '(A)') ' blasius_profile = 11'
1132 call neko_log%message(log_buf)
1133 call neko_log%end_section()
1134
1135 call this%scratch%request_field(bdry_field, temp_index)
1136 bdry_field = 0.0_rp
1137
1138
1139
1140 call bdry_mask%init_from_components(this%c_Xh, 6.0_rp)
1141 call bdry_mask%mark_zone(this%msh%periodic)
1142 call bdry_mask%finalize()
1143 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1144 call bdry_mask%free()
1145
1146 do i = 1, this%bcs_prs%size()
1147 bci => this%bcs_prs%get(i)
1148 select type (bc => bci)
1149 type is (zero_dirichlet_t)
1150 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1151 call bdry_mask%mark_facets(bci%marked_facet)
1152 call bdry_mask%finalize()
1153 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1154 call bdry_mask%free()
1155 type is (dong_outflow_t)
1156 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1157 call bdry_mask%mark_facets(bci%marked_facet)
1158 call bdry_mask%finalize()
1159 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1160 call bdry_mask%free()
1161 type is (field_dirichlet_t)
1162 call bdry_mask%init_from_components(this%c_Xh, 8.0_rp)
1163 call bdry_mask%mark_facets(bci%marked_facet)
1164 call bdry_mask%finalize()
1165 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1166 call bdry_mask%free()
1167 end select
1168 end do
1169
1170 do i = 1, this%bcs_vel%size()
1171 bci => this%bcs_vel%get(i)
1172 select type (bc => bci)
1173 type is (zero_dirichlet_t)
1174 call bdry_mask%init_from_components(this%c_Xh, 1.0_rp)
1175 call bdry_mask%mark_facets(bci%marked_facet)
1176 call bdry_mask%finalize()
1177 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1178 call bdry_mask%free()
1179 type is (inflow_t)
1180 call bdry_mask%init_from_components(this%c_Xh, 2.0_rp)
1181 call bdry_mask%mark_facets(bci%marked_facet)
1182 call bdry_mask%finalize()
1183 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1184 call bdry_mask%free()
1185 type is (symmetry_t)
1186 call bdry_mask%init_from_components(this%c_Xh, 4.0_rp)
1187 call bdry_mask%mark_facets(bci%marked_facet)
1188 call bdry_mask%finalize()
1189 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1190 call bdry_mask%free()
1191 type is (usr_inflow_t)
1192 call bdry_mask%init_from_components(this%c_Xh, 5.0_rp)
1193 call bdry_mask%mark_facets(bci%marked_facet)
1194 call bdry_mask%finalize()
1195 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1196 call bdry_mask%free()
1197 type is (field_dirichlet_vector_t)
1198 call bdry_mask%init_from_components(this%c_Xh, 7.0_rp)
1199 call bdry_mask%mark_facets(bci%marked_facet)
1200 call bdry_mask%finalize()
1201 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1202 call bdry_mask%free()
1203 type is (shear_stress_t)
1204 call bdry_mask%init_from_components(this%c_Xh, 9.0_rp)
1205 call bdry_mask%mark_facets(bci%marked_facet)
1206 call bdry_mask%finalize()
1207 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1208 call bdry_mask%free()
1209 type is (wall_model_bc_t)
1210 call bdry_mask%init_from_components(this%c_Xh, 10.0_rp)
1211 call bdry_mask%mark_facets(bci%marked_facet)
1212 call bdry_mask%finalize()
1213 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1214 call bdry_mask%free()
1215 type is (blasius_t)
1216 call bdry_mask%init_from_components(this%c_Xh, 11.0_rp)
1217 call bdry_mask%mark_facets(bci%marked_facet)
1218 call bdry_mask%finalize()
1219 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1220 call bdry_mask%free()
1221 end select
1222 end do
1223
1224
1225 call bdry_file%init('boundary_adjoint.fld')
1226 call bdry_file%write(bdry_field)
1227
1228 call this%scratch%relinquish_field(temp_index)
1229 end subroutine adjoint_fluid_pnpn_write_boundary_conditions
1230
1231 ! End of section to verify
1232 ! ========================================================================== !
1233
1234 subroutine rescale_fluid(fluid_data, scale)
1235
1236 class(adjoint_fluid_pnpn_t), intent(inout) :: fluid_data
1238 real(kind=rp), intent(in) :: scale
1239
1240 ! Local variables
1241 integer :: i
1242
1243 ! Scale the velocity fields
1244 if (neko_bcknd_device .eq. 1) then
1245 call device_cmult(fluid_data%u_adj%x_d, scale, fluid_data%u_adj%size())
1246 call device_cmult(fluid_data%v_adj%x_d, scale, fluid_data%v_adj%size())
1247 call device_cmult(fluid_data%w_adj%x_d, scale, fluid_data%w_adj%size())
1248 else
1249 call cmult(fluid_data%u_adj%x, scale, fluid_data%u_adj%size())
1250 call cmult(fluid_data%v_adj%x, scale, fluid_data%v_adj%size())
1251 call cmult(fluid_data%w_adj%x, scale, fluid_data%w_adj%size())
1252 end if
1253
1254 ! Scale the right hand sides
1255 if (neko_bcknd_device .eq. 1) then
1256 call device_cmult(fluid_data%f_adj_x%x_d, scale, &
1257 fluid_data%f_adj_x%size())
1258 call device_cmult(fluid_data%f_adj_y%x_d, scale, &
1259 fluid_data%f_adj_y%size())
1260 call device_cmult(fluid_data%f_adj_z%x_d, scale, &
1261 fluid_data%f_adj_z%size())
1262 ! HARRY
1263 ! maybe the abx's too
1264 call device_cmult(fluid_data%abx1%x_d, scale, fluid_data%abx1%size())
1265 call device_cmult(fluid_data%aby1%x_d, scale, fluid_data%aby1%size())
1266 call device_cmult(fluid_data%abz1%x_d, scale, fluid_data%abz1%size())
1267 call device_cmult(fluid_data%abx2%x_d, scale, fluid_data%abx2%size())
1268 call device_cmult(fluid_data%aby2%x_d, scale, fluid_data%aby2%size())
1269 call device_cmult(fluid_data%abz2%x_d, scale, fluid_data%abz2%size())
1270
1271 else
1272 call cmult(fluid_data%f_adj_x%x, scale, fluid_data%f_adj_x%size())
1273 call cmult(fluid_data%f_adj_y%x, scale, fluid_data%f_adj_y%size())
1274 call cmult(fluid_data%f_adj_z%x, scale, fluid_data%f_adj_z%size())
1275
1276 call cmult(fluid_data%abx1%x, scale, fluid_data%abx1%size())
1277 call cmult(fluid_data%aby1%x, scale, fluid_data%aby1%size())
1278 call cmult(fluid_data%abz1%x, scale, fluid_data%abz1%size())
1279
1280 call cmult(fluid_data%abx2%x, scale, fluid_data%abx2%size())
1281 call cmult(fluid_data%aby2%x, scale, fluid_data%aby2%size())
1282 call cmult(fluid_data%abz2%x, scale, fluid_data%abz2%size())
1283 end if
1284
1285 ! Scale the lag terms
1286 if (neko_bcknd_device .eq. 1) then
1287 do i = 1, fluid_data%ulag%size()
1288 call device_cmult(fluid_data%ulag%lf(i)%x_d, &
1289 scale, fluid_data%ulag%lf(i)%size())
1290 end do
1291
1292 do i = 1, fluid_data%vlag%size()
1293 call device_cmult(fluid_data%vlag%lf(i)%x_d, &
1294 scale, fluid_data%vlag%lf(i)%size())
1295 end do
1296
1297 do i = 1, fluid_data%wlag%size()
1298 call device_cmult(fluid_data%wlag%lf(i)%x_d, &
1299 scale, fluid_data%wlag%lf(i)%size())
1300 end do
1301 else
1302 do i = 1, fluid_data%ulag%size()
1303 call cmult(fluid_data%ulag%lf(i)%x, &
1304 scale, fluid_data%ulag%lf(i)%size())
1305 end do
1306
1307 do i = 1, fluid_data%vlag%size()
1308 call cmult(fluid_data%vlag%lf(i)%x, &
1309 scale, fluid_data%vlag%lf(i)%size())
1310 end do
1311
1312 do i = 1, fluid_data%wlag%size()
1313 call cmult(fluid_data%wlag%lf(i)%x, &
1314 scale, fluid_data%wlag%lf(i)%size())
1315 end do
1316 end if
1317
1318 end subroutine rescale_fluid
1319
1320 function norm(x, y, z, B, volume, n)
1321 use mpi_f08, only: mpi_in_place
1322
1323 integer, intent(in) :: n
1324 real(kind=rp), dimension(n), intent(in) :: x, y, z
1325 real(kind=rp), dimension(n), intent(in) :: b
1326 real(kind=rp), intent(in) :: volume
1327
1328 real(kind=rp) :: norm
1329
1330 norm = vlsc3(x, x, b, n) + vlsc3(y, y, b, n) + vlsc3(z, z, b, n)
1331
1332 call mpi_allreduce(mpi_in_place, norm, 1, &
1333 mpi_real_precision, mpi_sum, mpi_comm_world)
1334
1335 norm = sqrt(norm / volume)
1336 end function norm
1337
1338 function device_norm(x_d, y_d, z_d, B_d, volume, n)
1339 use mpi_f08, only: mpi_in_place
1340
1341 type(c_ptr), intent(in) :: x_d, y_d, z_d
1342 type(c_ptr), intent(in) :: B_d
1343 real(kind=rp), intent(in) :: volume
1344 integer, intent(in) :: n
1345
1346 real(kind=rp) :: device_norm
1347
1348 device_norm = device_vlsc3(x_d, x_d, b_d, n) + &
1349 device_vlsc3(y_d, y_d, b_d, n) + &
1350 device_vlsc3(z_d, z_d, b_d, n)
1351
1352 call mpi_allreduce(mpi_in_place, device_norm, 1, &
1353 mpi_real_precision, mpi_sum, mpi_comm_world)
1354
1355 device_norm = sqrt(device_norm / volume)
1356
1357 end function device_norm
1358
1363 subroutine power_iterations_compute(this, t, tstep)
1364 class(adjoint_fluid_pnpn_t), target, intent(inout) :: this
1365 real(kind=rp), intent(in) :: t
1366 integer, intent(in) :: tstep
1367
1368 ! Local variables
1369 real(kind=rp) :: scaling_factor
1370 real(kind=rp) :: norm_l2, norm_l2_base
1371 character(len=256) :: log_message
1372 type(vector_t) :: data_line
1373 integer :: n
1374
1375 n = this%c_Xh%dof%size()
1376 if (tstep .eq. 1) then
1377 if (neko_bcknd_device .eq. 1) then
1378 norm_l2_base = device_norm(this%u_adj%x_d, this%v_adj%x_d, &
1379 this%w_adj%x_d, &
1380 this%c_Xh%B_d, this%c_Xh%volume, n)
1381 else
1382 norm_l2_base = this%norm_scaling * norm(this%u_adj%x, this%v_adj%x, &
1383 this%w_adj%x, &
1384 this%c_Xh%B, this%c_Xh%volume, n)
1385 end if
1386 if (this%norm_target .lt. 0.0_rp) then
1387 this%norm_target = norm_l2_base
1388 end if
1389
1390 this%norm_l2_upper = this%norm_tolerance * this%norm_target
1391 this%norm_l2_lower = this%norm_target / this%norm_tolerance
1392
1393 end if
1394
1395 ! Compute the norm of the velocity field and eigenvalue estimate
1396 if (neko_bcknd_device .eq. 1) then
1397 norm_l2 = device_norm(this%u_adj%x_d, this%v_adj%x_d, this%w_adj%x_d, &
1398 this%c_Xh%B_d, this%c_Xh%volume, n)
1399 else
1400 norm_l2 = norm(this%u_adj%x, this%v_adj%x, this%w_adj%x, &
1401 this%c_Xh%B, this%c_Xh%volume, n)
1402 end if
1403 norm_l2 = sqrt(this%norm_scaling) * norm_l2
1404 scaling_factor = 1.0_rp
1405
1406 ! Rescale the flow if necessary
1407 if (norm_l2 .gt. this%norm_l2_upper &
1408 .or. norm_l2 .lt. this%norm_l2_lower) then
1409 scaling_factor = this%norm_target / norm_l2
1410 call rescale_fluid(this, scaling_factor)
1411 norm_l2 = this%norm_target
1412
1413 if (tstep .eq. 1) then
1414 scaling_factor = 1.0_rp
1415 end if
1416 end if
1417
1418 ! Log the results
1419 !call neko_log%section('Power Iterations', lvl = NEKO_LOG_DEBUG)
1420 call neko_log%section('Power Iterations')
1421
1422 write (log_message, '(A7,E20.14)') 'Norm: ', norm_l2
1423 call neko_log%message(log_message, lvl = neko_log_debug)
1424 write (log_message, '(A7,E20.14)') 'Scaling: ', scaling_factor
1425 call neko_log%message(log_message, lvl = neko_log_debug)
1426
1427 ! Save to file
1428 call data_line%init(2)
1429 data_line%x = [norm_l2, scaling_factor]
1430 call this%file_output%write(data_line, t)
1431
1432 !call neko_log%end_section('Power Iterations', lvl = NEKO_LOG_DEBUG)
1433 call neko_log%end_section('Power Iterations')
1434 end subroutine power_iterations_compute
1435
1436
1437end 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.