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, 2)
821 call this%wm_y_lag%init(this%wm_y, 2)
822 call this%wm_z_lag%init(this%wm_z, 2)
824 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
825 if (
allocated(bc_type))
deallocate(bc_type)
826 if (
allocated(zone_indices))
deallocate(zone_indices)
827 if (
allocated(ksp_solver))
deallocate(ksp_solver)
828 if (
allocated(precon_type))
deallocate(precon_type)
829 if (
allocated(tmp_str))
deallocate(tmp_str)
830 if (
allocated(tmp_vec))
deallocate(tmp_vec)
833 call this%mesh_preview(coef, json)
836 call this%register_checkpoint_fields(coef, chkp)
846 import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, &
847 precon_params, res_monitor)
849 class(
ax_t),
allocatable :: Ax
850 class(
ksp_t),
allocatable :: ksp
851 class(
pc_t),
allocatable :: pc
852 type(
coef_t),
intent(inout) :: coef
853 type(json_file),
intent(inout) :: json
854 logical,
intent(in) :: import_base_shapes
855 real(kind=
rp),
intent(in) :: abstol
856 logical,
intent(in) :: res_monitor
857 character(len=*),
intent(in) :: ksp_solver, precon_type
858 integer,
intent(in) :: ksp_max_iter
859 type(json_file),
intent(inout) :: precon_params
861 type(
field_t),
pointer :: phi_ptr => null()
865 real(kind=
rp) :: sample_start_time, sample_end_time
866 real(kind=
rp) :: sample_time
867 character(len=LOG_SIZE) :: log_buf
868 integer :: n, i, m, k, ierr, body_idx, z_idx
870 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
871 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
876 type(json_file) :: body_sub
877 character(len=256) :: phi_fname
878 character(len=:),
allocatable :: tmp_str
881 if (.not. this%active)
return
882 if (.not. this%has_moving_boundary)
return
883 if (this%config%nbodies .eq. 0)
return
885 if (import_base_shapes)
then
887 call neko_log%message(
"Importing ALE base shapes" // &
888 " (skipping Laplace solve)...")
890 do body_idx = 1, this%config%nbodies
895 call json_get(body_sub,
'base_shape_import_file', tmp_str)
898 phi_ptr => this%base_shapes(body_idx)
903 call neko_log%message(
" Loaded: " // &
906 trim(this%config%bodies(body_idx)%name))
913 call neko_log%message(
"Starting base mesh motion solve ...")
916 call ax_helm_factory(ax, full_formulation = .false.)
917 call krylov_solver_factory(ksp, n, ksp_solver, &
918 ksp_max_iter, abstol, monitor = res_monitor)
920 coef%gs_h, this%bc_list, precon_type, precon_params)
926 call rhs_field%init(coef%dof)
927 call corr_field%init(coef%dof)
931 if (.not.
associated(this%user_ale_base_shapes, &
933 call neko_log%message(
" Using user-defined base shapes " // &
934 "(skipping Laplace solve)")
937 call this%user_ale_base_shapes(this%base_shapes)
940 if (this%config%nbodies .gt. 1)
then
942 do body_idx = 1, this%config%nbodies
943 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
948 if (this%config%if_output_phi)
then
950 do body_idx = 1, this%config%nbodies
951 call phi_file%init(
'phi_' // &
952 trim(this%config%bodies(body_idx)%name) //
'.fld', &
954 select type (ft => phi_file%file_type)
956 ft%skip_pressure = .false.
958 call phi_file%write(this%base_shapes(body_idx))
961 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
965 if (this%config%nbodies .gt. 1)
then
966 call neko_log%message(
" phi_total.fld saved.")
967 select type (ft => phi_file%file_type)
969 ft%skip_pressure = .false.
971 call phi_file%init(
'phi_total.fld', precision =
rp)
972 call phi_file%write(this%phi_total)
983 if (this%config%if_output_stiffness)
then
984 rhs_field%x = coef%h1
985 call phi_file%init(
'stiffness.fld')
986 call phi_file%write(rhs_field)
992 do body_idx = 1, this%config%nbodies
994 sample_start_time = mpi_wtime()
995 call neko_log%message(
" Solving laplace for body: " // &
996 trim(this%config%bodies(body_idx)%name))
998 call bc_active_body%init_from_components(coef)
999 call bc_inactive_body%init_from_components(coef)
1002 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
1003 z_idx = this%config%bodies(body_idx)%zone_indices(j)
1004 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
1007 do i = 1, this%config%nbodies
1008 if (i /= body_idx)
then
1009 do j = 1,
size(this%config%bodies(i)%zone_indices)
1010 z_idx = this%config%bodies(i)%zone_indices(j)
1011 call bc_inactive_body%mark_zone(&
1012 coef%msh%labeled_zones(z_idx))
1017 call bc_active_body%finalize()
1018 call bc_inactive_body%finalize()
1022 call bcloc%append(this%bc_fixed)
1023 call bcloc%append(bc_active_body)
1024 call bcloc%append(bc_inactive_body)
1027 call bcloc_zeros_only%init()
1028 call bcloc_zeros_only%append(this%bc_fixed)
1029 call bcloc_zeros_only%append(bc_inactive_body)
1032 this%base_shapes(body_idx)%x = 0.0_rp
1033 rhs_field%x = 0.0_rp
1034 corr_field%x = 0.0_rp
1041 m = bc_active_body%msk(0)
1043 k = bc_active_body%msk(i)
1044 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1055 call bcloc_zeros_only%apply_scalar(this%base_shapes(body_idx)%x, n)
1059 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1060 coef, coef%msh, coef%Xh)
1065 call bcloc%apply_scalar(rhs_field%x, n)
1066 call coef%gs_h%op(rhs_field, gs_op_add)
1071 monitor(1) = ksp%solve(ax, corr_field, &
1072 rhs_field%x, n, coef, bcloc, coef%gs_h)
1075 call field_add2(this%base_shapes(body_idx), corr_field, n)
1079 if (this%config%nbodies .gt. 1)
then
1080 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1084 sample_end_time = mpi_wtime()
1085 sample_time = sample_end_time - sample_start_time
1086 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1087 trim(this%config%bodies(body_idx)%name),
"' took ", &
1092 call bc_active_body%free()
1093 call bc_inactive_body%free()
1095 call bcloc_zeros_only%free()
1105 if (this%config%if_output_phi)
then
1106 call phi_file%init(
'phi_' // &
1107 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1109 select type (ft => phi_file%file_type)
1111 ft%skip_pressure = .false.
1113 call phi_file%write(this%base_shapes(body_idx))
1114 call phi_file%free()
1116 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1120 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1123 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1127 call neko_log%message(
" phi_total.fld saved.")
1128 call phi_file%init(
'phi_total.fld', precision =
rp)
1129 select type (ft => phi_file%file_type)
1131 ft%skip_pressure = .false.
1133 call phi_file%write(this%phi_total)
1134 call phi_file%free()
1138 call rhs_field%free()
1139 call corr_field%free()
1140 if (this%config%nbodies > 1)
then
1141 call this%phi_total%free()
1145 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1146 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1152 if (
allocated(h1_restore))
deallocate(h1_restore)
1153 if (
allocated(h2_restore))
deallocate(h2_restore)
1154 if (
allocated(ax))
deallocate(ax)
1155 if (
allocated(ksp))
then
1159 if (
allocated(pc))
then
1160 call precon_destroy(pc)
1170 type(
coef_t),
intent(in) :: coef
1174 real(kind=
rp) :: rot_mat(3,3)
1175 real(kind=
rp) :: initial_rot_center(3)
1177 if (.not. this%active)
return
1178 if (.not. this%has_moving_boundary)
return
1185 do i = 1, this%config%nbodies
1189 this%config%bodies(i), time_s)
1192 if (.not.
associated(this%user_ale_rigid_kinematics, &
1194 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1196 current_kin%vel_trans, &
1197 current_kin%vel_ang)
1200 current_kin%center = this%ale_pivot(i)%pos
1201 this%ale_pivot(i)%vel = current_kin%vel_trans
1203 this%body_kin(i)%center = this%ale_pivot(i)%pos
1204 this%body_kin(i)%vel_trans = current_kin%vel_trans
1205 this%body_kin(i)%vel_ang = current_kin%vel_ang
1208 call this%compute_rotation_matrix(i, time_s)
1209 rot_mat = this%body_rot_matrices(:,:,i)
1210 initial_rot_center = this%config%bodies(i)%rot_center
1214 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1215 this%base_shapes(i), coef, current_kin, rot_mat, &
1219 call this%prep_checkpoint(i)
1225 if (.not.
associated(this%user_ale_mesh_vel, &
1227 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1228 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1238 type(
coef_t),
intent(inout) :: coef
1240 integer,
intent(in) :: nadv
1243 if (.not. this%active)
return
1244 if (.not. this%has_moving_boundary)
return
1246 do i = 1, this%config%nbodies
1251 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1254 this%ale_pivot(i)%pos, &
1255 this%ale_pivot(i)%vel, &
1258 this%config%bodies(i))
1262 call coef%update_B_history()
1266 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1270 call this%wm_x_lag%update()
1271 call this%wm_y_lag%update()
1272 call this%wm_z_lag%update()
1278 type(
coef_t),
intent(inout) :: coef
1280 integer :: i, n, b, ierr
1281 integer,
allocatable :: cheap_map(:)
1282 integer :: n_cheap, map_idx
1283 real(kind=
rp) :: x, y, z
1284 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1285 real(kind=
rp) :: cx, cy, cz
1286 real(kind=
rp) :: arg, decay, gain, norm_dist
1287 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1288 type(
field_t),
allocatable :: dist_fields(:)
1289 character(len=128) :: log_buf
1294 allocate(cheap_map(params%nbodies))
1298 do b = 1, params%nbodies
1299 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1300 n_cheap = n_cheap + 1
1301 cheap_map(b) = n_cheap
1306 if (n_cheap > 0)
then
1307 allocate(dist_fields(n_cheap))
1309 do b = 1, params%nbodies
1310 map_idx = cheap_map(b)
1311 if (map_idx .gt. 0)
then
1313 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1316 call neko_log%message(
" Start: cheap dist calculation " // &
1317 "for body '" // trim(params%bodies(b)%name) //
"'")
1320 sample_start_time = mpi_wtime()
1324 coef%msh, params%bodies(b)%zone_indices, &
1325 copy_to_host = .true.)
1328 coef%msh, params%bodies(b)%zone_indices)
1332 sample_end_time = mpi_wtime()
1333 sample_time = sample_end_time - sample_start_time
1335 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1336 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1344 select case (trim(params%stiffness_type))
1347 do concurrent(i = 1:n)
1348 x = coef%dof%x(i, 1, 1, 1)
1349 y = coef%dof%y(i, 1, 1, 1)
1350 z = coef%dof%z(i, 1, 1, 1)
1352 max_added_stiff = 0.0_rp
1355 do b = 1, params%nbodies
1356 gain = params%bodies(b)%stiff_geom%gain
1357 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1358 decay = params%bodies(b)%stiff_geom%stiff_dist
1360 decay = params%bodies(b)%stiff_geom%radius
1364 cx = params%bodies(b)%stiff_geom%center(1)
1365 cy = params%bodies(b)%stiff_geom%center(2)
1366 cz = params%bodies(b)%stiff_geom%center(3)
1368 raw_dist = huge(0.0_rp)
1371 select case (trim(params%bodies(b)%stiff_geom%type))
1373 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1377 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1383 map_idx = cheap_map(b)
1384 if (map_idx .gt. 0)
then
1385 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1390 body_stiff_val = 0.0_rp
1391 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1394 arg = -(raw_dist**2) / (decay**2)
1395 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1396 body_stiff_val = gain * exp(arg)
1400 norm_dist = (raw_dist / decay)
1401 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1402 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1405 if (body_stiff_val .gt. max_added_stiff)
then
1406 max_added_stiff = body_stiff_val
1410 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1411 coef%h2(i, 1, 1, 1) = 0.0_rp
1415 call neko_error(
"ALE Manager: Unknown stiffness type")
1425 if (
allocated(dist_fields))
then
1426 do i = 1,
size(dist_fields)
1427 call dist_fields(i)%free()
1429 deallocate(dist_fields)
1431 if (
allocated(cheap_map))
deallocate(cheap_map)
1437 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1438 type(
field_t),
intent(inout) :: wx, wy, wz
1439 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1440 type(
field_t),
intent(in) :: phi
1441 type(
coef_t),
intent(in) :: coef
1443 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1444 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1447 x_ref, y_ref, z_ref, &
1448 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1451 x_ref, y_ref, z_ref, &
1452 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1458 wm_z_lag, time, nadv, scheme_)
1459 type(
coef_t),
intent(inout) :: c_xh
1460 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1463 integer,
intent(in) :: nadv
1464 character(len=*),
intent(in) :: scheme_
1467 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1470 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1479 if (.not. this%active)
return
1481 call this%bc_moving%free()
1482 call this%bc_fixed%free()
1483 call this%bc_list%free()
1485 if (
allocated(this%base_shapes))
then
1486 do i = 1,
size(this%base_shapes)
1487 call this%base_shapes(i)%free()
1489 deallocate(this%base_shapes)
1492 call this%wm_x_lag%free()
1493 call this%wm_y_lag%free()
1494 call this%wm_z_lag%free()
1495 call this%x_ref%free()
1496 call this%y_ref%free()
1497 call this%z_ref%free()
1499 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1500 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1501 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1502 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1503 if (
associated(this%global_pivot_vel_lag)) &
1504 deallocate(this%global_pivot_vel_lag)
1505 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1506 if (
associated(this%global_basis_vel_lag)) &
1507 deallocate(this%global_basis_vel_lag)
1508 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1509 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1510 if (
allocated(this%trackers))
deallocate(this%trackers)
1517 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1518 class(
ksp_t),
target,
intent(inout) :: ksp
1519 type(
coef_t),
target,
intent(in) :: coef
1520 type(
dofmap_t),
target,
intent(in) :: dof
1521 type(
gs_t),
target,
intent(inout) :: gs
1522 type(
bc_list_t),
target,
intent(inout) :: bclst
1523 character(len=*),
intent(in) :: pctype
1524 type(json_file),
intent(inout) :: params
1525 call precon_factory(pc, pctype)
1526 select type (pcp => pc)
1528 call pcp%init(coef, dof, gs)
1530 call pcp%init(coef, dof, gs)
1532 call pcp%init(coef, dof, gs)
1534 call pcp%init(coef, bclst, params)
1536 call pcp%init(coef, bclst, params)
1544 real(kind=
dp),
intent(in) :: time_restart
1546 integer :: i, idx, handle_1, handle_2, offset_base
1548 time_state_dummy%t = time_restart
1552 do i = 1, this%config%nbodies
1555 this%config%bodies(i), time_state_dummy)
1558 if (.not.
associated(this%user_ale_rigid_kinematics, &
1560 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1562 kin_restart%vel_trans, &
1563 kin_restart%vel_ang)
1566 this%ale_pivot(i)%vel = kin_restart%vel_trans
1570 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1571 this%body_kin(i)%center = this%ale_pivot(i)%pos
1572 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1573 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1576 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1577 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1580 offset_base = (i-1)*6
1581 handle_1 = this%ghost_handles(1, i)
1582 handle_2 = this%ghost_handles(2, i)
1584 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1585 this%trackers(handle_1)%pos = &
1586 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1589 this%trackers(handle_1)%vel_lag = &
1590 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1593 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1594 this%trackers(handle_2)%pos = &
1595 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1598 this%trackers(handle_2)%vel_lag = &
1599 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1609 type(
coef_t),
intent(inout) :: coef
1610 type(
space_t),
intent(inout) :: Xh
1611 type(
chkp_t),
intent(in) :: chkp
1612 type(
gs_t),
intent(inout) :: gs_Xh
1616 if (.not. this%active)
return
1618 if (
allocated(chkp%previous_mesh%elements))
then
1620 "The current mesh has a different number " // &
1621 "of elements than the checkpoint.")
1625 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1627 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1628 do concurrent(j = 1:n)
1630 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1631 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1632 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1636 do i = 1, this%wm_x_lag%size()
1637 do concurrent(j = 1:n)
1638 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1639 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1640 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1641 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1642 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1643 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1668 if (c_associated(coef%dof%x_d))
then
1677 if (c_associated(coef%Blag_d))
then
1678 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1682 if (c_associated(coef%Blaglag_d))
then
1690 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1691 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1692 call gs_xh%op(this%wm_x, gs_op_add)
1693 call gs_xh%op(this%wm_y, gs_op_add)
1694 call gs_xh%op(this%wm_z, gs_op_add)
1695 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1697 do i = 1, this%wm_x_lag%size()
1698 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1699 this%wm_z_lag%lf(i)%x, 1, coef)
1700 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1701 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1702 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
1703 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1704 this%wm_z_lag%lf(i)%x, 0, coef)
1709 call this%set_pivot_restart(chkp%t)
1710 call coef%recompute_metrics()
1717 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1719 coef%Blaglag = coef%B
1721 if (c_associated(coef%Blag_d))
then
1725 if (c_associated(coef%Blaglag_d))
then
1733 call adv%recompute_metrics(coef, .true.)
1738 integer,
intent(in) :: body_idx
1739 integer :: idx, offset_base, h1, h2
1741 if (.not. this%active)
return
1742 if (.not. this%has_moving_boundary)
return
1744 idx = (body_idx - 1) * 3
1745 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1746 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1747 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1749 h1 = this%ghost_handles(1, body_idx)
1750 h2 = this%ghost_handles(2, body_idx)
1752 offset_base = (body_idx-1)*6
1755 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1756 this%get_tracker_pos(h1)
1757 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1758 this%get_tracker_pos(h2)
1761 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1762 this%trackers(h1)%vel_lag
1765 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1766 this%trackers(h2)%vel_lag
1771 integer,
allocatable,
intent(inout) :: arr(:)
1772 integer,
intent(inout) :: n
1773 integer,
intent(in) :: val
1774 integer,
allocatable :: tmp(:)
1778 if (arr(k) .eq. val)
return
1781 allocate(tmp(n + 1))
1782 if (n .gt. 0) tmp(1:n) = arr(1:n)
1785 if (
allocated(arr))
deallocate(arr)
1786 call move_alloc(tmp, arr)
1794 type(coef_t),
intent(inout) :: coef
1795 type(json_file),
intent(inout) :: json
1796 type(fld_file_output_t) :: fout
1797 type(field_t) :: dummy_field
1798 type(time_state_t) :: t_state
1799 type(file_t) :: out_file
1800 real(kind=rp) :: t_start
1801 real(kind=rp) :: t_end
1803 real(kind=rp) :: min_jac
1804 integer :: output_freq
1805 integer :: step, n_steps
1806 integer :: nadv, nadv_sim
1808 logical :: mesh_preview_active
1809 character(len=128) :: log_buf
1811 mesh_preview_active = .false.
1813 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1814 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1815 mesh_preview_active)
1818 if (.not. mesh_preview_active)
return
1820 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1822 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1824 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1826 call json_get(json, &
1827 'case.fluid.ale.mesh_preview.output_freq', &
1830 call neko_log%section(
"ALE Mesh Preview")
1831 call neko_log%message(
"Executing mesh motion preview...")
1833 n_steps = int((t_end - t_start) / dt)
1834 call json_get(json,
'case.numerics.time_order', nadv_sim)
1836 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1837 call neko_log%message(log_buf)
1838 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1839 call neko_log%message(log_buf)
1840 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1841 call neko_log%message(log_buf)
1842 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1843 call neko_log%message(log_buf)
1844 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1845 call neko_log%message(log_buf)
1846 call neko_log%message(
'')
1849 call dummy_field%init(coef%dof,
"mesh_preview")
1850 call field_rzero(dummy_field)
1852 call fout%init(rp,
"mesh_preview", 1)
1853 call fout%fields%assign_to_field(1, dummy_field)
1854 select type (ft => fout%file_%file_type)
1855 type is (fld_file_t)
1856 ft%write_mesh = .true.
1857 ft%skip_pressure = .false.
1870 if (neko_bcknd_device .eq. 1)
then
1871 min_jac = device_glmin(coef%jac_d, n)
1873 min_jac = glmin(coef%jac, n)
1877 call fout%sample(t_state%t)
1879 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1880 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1881 t_state%t,
" | Min Jac: ", min_jac
1883 call neko_log%message(trim(log_buf))
1884 call this%update_mesh_velocity(coef, t_state)
1886 do step = 1, n_steps
1887 t_state%tstep = step
1888 t_state%t = t_start + (step * dt)
1889 nadv = min(step, nadv_sim)
1891 call this%advance_mesh(coef, t_state, nadv)
1892 call coef%recompute_metrics()
1895 if (neko_bcknd_device .eq. 1)
then
1896 min_jac = device_glmin(coef%jac_d, n)
1898 min_jac = glmin(coef%jac, n)
1901 if (min_jac .le. 0.0_rp)
then
1902 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1903 "Negative Jacobian detected (", min_jac,
") at t = ", &
1905 call neko_log%message(log_buf)
1908 call fout%sample(t_state%t)
1910 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1911 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1912 t_state%t,
" | Min Jac:", min_jac
1913 call neko_log%message(trim(log_buf))
1915 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1918 if (mod(step, output_freq) .eq. 0)
then
1921 call fout%sample(t_state%t)
1923 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1924 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1925 t_state%t,
" | Min Jac:", min_jac
1926 call neko_log%message(trim(log_buf))
1930 call this%update_mesh_velocity(coef, t_state)
1934 call dummy_field%free()
1936 call neko_log%end_section()
1937 call neko_log%message(
"Mesh preview complete.")
1938 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1943 type(fld_file_output_t) :: fout
1944 type(coef_t),
intent(inout) :: coef
1945 type(field_t),
intent(inout) :: dummy_field
1949 if (neko_bcknd_device .eq. 1)
then
1950 call device_copy(dummy_field%x_d, coef%B_d, n)
1952 call copy(dummy_field%x, coef%B, n)
1955 if (neko_bcknd_device .eq. 1)
then
1956 associate(
mesh => coef%dof)
1958 device_to_host, sync = .false.)
1960 device_to_host, sync = .false.)
1962 device_to_host, sync = .false.)
1972 real(kind=rp),
intent(in) :: initial_pos(3)
1973 integer,
intent(in) :: body_id
1975 type(point_tracker_t),
allocatable :: tmp(:)
1978 if (.not. this%active)
return
1979 if (.not. this%has_moving_boundary)
return
1981 if (.not.
allocated(this%trackers))
then
1982 allocate(this%trackers(30))
1984 elseif (this%n_trackers .ge.
size(this%trackers))
then
1985 allocate(tmp(
size(this%trackers) + 30))
1986 tmp(1:
size(this%trackers)) = this%trackers
1987 deallocate(this%trackers)
1988 call move_alloc(tmp, this%trackers)
1990 this%n_trackers = this%n_trackers + 1
1991 handle = this%n_trackers
1993 this%trackers(handle)%pos = initial_pos
1994 this%trackers(handle)%body_id = body_id
1995 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
2000 integer,
intent(in) :: handle
2001 real(kind=rp) :: pos(3)
2003 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
2004 pos = this%trackers(handle)%pos
2014 integer,
intent(in) :: body_idx
2015 type(time_state_t),
intent(in) :: time
2017 real(kind=rp) :: p(3), gx(3), gy(3)
2018 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
2020 if (.not. this%active)
return
2021 if (.not. this%has_moving_boundary)
return
2024 h_x = this%ghost_handles(1, body_idx)
2025 h_y = this%ghost_handles(2, body_idx)
2027 p = this%ale_pivot(body_idx)%pos
2028 gx = this%get_tracker_pos(h_x)
2029 gy = this%get_tracker_pos(h_y)
2033 u = u / sqrt(sum(u**2))
2037 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2038 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2039 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2040 w = w / sqrt(sum(w**2))
2043 v(1) = w(2)*u(3) - w(3)*u(2)
2044 v(2) = w(3)*u(1) - w(1)*u(3)
2045 v(3) = w(1)*u(2) - w(2)*u(1)
2047 this%body_rot_matrices(:, 1, body_idx) = u
2048 this%body_rot_matrices(:, 2, body_idx) = v
2049 this%body_rot_matrices(:, 3, body_idx) = w
2059 type(time_state_t),
intent(in) :: time
2060 integer,
optional,
intent(in) :: body_idxs(:)
2062 integer :: i, idx, n_log
2063 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2064 real(kind=rp) :: r(3,3)
2065 character(len=256) :: log_buf
2066 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2068 if (.not. this%active)
return
2069 if (.not. this%has_moving_boundary)
return
2071 if (
present(body_idxs))
then
2072 n_log =
size(body_idxs)
2074 n_log = this%config%nbodies
2077 call neko_log%message(
" ")
2078 call neko_log%message(
"---------Rotation log---------")
2079 call neko_log%message(
"variable, time step, time, body, " // &
2080 "x_val, y_val, z_val")
2085 if (
present(body_idxs))
then
2091 r = this%body_rot_matrices(:,:,idx)
2094 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2095 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2096 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2099 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2100 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2101 trim(this%config%bodies(idx)%name),
" ", &
2102 roll_deg, pitch_deg, yaw_deg
2103 call neko_log%message(trim(log_buf))
2114 type(time_state_t),
intent(in) :: time
2115 integer,
optional,
intent(in) :: body_idxs(:)
2116 integer :: i, idx, n_log
2117 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2118 character(len=256) :: log_buf
2120 if (.not. this%active)
return
2121 if (.not. this%has_moving_boundary)
return
2123 if (
present(body_idxs))
then
2124 n_log =
size(body_idxs)
2126 n_log = this%config%nbodies
2129 call neko_log%message(
" ")
2130 call neko_log%message(
"----------Pivot Log-----------")
2131 call neko_log%message(
"variable, time step, time, body, " // &
2132 "x_val, y_val, z_val")
2137 if (
present(body_idxs))
then
2143 pivot_pos = this%ale_pivot(idx)%pos
2144 pivot_vel = this%ale_pivot(idx)%vel
2147 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2148 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2149 trim(this%config%bodies(idx)%name),
" ", &
2150 this%ale_pivot(idx)%pos
2151 call neko_log%message(trim(log_buf))
2154 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2155 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2156 trim(this%config%bodies(idx)%name),
" ", &
2157 this%ale_pivot(idx)%vel
2158 call neko_log%message(trim(log_buf))
2165 type(body_kinematics_t),
intent(in) :: kin_object
2166 type(time_state_t),
intent(in) :: time_s
2167 integer,
intent(in) :: nadv
2168 integer,
intent(in) :: body_idx
2170 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2172 if (.not. this%active)
return
2173 if (.not. this%has_moving_boundary)
return
2175 if (
allocated(this%trackers))
then
2176 do t = 1, this%n_trackers
2177 if (this%trackers(t)%body_id .eq. &
2178 this%config%bodies(body_idx)%id)
then
2179 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2180 t .eq. this%ghost_handles(2, body_idx))
then
2183 rel_pos = this%trackers(t)%pos - kin_object%center
2186 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2187 kin_object%vel_ang(3) * rel_pos(2)
2188 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2189 kin_object%vel_ang(1) * rel_pos(3)
2190 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2191 kin_object%vel_ang(2) * rel_pos(1)
2194 p_vel = kin_object%vel_trans + v_tan
2196 if (time_s%tstep .gt. 0)
then
2197 call ab_integrate_point_pos(this%trackers(t)%pos, &
2198 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2210 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
2212 type(json_file),
intent(inout) :: json
2213 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2214 character(len=:),
allocatable,
intent(inout) :: precon_type
2215 type(json_file),
intent(inout) :: precon_params
2216 real(kind=rp),
intent(out) :: abstol
2217 integer,
intent(out) :: ksp_max_iter
2218 logical,
intent(out) :: res_monitor
2219 logical,
intent(out) :: import_base_shapes
2220 logical :: tmp_logical
2221 character(len=:),
allocatable :: tmp_str
2223 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2224 if (
allocated(precon_type))
deallocate(precon_type)
2226 call json_get_or_default(json, &
2227 'case.fluid.ale.solver.import_base_shape', &
2228 import_base_shapes, .false.)
2230 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2233 call json_get_or_default(json, &
2234 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2236 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2237 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2241 call json_get_or_default(json, &
2242 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2243 call json_get_or_default(json,
'case.fluid.ale.solver.monitor', &
2244 res_monitor, .false.)
2245 call json_get_or_default(json,
'case.fluid.ale.solver.max_iterations', &
2246 ksp_max_iter, 10000)
2248 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2249 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2250 this%config%if_output_phi = tmp_logical
2252 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2253 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2254 this%config%if_output_stiffness = tmp_logical
2258 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2259 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2260 this%config%stiffness_type = tmp_str
2261 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2262 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2270 type(coef_t),
intent(inout) :: coef
2271 type(chkp_t),
intent(inout) :: checkpoint
2274 if (.not. this%active)
return
2277 call checkpoint%add_ale(coef%dof%x, coef%dof%y, &
2278 coef%dof%z, coef%dof%x_d, coef%dof%y_d, &
2280 coef%Blag, coef%Blaglag, coef%Blag_d, coef%Blaglag_d, &
2281 this%wm_x, this%wm_y, this%wm_z, &
2282 this%wm_x_lag, this%wm_y_lag, &
2284 this%global_pivot_pos, &
2285 this%global_pivot_vel_lag, &
2286 this%global_basis_pos, &
2287 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...