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