36 use json_module,
only : json_file
43 use precon,
only :
pc_t, precon_factory, precon_destroy
68 use mpi_f08,
only : mpi_wtime, mpi_barrier
86 use,
intrinsic :: iso_c_binding, only : c_associated
98 logical :: active = .false.
99 logical :: has_moving_boundary = .false.
131 real(kind=
rp),
pointer :: global_pivot_pos(:) => null()
132 real(kind=
rp),
pointer :: global_pivot_vel_lag(:, :) => null()
135 real(kind=
rp),
pointer :: global_basis_pos(:) => null()
137 real(kind=
rp),
pointer :: global_basis_vel_lag(:, :) => null()
139 integer,
allocatable :: ghost_handles(:,:)
141 real(kind=
rp),
allocatable :: body_rot_matrices(:,:,:)
144 integer :: n_trackers = 0
147 user_ale_mesh_vel => null()
149 user_ale_base_shapes => null()
151 user_ale_rigid_kinematics => null()
180 type(
coef_t),
intent(inout) :: coef
181 type(json_file),
intent(inout) :: json
182 type(
user_t),
intent(in) :: user
183 type(
chkp_t),
intent(inout) :: chkp
184 type(json_file) :: body_sub, bc_subdict
185 type(json_file) :: precon_params
187 integer,
allocatable :: zone_indices(:)
188 integer :: time_order
189 integer :: n_moving_zones
190 integer :: z, tmp_int, ksp_max_iter
191 integer,
allocatable :: moving_zone_ids(:)
192 integer :: i, j, k, n_bcs, n, n_bodies
193 real(kind=
rp),
allocatable :: tmp_vec(:)
194 real(kind=
rp) :: tmp_val, abstol
195 character(len=128) :: log_buf
196 character(len=256) :: log_buf_l
197 character(len=:),
allocatable :: bc_type
198 character(len=:),
allocatable :: tmp_str
199 character(len=:),
allocatable :: ksp_solver
200 character(len=:),
allocatable :: precon_type
201 logical :: tmp_logical, oifs
203 logical :: found_zone
204 logical :: has_user_rigid_kin, has_user_mesh_vel
205 logical :: has_builtin_osc, has_builtin_rot, is_rot_active
206 logical :: res_monitor, import_base_shapes
208 if (json%valid_path(
'case.fluid.ale'))
then
209 call json_get(json,
'case.fluid.ale.enabled', this%active)
213 if (.not. this%active)
then
216 else if (this%active)
then
221 "supported only with HIP or CUDA backend.")
225 call neko_error(
"ALE not currently supported with OIFS.")
227 if (json%valid_path(
'case.checkpoint_format'))
then
228 call json_get(json,
'case.checkpoint_format', tmp_str)
229 if (trim(tmp_str) /=
'chkp')
then
230 call neko_error(
"ALE is not supported with the '" // &
232 "' checkpoint format. Please use 'chkp'.")
238 call neko_log%section(
"ALE Initialization")
242 call neko_log%message(
"Initializing ALE " // &
243 "with device backend (HIP).")
245 call neko_log%message(
"Initializing ALE " // &
246 "with device backend (CUDA).")
248 call neko_log%message(
"Initializing ALE " // &
252 tmp_logical = .false.
255 call this%x_ref%init(coef%dof,
"x_ref")
256 call this%y_ref%init(coef%dof,
"y_ref")
257 call this%z_ref%init(coef%dof,
"z_ref")
259 call copy(this%x_ref%x, coef%dof%x, n)
260 call copy(this%y_ref%x, coef%dof%y, n)
261 call copy(this%z_ref%x, coef%dof%z, n)
271 this%user_ale_mesh_vel =>
user%ale_mesh_velocity
272 this%user_ale_base_shapes =>
user%ale_base_shapes
273 this%user_ale_rigid_kinematics =>
user%ale_rigid_kinematics
276 has_user_rigid_kin = .not.
associated(this%user_ale_rigid_kinematics, &
278 has_user_mesh_vel = .not.
associated(this%user_ale_mesh_vel, &
282 call coef%enable_B_history()
283 call json_get(json,
'case.numerics.time_order', time_order)
287 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
288 allocate(moving_zone_ids(0))
299 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
302 call this%bc_moving%init_from_components(coef)
303 call this%bc_fixed%init_from_components(coef)
305 if (json%valid_path(
'case.fluid.boundary_conditions'))
then
306 call json%info(
'case.fluid.boundary_conditions', n_children = n_bcs)
312 if (
allocated(bc_type))
deallocate(bc_type)
313 call json_get(bc_subdict,
'type', bc_type)
315 if (
allocated(zone_indices))
deallocate(zone_indices)
316 call json_get(bc_subdict,
'zone_indices', zone_indices)
319 if (trim(bc_type) .eq.
'no_slip')
then
324 do j = 1,
size(zone_indices)
328 call this%bc_moving%mark_zone(coef%msh%labeled_zones(&
331 this%has_moving_boundary = .true.
333 do j = 1,
size(zone_indices)
334 call this%bc_fixed%mark_zone(coef%msh%labeled_zones(&
341 call this%bc_moving%finalize()
342 call this%bc_fixed%finalize()
343 call this%bc_list%init()
344 call this%bc_list%append(this%bc_moving)
345 call this%bc_list%append(this%bc_fixed)
348 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
349 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
350 this%config%stiffness_type = tmp_str
351 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
352 call neko_error(
"ALE: stiffness_type must be 'built-in'")
356 if (
associated(this%user_ale_base_shapes, &
358 call neko_log%message(
'Solver Type : (' // &
359 trim(ksp_solver) //
', ' // trim(precon_type) //
')')
360 write(log_buf,
'(A,ES13.6)')
'Abs tol :', abstol
362 call neko_log%message(
'Mesh Stiffness : ' // &
363 trim(this%config%stiffness_type))
368 if (json%valid_path(
'case.fluid.ale.bodies'))
then
369 call json%info(
'case.fluid.ale.bodies', n_children = n_bodies)
370 this%config%nbodies = n_bodies
371 allocate(this%config%bodies(n_bodies))
372 allocate(this%ale_pivot(n_bodies))
373 allocate(this%body_kin(n_bodies))
374 allocate(this%base_shapes(n_bodies))
375 allocate(this%global_pivot_pos(3 * this%config%nbodies))
376 allocate(this%global_pivot_vel_lag(3 * this%config%nbodies, 3))
377 allocate(this%global_basis_pos(6 * this%config%nbodies))
378 allocate(this%ghost_handles(2, this%config%nbodies))
379 allocate(this%global_basis_vel_lag(6 * this%config%nbodies, 3))
380 allocate(this%body_rot_matrices(3, 3, this%config%nbodies))
382 this%global_pivot_pos = 0.0_rp
383 this%global_pivot_vel_lag = 0.0_rp
384 this%global_basis_pos = 0.0_rp
385 this%global_basis_vel_lag = 0.0_rp
386 this%body_rot_matrices = 0.0_rp
389 this%body_rot_matrices(1, 1, i) = 1.0_rp
390 this%body_rot_matrices(2, 2, i) = 1.0_rp
391 this%body_rot_matrices(3, 3, i) = 1.0_rp
396 this%config%bodies(i)%id = i
398 if (body_sub%valid_path(
'name'))
then
399 call json_get(body_sub,
'name', tmp_str)
400 this%config%bodies(i)%name = tmp_str
402 write(this%config%bodies(i)%name,
'(A,I0)')
'body_', i
405 if (body_sub%valid_path(
'zone_indices'))
then
406 call json_get(body_sub,
'zone_indices', zone_indices)
407 this%config%bodies(i)%zone_indices = zone_indices
410 trim(this%config%bodies(i)%name) // &
411 " must have 'zone_indices'")
415 this%config%bodies(i)%osc_amp = 0.0_rp
416 this%config%bodies(i)%osc_freq = 0.0_rp
417 if (body_sub%valid_path(
'oscillation'))
then
418 call json_get(body_sub,
'oscillation.amplitude', tmp_vec, &
420 this%config%bodies(i)%osc_amp = tmp_vec
421 call json_get(body_sub,
'oscillation.frequency', tmp_vec, &
423 this%config%bodies(i)%osc_freq = tmp_vec
427 if (body_sub%valid_path(
'rotation'))
then
429 if (.not. body_sub%valid_path(
'pivot'))
then
430 call neko_error(
"ale.bodies.pivot is missing " // &
431 "from the case file.")
434 call json_get(body_sub,
'rotation.type', tmp_str)
435 this%config%bodies(i)%rotation_type = tmp_str
437 select case (trim(tmp_str))
439 call json_get(body_sub,
'rotation.amplitude_deg', tmp_vec, &
441 this%config%bodies(i)%rot_amp_degree = tmp_vec
443 call json_get(body_sub,
'rotation.frequency', tmp_vec, &
445 this%config%bodies(i)%rot_freq = tmp_vec
449 call json_get(body_sub,
'rotation.ramp_t0', tmp_vec, &
451 this%config%bodies(i)%ramp_t0 = tmp_vec
453 call json_get(body_sub,
'rotation.ramp_omega0', tmp_vec, &
455 this%config%bodies(i)%ramp_omega0 = tmp_vec
461 if (tmp_int .ge. 1 .and. tmp_int .le. 3)
then
462 this%config%bodies(i)%rotation_axis = tmp_int
464 call neko_error(
"ALE: rotation.axis must be (integer) " // &
465 "1 -> x, 2 -> y, or 3 -> z")
467 call json_get(body_sub,
'rotation.step_control_times', &
468 tmp_vec, expected_size = 4)
469 this%config%bodies(i)%step_control_times = tmp_vec
471 call json_get(body_sub,
'rotation.target_angle_deg', tmp_val)
472 this%config%bodies(i)%target_rot_angle_deg = tmp_val
475 call neko_error(
"ALE: rotation.type must be 'harmonic', " // &
476 "'ramp', or 'smooth_step'")
481 if (body_sub%valid_path(
'pivot'))
then
484 this%config%bodies(i)%rotation_center_type = tmp_str
485 call json_get(body_sub,
'pivot.value', tmp_vec, expected_size = 3)
486 this%config%bodies(i)%rot_center = tmp_vec
489 tmp_str = this%config%bodies(i)%rotation_center_type
490 if (trim(tmp_str) /=
'relative' .and. &
491 trim(tmp_str) /=
'relative_sin')
then
492 call neko_error(
"ALE: pivot.type must be " // &
493 "'relative', or 'relative_sin'.")
498 if (body_sub%valid_path(
'stiff_geom'))
then
499 call json_get(body_sub,
'stiff_geom.type', tmp_str)
500 this%config%bodies(i)%stiff_geom%type = tmp_str
501 call json_get(body_sub,
'stiff_geom.gain', &
502 this%config%bodies(i)%stiff_geom%gain)
503 call json_get(body_sub,
'stiff_geom.decay_profile', tmp_str)
504 this%config%bodies(i)%stiff_geom%decay_profile = tmp_str
506 select case (trim(this%config%bodies(i)%stiff_geom%decay_profile))
509 'stiff_geom.cutoff_coef', &
510 this%config%bodies(i)%stiff_geom%cutoff_coef, 9.0_rp)
513 'stiff_geom.cutoff_coef', &
514 this%config%bodies(i)%stiff_geom%cutoff_coef, 3.5_rp)
516 call neko_error(
"ALE: Invalid stiff_geom.decay_profile: " // &
517 trim(this%config%bodies(i)%stiff_geom%decay_profile))
520 select case (trim(this%config%bodies(i)%stiff_geom%type))
521 case (
'cylinder',
'sphere')
522 call json_get(body_sub,
'stiff_geom.center', tmp_vec, &
524 this%config%bodies(i)%stiff_geom%center = tmp_vec
526 call json_get(body_sub,
'stiff_geom.radius', &
527 this%config%bodies(i)%stiff_geom%radius)
529 call json_get(body_sub,
'stiff_geom.stiff_dist', &
530 this%config%bodies(i)%stiff_geom%stiff_dist)
532 call neko_error(
"ALE: stiff_geom.type 'box' not yet" // &
535 call neko_error(
"ALE: Invalid stiff_geom.type: " // &
536 trim(this%config%bodies(i)%stiff_geom%type))
538 elseif (import_base_shapes)
then
542 trim(this%config%bodies(i)%name) // &
543 "' must have 'stiff_geom' definition.")
549 call this%base_shapes(i)%init(coef%dof, &
550 "phi_" // trim(this%config%bodies(i)%name))
556 this%ghost_handles(1, i) = this%request_tracker( &
557 this%config%bodies(i)%rot_center + [1.0_rp, 0.0_rp, 0.0_rp], &
558 this%config%bodies(i)%id)
560 this%ghost_handles(2, i) = this%request_tracker( &
561 this%config%bodies(i)%rot_center + [0.0_rp, 1.0_rp, 0.0_rp], &
562 this%config%bodies(i)%id)
564 call neko_log%message(
'Registered Body : ' // &
565 trim(this%config%bodies(i)%name))
569 if (
associated(this%user_ale_base_shapes, &
571 (.not. import_base_shapes))
then
572 write(log_buf,
'(A,A)')
' Stiff Type : ', &
573 trim(this%config%bodies(i)%stiff_geom%type)
575 write(log_buf,
'(A,ES18.11,A,A,A,ES10.4)')
' Gain : ', &
576 this%config%bodies(i)%stiff_geom%gain,
' | Profile: ', &
577 trim(this%config%bodies(i)%stiff_geom%decay_profile), &
578 ' | Cutoff: ', this%config%bodies(i)%stiff_geom%cutoff_coef
580 select case (trim(this%config%bodies(i)%stiff_geom%type))
581 case (
'cylinder',
'sphere')
582 write(log_buf,
'(A,3(ES23.15,1X))')
' Center :', &
583 this%config%bodies(i)%stiff_geom%center
585 write(log_buf,
'(A,ES23.15)')
' Radius :', &
586 this%config%bodies(i)%stiff_geom%radius
589 write(log_buf,
'(A,ES23.15)')
' Stiff Dist:', &
590 this%config%bodies(i)%stiff_geom%stiff_dist
597 has_builtin_osc = any(abs(this%config%bodies(i)%osc_amp) .gt. 0.0_rp)
599 if (has_builtin_osc)
then
600 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
601 call neko_log%message(
' Oscillation : ' // &
602 'X(t) = Amp*sin(2*pi*Freq*t) + User')
603 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
604 this%config%bodies(i)%osc_amp
606 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
607 this%config%bodies(i)%osc_freq
610 call neko_log%message(
' Oscillation : ' // &
611 'X(t) = Amp*sin(2*pi*Freq*t)')
612 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
613 this%config%bodies(i)%osc_amp
615 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
616 this%config%bodies(i)%osc_freq
620 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
621 call neko_log%message(
' Oscillation : User-defined')
623 call neko_log%message(
' Oscillation : None')
629 has_builtin_rot = (trim(this%config%bodies(i)%rotation_type) &
632 if (trim(this%config%bodies(i)%rotation_type) .eq.
'user')
then
634 call neko_log%message(
' Rotation Type: User-defined')
636 elseif (has_builtin_rot)
then
639 is_rot_active = .false.
640 select case (trim(this%config%bodies(i)%rotation_type))
642 is_rot_active = any(abs(this%config%bodies(i)%rot_amp_degree) &
645 is_rot_active = any(abs(this%config%bodies(i)%ramp_omega0) &
649 (abs(this%config%bodies(i)%target_rot_angle_deg) &
653 if (is_rot_active)
then
655 if (trim(this%config%bodies(i)%rotation_type) &
656 .eq.
'harmonic')
then
657 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
658 call neko_log%message(
' Rotation : ' // &
659 'Theta(t) = Amp*sin(2*pi*Freq*t) + User')
661 call neko_log%message(
' Rotation : ' // &
662 'Theta(t) = Amp*sin(2*pi*Freq*t)')
664 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp (deg) :', &
665 this%config%bodies(i)%rot_amp_degree
667 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
668 this%config%bodies(i)%rot_freq
672 elseif (trim(this%config%bodies(i)%rotation_type) &
674 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
675 call neko_log%message(
' Rotation : ' // &
676 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0)) + User')
678 call neko_log%message(
' Rotation : ' // &
679 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0))')
681 write(log_buf,
'(A,3(ES18.11,1X))')
' Omega0 :', &
682 this%config%bodies(i)%ramp_omega0
684 write(log_buf,
'(A,3(ES18.11,1X))')
' t0 :', &
685 this%config%bodies(i)%ramp_t0
689 elseif (trim(this%config%bodies(i)%rotation_type) &
690 .eq.
'smooth_step')
then
691 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
692 call neko_log%message(
' Rotation : ' // &
693 'Smooth Step Control + User')
695 call neko_log%message(
' Rotation : ' // &
696 'Smooth Step Control')
698 write(log_buf,
'(A,I10)')
' Rotation Axis :', &
699 this%config%bodies(i)%rotation_axis
701 write(log_buf,
'(A,ES18.11)')
' Target Rot ' // &
703 this%config%bodies(i)%target_rot_angle_deg
705 write(log_buf,
'(A,4(ES18.11,1X))') &
706 ' Control Times [t0, t1, t2, t3] :', &
707 this%config%bodies(i)%step_control_times
711 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
712 call neko_log%message(
' Rotation Type: User-defined')
714 call neko_log%message(
' Rotation Type: None')
722 call neko_log%message(
' Pivot Type : ' // &
723 trim(this%config%bodies(i)%rotation_center_type))
725 write(log_buf,
'(A,3(ES18.11,1X))')
' Init Pivot:', &
726 this%config%bodies(i)%rot_center
732 call neko_error(
"ALE: No 'ale bodies' found in case file!")
735 if (this%config%nbodies .gt. 1 .and. (.not. import_base_shapes))
then
736 call this%phi_total%init(coef%dof,
"phi_total")
741 do i = 1, n_moving_zones
742 z = moving_zone_ids(i)
745 do while ((.not. found_zone) .and. (j .le. this%config%nbodies))
746 if (any(this%config%bodies(j)%zone_indices .eq. z))
then
751 if (.not. found_zone)
then
752 write(log_buf_l,
'(A,I0,A)') &
753 "ALE: zone index ", z, &
754 " has BC no_slip with moving: true, " // &
755 "but it is not registered in ALE bodies."
762 do j = 1, this%config%nbodies
763 if (
allocated(this%config%bodies(j)%zone_indices))
then
764 do i = 1,
size(this%config%bodies(j)%zone_indices)
765 z = this%config%bodies(j)%zone_indices(i)
767 if (n_moving_zones .gt. 0)
then
768 if (any(moving_zone_ids(1:n_moving_zones) .eq. z))
then
772 if (.not. found_zone)
then
773 write(log_buf_l,
'(A,I0,A,A)') &
774 "ALE: zone index ", z, &
775 " is registered in ALE bodies, ", &
776 "but the BC is not no_slip with moving: true."
784 do j = 1, this%config%nbodies
785 if (
allocated(this%config%bodies(j)%zone_indices))
then
786 do i = 1,
size(this%config%bodies(j)%zone_indices)
787 z = this%config%bodies(j)%zone_indices(i)
789 do k = j + 1, this%config%nbodies
790 if (
allocated(this%config%bodies(k)%zone_indices))
then
791 if (any(this%config%bodies(k)%zone_indices .eq. z))
then
792 write(log_buf_l,
'(A,I0,A,A,A,A,A)') &
793 "ALE: zone index ", z, &
794 " is assigned to multiple bodies ('", &
795 trim(this%config%bodies(j)%name),
"' and '", &
796 trim(this%config%bodies(k)%name),
"')."
807 call this%solve_base_mesh_displacement(coef, json, import_base_shapes, &
808 abstol, ksp_solver, ksp_max_iter, &
809 precon_type, precon_params, res_monitor)
813 if (.not. json%valid_path(
'case.restart_file'))
then
817 call this%update_mesh_velocity(coef, t_init)
820 call this%wm_x_lag%init(this%wm_x, time_order)
821 call this%wm_y_lag%init(this%wm_y, time_order)
822 call this%wm_z_lag%init(this%wm_z, time_order)
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)
852 import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, &
853 precon_params, res_monitor)
855 class(
ax_t),
allocatable :: Ax
856 class(
ksp_t),
allocatable :: ksp
857 class(
pc_t),
allocatable :: pc
858 type(
coef_t),
intent(inout) :: coef
859 type(json_file),
intent(inout) :: json
860 logical,
intent(in) :: import_base_shapes
861 real(kind=
rp),
intent(in) :: abstol
862 logical,
intent(in) :: res_monitor
863 character(len=*),
intent(in) :: ksp_solver, precon_type
864 integer,
intent(in) :: ksp_max_iter
865 type(json_file),
intent(inout) :: precon_params
867 type(
field_t),
pointer :: phi_ptr => null()
871 real(kind=
rp) :: sample_start_time, sample_end_time
872 real(kind=
rp) :: sample_time
873 character(len=LOG_SIZE) :: log_buf
874 integer :: n, i, m, k, ierr, body_idx, z_idx
876 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
877 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
882 type(json_file) :: body_sub
883 character(len=256) :: phi_fname
884 character(len=:),
allocatable :: tmp_str
887 if (.not. this%active)
return
888 if (.not. this%has_moving_boundary)
return
889 if (this%config%nbodies .eq. 0)
return
891 if (import_base_shapes)
then
893 call neko_log%message(
"Importing ALE base shapes" // &
894 " (skipping Laplace solve)...")
896 do body_idx = 1, this%config%nbodies
901 call json_get(body_sub,
'base_shape_import_file', tmp_str)
904 phi_ptr => this%base_shapes(body_idx)
909 call neko_log%message(
" Loaded: " // &
912 trim(this%config%bodies(body_idx)%name))
919 call neko_log%message(
"Starting base mesh motion solve ...")
922 call ax_helm_factory(ax, full_formulation = .false.)
923 call krylov_solver_factory(ksp, n, ksp_solver, &
924 ksp_max_iter, abstol, monitor = res_monitor)
926 coef%gs_h, this%bc_list, precon_type, precon_params)
932 call rhs_field%init(coef%dof)
933 call corr_field%init(coef%dof)
937 if (.not.
associated(this%user_ale_base_shapes, &
939 call neko_log%message(
" Using user-defined base shapes " // &
940 "(skipping Laplace solve)")
943 call this%user_ale_base_shapes(this%base_shapes)
946 if (this%config%nbodies .gt. 1)
then
948 do body_idx = 1, this%config%nbodies
949 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
954 if (this%config%if_output_phi)
then
956 do body_idx = 1, this%config%nbodies
957 call phi_file%init(
'phi_' // &
958 trim(this%config%bodies(body_idx)%name) //
'.fld', &
960 select type (ft => phi_file%file_type)
962 ft%skip_pressure = .false.
964 call phi_file%write(this%base_shapes(body_idx))
967 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
971 if (this%config%nbodies .gt. 1)
then
972 call neko_log%message(
" phi_total.fld saved.")
973 select type (ft => phi_file%file_type)
975 ft%skip_pressure = .false.
977 call phi_file%init(
'phi_total.fld', precision =
rp)
978 call phi_file%write(this%phi_total)
989 if (this%config%if_output_stiffness)
then
990 rhs_field%x = coef%h1
991 call phi_file%init(
'stiffness.fld')
992 call phi_file%write(rhs_field)
998 do body_idx = 1, this%config%nbodies
1000 sample_start_time = mpi_wtime()
1001 call neko_log%message(
" Solving laplace for body: " // &
1002 trim(this%config%bodies(body_idx)%name))
1004 call bc_active_body%init_from_components(coef)
1005 call bc_inactive_body%init_from_components(coef)
1008 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
1009 z_idx = this%config%bodies(body_idx)%zone_indices(j)
1010 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
1013 do i = 1, this%config%nbodies
1014 if (i /= body_idx)
then
1015 do j = 1,
size(this%config%bodies(i)%zone_indices)
1016 z_idx = this%config%bodies(i)%zone_indices(j)
1017 call bc_inactive_body%mark_zone(&
1018 coef%msh%labeled_zones(z_idx))
1023 call bc_active_body%finalize()
1024 call bc_inactive_body%finalize()
1028 call bcloc%append(this%bc_fixed)
1029 call bcloc%append(bc_active_body)
1030 call bcloc%append(bc_inactive_body)
1033 call bcloc_zeros_only%init()
1034 call bcloc_zeros_only%append(this%bc_fixed)
1035 call bcloc_zeros_only%append(bc_inactive_body)
1038 this%base_shapes(body_idx)%x = 0.0_rp
1039 rhs_field%x = 0.0_rp
1040 corr_field%x = 0.0_rp
1047 m = bc_active_body%msk(0)
1049 k = bc_active_body%msk(i)
1050 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1061 call bcloc_zeros_only%apply_scalar(this%base_shapes(body_idx)%x, n)
1065 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1066 coef, coef%msh, coef%Xh)
1071 call bcloc%apply_scalar(rhs_field%x, n)
1072 call coef%gs_h%op(rhs_field, gs_op_add)
1077 monitor(1) = ksp%solve(ax, corr_field, &
1078 rhs_field%x, n, coef, bcloc, coef%gs_h)
1081 call field_add2(this%base_shapes(body_idx), corr_field, n)
1085 if (this%config%nbodies .gt. 1)
then
1086 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1090 sample_end_time = mpi_wtime()
1091 sample_time = sample_end_time - sample_start_time
1092 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1093 trim(this%config%bodies(body_idx)%name),
"' took ", &
1098 call bc_active_body%free()
1099 call bc_inactive_body%free()
1101 call bcloc_zeros_only%free()
1111 if (this%config%if_output_phi)
then
1112 call phi_file%init(
'phi_' // &
1113 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1115 select type (ft => phi_file%file_type)
1117 ft%skip_pressure = .false.
1119 call phi_file%write(this%base_shapes(body_idx))
1120 call phi_file%free()
1122 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1126 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1129 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1133 call neko_log%message(
" phi_total.fld saved.")
1134 call phi_file%init(
'phi_total.fld', precision =
rp)
1135 select type (ft => phi_file%file_type)
1137 ft%skip_pressure = .false.
1139 call phi_file%write(this%phi_total)
1140 call phi_file%free()
1144 call rhs_field%free()
1145 call corr_field%free()
1146 if (this%config%nbodies > 1)
then
1147 call this%phi_total%free()
1151 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1152 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1158 if (
allocated(h1_restore))
deallocate(h1_restore)
1159 if (
allocated(h2_restore))
deallocate(h2_restore)
1160 if (
allocated(ax))
deallocate(ax)
1161 if (
allocated(ksp))
then
1165 if (
allocated(pc))
then
1166 call precon_destroy(pc)
1176 type(
coef_t),
intent(in) :: coef
1180 real(kind=
rp) :: rot_mat(3,3)
1181 real(kind=
rp) :: initial_rot_center(3)
1183 if (.not. this%active)
return
1184 if (.not. this%has_moving_boundary)
return
1191 do i = 1, this%config%nbodies
1195 this%config%bodies(i), time_s)
1198 if (.not.
associated(this%user_ale_rigid_kinematics, &
1200 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1202 current_kin%vel_trans, &
1203 current_kin%vel_ang)
1206 current_kin%center = this%ale_pivot(i)%pos
1207 this%ale_pivot(i)%vel = current_kin%vel_trans
1209 this%body_kin(i)%center = this%ale_pivot(i)%pos
1210 this%body_kin(i)%vel_trans = current_kin%vel_trans
1211 this%body_kin(i)%vel_ang = current_kin%vel_ang
1214 call this%compute_rotation_matrix(i, time_s)
1215 rot_mat = this%body_rot_matrices(:,:,i)
1216 initial_rot_center = this%config%bodies(i)%rot_center
1220 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1221 this%base_shapes(i), coef, current_kin, rot_mat, &
1225 call this%prep_checkpoint(i)
1231 if (.not.
associated(this%user_ale_mesh_vel, &
1233 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1234 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1244 type(
coef_t),
intent(inout) :: coef
1246 integer,
intent(in) :: nadv
1249 if (.not. this%active)
return
1250 if (.not. this%has_moving_boundary)
return
1252 do i = 1, this%config%nbodies
1257 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1260 this%ale_pivot(i)%pos, &
1261 this%ale_pivot(i)%vel, &
1264 this%config%bodies(i))
1268 call coef%update_B_history()
1272 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1276 call this%wm_x_lag%update()
1277 call this%wm_y_lag%update()
1278 call this%wm_z_lag%update()
1284 type(
coef_t),
intent(inout) :: coef
1286 integer :: i, n, b, ierr
1287 integer,
allocatable :: cheap_map(:)
1288 integer :: n_cheap, map_idx
1289 real(kind=
rp) :: x, y, z
1290 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1291 real(kind=
rp) :: cx, cy, cz
1292 real(kind=
rp) :: arg, decay, gain, norm_dist
1293 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1294 type(
field_t),
allocatable :: dist_fields(:)
1295 character(len=128) :: log_buf
1300 allocate(cheap_map(params%nbodies))
1304 do b = 1, params%nbodies
1305 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1306 n_cheap = n_cheap + 1
1307 cheap_map(b) = n_cheap
1312 if (n_cheap > 0)
then
1313 allocate(dist_fields(n_cheap))
1315 do b = 1, params%nbodies
1316 map_idx = cheap_map(b)
1317 if (map_idx .gt. 0)
then
1319 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1322 call neko_log%message(
" Start: cheap dist calculation " // &
1323 "for body '" // trim(params%bodies(b)%name) //
"'")
1326 sample_start_time = mpi_wtime()
1330 coef%msh, params%bodies(b)%zone_indices, &
1331 copy_to_host = .true.)
1334 coef%msh, params%bodies(b)%zone_indices)
1338 sample_end_time = mpi_wtime()
1339 sample_time = sample_end_time - sample_start_time
1341 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1342 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1350 select case (trim(params%stiffness_type))
1353 do concurrent(i = 1:n)
1354 x = coef%dof%x(i, 1, 1, 1)
1355 y = coef%dof%y(i, 1, 1, 1)
1356 z = coef%dof%z(i, 1, 1, 1)
1358 max_added_stiff = 0.0_rp
1361 do b = 1, params%nbodies
1362 gain = params%bodies(b)%stiff_geom%gain
1363 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1364 decay = params%bodies(b)%stiff_geom%stiff_dist
1366 decay = params%bodies(b)%stiff_geom%radius
1370 cx = params%bodies(b)%stiff_geom%center(1)
1371 cy = params%bodies(b)%stiff_geom%center(2)
1372 cz = params%bodies(b)%stiff_geom%center(3)
1374 raw_dist = huge(0.0_rp)
1377 select case (trim(params%bodies(b)%stiff_geom%type))
1379 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1383 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1389 map_idx = cheap_map(b)
1390 if (map_idx .gt. 0)
then
1391 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1396 body_stiff_val = 0.0_rp
1397 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1400 arg = -(raw_dist**2) / (decay**2)
1401 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1402 body_stiff_val = gain * exp(arg)
1406 norm_dist = (raw_dist / decay)
1407 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1408 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1411 if (body_stiff_val .gt. max_added_stiff)
then
1412 max_added_stiff = body_stiff_val
1416 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1417 coef%h2(i, 1, 1, 1) = 0.0_rp
1421 call neko_error(
"ALE Manager: Unknown stiffness type")
1431 if (
allocated(dist_fields))
then
1432 do i = 1,
size(dist_fields)
1433 call dist_fields(i)%free()
1435 deallocate(dist_fields)
1437 if (
allocated(cheap_map))
deallocate(cheap_map)
1443 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1444 type(
field_t),
intent(inout) :: wx, wy, wz
1445 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1446 type(
field_t),
intent(in) :: phi
1447 type(
coef_t),
intent(in) :: coef
1449 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1450 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1453 x_ref, y_ref, z_ref, &
1454 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1457 x_ref, y_ref, z_ref, &
1458 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1464 wm_z_lag, time, nadv, scheme_)
1465 type(
coef_t),
intent(inout) :: c_xh
1466 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1469 integer,
intent(in) :: nadv
1470 character(len=*),
intent(in) :: scheme_
1473 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1476 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1485 if (.not. this%active)
return
1487 call this%bc_moving%free()
1488 call this%bc_fixed%free()
1489 call this%bc_list%free()
1491 if (
allocated(this%base_shapes))
then
1492 do i = 1,
size(this%base_shapes)
1493 call this%base_shapes(i)%free()
1495 deallocate(this%base_shapes)
1498 call this%wm_x_lag%free()
1499 call this%wm_y_lag%free()
1500 call this%wm_z_lag%free()
1501 call this%x_ref%free()
1502 call this%y_ref%free()
1503 call this%z_ref%free()
1505 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1506 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1507 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1508 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1509 if (
associated(this%global_pivot_vel_lag)) &
1510 deallocate(this%global_pivot_vel_lag)
1511 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1512 if (
associated(this%global_basis_vel_lag)) &
1513 deallocate(this%global_basis_vel_lag)
1514 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1515 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1516 if (
allocated(this%trackers))
deallocate(this%trackers)
1523 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1524 class(
ksp_t),
target,
intent(inout) :: ksp
1525 type(
coef_t),
target,
intent(in) :: coef
1526 type(
dofmap_t),
target,
intent(in) :: dof
1527 type(
gs_t),
target,
intent(inout) :: gs
1528 type(
bc_list_t),
target,
intent(inout) :: bclst
1529 character(len=*),
intent(in) :: pctype
1530 type(json_file),
intent(inout) :: params
1531 call precon_factory(pc, pctype)
1532 select type (pcp => pc)
1534 call pcp%init(coef, dof, gs)
1536 call pcp%init(coef, dof, gs)
1538 call pcp%init(coef, dof, gs)
1540 call pcp%init(coef, bclst, params)
1542 call pcp%init(coef, bclst, params)
1550 real(kind=
dp),
intent(in) :: time_restart
1552 integer :: i, idx, handle_1, handle_2, offset_base
1554 time_state_dummy%t = time_restart
1558 do i = 1, this%config%nbodies
1561 this%config%bodies(i), time_state_dummy)
1564 if (.not.
associated(this%user_ale_rigid_kinematics, &
1566 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1568 kin_restart%vel_trans, &
1569 kin_restart%vel_ang)
1572 this%ale_pivot(i)%vel = kin_restart%vel_trans
1576 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1577 this%body_kin(i)%center = this%ale_pivot(i)%pos
1578 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1579 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1582 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1583 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1586 offset_base = (i-1)*6
1587 handle_1 = this%ghost_handles(1, i)
1588 handle_2 = this%ghost_handles(2, i)
1590 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1591 this%trackers(handle_1)%pos = &
1592 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1595 this%trackers(handle_1)%vel_lag = &
1596 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1599 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1600 this%trackers(handle_2)%pos = &
1601 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1604 this%trackers(handle_2)%vel_lag = &
1605 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1615 type(
coef_t),
intent(inout) :: coef
1616 type(
space_t),
intent(inout) :: Xh
1617 type(
chkp_t),
intent(in) :: chkp
1618 type(
gs_t),
intent(inout) :: gs_Xh
1622 if (.not. this%active)
return
1624 if (
allocated(chkp%previous_mesh%elements))
then
1626 "The current mesh has a different number " // &
1627 "of elements than the checkpoint.")
1631 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1633 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1634 do concurrent(j = 1:n)
1636 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1637 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1638 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1642 do i = 1, this%wm_x_lag%size()
1643 do concurrent(j = 1:n)
1644 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1645 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1646 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1647 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1648 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1649 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1674 if (c_associated(coef%dof%x_d))
then
1683 if (c_associated(coef%Blag_d))
then
1684 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1688 if (c_associated(coef%Blaglag_d))
then
1696 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1697 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1698 call gs_xh%op(this%wm_x, gs_op_add)
1699 call gs_xh%op(this%wm_y, gs_op_add)
1700 call gs_xh%op(this%wm_z, gs_op_add)
1701 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1703 do i = 1, this%wm_x_lag%size()
1704 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1705 this%wm_z_lag%lf(i)%x, 1, coef)
1706 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1707 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1708 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
1709 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1710 this%wm_z_lag%lf(i)%x, 0, coef)
1715 call this%set_pivot_restart(chkp%t)
1716 call coef%recompute_metrics()
1723 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1725 coef%Blaglag = coef%B
1727 if (c_associated(coef%Blag_d))
then
1731 if (c_associated(coef%Blaglag_d))
then
1739 call adv%recompute_metrics(coef, .true.)
1744 integer,
intent(in) :: body_idx
1745 integer :: idx, offset_base, h1, h2
1747 if (.not. this%active)
return
1748 if (.not. this%has_moving_boundary)
return
1750 idx = (body_idx - 1) * 3
1751 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1752 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1753 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1755 h1 = this%ghost_handles(1, body_idx)
1756 h2 = this%ghost_handles(2, body_idx)
1758 offset_base = (body_idx-1)*6
1761 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1762 this%get_tracker_pos(h1)
1763 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1764 this%get_tracker_pos(h2)
1767 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1768 this%trackers(h1)%vel_lag
1771 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1772 this%trackers(h2)%vel_lag
1777 integer,
allocatable,
intent(inout) :: arr(:)
1778 integer,
intent(inout) :: n
1779 integer,
intent(in) :: val
1780 integer,
allocatable :: tmp(:)
1784 if (arr(k) .eq. val)
return
1787 allocate(tmp(n + 1))
1788 if (n .gt. 0) tmp(1:n) = arr(1:n)
1791 if (
allocated(arr))
deallocate(arr)
1792 call move_alloc(tmp, arr)
1800 type(coef_t),
intent(inout) :: coef
1801 type(json_file),
intent(inout) :: json
1802 type(fld_file_output_t) :: fout
1803 type(field_t) :: dummy_field
1804 type(time_state_t) :: t_state
1805 type(file_t) :: out_file
1806 real(kind=rp) :: t_start
1807 real(kind=rp) :: t_end
1809 real(kind=rp) :: min_jac
1810 integer :: output_freq
1811 integer :: step, n_steps
1812 integer :: nadv, nadv_sim
1814 logical :: mesh_preview_active
1815 character(len=128) :: log_buf
1817 mesh_preview_active = .false.
1819 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1820 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1821 mesh_preview_active)
1824 if (.not. mesh_preview_active)
return
1826 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1828 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1830 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1832 call json_get(json, &
1833 'case.fluid.ale.mesh_preview.output_freq', &
1836 call neko_log%section(
"ALE Mesh Preview")
1837 call neko_log%message(
"Executing mesh motion preview...")
1839 n_steps = int((t_end - t_start) / dt)
1840 call json_get(json,
'case.numerics.time_order', nadv_sim)
1842 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1843 call neko_log%message(log_buf)
1844 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1845 call neko_log%message(log_buf)
1846 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1847 call neko_log%message(log_buf)
1848 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1849 call neko_log%message(log_buf)
1850 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1851 call neko_log%message(log_buf)
1852 call neko_log%message(
'')
1855 call dummy_field%init(coef%dof,
"mesh_preview")
1856 call field_rzero(dummy_field)
1858 call fout%init(rp,
"mesh_preview", 1)
1859 call fout%fields%assign_to_field(1, dummy_field)
1860 select type (ft => fout%file_%file_type)
1861 type is (fld_file_t)
1862 ft%write_mesh = .true.
1863 ft%skip_pressure = .false.
1876 if (neko_bcknd_device .eq. 1)
then
1877 min_jac = device_glmin(coef%jac_d, n)
1879 min_jac = glmin(coef%jac, n)
1883 call fout%sample(t_state%t)
1885 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1886 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1887 t_state%t,
" | Min Jac: ", min_jac
1889 call neko_log%message(trim(log_buf))
1890 call this%update_mesh_velocity(coef, t_state)
1892 do step = 1, n_steps
1893 t_state%tstep = step
1894 t_state%t = t_start + (step * dt)
1895 nadv = min(step, nadv_sim)
1897 call this%advance_mesh(coef, t_state, nadv)
1898 call coef%recompute_metrics()
1901 if (neko_bcknd_device .eq. 1)
then
1902 min_jac = device_glmin(coef%jac_d, n)
1904 min_jac = glmin(coef%jac, n)
1907 if (min_jac .le. 0.0_rp)
then
1908 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1909 "Negative Jacobian detected (", min_jac,
") at t = ", &
1911 call neko_log%message(log_buf)
1914 call fout%sample(t_state%t)
1916 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1917 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1918 t_state%t,
" | Min Jac:", min_jac
1919 call neko_log%message(trim(log_buf))
1921 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1924 if (mod(step, output_freq) .eq. 0)
then
1927 call fout%sample(t_state%t)
1929 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1930 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1931 t_state%t,
" | Min Jac:", min_jac
1932 call neko_log%message(trim(log_buf))
1936 call this%update_mesh_velocity(coef, t_state)
1940 call dummy_field%free()
1942 call neko_log%end_section()
1943 call neko_log%message(
"Mesh preview complete.")
1944 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1949 type(fld_file_output_t) :: fout
1950 type(coef_t),
intent(inout) :: coef
1951 type(field_t),
intent(inout) :: dummy_field
1955 if (neko_bcknd_device .eq. 1)
then
1956 call device_copy(dummy_field%x_d, coef%B_d, n)
1958 call copy(dummy_field%x, coef%B, n)
1961 if (neko_bcknd_device .eq. 1)
then
1962 associate(
mesh => coef%dof)
1964 device_to_host, sync = .false.)
1966 device_to_host, sync = .false.)
1968 device_to_host, sync = .false.)
1978 real(kind=rp),
intent(in) :: initial_pos(3)
1979 integer,
intent(in) :: body_id
1981 type(point_tracker_t),
allocatable :: tmp(:)
1984 if (.not. this%active)
return
1985 if (.not. this%has_moving_boundary)
return
1987 if (.not.
allocated(this%trackers))
then
1988 allocate(this%trackers(30))
1990 elseif (this%n_trackers .ge.
size(this%trackers))
then
1991 allocate(tmp(
size(this%trackers) + 30))
1992 tmp(1:
size(this%trackers)) = this%trackers
1993 deallocate(this%trackers)
1994 call move_alloc(tmp, this%trackers)
1996 this%n_trackers = this%n_trackers + 1
1997 handle = this%n_trackers
1999 this%trackers(handle)%pos = initial_pos
2000 this%trackers(handle)%body_id = body_id
2001 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
2006 integer,
intent(in) :: handle
2007 real(kind=rp) :: pos(3)
2009 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
2010 pos = this%trackers(handle)%pos
2020 integer,
intent(in) :: body_idx
2021 type(time_state_t),
intent(in) :: time
2023 real(kind=rp) :: p(3), gx(3), gy(3)
2024 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
2026 if (.not. this%active)
return
2027 if (.not. this%has_moving_boundary)
return
2030 h_x = this%ghost_handles(1, body_idx)
2031 h_y = this%ghost_handles(2, body_idx)
2033 p = this%ale_pivot(body_idx)%pos
2034 gx = this%get_tracker_pos(h_x)
2035 gy = this%get_tracker_pos(h_y)
2039 u = u / sqrt(sum(u**2))
2043 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2044 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2045 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2046 w = w / sqrt(sum(w**2))
2049 v(1) = w(2)*u(3) - w(3)*u(2)
2050 v(2) = w(3)*u(1) - w(1)*u(3)
2051 v(3) = w(1)*u(2) - w(2)*u(1)
2053 this%body_rot_matrices(:, 1, body_idx) = u
2054 this%body_rot_matrices(:, 2, body_idx) = v
2055 this%body_rot_matrices(:, 3, body_idx) = w
2065 type(time_state_t),
intent(in) :: time
2066 integer,
optional,
intent(in) :: body_idxs(:)
2068 integer :: i, idx, n_log
2069 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2070 real(kind=rp) :: r(3,3)
2071 character(len=256) :: log_buf
2072 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2074 if (.not. this%active)
return
2075 if (.not. this%has_moving_boundary)
return
2077 if (
present(body_idxs))
then
2078 n_log =
size(body_idxs)
2080 n_log = this%config%nbodies
2083 call neko_log%message(
" ")
2084 call neko_log%message(
"---------Rotation log---------")
2085 call neko_log%message(
"variable, time step, time, body, " // &
2086 "x_val, y_val, z_val")
2091 if (
present(body_idxs))
then
2097 r = this%body_rot_matrices(:,:,idx)
2100 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2101 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2102 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2105 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2106 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2107 trim(this%config%bodies(idx)%name),
" ", &
2108 roll_deg, pitch_deg, yaw_deg
2109 call neko_log%message(trim(log_buf))
2120 type(time_state_t),
intent(in) :: time
2121 integer,
optional,
intent(in) :: body_idxs(:)
2122 integer :: i, idx, n_log
2123 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2124 character(len=256) :: log_buf
2126 if (.not. this%active)
return
2127 if (.not. this%has_moving_boundary)
return
2129 if (
present(body_idxs))
then
2130 n_log =
size(body_idxs)
2132 n_log = this%config%nbodies
2135 call neko_log%message(
" ")
2136 call neko_log%message(
"----------Pivot Log-----------")
2137 call neko_log%message(
"variable, time step, time, body, " // &
2138 "x_val, y_val, z_val")
2143 if (
present(body_idxs))
then
2149 pivot_pos = this%ale_pivot(idx)%pos
2150 pivot_vel = this%ale_pivot(idx)%vel
2153 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2154 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2155 trim(this%config%bodies(idx)%name),
" ", &
2156 this%ale_pivot(idx)%pos
2157 call neko_log%message(trim(log_buf))
2160 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2161 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2162 trim(this%config%bodies(idx)%name),
" ", &
2163 this%ale_pivot(idx)%vel
2164 call neko_log%message(trim(log_buf))
2171 type(body_kinematics_t),
intent(in) :: kin_object
2172 type(time_state_t),
intent(in) :: time_s
2173 integer,
intent(in) :: nadv
2174 integer,
intent(in) :: body_idx
2176 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2178 if (.not. this%active)
return
2179 if (.not. this%has_moving_boundary)
return
2181 if (
allocated(this%trackers))
then
2182 do t = 1, this%n_trackers
2183 if (this%trackers(t)%body_id .eq. &
2184 this%config%bodies(body_idx)%id)
then
2185 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2186 t .eq. this%ghost_handles(2, body_idx))
then
2189 rel_pos = this%trackers(t)%pos - kin_object%center
2192 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2193 kin_object%vel_ang(3) * rel_pos(2)
2194 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2195 kin_object%vel_ang(1) * rel_pos(3)
2196 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2197 kin_object%vel_ang(2) * rel_pos(1)
2200 p_vel = kin_object%vel_trans + v_tan
2202 if (time_s%tstep .gt. 0)
then
2203 call ab_integrate_point_pos(this%trackers(t)%pos, &
2204 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2216 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
2218 type(json_file),
intent(inout) :: json
2219 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2220 character(len=:),
allocatable,
intent(inout) :: precon_type
2221 type(json_file),
intent(inout) :: precon_params
2222 real(kind=rp),
intent(out) :: abstol
2223 integer,
intent(out) :: ksp_max_iter
2224 logical,
intent(out) :: res_monitor
2225 logical,
intent(out) :: import_base_shapes
2226 logical :: tmp_logical
2227 character(len=:),
allocatable :: tmp_str
2229 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2230 if (
allocated(precon_type))
deallocate(precon_type)
2232 call json_get_or_default(json, &
2233 'case.fluid.ale.solver.import_base_shape', &
2234 import_base_shapes, .false.)
2236 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2239 call json_get_or_default(json, &
2240 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2242 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2243 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2247 call json_get_or_default(json, &
2248 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2249 call json_get_or_default(json,
'case.fluid.ale.solver.monitor', &
2250 res_monitor, .false.)
2251 call json_get_or_default(json,
'case.fluid.ale.solver.max_iterations', &
2252 ksp_max_iter, 10000)
2254 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2255 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2256 this%config%if_output_phi = tmp_logical
2258 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2259 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2260 this%config%if_output_stiffness = tmp_logical
2264 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2265 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2266 this%config%stiffness_type = tmp_str
2267 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2268 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2276 type(coef_t),
intent(inout) :: coef
2277 type(chkp_t),
intent(inout) :: checkpoint
2280 if (.not. this%active)
return
2283 call checkpoint%add_ale(coef%dof%x, coef%dof%y, &
2284 coef%dof%z, coef%dof%x_d, coef%dof%y_d, &
2286 coef%Blag, coef%Blaglag, coef%Blag_d, coef%Blaglag_d, &
2287 this%wm_x, this%wm_y, this%wm_z, &
2288 this%wm_x_lag, this%wm_y_lag, &
2290 this%global_pivot_pos, &
2291 this%global_pivot_vel_lag, &
2292 this%global_basis_pos, &
2293 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.
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.
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...