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