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