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