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