36 use json_module,
only : json_file
43 use precon,
only :
pc_t, precon_allocator, precon_destroy
68 use mpi_f08,
only : mpi_wtime, mpi_barrier
88 use,
intrinsic :: iso_c_binding, only : c_associated
100 logical :: active = .false.
101 logical :: has_moving_boundary = .false.
133 real(kind=
rp),
pointer :: global_pivot_pos(:) => null()
134 real(kind=
rp),
pointer :: global_pivot_vel_lag(:, :) => null()
137 real(kind=
rp),
pointer :: global_basis_pos(:) => null()
139 real(kind=
rp),
pointer :: global_basis_vel_lag(:, :) => null()
141 integer,
allocatable :: ghost_handles(:,:)
143 real(kind=
rp),
allocatable :: body_rot_matrices(:,:,:)
146 integer :: n_trackers = 0
149 user_ale_mesh_vel => null()
151 user_ale_base_shapes => null()
153 user_ale_rigid_kinematics => null()
182 type(
coef_t),
intent(inout) :: coef
183 type(json_file),
intent(inout) :: json
184 type(
user_t),
intent(in) :: user
185 type(
chkp_t),
intent(inout) :: chkp
186 type(json_file) :: body_sub, bc_subdict
187 type(json_file) :: precon_params
189 integer,
allocatable :: zone_indices(:)
190 integer :: time_order
191 integer :: n_moving_zones
192 integer :: z, tmp_int, ksp_max_iter
193 integer,
allocatable :: moving_zone_ids(:)
194 integer :: i, j, k, n_bcs, n, n_bodies
195 real(kind=
rp),
allocatable :: tmp_vec(:)
196 real(kind=
rp) :: tmp_val, abstol
197 character(len=128) :: log_buf
198 character(len=256) :: log_buf_l
199 character(len=:),
allocatable :: bc_type
200 character(len=:),
allocatable :: tmp_str
201 character(len=:),
allocatable :: ksp_solver
202 character(len=:),
allocatable :: precon_type
203 logical :: tmp_logical, oifs
205 logical :: found_zone
206 logical :: has_user_rigid_kin, has_user_mesh_vel
207 logical :: has_builtin_osc, has_builtin_rot, is_rot_active
208 logical :: res_monitor, import_base_shapes
210 if (json%valid_path(
'case.fluid.ale'))
then
211 call json_get(json,
'case.fluid.ale.enabled', this%active)
215 if (.not. this%active)
then
218 else if (this%active)
then
220 call coef%msh%all_deformed()
226 "supported only with HIP or CUDA backend.")
230 call neko_error(
"ALE not currently supported with OIFS.")
232 if (json%valid_path(
'case.checkpoint_format'))
then
233 call json_get(json,
'case.checkpoint_format', tmp_str)
234 if (trim(tmp_str) /=
'chkp')
then
235 call neko_error(
"ALE is not supported with the '" // &
237 "' checkpoint format. Please use 'chkp'.")
243 call neko_log%section(
"ALE Initialization")
247 call neko_log%message(
"Initializing ALE " // &
248 "with device backend (HIP).")
250 call neko_log%message(
"Initializing ALE " // &
251 "with device backend (CUDA).")
253 call neko_log%message(
"Initializing ALE " // &
257 tmp_logical = .false.
260 call this%x_ref%init(coef%dof,
"x_ref")
261 call this%y_ref%init(coef%dof,
"y_ref")
262 call this%z_ref%init(coef%dof,
"z_ref")
264 call copy(this%x_ref%x, coef%dof%x, n)
265 call copy(this%y_ref%x, coef%dof%y, n)
266 call copy(this%z_ref%x, coef%dof%z, n)
276 this%user_ale_mesh_vel =>
user%ale_mesh_velocity
277 this%user_ale_base_shapes =>
user%ale_base_shapes
278 this%user_ale_rigid_kinematics =>
user%ale_rigid_kinematics
281 has_user_rigid_kin = .not.
associated(this%user_ale_rigid_kinematics, &
283 has_user_mesh_vel = .not.
associated(this%user_ale_mesh_vel, &
287 call coef%enable_B_history()
288 call json_get(json,
'case.numerics.time_order', time_order)
292 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
293 allocate(moving_zone_ids(0))
304 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
307 call this%bc_moving%init_from_components(coef)
308 call this%bc_fixed%init_from_components(coef)
310 if (json%valid_path(
'case.fluid.boundary_conditions'))
then
311 call json%info(
'case.fluid.boundary_conditions', n_children = n_bcs)
317 if (
allocated(bc_type))
deallocate(bc_type)
318 call json_get(bc_subdict,
'type', bc_type)
320 if (
allocated(zone_indices))
deallocate(zone_indices)
321 call json_get(bc_subdict,
'zone_indices', zone_indices)
324 if (trim(bc_type) .eq.
'no_slip')
then
329 do j = 1,
size(zone_indices)
333 call this%bc_moving%mark_zone(coef%msh%labeled_zones(&
336 this%has_moving_boundary = .true.
338 do j = 1,
size(zone_indices)
339 call this%bc_fixed%mark_zone(coef%msh%labeled_zones(&
346 call this%bc_moving%finalize()
347 call this%bc_fixed%finalize()
348 call this%bc_list%init()
349 call this%bc_list%append(this%bc_moving)
350 call this%bc_list%append(this%bc_fixed)
353 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
354 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
355 this%config%stiffness_type = tmp_str
356 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
357 call neko_error(
"ALE: stiffness_type must be 'built-in'")
361 if (
associated(this%user_ale_base_shapes, &
363 call neko_log%message(
'Solver Type : (' // &
364 trim(ksp_solver) //
', ' // trim(precon_type) //
')')
365 write(log_buf,
'(A,ES13.6)')
'Abs tol :', abstol
367 call neko_log%message(
'Mesh Stiffness : ' // &
368 trim(this%config%stiffness_type))
373 if (json%valid_path(
'case.fluid.ale.bodies'))
then
374 call json%info(
'case.fluid.ale.bodies', n_children = n_bodies)
375 this%config%nbodies = n_bodies
376 allocate(this%config%bodies(n_bodies))
377 allocate(this%ale_pivot(n_bodies))
378 allocate(this%body_kin(n_bodies))
379 allocate(this%base_shapes(n_bodies))
380 allocate(this%global_pivot_pos(3 * this%config%nbodies))
381 allocate(this%global_pivot_vel_lag(3 * this%config%nbodies, 3))
382 allocate(this%global_basis_pos(6 * this%config%nbodies))
383 allocate(this%ghost_handles(2, this%config%nbodies))
384 allocate(this%global_basis_vel_lag(6 * this%config%nbodies, 3))
385 allocate(this%body_rot_matrices(3, 3, this%config%nbodies))
387 this%global_pivot_pos = 0.0_rp
388 this%global_pivot_vel_lag = 0.0_rp
389 this%global_basis_pos = 0.0_rp
390 this%global_basis_vel_lag = 0.0_rp
391 this%body_rot_matrices = 0.0_rp
394 this%body_rot_matrices(1, 1, i) = 1.0_rp
395 this%body_rot_matrices(2, 2, i) = 1.0_rp
396 this%body_rot_matrices(3, 3, i) = 1.0_rp
401 this%config%bodies(i)%id = i
403 if (body_sub%valid_path(
'name'))
then
404 call json_get(body_sub,
'name', tmp_str)
405 this%config%bodies(i)%name = tmp_str
407 write(this%config%bodies(i)%name,
'(A,I0)')
'body_', i
410 if (body_sub%valid_path(
'zone_indices'))
then
411 call json_get(body_sub,
'zone_indices', zone_indices)
412 this%config%bodies(i)%zone_indices = zone_indices
415 trim(this%config%bodies(i)%name) // &
416 " must have 'zone_indices'")
420 this%config%bodies(i)%osc_amp = 0.0_rp
421 this%config%bodies(i)%osc_freq = 0.0_rp
422 if (body_sub%valid_path(
'oscillation'))
then
423 call json_get(body_sub,
'oscillation.amplitude', tmp_vec, &
425 this%config%bodies(i)%osc_amp = tmp_vec
426 call json_get(body_sub,
'oscillation.frequency', tmp_vec, &
428 this%config%bodies(i)%osc_freq = tmp_vec
432 if (body_sub%valid_path(
'rotation'))
then
434 if (.not. body_sub%valid_path(
'pivot'))
then
435 call neko_error(
"ale.bodies.pivot is missing " // &
436 "from the case file.")
439 call json_get(body_sub,
'rotation.type', tmp_str)
440 this%config%bodies(i)%rotation_type = tmp_str
442 select case (trim(tmp_str))
444 call json_get(body_sub,
'rotation.amplitude_deg', tmp_vec, &
446 this%config%bodies(i)%rot_amp_degree = tmp_vec
448 call json_get(body_sub,
'rotation.frequency', tmp_vec, &
450 this%config%bodies(i)%rot_freq = tmp_vec
454 call json_get(body_sub,
'rotation.ramp_t0', tmp_vec, &
456 this%config%bodies(i)%ramp_t0 = tmp_vec
458 call json_get(body_sub,
'rotation.ramp_omega0', tmp_vec, &
460 this%config%bodies(i)%ramp_omega0 = tmp_vec
466 if (tmp_int .ge. 1 .and. tmp_int .le. 3)
then
467 this%config%bodies(i)%rotation_axis = tmp_int
469 call neko_error(
"ALE: rotation.axis must be (integer) " // &
470 "1 -> x, 2 -> y, or 3 -> z")
472 call json_get(body_sub,
'rotation.step_control_times', &
473 tmp_vec, expected_size = 4)
474 this%config%bodies(i)%step_control_times = tmp_vec
476 call json_get(body_sub,
'rotation.target_angle_deg', tmp_val)
477 this%config%bodies(i)%target_rot_angle_deg = tmp_val
480 call neko_error(
"ALE: rotation.type must be 'harmonic', " // &
481 "'ramp', or 'smooth_step'")
486 if (body_sub%valid_path(
'pivot'))
then
489 this%config%bodies(i)%rotation_center_type = tmp_str
490 call json_get(body_sub,
'pivot.value', tmp_vec, expected_size = 3)
491 this%config%bodies(i)%rot_center = tmp_vec
494 tmp_str = this%config%bodies(i)%rotation_center_type
495 if (trim(tmp_str) /=
'relative' .and. &
496 trim(tmp_str) /=
'relative_sin')
then
497 call neko_error(
"ALE: pivot.type must be " // &
498 "'relative', or 'relative_sin'.")
503 if (body_sub%valid_path(
'stiff_geom'))
then
504 call json_get(body_sub,
'stiff_geom.type', tmp_str)
505 this%config%bodies(i)%stiff_geom%type = tmp_str
506 call json_get(body_sub,
'stiff_geom.gain', &
507 this%config%bodies(i)%stiff_geom%gain)
508 call json_get(body_sub,
'stiff_geom.decay_profile', tmp_str)
509 this%config%bodies(i)%stiff_geom%decay_profile = tmp_str
511 select case (trim(this%config%bodies(i)%stiff_geom%decay_profile))
514 'stiff_geom.cutoff_coef', &
515 this%config%bodies(i)%stiff_geom%cutoff_coef, 9.0_rp)
518 'stiff_geom.cutoff_coef', &
519 this%config%bodies(i)%stiff_geom%cutoff_coef, 3.5_rp)
521 call neko_error(
"ALE: Invalid stiff_geom.decay_profile: " // &
522 trim(this%config%bodies(i)%stiff_geom%decay_profile))
525 select case (trim(this%config%bodies(i)%stiff_geom%type))
526 case (
'cylinder',
'sphere')
527 call json_get(body_sub,
'stiff_geom.center', tmp_vec, &
529 this%config%bodies(i)%stiff_geom%center = tmp_vec
531 call json_get(body_sub,
'stiff_geom.radius', &
532 this%config%bodies(i)%stiff_geom%radius)
534 call json_get(body_sub,
'stiff_geom.stiff_dist', &
535 this%config%bodies(i)%stiff_geom%stiff_dist)
537 call neko_error(
"ALE: stiff_geom.type 'box' not yet" // &
540 call neko_error(
"ALE: Invalid stiff_geom.type: " // &
541 trim(this%config%bodies(i)%stiff_geom%type))
543 elseif (import_base_shapes)
then
547 trim(this%config%bodies(i)%name) // &
548 "' must have 'stiff_geom' definition.")
554 call this%base_shapes(i)%init(coef%dof, &
555 "phi_" // trim(this%config%bodies(i)%name))
561 this%ghost_handles(1, i) = this%request_tracker( &
562 this%config%bodies(i)%rot_center + [1.0_rp, 0.0_rp, 0.0_rp], &
563 this%config%bodies(i)%id)
565 this%ghost_handles(2, i) = this%request_tracker( &
566 this%config%bodies(i)%rot_center + [0.0_rp, 1.0_rp, 0.0_rp], &
567 this%config%bodies(i)%id)
569 call neko_log%message(
'Registered Body : ' // &
570 trim(this%config%bodies(i)%name))
574 if (
associated(this%user_ale_base_shapes, &
576 (.not. import_base_shapes))
then
577 write(log_buf,
'(A,A)')
' Stiff Type : ', &
578 trim(this%config%bodies(i)%stiff_geom%type)
580 write(log_buf,
'(A,ES18.11,A,A,A,ES10.4)')
' Gain : ', &
581 this%config%bodies(i)%stiff_geom%gain,
' | Profile: ', &
582 trim(this%config%bodies(i)%stiff_geom%decay_profile), &
583 ' | Cutoff: ', this%config%bodies(i)%stiff_geom%cutoff_coef
585 select case (trim(this%config%bodies(i)%stiff_geom%type))
586 case (
'cylinder',
'sphere')
587 write(log_buf,
'(A,3(ES23.15,1X))')
' Center :', &
588 this%config%bodies(i)%stiff_geom%center
590 write(log_buf,
'(A,ES23.15)')
' Radius :', &
591 this%config%bodies(i)%stiff_geom%radius
594 write(log_buf,
'(A,ES23.15)')
' Stiff Dist:', &
595 this%config%bodies(i)%stiff_geom%stiff_dist
602 has_builtin_osc = any(abs(this%config%bodies(i)%osc_amp) .gt. 0.0_rp)
604 if (has_builtin_osc)
then
605 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
606 call neko_log%message(
' Oscillation : ' // &
607 'X(t) = Amp*sin(2*pi*Freq*t) + User')
608 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
609 this%config%bodies(i)%osc_amp
611 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
612 this%config%bodies(i)%osc_freq
615 call neko_log%message(
' Oscillation : ' // &
616 'X(t) = Amp*sin(2*pi*Freq*t)')
617 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
618 this%config%bodies(i)%osc_amp
620 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
621 this%config%bodies(i)%osc_freq
625 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
626 call neko_log%message(
' Oscillation : User-defined')
628 call neko_log%message(
' Oscillation : None')
634 has_builtin_rot = (trim(this%config%bodies(i)%rotation_type) &
637 if (trim(this%config%bodies(i)%rotation_type) .eq.
'user')
then
639 call neko_log%message(
' Rotation Type: User-defined')
641 elseif (has_builtin_rot)
then
644 is_rot_active = .false.
645 select case (trim(this%config%bodies(i)%rotation_type))
647 is_rot_active = any(abs(this%config%bodies(i)%rot_amp_degree) &
650 is_rot_active = any(abs(this%config%bodies(i)%ramp_omega0) &
654 (abs(this%config%bodies(i)%target_rot_angle_deg) &
658 if (is_rot_active)
then
660 if (trim(this%config%bodies(i)%rotation_type) &
661 .eq.
'harmonic')
then
662 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
663 call neko_log%message(
' Rotation : ' // &
664 'Theta(t) = Amp*sin(2*pi*Freq*t) + User')
666 call neko_log%message(
' Rotation : ' // &
667 'Theta(t) = Amp*sin(2*pi*Freq*t)')
669 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp (deg) :', &
670 this%config%bodies(i)%rot_amp_degree
672 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
673 this%config%bodies(i)%rot_freq
677 elseif (trim(this%config%bodies(i)%rotation_type) &
679 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
680 call neko_log%message(
' Rotation : ' // &
681 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0)) + User')
683 call neko_log%message(
' Rotation : ' // &
684 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0))')
686 write(log_buf,
'(A,3(ES18.11,1X))')
' Omega0 :', &
687 this%config%bodies(i)%ramp_omega0
689 write(log_buf,
'(A,3(ES18.11,1X))')
' t0 :', &
690 this%config%bodies(i)%ramp_t0
694 elseif (trim(this%config%bodies(i)%rotation_type) &
695 .eq.
'smooth_step')
then
696 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
697 call neko_log%message(
' Rotation : ' // &
698 'Smooth Step Control + User')
700 call neko_log%message(
' Rotation : ' // &
701 'Smooth Step Control')
703 write(log_buf,
'(A,I10)')
' Rotation Axis :', &
704 this%config%bodies(i)%rotation_axis
706 write(log_buf,
'(A,ES18.11)')
' Target Rot ' // &
708 this%config%bodies(i)%target_rot_angle_deg
710 write(log_buf,
'(A,4(ES18.11,1X))') &
711 ' Control Times [t0, t1, t2, t3] :', &
712 this%config%bodies(i)%step_control_times
716 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
717 call neko_log%message(
' Rotation Type: User-defined')
719 call neko_log%message(
' Rotation Type: None')
727 call neko_log%message(
' Pivot Type : ' // &
728 trim(this%config%bodies(i)%rotation_center_type))
730 write(log_buf,
'(A,3(ES18.11,1X))')
' Init Pivot:', &
731 this%config%bodies(i)%rot_center
737 call neko_error(
"ALE: No 'ale bodies' found in case file!")
740 if (this%config%nbodies .gt. 1 .and. (.not. import_base_shapes))
then
741 call this%phi_total%init(coef%dof,
"phi_total")
746 do i = 1, n_moving_zones
747 z = moving_zone_ids(i)
750 do while ((.not. found_zone) .and. (j .le. this%config%nbodies))
751 if (any(this%config%bodies(j)%zone_indices .eq. z))
then
756 if (.not. found_zone)
then
757 write(log_buf_l,
'(A,I0,A)') &
758 "ALE: zone index ", z, &
759 " has BC no_slip with moving: true, " // &
760 "but it is not registered in ALE bodies."
767 do j = 1, this%config%nbodies
768 if (
allocated(this%config%bodies(j)%zone_indices))
then
769 do i = 1,
size(this%config%bodies(j)%zone_indices)
770 z = this%config%bodies(j)%zone_indices(i)
772 if (n_moving_zones .gt. 0)
then
773 if (any(moving_zone_ids(1:n_moving_zones) .eq. z))
then
777 if (.not. found_zone)
then
778 write(log_buf_l,
'(A,I0,A,A)') &
779 "ALE: zone index ", z, &
780 " is registered in ALE bodies, ", &
781 "but the BC is not no_slip with moving: true."
789 do j = 1, this%config%nbodies
790 if (
allocated(this%config%bodies(j)%zone_indices))
then
791 do i = 1,
size(this%config%bodies(j)%zone_indices)
792 z = this%config%bodies(j)%zone_indices(i)
794 do k = j + 1, this%config%nbodies
795 if (
allocated(this%config%bodies(k)%zone_indices))
then
796 if (any(this%config%bodies(k)%zone_indices .eq. z))
then
797 write(log_buf_l,
'(A,I0,A,A,A,A,A)') &
798 "ALE: zone index ", z, &
799 " is assigned to multiple bodies ('", &
800 trim(this%config%bodies(j)%name),
"' and '", &
801 trim(this%config%bodies(k)%name),
"')."
812 call this%solve_base_mesh_displacement(coef, json, import_base_shapes, &
813 abstol, ksp_solver, ksp_max_iter, &
814 precon_type, precon_params, res_monitor)
818 if (.not. json%valid_path(
'case.restart_file'))
then
822 call this%update_mesh_velocity(coef, t_init)
825 call this%wm_x_lag%init(this%wm_x, 2)
826 call this%wm_y_lag%init(this%wm_y, 2)
827 call this%wm_z_lag%init(this%wm_z, 2)
829 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
830 if (
allocated(bc_type))
deallocate(bc_type)
831 if (
allocated(zone_indices))
deallocate(zone_indices)
832 if (
allocated(ksp_solver))
deallocate(ksp_solver)
833 if (
allocated(precon_type))
deallocate(precon_type)
834 if (
allocated(tmp_str))
deallocate(tmp_str)
835 if (
allocated(tmp_vec))
deallocate(tmp_vec)
838 call this%mesh_preview(coef, json)
841 call this%register_checkpoint_fields(coef, chkp)
851 import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, &
852 precon_params, res_monitor)
854 class(
ax_t),
allocatable :: Ax
855 class(
ksp_t),
allocatable :: ksp
856 class(
pc_t),
allocatable :: pc
857 type(
coef_t),
intent(inout) :: coef
858 type(json_file),
intent(inout) :: json
859 logical,
intent(in) :: import_base_shapes
860 real(kind=
rp),
intent(in) :: abstol
861 logical,
intent(in) :: res_monitor
862 character(len=*),
intent(in) :: ksp_solver, precon_type
863 integer,
intent(in) :: ksp_max_iter
864 type(json_file),
intent(inout) :: precon_params
866 type(
field_t),
pointer :: phi_ptr => null()
870 real(kind=
rp) :: sample_start_time, sample_end_time
871 real(kind=
rp) :: sample_time
872 character(len=LOG_SIZE) :: log_buf
873 integer :: n, i, m, k, ierr, body_idx, z_idx
875 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
876 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
881 type(json_file) :: body_sub
882 character(len=256) :: phi_fname
883 character(len=:),
allocatable :: tmp_str
886 if (.not. this%active)
return
887 if (.not. this%has_moving_boundary)
return
888 if (this%config%nbodies .eq. 0)
return
890 if (import_base_shapes)
then
892 call neko_log%message(
"Importing ALE base shapes" // &
893 " (skipping Laplace solve)...")
895 do body_idx = 1, this%config%nbodies
900 call json_get(body_sub,
'base_shape_import_file', tmp_str)
903 phi_ptr => this%base_shapes(body_idx)
908 call neko_log%message(
" Loaded: " // &
911 trim(this%config%bodies(body_idx)%name))
918 call neko_log%message(
"Starting base mesh motion solve ...")
921 call ax_helm_allocator(ax, type_name =
"standard")
922 call krylov_solver_factory(ksp, n, ksp_solver, &
923 ksp_max_iter, abstol, monitor = res_monitor)
925 coef%gs_h, this%bc_list, precon_type, precon_params)
931 call rhs_field%init(coef%dof)
932 call corr_field%init(coef%dof)
936 if (.not.
associated(this%user_ale_base_shapes, &
938 call neko_log%message(
" Using user-defined base shapes " // &
939 "(skipping Laplace solve)")
942 call this%user_ale_base_shapes(this%base_shapes)
945 if (this%config%nbodies .gt. 1)
then
947 do body_idx = 1, this%config%nbodies
948 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
953 if (this%config%if_output_phi)
then
955 do body_idx = 1, this%config%nbodies
956 call phi_file%init(
'phi_' // &
957 trim(this%config%bodies(body_idx)%name) //
'.fld', &
959 select type (ft => phi_file%file_type)
961 ft%skip_pressure = .false.
963 call phi_file%write(this%base_shapes(body_idx))
966 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
970 if (this%config%nbodies .gt. 1)
then
971 call neko_log%message(
" phi_total.fld saved.")
972 select type (ft => phi_file%file_type)
974 ft%skip_pressure = .false.
976 call phi_file%init(
'phi_total.fld', precision =
rp)
977 call phi_file%write(this%phi_total)
988 if (this%config%if_output_stiffness)
then
989 rhs_field%x = coef%h1
990 call phi_file%init(
'stiffness.fld')
991 call phi_file%write(rhs_field)
997 do body_idx = 1, this%config%nbodies
999 sample_start_time = mpi_wtime()
1000 call neko_log%message(
" Solving laplace for body: " // &
1001 trim(this%config%bodies(body_idx)%name))
1003 call bc_active_body%init_from_components(coef)
1004 call bc_inactive_body%init_from_components(coef)
1007 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
1008 z_idx = this%config%bodies(body_idx)%zone_indices(j)
1009 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
1012 do i = 1, this%config%nbodies
1013 if (i /= body_idx)
then
1014 do j = 1,
size(this%config%bodies(i)%zone_indices)
1015 z_idx = this%config%bodies(i)%zone_indices(j)
1016 call bc_inactive_body%mark_zone(&
1017 coef%msh%labeled_zones(z_idx))
1022 call bc_active_body%finalize()
1023 call bc_inactive_body%finalize()
1026 call bc_projector%mark(this%bc_fixed)
1027 call bc_projector%mark(bc_active_body)
1028 call bc_projector%mark(bc_inactive_body)
1031 call bc_projector_zeros_only%mark(this%bc_fixed)
1032 call bc_projector_zeros_only%mark(bc_inactive_body)
1035 this%base_shapes(body_idx)%x = 0.0_rp
1036 rhs_field%x = 0.0_rp
1037 corr_field%x = 0.0_rp
1044 m = bc_active_body%msk(0)
1046 k = bc_active_body%msk(i)
1047 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1058 call bc_projector_zeros_only%apply(this%base_shapes(body_idx)%x, n)
1062 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1063 coef, coef%msh, coef%Xh)
1068 call bc_projector%apply(rhs_field%x, n)
1069 call coef%gs_h%op(rhs_field, gs_op_add)
1074 monitor(1) = ksp%solve(ax, corr_field, &
1075 rhs_field%x, n, coef, bc_projector, coef%gs_h)
1078 call field_add2(this%base_shapes(body_idx), corr_field, n)
1082 if (this%config%nbodies .gt. 1)
then
1083 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1087 sample_end_time = mpi_wtime()
1088 sample_time = sample_end_time - sample_start_time
1089 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1090 trim(this%config%bodies(body_idx)%name),
"' took ", &
1095 call bc_active_body%free()
1096 call bc_inactive_body%free()
1097 call bc_projector%free()
1098 call bc_projector_zeros_only%free()
1108 if (this%config%if_output_phi)
then
1109 call phi_file%init(
'phi_' // &
1110 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1112 select type (ft => phi_file%file_type)
1114 ft%skip_pressure = .false.
1116 call phi_file%write(this%base_shapes(body_idx))
1117 call phi_file%free()
1119 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1123 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1126 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1130 call neko_log%message(
" phi_total.fld saved.")
1131 call phi_file%init(
'phi_total.fld', precision =
rp)
1132 select type (ft => phi_file%file_type)
1134 ft%skip_pressure = .false.
1136 call phi_file%write(this%phi_total)
1137 call phi_file%free()
1141 call rhs_field%free()
1142 call corr_field%free()
1143 if (this%config%nbodies > 1)
then
1144 call this%phi_total%free()
1148 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1149 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1155 if (
allocated(h1_restore))
deallocate(h1_restore)
1156 if (
allocated(h2_restore))
deallocate(h2_restore)
1157 if (
allocated(ax))
deallocate(ax)
1158 if (
allocated(ksp))
then
1162 if (
allocated(pc))
then
1163 call precon_destroy(pc)
1173 type(
coef_t),
intent(in) :: coef
1177 real(kind=
rp) :: rot_mat(3,3)
1178 real(kind=
rp) :: initial_rot_center(3)
1180 if (.not. this%active)
return
1181 if (.not. this%has_moving_boundary)
return
1188 do i = 1, this%config%nbodies
1192 this%config%bodies(i), time_s)
1195 if (.not.
associated(this%user_ale_rigid_kinematics, &
1197 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1199 current_kin%vel_trans, &
1200 current_kin%vel_ang)
1203 current_kin%center = this%ale_pivot(i)%pos
1204 this%ale_pivot(i)%vel = current_kin%vel_trans
1206 this%body_kin(i)%center = this%ale_pivot(i)%pos
1207 this%body_kin(i)%vel_trans = current_kin%vel_trans
1208 this%body_kin(i)%vel_ang = current_kin%vel_ang
1211 call this%compute_rotation_matrix(i, time_s)
1212 rot_mat = this%body_rot_matrices(:,:,i)
1213 initial_rot_center = this%config%bodies(i)%rot_center
1217 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1218 this%base_shapes(i), coef, current_kin, rot_mat, &
1222 call this%prep_checkpoint(i)
1228 if (.not.
associated(this%user_ale_mesh_vel, &
1230 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1231 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1241 type(
coef_t),
intent(inout) :: coef
1243 integer,
intent(in) :: nadv
1246 if (.not. this%active)
return
1247 if (.not. this%has_moving_boundary)
return
1249 do i = 1, this%config%nbodies
1254 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1257 this%ale_pivot(i)%pos, &
1258 this%ale_pivot(i)%vel, &
1261 this%config%bodies(i))
1265 call coef%update_B_history()
1269 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1273 call this%wm_x_lag%update()
1274 call this%wm_y_lag%update()
1275 call this%wm_z_lag%update()
1281 type(
coef_t),
intent(inout) :: coef
1283 integer :: i, n, b, ierr
1284 integer,
allocatable :: cheap_map(:)
1285 integer :: n_cheap, map_idx
1286 real(kind=
rp) :: x, y, z
1287 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1288 real(kind=
rp) :: cx, cy, cz
1289 real(kind=
rp) :: arg, decay, gain, norm_dist
1290 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1291 type(
field_t),
allocatable :: dist_fields(:)
1292 character(len=128) :: log_buf
1297 allocate(cheap_map(params%nbodies))
1301 do b = 1, params%nbodies
1302 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1303 n_cheap = n_cheap + 1
1304 cheap_map(b) = n_cheap
1309 if (n_cheap > 0)
then
1310 allocate(dist_fields(n_cheap))
1312 do b = 1, params%nbodies
1313 map_idx = cheap_map(b)
1314 if (map_idx .gt. 0)
then
1316 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1319 call neko_log%message(
" Start: cheap dist calculation " // &
1320 "for body '" // trim(params%bodies(b)%name) //
"'")
1323 sample_start_time = mpi_wtime()
1327 coef%msh, params%bodies(b)%zone_indices, &
1328 copy_to_host = .true.)
1331 coef%msh, params%bodies(b)%zone_indices)
1335 sample_end_time = mpi_wtime()
1336 sample_time = sample_end_time - sample_start_time
1338 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1339 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1347 select case (trim(params%stiffness_type))
1350 do concurrent(i = 1:n)
1351 x = coef%dof%x(i, 1, 1, 1)
1352 y = coef%dof%y(i, 1, 1, 1)
1353 z = coef%dof%z(i, 1, 1, 1)
1355 max_added_stiff = 0.0_rp
1358 do b = 1, params%nbodies
1359 gain = params%bodies(b)%stiff_geom%gain
1360 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1361 decay = params%bodies(b)%stiff_geom%stiff_dist
1363 decay = params%bodies(b)%stiff_geom%radius
1367 cx = params%bodies(b)%stiff_geom%center(1)
1368 cy = params%bodies(b)%stiff_geom%center(2)
1369 cz = params%bodies(b)%stiff_geom%center(3)
1371 raw_dist = huge(0.0_rp)
1374 select case (trim(params%bodies(b)%stiff_geom%type))
1376 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1380 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1386 map_idx = cheap_map(b)
1387 if (map_idx .gt. 0)
then
1388 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1393 body_stiff_val = 0.0_rp
1394 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1397 arg = -(raw_dist**2) / (decay**2)
1398 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1399 body_stiff_val = gain * exp(arg)
1403 norm_dist = (raw_dist / decay)
1404 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1405 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1408 if (body_stiff_val .gt. max_added_stiff)
then
1409 max_added_stiff = body_stiff_val
1413 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1414 coef%h2(i, 1, 1, 1) = 0.0_rp
1418 call neko_error(
"ALE Manager: Unknown stiffness type")
1428 if (
allocated(dist_fields))
then
1429 do i = 1,
size(dist_fields)
1430 call dist_fields(i)%free()
1432 deallocate(dist_fields)
1434 if (
allocated(cheap_map))
deallocate(cheap_map)
1440 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1441 type(
field_t),
intent(inout) :: wx, wy, wz
1442 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1443 type(
field_t),
intent(in) :: phi
1444 type(
coef_t),
intent(in) :: coef
1446 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1447 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1450 x_ref, y_ref, z_ref, &
1451 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1454 x_ref, y_ref, z_ref, &
1455 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1461 wm_z_lag, time, nadv, scheme_)
1462 type(
coef_t),
intent(inout) :: c_xh
1463 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1466 integer,
intent(in) :: nadv
1467 character(len=*),
intent(in) :: scheme_
1470 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1473 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1482 if (.not. this%active)
return
1484 call this%bc_moving%free()
1485 call this%bc_fixed%free()
1486 call this%bc_list%free()
1488 if (
allocated(this%base_shapes))
then
1489 do i = 1,
size(this%base_shapes)
1490 call this%base_shapes(i)%free()
1492 deallocate(this%base_shapes)
1495 call this%wm_x_lag%free()
1496 call this%wm_y_lag%free()
1497 call this%wm_z_lag%free()
1498 call this%x_ref%free()
1499 call this%y_ref%free()
1500 call this%z_ref%free()
1502 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1503 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1504 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1505 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1506 if (
associated(this%global_pivot_vel_lag)) &
1507 deallocate(this%global_pivot_vel_lag)
1508 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1509 if (
associated(this%global_basis_vel_lag)) &
1510 deallocate(this%global_basis_vel_lag)
1511 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1512 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1513 if (
allocated(this%trackers))
deallocate(this%trackers)
1520 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1521 class(
ksp_t),
target,
intent(inout) :: ksp
1522 type(
coef_t),
target,
intent(in) :: coef
1523 type(
dofmap_t),
target,
intent(in) :: dof
1524 type(
gs_t),
target,
intent(inout) :: gs
1525 type(
bc_list_t),
target,
intent(inout) :: bclst
1526 character(len=*),
intent(in) :: pctype
1527 type(json_file),
intent(inout) :: params
1528 call precon_allocator(pc, pctype)
1529 select type (pcp => pc)
1531 call pcp%init(coef, dof, gs)
1533 call pcp%init(coef, dof, gs)
1535 call pcp%init(coef, dof, gs)
1537 call pcp%init(coef, bclst, params)
1539 call pcp%init(coef, bclst, params)
1547 real(kind=
dp),
intent(in) :: time_restart
1549 integer :: i, idx, handle_1, handle_2, offset_base
1551 time_state_dummy%t = time_restart
1555 do i = 1, this%config%nbodies
1558 this%config%bodies(i), time_state_dummy)
1561 if (.not.
associated(this%user_ale_rigid_kinematics, &
1563 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1565 kin_restart%vel_trans, &
1566 kin_restart%vel_ang)
1569 this%ale_pivot(i)%vel = kin_restart%vel_trans
1573 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1574 this%body_kin(i)%center = this%ale_pivot(i)%pos
1575 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1576 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1579 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1580 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1583 offset_base = (i-1)*6
1584 handle_1 = this%ghost_handles(1, i)
1585 handle_2 = this%ghost_handles(2, i)
1587 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1588 this%trackers(handle_1)%pos = &
1589 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1592 this%trackers(handle_1)%vel_lag = &
1593 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1596 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1597 this%trackers(handle_2)%pos = &
1598 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1601 this%trackers(handle_2)%vel_lag = &
1602 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1612 type(
coef_t),
intent(inout) :: coef
1613 type(
space_t),
intent(inout) :: Xh
1614 type(
chkp_t),
intent(in) :: chkp
1615 type(
gs_t),
intent(inout) :: gs_Xh
1619 if (.not. this%active)
return
1621 if (
allocated(chkp%previous_mesh%elements))
then
1623 "The current mesh has a different number " // &
1624 "of elements than the checkpoint.")
1628 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1630 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1631 do concurrent(j = 1:n)
1633 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1634 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1635 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1639 do i = 1, this%wm_x_lag%size()
1640 do concurrent(j = 1:n)
1641 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1642 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1643 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1644 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1645 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1646 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1671 if (c_associated(coef%dof%x_d))
then
1680 if (c_associated(coef%Blag_d))
then
1681 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1685 if (c_associated(coef%Blaglag_d))
then
1693 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1694 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1695 call gs_xh%op(this%wm_x, gs_op_add)
1696 call gs_xh%op(this%wm_y, gs_op_add)
1697 call gs_xh%op(this%wm_z, gs_op_add)
1698 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1700 do i = 1, this%wm_x_lag%size()
1701 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1702 this%wm_z_lag%lf(i)%x, 1, coef)
1703 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1704 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1705 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
1706 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1707 this%wm_z_lag%lf(i)%x, 0, coef)
1712 call this%set_pivot_restart(chkp%t)
1713 call coef%recompute_metrics()
1720 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1722 coef%Blaglag = coef%B
1724 if (c_associated(coef%Blag_d))
then
1728 if (c_associated(coef%Blaglag_d))
then
1736 call adv%recompute_metrics(coef, .true.)
1741 integer,
intent(in) :: body_idx
1742 integer :: idx, offset_base, h1, h2
1744 if (.not. this%active)
return
1745 if (.not. this%has_moving_boundary)
return
1747 idx = (body_idx - 1) * 3
1748 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1749 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1750 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1752 h1 = this%ghost_handles(1, body_idx)
1753 h2 = this%ghost_handles(2, body_idx)
1755 offset_base = (body_idx-1)*6
1758 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1759 this%get_tracker_pos(h1)
1760 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1761 this%get_tracker_pos(h2)
1764 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1765 this%trackers(h1)%vel_lag
1768 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1769 this%trackers(h2)%vel_lag
1774 integer,
allocatable,
intent(inout) :: arr(:)
1775 integer,
intent(inout) :: n
1776 integer,
intent(in) :: val
1777 integer,
allocatable :: tmp(:)
1781 if (arr(k) .eq. val)
return
1784 allocate(tmp(n + 1))
1785 if (n .gt. 0) tmp(1:n) = arr(1:n)
1788 if (
allocated(arr))
deallocate(arr)
1789 call move_alloc(tmp, arr)
1797 type(coef_t),
intent(inout) :: coef
1798 type(json_file),
intent(inout) :: json
1799 type(fld_file_output_t) :: fout
1800 type(field_t) :: dummy_field
1801 type(time_state_t) :: t_state
1802 type(file_t) :: out_file
1803 real(kind=rp) :: t_start
1804 real(kind=rp) :: t_end
1806 real(kind=rp) :: min_jac
1807 integer :: output_freq
1808 integer :: step, n_steps
1809 integer :: nadv, nadv_sim
1811 logical :: mesh_preview_active
1812 character(len=128) :: log_buf
1814 mesh_preview_active = .false.
1816 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1817 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1818 mesh_preview_active)
1821 if (.not. mesh_preview_active)
return
1823 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1825 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1827 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1829 call json_get(json, &
1830 'case.fluid.ale.mesh_preview.output_freq', &
1833 call neko_log%section(
"ALE Mesh Preview")
1834 call neko_log%message(
"Executing mesh motion preview...")
1836 n_steps = int((t_end - t_start) / dt)
1837 call json_get(json,
'case.numerics.time_order', nadv_sim)
1839 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1840 call neko_log%message(log_buf)
1841 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1842 call neko_log%message(log_buf)
1843 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1844 call neko_log%message(log_buf)
1845 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1846 call neko_log%message(log_buf)
1847 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1848 call neko_log%message(log_buf)
1849 call neko_log%message(
'')
1852 call dummy_field%init(coef%dof,
"mesh_preview")
1853 call field_rzero(dummy_field)
1855 call fout%init(rp,
"mesh_preview", 1)
1856 call fout%fields%assign_to_field(1, dummy_field)
1857 select type (ft => fout%file_%file_type)
1858 type is (fld_file_t)
1859 ft%write_mesh = .true.
1860 ft%skip_pressure = .false.
1873 if (neko_bcknd_device .eq. 1)
then
1874 min_jac = device_glmin(coef%jac_d, n)
1876 min_jac = glmin(coef%jac, n)
1880 call fout%sample(t_state%t)
1882 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1883 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1884 t_state%t,
" | Min Jac: ", min_jac
1886 call neko_log%message(trim(log_buf))
1887 call this%update_mesh_velocity(coef, t_state)
1889 do step = 1, n_steps
1890 t_state%tstep = step
1891 t_state%t = t_start + (step * dt)
1892 nadv = min(step, nadv_sim)
1894 call this%advance_mesh(coef, t_state, nadv)
1895 call coef%recompute_metrics()
1898 if (neko_bcknd_device .eq. 1)
then
1899 min_jac = device_glmin(coef%jac_d, n)
1901 min_jac = glmin(coef%jac, n)
1904 if (min_jac .le. 0.0_rp)
then
1905 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1906 "Negative Jacobian detected (", min_jac,
") at t = ", &
1908 call neko_log%message(log_buf)
1911 call fout%sample(t_state%t)
1913 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1914 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1915 t_state%t,
" | Min Jac:", min_jac
1916 call neko_log%message(trim(log_buf))
1918 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1921 if (mod(step, output_freq) .eq. 0)
then
1924 call fout%sample(t_state%t)
1926 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1927 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1928 t_state%t,
" | Min Jac:", min_jac
1929 call neko_log%message(trim(log_buf))
1933 call this%update_mesh_velocity(coef, t_state)
1937 call dummy_field%free()
1939 call neko_log%end_section()
1940 call neko_log%message(
"Mesh preview complete.")
1941 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1946 type(fld_file_output_t) :: fout
1947 type(coef_t),
intent(inout) :: coef
1948 type(field_t),
intent(inout) :: dummy_field
1952 if (neko_bcknd_device .eq. 1)
then
1953 call device_copy(dummy_field%x_d, coef%B_d, n)
1955 call copy(dummy_field%x, coef%B, n)
1958 if (neko_bcknd_device .eq. 1)
then
1959 associate(
mesh => coef%dof)
1961 device_to_host, sync = .false.)
1963 device_to_host, sync = .false.)
1965 device_to_host, sync = .false.)
1975 real(kind=rp),
intent(in) :: initial_pos(3)
1976 integer,
intent(in) :: body_id
1978 type(point_tracker_t),
allocatable :: tmp(:)
1981 if (.not. this%active)
return
1982 if (.not. this%has_moving_boundary)
return
1984 if (.not.
allocated(this%trackers))
then
1985 allocate(this%trackers(30))
1987 elseif (this%n_trackers .ge.
size(this%trackers))
then
1988 allocate(tmp(
size(this%trackers) + 30))
1989 tmp(1:
size(this%trackers)) = this%trackers
1990 deallocate(this%trackers)
1991 call move_alloc(tmp, this%trackers)
1993 this%n_trackers = this%n_trackers + 1
1994 handle = this%n_trackers
1996 this%trackers(handle)%pos = initial_pos
1997 this%trackers(handle)%body_id = body_id
1998 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
2003 integer,
intent(in) :: handle
2004 real(kind=rp) :: pos(3)
2006 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
2007 pos = this%trackers(handle)%pos
2017 integer,
intent(in) :: body_idx
2018 type(time_state_t),
intent(in) :: time
2020 real(kind=rp) :: p(3), gx(3), gy(3)
2021 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
2023 if (.not. this%active)
return
2024 if (.not. this%has_moving_boundary)
return
2027 h_x = this%ghost_handles(1, body_idx)
2028 h_y = this%ghost_handles(2, body_idx)
2030 p = this%ale_pivot(body_idx)%pos
2031 gx = this%get_tracker_pos(h_x)
2032 gy = this%get_tracker_pos(h_y)
2036 u = u / sqrt(sum(u**2))
2040 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2041 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2042 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2043 w = w / sqrt(sum(w**2))
2046 v(1) = w(2)*u(3) - w(3)*u(2)
2047 v(2) = w(3)*u(1) - w(1)*u(3)
2048 v(3) = w(1)*u(2) - w(2)*u(1)
2050 this%body_rot_matrices(:, 1, body_idx) = u
2051 this%body_rot_matrices(:, 2, body_idx) = v
2052 this%body_rot_matrices(:, 3, body_idx) = w
2062 type(time_state_t),
intent(in) :: time
2063 integer,
optional,
intent(in) :: body_idxs(:)
2065 integer :: i, idx, n_log
2066 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2067 real(kind=rp) :: r(3,3)
2068 character(len=256) :: log_buf
2069 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2071 if (.not. this%active)
return
2072 if (.not. this%has_moving_boundary)
return
2074 if (
present(body_idxs))
then
2075 n_log =
size(body_idxs)
2077 n_log = this%config%nbodies
2080 call neko_log%message(
" ")
2081 call neko_log%message(
"---------Rotation log---------")
2082 call neko_log%message(
"variable, time step, time, body, " // &
2083 "x_val, y_val, z_val")
2088 if (
present(body_idxs))
then
2094 r = this%body_rot_matrices(:, :, idx)
2097 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2098 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2099 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2102 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2103 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2104 trim(this%config%bodies(idx)%name),
" ", &
2105 roll_deg, pitch_deg, yaw_deg
2106 call neko_log%message(trim(log_buf))
2117 type(time_state_t),
intent(in) :: time
2118 integer,
optional,
intent(in) :: body_idxs(:)
2119 integer :: i, idx, n_log
2120 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2121 character(len=256) :: log_buf
2123 if (.not. this%active)
return
2124 if (.not. this%has_moving_boundary)
return
2126 if (
present(body_idxs))
then
2127 n_log =
size(body_idxs)
2129 n_log = this%config%nbodies
2132 call neko_log%message(
" ")
2133 call neko_log%message(
"----------Pivot Log-----------")
2134 call neko_log%message(
"variable, time step, time, body, " // &
2135 "x_val, y_val, z_val")
2140 if (
present(body_idxs))
then
2146 pivot_pos = this%ale_pivot(idx)%pos
2147 pivot_vel = this%ale_pivot(idx)%vel
2150 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2151 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2152 trim(this%config%bodies(idx)%name),
" ", &
2153 this%ale_pivot(idx)%pos
2154 call neko_log%message(trim(log_buf))
2157 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2158 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2159 trim(this%config%bodies(idx)%name),
" ", &
2160 this%ale_pivot(idx)%vel
2161 call neko_log%message(trim(log_buf))
2168 type(body_kinematics_t),
intent(in) :: kin_object
2169 type(time_state_t),
intent(in) :: time_s
2170 integer,
intent(in) :: nadv
2171 integer,
intent(in) :: body_idx
2173 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2175 if (.not. this%active)
return
2176 if (.not. this%has_moving_boundary)
return
2178 if (
allocated(this%trackers))
then
2179 do t = 1, this%n_trackers
2180 if (this%trackers(t)%body_id .eq. &
2181 this%config%bodies(body_idx)%id)
then
2182 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2183 t .eq. this%ghost_handles(2, body_idx))
then
2186 rel_pos = this%trackers(t)%pos - kin_object%center
2189 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2190 kin_object%vel_ang(3) * rel_pos(2)
2191 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2192 kin_object%vel_ang(1) * rel_pos(3)
2193 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2194 kin_object%vel_ang(2) * rel_pos(1)
2197 p_vel = kin_object%vel_trans + v_tan
2199 if (time_s%tstep .gt. 0)
then
2200 call ab_integrate_point_pos(this%trackers(t)%pos, &
2201 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2213 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
2215 type(json_file),
intent(inout) :: json
2216 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2217 character(len=:),
allocatable,
intent(inout) :: precon_type
2218 type(json_file),
intent(inout) :: precon_params
2219 real(kind=rp),
intent(out) :: abstol
2220 integer,
intent(out) :: ksp_max_iter
2221 logical,
intent(out) :: res_monitor
2222 logical,
intent(out) :: import_base_shapes
2223 logical :: tmp_logical
2224 character(len=:),
allocatable :: tmp_str
2226 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2227 if (
allocated(precon_type))
deallocate(precon_type)
2229 call json_get_or_default(json, &
2230 'case.fluid.ale.solver.import_base_shape', &
2231 import_base_shapes, .false.)
2233 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2236 call json_get_or_default(json, &
2237 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2239 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2240 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2244 call json_get_or_default(json, &
2245 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2246 call json_get_or_default(json,
'case.fluid.ale.solver.monitor', &
2247 res_monitor, .false.)
2248 call json_get_or_default(json,
'case.fluid.ale.solver.max_iterations', &
2249 ksp_max_iter, 10000)
2251 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2252 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2253 this%config%if_output_phi = tmp_logical
2255 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2256 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2257 this%config%if_output_stiffness = tmp_logical
2261 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2262 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2263 this%config%stiffness_type = tmp_str
2264 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2265 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2273 type(coef_t),
intent(inout) :: coef
2274 type(chkp_t),
intent(inout) :: checkpoint
2277 if (.not. this%active)
return
2280 call checkpoint%add_ale(coef%dof%x, coef%dof%y, &
2281 coef%dof%z, coef%dof%x_d, coef%dof%y_d, &
2283 coef%Blag, coef%Blaglag, coef%Blag_d, coef%Blaglag_d, &
2284 this%wm_x, this%wm_y, this%wm_z, &
2285 this%wm_x_lag, this%wm_y_lag, &
2287 this%global_pivot_pos, &
2288 this%global_pivot_vel_lag, &
2289 this%global_basis_pos, &
2290 this%global_basis_vel_lag)
Copy data between host and device (or device and device)
Synchronize a device or stream.
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
Apply cyclic boundary condition to a vector field.
Abstract interface for user defined ALE base shapes.
Abstract interface for user defined ALE mesh velocity.
Abstract interface for user defined ALE rigid body kinematics.
Subroutines to add advection terms to the RHS of a transport equation.
ALE Manager: Handles Mesh Motion.
type(ale_manager_t), pointer, public neko_ale
subroutine ale_manager_free(this)
subroutine, public log_pivot(this, time, body_idxs)
Logs pivot positions for all or selected bodies. can be called in usercompute. eg: call neko_alelog_p...
subroutine ale_precon_factory(pc, ksp, coef, dof, gs, bclst, pctype, params)
Factory for ALE Preconditioner.
real(kind=rp) function, dimension(3) get_tracker_pos(this, handle)
subroutine set_pivot_basis_for_checkpoint(this, body_idx)
subroutine compute_rotation_matrix(this, body_idx, time)
Computes Rotation Matrix.
subroutine, public update_ale_mesh(c_xh, wm_x, wm_y, wm_z, wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
subroutine, public add_kinematics_to_mesh_velocity(wx, wy, wz, x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
subroutine update_mesh_velocity(this, coef, time_s)
Updates the mesh velocity field based on current time and kinematics Sums contributions from all bodi...
subroutine set_pivot_restart(this, time_restart)
subroutine, public compute_stiffness_ale(coef, params)
subroutine solve_base_mesh_displacement(this, coef, json, import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, precon_params, res_monitor)
Solves the Laplace equation to determine the base shape (phi) for each body. It finds a smooth blendi...
subroutine mesh_preview(this, coef, json)
Performs a preview of the mesh motion to verify quality/topology.
subroutine sync_mesh_preview_step(coef, dummy_field)
subroutine append_unique_int(arr, n, val)
subroutine get_ale_solver_params_json(this, json, ksp_solver, precon_type, precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
integer function request_tracker(this, initial_pos, body_id)
subroutine, public log_rot_angles(this, time, body_idxs)
Logs rotation angles for all or selected bodies. can be called in usercompute. eg: call neko_alelog_r...
subroutine register_checkpoint_fields(this, coef, checkpoint)
subroutine ale_manager_init(this, coef, json, user, chkp)
Initialize ALE Manager Sets up solver, registers fields, solves for base shape, etc.
subroutine ghost_tracker_coord_step(this, kin_object, time_s, nadv, body_idx)
subroutine advance_mesh(this, coef, time, nadv)
Main routine to advance the mesh in time.
subroutine sync_chkp(this, coef, xh, adv, chkp, gs_xh)
Defines data structures and algorithms for configuring, calculating, and time-integrating the rigid-b...
subroutine, public compute_body_kinematics_built_in(kinematics, body_conf, time)
Compute built-in kinematics for a body. Uses inputs from JSON. CPU-only.
subroutine, public ab_integrate_point_pos(pos, vel_lag, current_vel, time, nadv)
Advance a single point position (x,y,z) from the point's velocity using AB time-integration.
subroutine, public init_pivot_state(pivot, body_conf)
Initialize pivot state.
subroutine, public update_pivot_location(pivot, pivot_loc, pivot_vel, time, nadv, body_conf)
Updates pivot location.
subroutine, public add_kinematics_to_mesh_velocity_cpu(wx, wy, wz, x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, inital_pivot_loc)
Adds kinematics to mesh velocity (CPU)
subroutine, public compute_cheap_dist_v2_cpu(dist_field, coef, msh, zone_indices)
Compute cheap_dist field by passing distance information throughout an entire local element before do...
subroutine, public update_ale_mesh_cpu(c_xh, wm_x, wm_y, wm_z, wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_type)
Updates mesh position by integrating mesh velocity in time using AB (CPU)
subroutine, public add_kinematics_to_mesh_velocity_device(wx, wy, wz, x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, inital_pivot_loc)
Add Kinematics to Mesh Velocity.
subroutine, public compute_cheap_dist_device(dist_field, coef, msh, zone_indices, copy_to_host)
Cheap dist device implementation.
subroutine, public update_ale_mesh_device(c_xh, wm_x, wm_y, wm_z, wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_type)
Update ALE Mesh.
Defines a Matrix-vector product.
type(mpi_comm), public neko_comm
MPI communicator.
Jacobi preconditioner accelerator backend.
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
real(kind=rp) function, public device_glmin(a_d, n, strm)
Min of a vector of length n.
Device abstraction, common interface for various accelerators.
integer, parameter, public host_to_device
integer, parameter, public device_to_host
Defines a mapping of the degrees of freedom.
subroutine, public field_rzero(a, n)
Zero a real vector.
subroutine, public field_add2(a, b, n)
Vector addition .
subroutine, public field_cmult(a, c, n)
Multiplication by constant c .
Contains the field_serties_t type.
Module for file I/O operations.
Implements fld_file_output_t.
Importation of fields from fld files.
Utilities for retrieving parameters from the case files.
Implements the base abstract type for Krylov solvers plus helper types.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
real(kind=rp), parameter, public pi
subroutine, public copy(a, b, n)
Copy a vector .
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
integer, parameter neko_bcknd_hip
integer, parameter neko_bcknd_device
integer, parameter neko_bcknd_cuda
integer, parameter, public dp
integer, parameter, public rp
Global precision used in computations.
Hybrid ph-multigrid preconditioner.
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Defines a registry for storing solution fields.
type(registry_t), target, public neko_registry
Global field registry.
Implements scalar_projector_t.
Defines a function space.
Jacobi preconditioner SX-Aurora backend.
Module with things related to the simulation time.
Interfaces for user interaction with NEKO.
subroutine, public dummy_user_ale_mesh_velocity(wm_x, wm_y, wm_z, coef, x_ref, y_ref, z_ref, base_shapes, time)
subroutine, public dummy_user_ale_base_shapes(base_shapes)
subroutine, public dummy_user_ale_rigid_kinematics(body_id, time, vel_trans, vel_ang)
Defines a zero-valued Dirichlet boundary condition.
Base abstract type for computing the advection operator.
Global ALE Configuration.
Calculated Kinematics for a body at current time.
State history for time-integration of pivots.
Type for a tracked point linked to a body.
Base type for a matrix-vector product providing .
A list of allocatable `bc_t`. Follows the standard interface of lists.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Defines a jacobi preconditioner.
Stores a series (sequence) of fields, logically connected to a base field, and arranged according to ...
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Interface for NEKTON fld files.
A simple output saving a list of fields to a .fld file.
Defines a jacobi preconditioner.
Type for storing initial and final residuals in a Krylov solver.
Base abstract type for a canonical Krylov method, solving .
Defines a canonical Krylov preconditioner.
Projector for scalar boundary conditions.
The function space for the SEM solution fields.
Defines a jacobi preconditioner for SX-Aurora.
A struct that contains all info about the time, expand as needed.
A type collecting all the overridable user routines and flag to suppress type injection from custom m...
Zero-valued Dirichlet boundary condition. Used for no-slip walls, but also for various auxillary cond...