36 use json_module,
only : json_file
43 use precon,
only :
pc_t, precon_allocator, precon_destroy
69 use mpi_f08,
only : mpi_wtime, mpi_barrier
89 use,
intrinsic :: iso_c_binding, only : c_associated
101 logical :: active = .false.
102 logical :: has_moving_boundary = .false.
134 real(kind=
rp),
pointer :: global_pivot_pos(:) => null()
135 real(kind=
rp),
pointer :: global_pivot_vel_lag(:, :) => null()
138 real(kind=
rp),
pointer :: global_basis_pos(:) => null()
140 real(kind=
rp),
pointer :: global_basis_vel_lag(:, :) => null()
142 integer,
allocatable :: ghost_handles(:,:)
144 real(kind=
rp),
allocatable :: body_rot_matrices(:,:,:)
147 integer :: n_trackers = 0
150 user_ale_mesh_vel => null()
152 user_ale_base_shapes => null()
154 user_ale_rigid_kinematics => null()
183 type(
coef_t),
target,
intent(inout) :: coef
184 type(json_file),
intent(inout) :: json
185 type(
user_t),
intent(in) :: user
186 type(
chkp_t),
intent(inout) :: chkp
187 type(json_file) :: body_sub, bc_subdict
188 type(json_file) :: precon_params
190 integer,
allocatable :: zone_indices(:)
191 integer :: time_order
192 integer :: n_moving_zones
193 integer :: z, tmp_int, ksp_max_iter
194 integer,
allocatable :: moving_zone_ids(:)
195 integer :: i, j, k, n_bcs, n, n_bodies
196 real(kind=
rp),
allocatable :: tmp_vec(:)
197 real(kind=
rp) :: tmp_val, abstol
198 character(len=128) :: log_buf
199 character(len=256) :: log_buf_l
200 character(len=:),
allocatable :: bc_type
201 character(len=:),
allocatable :: tmp_str
202 character(len=:),
allocatable :: ksp_solver
203 character(len=:),
allocatable :: precon_type
204 logical :: tmp_logical, oifs
206 logical :: found_zone
207 logical :: has_user_rigid_kin, has_user_mesh_vel
208 logical :: has_builtin_osc, has_builtin_rot, is_rot_active
209 logical :: res_monitor, import_base_shapes
211 if (json%valid_path(
'case.fluid.ale'))
then
212 call json_get(json,
'case.fluid.ale.enabled', this%active)
216 if (.not. this%active)
then
219 else if (this%active)
then
221 call coef%msh%all_deformed()
227 "supported only with HIP or CUDA backend.")
231 call neko_error(
"ALE not currently supported with OIFS.")
236 call neko_log%section(
"ALE Initialization")
240 call neko_log%message(
"Initializing ALE " // &
241 "with device backend (HIP).")
243 call neko_log%message(
"Initializing ALE " // &
244 "with device backend (CUDA).")
246 call neko_log%message(
"Initializing ALE " // &
250 tmp_logical = .false.
253 call this%x_ref%init(coef%dof,
"x_ref")
254 call this%y_ref%init(coef%dof,
"y_ref")
255 call this%z_ref%init(coef%dof,
"z_ref")
257 call copy(this%x_ref%x, coef%dof%x%x, n)
258 call copy(this%y_ref%x, coef%dof%y%x, n)
259 call copy(this%z_ref%x, coef%dof%z%x, n)
269 this%user_ale_mesh_vel =>
user%ale_mesh_velocity
270 this%user_ale_base_shapes =>
user%ale_base_shapes
271 this%user_ale_rigid_kinematics =>
user%ale_rigid_kinematics
274 has_user_rigid_kin = .not.
associated(this%user_ale_rigid_kinematics, &
276 has_user_mesh_vel = .not.
associated(this%user_ale_mesh_vel, &
280 call coef%enable_B_history()
281 call json_get(json,
'case.numerics.time_order', time_order)
285 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
286 allocate(moving_zone_ids(0))
297 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
300 call this%bc_moving%init_from_components(coef)
301 call this%bc_fixed%init_from_components(coef)
303 if (json%valid_path(
'case.fluid.boundary_conditions'))
then
304 call json%info(
'case.fluid.boundary_conditions', n_children = n_bcs)
310 if (
allocated(bc_type))
deallocate(bc_type)
311 call json_get(bc_subdict,
'type', bc_type)
313 if (
allocated(zone_indices))
deallocate(zone_indices)
314 call json_get(bc_subdict,
'zone_indices', zone_indices)
317 if (trim(bc_type) .eq.
'no_slip')
then
322 do j = 1,
size(zone_indices)
326 call this%bc_moving%mark_zone(coef%msh%labeled_zones(&
329 this%has_moving_boundary = .true.
331 do j = 1,
size(zone_indices)
332 call this%bc_fixed%mark_zone(coef%msh%labeled_zones(&
339 call this%bc_moving%finalize()
340 call this%bc_fixed%finalize()
341 call this%bc_list%init()
342 call this%bc_list%append(this%bc_moving)
343 call this%bc_list%append(this%bc_fixed)
346 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
347 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
348 this%config%stiffness_type = tmp_str
349 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
350 call neko_error(
"ALE: stiffness_type must be 'built-in'")
354 if (
associated(this%user_ale_base_shapes, &
356 call neko_log%message(
'Solver Type : (' // &
357 trim(ksp_solver) //
', ' // trim(precon_type) //
')')
358 write(log_buf,
'(A,ES13.6)')
'Abs tol :', abstol
360 call neko_log%message(
'Mesh Stiffness : ' // &
361 trim(this%config%stiffness_type))
366 if (json%valid_path(
'case.fluid.ale.bodies'))
then
367 call json%info(
'case.fluid.ale.bodies', n_children = n_bodies)
368 this%config%nbodies = n_bodies
369 allocate(this%config%bodies(n_bodies))
370 allocate(this%ale_pivot(n_bodies))
371 allocate(this%body_kin(n_bodies))
372 allocate(this%base_shapes(n_bodies))
373 allocate(this%global_pivot_pos(3 * this%config%nbodies))
374 allocate(this%global_pivot_vel_lag(3 * this%config%nbodies, 3))
375 allocate(this%global_basis_pos(6 * this%config%nbodies))
376 allocate(this%ghost_handles(2, this%config%nbodies))
377 allocate(this%global_basis_vel_lag(6 * this%config%nbodies, 3))
378 allocate(this%body_rot_matrices(3, 3, this%config%nbodies))
380 this%global_pivot_pos = 0.0_rp
381 this%global_pivot_vel_lag = 0.0_rp
382 this%global_basis_pos = 0.0_rp
383 this%global_basis_vel_lag = 0.0_rp
384 this%body_rot_matrices = 0.0_rp
387 this%body_rot_matrices(1, 1, i) = 1.0_rp
388 this%body_rot_matrices(2, 2, i) = 1.0_rp
389 this%body_rot_matrices(3, 3, i) = 1.0_rp
394 this%config%bodies(i)%id = i
396 if (body_sub%valid_path(
'name'))
then
397 call json_get(body_sub,
'name', tmp_str)
398 this%config%bodies(i)%name = tmp_str
400 write(this%config%bodies(i)%name,
'(A,I0)')
'body_', i
403 if (body_sub%valid_path(
'zone_indices'))
then
404 call json_get(body_sub,
'zone_indices', zone_indices)
405 this%config%bodies(i)%zone_indices = zone_indices
408 trim(this%config%bodies(i)%name) // &
409 " must have 'zone_indices'")
413 this%config%bodies(i)%osc_amp = 0.0_rp
414 this%config%bodies(i)%osc_freq = 0.0_rp
415 if (body_sub%valid_path(
'oscillation'))
then
416 call json_get(body_sub,
'oscillation.amplitude', tmp_vec, &
418 this%config%bodies(i)%osc_amp = tmp_vec
419 call json_get(body_sub,
'oscillation.frequency', tmp_vec, &
421 this%config%bodies(i)%osc_freq = tmp_vec
425 if (body_sub%valid_path(
'rotation'))
then
427 if (.not. body_sub%valid_path(
'pivot'))
then
428 call neko_error(
"ale.bodies.pivot is missing " // &
429 "from the case file.")
432 call json_get(body_sub,
'rotation.type', tmp_str)
433 this%config%bodies(i)%rotation_type = tmp_str
435 select case (trim(tmp_str))
437 call json_get(body_sub,
'rotation.amplitude_deg', tmp_vec, &
439 this%config%bodies(i)%rot_amp_degree = tmp_vec
441 call json_get(body_sub,
'rotation.frequency', tmp_vec, &
443 this%config%bodies(i)%rot_freq = tmp_vec
447 call json_get(body_sub,
'rotation.ramp_t0', tmp_vec, &
449 this%config%bodies(i)%ramp_t0 = tmp_vec
451 call json_get(body_sub,
'rotation.ramp_omega0', tmp_vec, &
453 this%config%bodies(i)%ramp_omega0 = tmp_vec
459 if (tmp_int .ge. 1 .and. tmp_int .le. 3)
then
460 this%config%bodies(i)%rotation_axis = tmp_int
462 call neko_error(
"ALE: rotation.axis must be (integer) " // &
463 "1 -> x, 2 -> y, or 3 -> z")
465 call json_get(body_sub,
'rotation.step_control_times', &
466 tmp_vec, expected_size = 4)
467 this%config%bodies(i)%step_control_times = tmp_vec
469 call json_get(body_sub,
'rotation.target_angle_deg', tmp_val)
470 this%config%bodies(i)%target_rot_angle_deg = tmp_val
473 call neko_error(
"ALE: rotation.type must be 'harmonic', " // &
474 "'ramp', or 'smooth_step'")
479 if (body_sub%valid_path(
'pivot'))
then
482 this%config%bodies(i)%rotation_center_type = tmp_str
483 call json_get(body_sub,
'pivot.value', tmp_vec, expected_size = 3)
484 this%config%bodies(i)%rot_center = tmp_vec
487 tmp_str = this%config%bodies(i)%rotation_center_type
488 if (trim(tmp_str) /=
'relative' .and. &
489 trim(tmp_str) /=
'relative_sin')
then
490 call neko_error(
"ALE: pivot.type must be " // &
491 "'relative', or 'relative_sin'.")
496 if (body_sub%valid_path(
'stiff_geom'))
then
497 call json_get(body_sub,
'stiff_geom.type', tmp_str)
498 this%config%bodies(i)%stiff_geom%type = tmp_str
499 call json_get(body_sub,
'stiff_geom.gain', &
500 this%config%bodies(i)%stiff_geom%gain)
501 call json_get(body_sub,
'stiff_geom.decay_profile', tmp_str)
502 this%config%bodies(i)%stiff_geom%decay_profile = tmp_str
504 select case (trim(this%config%bodies(i)%stiff_geom%decay_profile))
507 'stiff_geom.cutoff_coef', &
508 this%config%bodies(i)%stiff_geom%cutoff_coef, 9.0_rp)
511 'stiff_geom.cutoff_coef', &
512 this%config%bodies(i)%stiff_geom%cutoff_coef, 3.5_rp)
514 call neko_error(
"ALE: Invalid stiff_geom.decay_profile: " // &
515 trim(this%config%bodies(i)%stiff_geom%decay_profile))
518 select case (trim(this%config%bodies(i)%stiff_geom%type))
519 case (
'cylinder',
'sphere')
520 call json_get(body_sub,
'stiff_geom.center', tmp_vec, &
522 this%config%bodies(i)%stiff_geom%center = tmp_vec
524 call json_get(body_sub,
'stiff_geom.radius', &
525 this%config%bodies(i)%stiff_geom%radius)
527 call json_get(body_sub,
'stiff_geom.stiff_dist', &
528 this%config%bodies(i)%stiff_geom%stiff_dist)
530 call neko_error(
"ALE: stiff_geom.type 'box' not yet" // &
533 call neko_error(
"ALE: Invalid stiff_geom.type: " // &
534 trim(this%config%bodies(i)%stiff_geom%type))
536 elseif (import_base_shapes)
then
540 trim(this%config%bodies(i)%name) // &
541 "' must have 'stiff_geom' definition.")
547 call this%base_shapes(i)%init(coef%dof, &
548 "phi_" // trim(this%config%bodies(i)%name))
554 this%ghost_handles(1, i) = this%request_tracker( &
555 this%config%bodies(i)%rot_center + [1.0_rp, 0.0_rp, 0.0_rp], &
556 this%config%bodies(i)%id)
558 this%ghost_handles(2, i) = this%request_tracker( &
559 this%config%bodies(i)%rot_center + [0.0_rp, 1.0_rp, 0.0_rp], &
560 this%config%bodies(i)%id)
562 call neko_log%message(
'Registered Body : ' // &
563 trim(this%config%bodies(i)%name))
567 if (
associated(this%user_ale_base_shapes, &
569 (.not. import_base_shapes))
then
570 write(log_buf,
'(A,A)')
' Stiff Type : ', &
571 trim(this%config%bodies(i)%stiff_geom%type)
573 write(log_buf,
'(A,ES18.11,A,A,A,ES10.4)')
' Gain : ', &
574 this%config%bodies(i)%stiff_geom%gain,
' | Profile: ', &
575 trim(this%config%bodies(i)%stiff_geom%decay_profile), &
576 ' | Cutoff: ', this%config%bodies(i)%stiff_geom%cutoff_coef
578 select case (trim(this%config%bodies(i)%stiff_geom%type))
579 case (
'cylinder',
'sphere')
580 write(log_buf,
'(A,3(ES23.15,1X))')
' Center :', &
581 this%config%bodies(i)%stiff_geom%center
583 write(log_buf,
'(A,ES23.15)')
' Radius :', &
584 this%config%bodies(i)%stiff_geom%radius
587 write(log_buf,
'(A,ES23.15)')
' Stiff Dist:', &
588 this%config%bodies(i)%stiff_geom%stiff_dist
595 has_builtin_osc = any(abs(this%config%bodies(i)%osc_amp) .gt. 0.0_rp)
597 if (has_builtin_osc)
then
598 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
599 call neko_log%message(
' Oscillation : ' // &
600 'X(t) = Amp*sin(2*pi*Freq*t) + User')
601 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
602 this%config%bodies(i)%osc_amp
604 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
605 this%config%bodies(i)%osc_freq
608 call neko_log%message(
' Oscillation : ' // &
609 'X(t) = Amp*sin(2*pi*Freq*t)')
610 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
611 this%config%bodies(i)%osc_amp
613 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
614 this%config%bodies(i)%osc_freq
618 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
619 call neko_log%message(
' Oscillation : User-defined')
621 call neko_log%message(
' Oscillation : None')
627 has_builtin_rot = (trim(this%config%bodies(i)%rotation_type) &
630 if (trim(this%config%bodies(i)%rotation_type) .eq.
'user')
then
632 call neko_log%message(
' Rotation Type: User-defined')
634 elseif (has_builtin_rot)
then
637 is_rot_active = .false.
638 select case (trim(this%config%bodies(i)%rotation_type))
640 is_rot_active = any(abs(this%config%bodies(i)%rot_amp_degree) &
643 is_rot_active = any(abs(this%config%bodies(i)%ramp_omega0) &
647 (abs(this%config%bodies(i)%target_rot_angle_deg) &
651 if (is_rot_active)
then
653 if (trim(this%config%bodies(i)%rotation_type) &
654 .eq.
'harmonic')
then
655 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
656 call neko_log%message(
' Rotation : ' // &
657 'Theta(t) = Amp*sin(2*pi*Freq*t) + User')
659 call neko_log%message(
' Rotation : ' // &
660 'Theta(t) = Amp*sin(2*pi*Freq*t)')
662 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp (deg) :', &
663 this%config%bodies(i)%rot_amp_degree
665 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
666 this%config%bodies(i)%rot_freq
670 elseif (trim(this%config%bodies(i)%rotation_type) &
672 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
673 call neko_log%message(
' Rotation : ' // &
674 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0)) + User')
676 call neko_log%message(
' Rotation : ' // &
677 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0))')
679 write(log_buf,
'(A,3(ES18.11,1X))')
' Omega0 :', &
680 this%config%bodies(i)%ramp_omega0
682 write(log_buf,
'(A,3(ES18.11,1X))')
' t0 :', &
683 this%config%bodies(i)%ramp_t0
687 elseif (trim(this%config%bodies(i)%rotation_type) &
688 .eq.
'smooth_step')
then
689 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
690 call neko_log%message(
' Rotation : ' // &
691 'Smooth Step Control + User')
693 call neko_log%message(
' Rotation : ' // &
694 'Smooth Step Control')
696 write(log_buf,
'(A,I10)')
' Rotation Axis :', &
697 this%config%bodies(i)%rotation_axis
699 write(log_buf,
'(A,ES18.11)')
' Target Rot ' // &
701 this%config%bodies(i)%target_rot_angle_deg
703 write(log_buf,
'(A,4(ES18.11,1X))') &
704 ' Control Times [t0, t1, t2, t3] :', &
705 this%config%bodies(i)%step_control_times
709 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
710 call neko_log%message(
' Rotation Type: User-defined')
712 call neko_log%message(
' Rotation Type: None')
720 call neko_log%message(
' Pivot Type : ' // &
721 trim(this%config%bodies(i)%rotation_center_type))
723 write(log_buf,
'(A,3(ES18.11,1X))')
' Init Pivot:', &
724 this%config%bodies(i)%rot_center
730 call neko_error(
"ALE: No 'ale bodies' found in case file!")
733 if (this%config%nbodies .gt. 1 .and. (.not. import_base_shapes))
then
734 call this%phi_total%init(coef%dof,
"phi_total")
739 do i = 1, n_moving_zones
740 z = moving_zone_ids(i)
743 do while ((.not. found_zone) .and. (j .le. this%config%nbodies))
744 if (any(this%config%bodies(j)%zone_indices .eq. z))
then
749 if (.not. found_zone)
then
750 write(log_buf_l,
'(A,I0,A)') &
751 "ALE: zone index ", z, &
752 " has BC no_slip with moving: true, " // &
753 "but it is not registered in ALE bodies."
760 do j = 1, this%config%nbodies
761 if (
allocated(this%config%bodies(j)%zone_indices))
then
762 do i = 1,
size(this%config%bodies(j)%zone_indices)
763 z = this%config%bodies(j)%zone_indices(i)
765 if (n_moving_zones .gt. 0)
then
766 if (any(moving_zone_ids(1:n_moving_zones) .eq. z))
then
770 if (.not. found_zone)
then
771 write(log_buf_l,
'(A,I0,A,A)') &
772 "ALE: zone index ", z, &
773 " is registered in ALE bodies, ", &
774 "but the BC is not no_slip with moving: true."
782 do j = 1, this%config%nbodies
783 if (
allocated(this%config%bodies(j)%zone_indices))
then
784 do i = 1,
size(this%config%bodies(j)%zone_indices)
785 z = this%config%bodies(j)%zone_indices(i)
787 do k = j + 1, this%config%nbodies
788 if (
allocated(this%config%bodies(k)%zone_indices))
then
789 if (any(this%config%bodies(k)%zone_indices .eq. z))
then
790 write(log_buf_l,
'(A,I0,A,A,A,A,A)') &
791 "ALE: zone index ", z, &
792 " is assigned to multiple bodies ('", &
793 trim(this%config%bodies(j)%name),
"' and '", &
794 trim(this%config%bodies(k)%name),
"')."
805 call this%solve_base_mesh_displacement(coef, json, import_base_shapes, &
806 abstol, ksp_solver, ksp_max_iter, &
807 precon_type, precon_params, res_monitor)
811 if (.not. json%valid_path(
'case.restart_file'))
then
815 call this%update_mesh_velocity(coef, t_init)
818 call this%wm_x_lag%init(this%wm_x, 2)
819 call this%wm_y_lag%init(this%wm_y, 2)
820 call this%wm_z_lag%init(this%wm_z, 2)
822 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
823 if (
allocated(bc_type))
deallocate(bc_type)
824 if (
allocated(zone_indices))
deallocate(zone_indices)
825 if (
allocated(ksp_solver))
deallocate(ksp_solver)
826 if (
allocated(precon_type))
deallocate(precon_type)
827 if (
allocated(tmp_str))
deallocate(tmp_str)
828 if (
allocated(tmp_vec))
deallocate(tmp_vec)
831 call this%mesh_preview(coef, json)
834 call this%register_checkpoint_fields(coef, chkp)
844 import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, &
845 precon_params, res_monitor)
847 class(
ax_t),
allocatable :: Ax
848 class(
ksp_t),
allocatable :: ksp
849 class(
pc_t),
allocatable :: pc
850 type(
coef_t),
intent(inout) :: coef
851 type(json_file),
intent(inout) :: json
852 logical,
intent(in) :: import_base_shapes
853 real(kind=
rp),
intent(in) :: abstol
854 logical,
intent(in) :: res_monitor
855 character(len=*),
intent(in) :: ksp_solver, precon_type
856 integer,
intent(in) :: ksp_max_iter
857 type(json_file),
intent(inout) :: precon_params
859 type(
field_t),
pointer :: phi_ptr => null()
863 real(kind=
rp) :: sample_start_time, sample_end_time
864 real(kind=
rp) :: sample_time
865 character(len=LOG_SIZE) :: log_buf
866 integer :: n, i, m, k, ierr, body_idx, z_idx
868 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
869 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
874 type(json_file) :: body_sub
875 character(len=256) :: phi_fname
876 character(len=:),
allocatable :: tmp_str
879 if (.not. this%active)
return
880 if (.not. this%has_moving_boundary)
return
881 if (this%config%nbodies .eq. 0)
return
883 if (import_base_shapes)
then
885 call neko_log%message(
"Importing ALE base shapes" // &
886 " (skipping Laplace solve)...")
888 do body_idx = 1, this%config%nbodies
893 call json_get(body_sub,
'base_shape_import_file', tmp_str)
896 phi_ptr => this%base_shapes(body_idx)
901 call neko_log%message(
" Loaded: " // &
904 trim(this%config%bodies(body_idx)%name))
911 call neko_log%message(
"Starting base mesh motion solve ...")
914 call ax_helm_allocator(ax, type_name =
"standard")
915 call krylov_solver_factory(ksp, n, ksp_solver, &
916 ksp_max_iter, abstol, monitor = res_monitor)
918 coef%gs_h, this%bc_list, precon_type, precon_params)
924 call rhs_field%init(coef%dof)
925 call corr_field%init(coef%dof)
929 if (.not.
associated(this%user_ale_base_shapes, &
931 call neko_log%message(
" Using user-defined base shapes " // &
932 "(skipping Laplace solve)")
935 call this%user_ale_base_shapes(this%base_shapes)
938 if (this%config%nbodies .gt. 1)
then
940 do body_idx = 1, this%config%nbodies
941 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
946 if (this%config%if_output_phi)
then
948 do body_idx = 1, this%config%nbodies
949 call phi_file%init(
'phi_' // &
950 trim(this%config%bodies(body_idx)%name) //
'.fld', &
952 select type (ft => phi_file%file_type)
954 ft%skip_pressure = .false.
956 call phi_file%write(this%base_shapes(body_idx))
959 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
963 if (this%config%nbodies .gt. 1)
then
964 call neko_log%message(
" phi_total.fld saved.")
965 select type (ft => phi_file%file_type)
967 ft%skip_pressure = .false.
969 call phi_file%init(
'phi_total.fld', precision =
rp)
970 call phi_file%write(this%phi_total)
981 if (this%config%if_output_stiffness)
then
982 rhs_field%x = coef%h1
983 call phi_file%init(
'stiffness.fld')
984 call phi_file%write(rhs_field)
990 do body_idx = 1, this%config%nbodies
992 sample_start_time = mpi_wtime()
993 call neko_log%message(
" Solving laplace for body: " // &
994 trim(this%config%bodies(body_idx)%name))
996 call bc_active_body%init_from_components(coef)
997 call bc_inactive_body%init_from_components(coef)
1000 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
1001 z_idx = this%config%bodies(body_idx)%zone_indices(j)
1002 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
1005 do i = 1, this%config%nbodies
1006 if (i /= body_idx)
then
1007 do j = 1,
size(this%config%bodies(i)%zone_indices)
1008 z_idx = this%config%bodies(i)%zone_indices(j)
1009 call bc_inactive_body%mark_zone(&
1010 coef%msh%labeled_zones(z_idx))
1015 call bc_active_body%finalize()
1016 call bc_inactive_body%finalize()
1019 call bc_projector%mark(this%bc_fixed)
1020 call bc_projector%mark(bc_active_body)
1021 call bc_projector%mark(bc_inactive_body)
1024 call bc_projector_zeros_only%mark(this%bc_fixed)
1025 call bc_projector_zeros_only%mark(bc_inactive_body)
1028 this%base_shapes(body_idx)%x = 0.0_rp
1029 rhs_field%x = 0.0_rp
1030 corr_field%x = 0.0_rp
1037 m = bc_active_body%msk(0)
1039 k = bc_active_body%msk(i)
1040 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1051 call bc_projector_zeros_only%apply(this%base_shapes(body_idx)%x, n)
1055 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1056 coef, coef%msh, coef%Xh)
1061 call bc_projector%apply(rhs_field%x, n)
1062 call coef%gs_h%op(rhs_field, gs_op_add)
1067 monitor(1) = ksp%solve(ax, corr_field, &
1068 rhs_field%x, n, coef, bc_projector, coef%gs_h)
1071 call field_add2(this%base_shapes(body_idx), corr_field, n)
1075 if (this%config%nbodies .gt. 1)
then
1076 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1080 sample_end_time = mpi_wtime()
1081 sample_time = sample_end_time - sample_start_time
1082 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1083 trim(this%config%bodies(body_idx)%name),
"' took ", &
1088 call bc_active_body%free()
1089 call bc_inactive_body%free()
1090 call bc_projector%free()
1091 call bc_projector_zeros_only%free()
1101 if (this%config%if_output_phi)
then
1102 call phi_file%init(
'phi_' // &
1103 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1105 select type (ft => phi_file%file_type)
1107 ft%skip_pressure = .false.
1109 call phi_file%write(this%base_shapes(body_idx))
1110 call phi_file%free()
1112 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1116 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1119 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1123 call neko_log%message(
" phi_total.fld saved.")
1124 call phi_file%init(
'phi_total.fld', precision =
rp)
1125 select type (ft => phi_file%file_type)
1127 ft%skip_pressure = .false.
1129 call phi_file%write(this%phi_total)
1130 call phi_file%free()
1134 call rhs_field%free()
1135 call corr_field%free()
1136 if (this%config%nbodies > 1)
then
1137 call this%phi_total%free()
1141 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1142 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1148 if (
allocated(h1_restore))
deallocate(h1_restore)
1149 if (
allocated(h2_restore))
deallocate(h2_restore)
1150 if (
allocated(ax))
then
1154 if (
allocated(ksp))
then
1158 if (
allocated(pc))
then
1159 call precon_destroy(pc)
1169 type(
coef_t),
intent(in) :: coef
1173 real(kind=
rp) :: rot_mat(3,3)
1174 real(kind=
rp) :: initial_rot_center(3)
1176 if (.not. this%active)
return
1177 if (.not. this%has_moving_boundary)
return
1184 do i = 1, this%config%nbodies
1188 this%config%bodies(i), time_s)
1191 if (.not.
associated(this%user_ale_rigid_kinematics, &
1193 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1195 current_kin%vel_trans, &
1196 current_kin%vel_ang)
1199 current_kin%center = this%ale_pivot(i)%pos
1200 this%ale_pivot(i)%vel = current_kin%vel_trans
1202 this%body_kin(i)%center = this%ale_pivot(i)%pos
1203 this%body_kin(i)%vel_trans = current_kin%vel_trans
1204 this%body_kin(i)%vel_ang = current_kin%vel_ang
1207 call this%compute_rotation_matrix(i, time_s)
1208 rot_mat = this%body_rot_matrices(:,:,i)
1209 initial_rot_center = this%config%bodies(i)%rot_center
1213 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1214 this%base_shapes(i), coef, current_kin, rot_mat, &
1218 call this%prep_checkpoint(i)
1224 if (.not.
associated(this%user_ale_mesh_vel, &
1226 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1227 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1237 type(
coef_t),
intent(inout) :: coef
1239 integer,
intent(in) :: nadv
1242 if (.not. this%active)
return
1243 if (.not. this%has_moving_boundary)
return
1245 do i = 1, this%config%nbodies
1250 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1253 this%ale_pivot(i)%pos, &
1254 this%ale_pivot(i)%vel, &
1257 this%config%bodies(i))
1261 call coef%update_B_history()
1265 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1269 call this%wm_x_lag%update()
1270 call this%wm_y_lag%update()
1271 call this%wm_z_lag%update()
1277 type(
coef_t),
intent(inout) :: coef
1279 integer :: i, n, b, ierr
1280 integer,
allocatable :: cheap_map(:)
1281 integer :: n_cheap, map_idx
1282 real(kind=
rp) :: x, y, z
1283 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1284 real(kind=
rp) :: cx, cy, cz
1285 real(kind=
rp) :: arg, decay, gain, norm_dist
1286 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1287 type(
field_t),
allocatable :: dist_fields(:)
1288 character(len=128) :: log_buf
1293 allocate(cheap_map(params%nbodies))
1297 do b = 1, params%nbodies
1298 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1299 n_cheap = n_cheap + 1
1300 cheap_map(b) = n_cheap
1305 if (n_cheap > 0)
then
1306 allocate(dist_fields(n_cheap))
1308 do b = 1, params%nbodies
1309 map_idx = cheap_map(b)
1310 if (map_idx .gt. 0)
then
1312 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1315 call neko_log%message(
" Start: cheap dist calculation " // &
1316 "for body '" // trim(params%bodies(b)%name) //
"'")
1319 sample_start_time = mpi_wtime()
1323 coef%msh, params%bodies(b)%zone_indices, &
1324 copy_to_host = .true.)
1327 coef%msh, params%bodies(b)%zone_indices)
1331 sample_end_time = mpi_wtime()
1332 sample_time = sample_end_time - sample_start_time
1334 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1335 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1343 select case (trim(params%stiffness_type))
1346 do concurrent(i = 1:n)
1347 x = coef%dof%x%x(i, 1, 1, 1)
1348 y = coef%dof%y%x(i, 1, 1, 1)
1349 z = coef%dof%z%x(i, 1, 1, 1)
1351 max_added_stiff = 0.0_rp
1354 do b = 1, params%nbodies
1355 gain = params%bodies(b)%stiff_geom%gain
1356 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1357 decay = params%bodies(b)%stiff_geom%stiff_dist
1359 decay = params%bodies(b)%stiff_geom%radius
1363 cx = params%bodies(b)%stiff_geom%center(1)
1364 cy = params%bodies(b)%stiff_geom%center(2)
1365 cz = params%bodies(b)%stiff_geom%center(3)
1367 raw_dist = huge(0.0_rp)
1370 select case (trim(params%bodies(b)%stiff_geom%type))
1372 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1376 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1382 map_idx = cheap_map(b)
1383 if (map_idx .gt. 0)
then
1384 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1389 body_stiff_val = 0.0_rp
1390 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1393 arg = -(raw_dist**2) / (decay**2)
1394 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1395 body_stiff_val = gain * exp(arg)
1399 norm_dist = (raw_dist / decay)
1400 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1401 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1404 if (body_stiff_val .gt. max_added_stiff)
then
1405 max_added_stiff = body_stiff_val
1409 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1410 coef%h2(i, 1, 1, 1) = 0.0_rp
1414 call neko_error(
"ALE Manager: Unknown stiffness type")
1424 if (
allocated(dist_fields))
then
1425 do i = 1,
size(dist_fields)
1426 call dist_fields(i)%free()
1428 deallocate(dist_fields)
1430 if (
allocated(cheap_map))
deallocate(cheap_map)
1436 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1437 type(
field_t),
intent(inout) :: wx, wy, wz
1438 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1439 type(
field_t),
intent(in) :: phi
1440 type(
coef_t),
intent(in) :: coef
1442 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1443 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1446 x_ref, y_ref, z_ref, &
1447 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1450 x_ref, y_ref, z_ref, &
1451 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1457 wm_z_lag, time, nadv, scheme_)
1458 type(
coef_t),
intent(inout) :: c_xh
1459 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1462 integer,
intent(in) :: nadv
1463 character(len=*),
intent(in) :: scheme_
1466 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1469 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1478 if (.not. this%active)
return
1480 call this%bc_moving%free()
1481 call this%bc_fixed%free()
1482 call this%bc_list%free()
1484 if (
allocated(this%base_shapes))
then
1485 do i = 1,
size(this%base_shapes)
1486 call this%base_shapes(i)%free()
1488 deallocate(this%base_shapes)
1491 call this%wm_x_lag%free()
1492 call this%wm_y_lag%free()
1493 call this%wm_z_lag%free()
1494 call this%x_ref%free()
1495 call this%y_ref%free()
1496 call this%z_ref%free()
1498 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1499 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1500 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1501 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1502 if (
associated(this%global_pivot_vel_lag)) &
1503 deallocate(this%global_pivot_vel_lag)
1504 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1505 if (
associated(this%global_basis_vel_lag)) &
1506 deallocate(this%global_basis_vel_lag)
1507 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1508 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1509 if (
allocated(this%trackers))
deallocate(this%trackers)
1516 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1517 class(
ksp_t),
target,
intent(inout) :: ksp
1518 type(
coef_t),
target,
intent(in) :: coef
1519 type(
dofmap_t),
target,
intent(in) :: dof
1520 type(
gs_t),
target,
intent(inout) :: gs
1521 type(
bc_list_t),
target,
intent(inout) :: bclst
1522 character(len=*),
intent(in) :: pctype
1523 type(json_file),
intent(inout) :: params
1524 call precon_allocator(pc, pctype)
1525 select type (pcp => pc)
1527 call pcp%init(coef, dof, gs)
1529 call pcp%init(coef, dof, gs)
1531 call pcp%init(coef, dof, gs)
1533 call pcp%init(coef, bclst, params)
1535 call pcp%init(coef, bclst, params)
1543 real(kind=
dp),
intent(in) :: time_restart
1545 integer :: i, idx, handle_1, handle_2, offset_base
1547 time_state_dummy%t = time_restart
1551 do i = 1, this%config%nbodies
1554 this%config%bodies(i), time_state_dummy)
1557 if (.not.
associated(this%user_ale_rigid_kinematics, &
1559 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1561 kin_restart%vel_trans, &
1562 kin_restart%vel_ang)
1565 this%ale_pivot(i)%vel = kin_restart%vel_trans
1569 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1570 this%body_kin(i)%center = this%ale_pivot(i)%pos
1571 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1572 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1575 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1576 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1579 offset_base = (i-1)*6
1580 handle_1 = this%ghost_handles(1, i)
1581 handle_2 = this%ghost_handles(2, i)
1583 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1584 this%trackers(handle_1)%pos = &
1585 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1588 this%trackers(handle_1)%vel_lag = &
1589 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1592 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1593 this%trackers(handle_2)%pos = &
1594 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1597 this%trackers(handle_2)%vel_lag = &
1598 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1608 type(
coef_t),
intent(inout) :: coef
1609 type(
space_t),
intent(inout) :: Xh
1610 type(
chkp_t),
intent(in) :: chkp
1611 type(
gs_t),
intent(inout) :: gs_Xh
1615 if (.not. this%active)
return
1617 if (
allocated(chkp%previous_mesh%elements))
then
1619 "The current mesh has a different number " // &
1620 "of elements than the checkpoint.")
1624 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1626 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1627 do concurrent(j = 1:n)
1629 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1630 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1631 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1635 do i = 1, this%wm_x_lag%size()
1636 do concurrent(j = 1:n)
1637 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1638 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1639 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1640 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1641 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1642 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1652 call this%wm_x_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1653 call this%wm_x_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1655 call this%wm_y_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1656 call this%wm_y_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1658 call this%wm_z_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1659 call this%wm_z_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1661 if (c_associated(coef%dof%x%x_d))
then
1667 if (c_associated(coef%Blag_d))
then
1668 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1672 if (c_associated(coef%Blaglag_d))
then
1680 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1681 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1682 call gs_xh%op(this%wm_x, gs_op_add)
1683 call gs_xh%op(this%wm_y, gs_op_add)
1684 call gs_xh%op(this%wm_z, gs_op_add)
1685 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1687 do i = 1, this%wm_x_lag%size()
1688 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1689 this%wm_z_lag%lf(i)%x, 1, coef)
1690 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1691 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1692 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
1693 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1694 this%wm_z_lag%lf(i)%x, 0, coef)
1699 call this%set_pivot_restart(chkp%t)
1700 call coef%recompute_metrics()
1707 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1709 coef%Blaglag = coef%B
1711 if (c_associated(coef%Blag_d))
then
1715 if (c_associated(coef%Blaglag_d))
then
1723 call adv%recompute_metrics(coef, .true.)
1728 integer,
intent(in) :: body_idx
1729 integer :: idx, offset_base, h1, h2
1731 if (.not. this%active)
return
1732 if (.not. this%has_moving_boundary)
return
1734 idx = (body_idx - 1) * 3
1735 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1736 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1737 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1739 h1 = this%ghost_handles(1, body_idx)
1740 h2 = this%ghost_handles(2, body_idx)
1742 offset_base = (body_idx-1)*6
1745 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1746 this%get_tracker_pos(h1)
1747 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1748 this%get_tracker_pos(h2)
1751 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1752 this%trackers(h1)%vel_lag
1755 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1756 this%trackers(h2)%vel_lag
1761 integer,
allocatable,
intent(inout) :: arr(:)
1762 integer,
intent(inout) :: n
1763 integer,
intent(in) :: val
1764 integer,
allocatable :: tmp(:)
1768 if (arr(k) .eq. val)
return
1771 allocate(tmp(n + 1))
1772 if (n .gt. 0) tmp(1:n) = arr(1:n)
1775 if (
allocated(arr))
deallocate(arr)
1776 call move_alloc(tmp, arr)
1784 type(coef_t),
intent(inout) :: coef
1785 type(json_file),
intent(inout) :: json
1786 type(fld_file_output_t) :: fout
1787 type(field_t) :: dummy_field
1788 type(time_state_t) :: t_state
1789 type(file_t) :: out_file
1790 real(kind=rp) :: t_start
1791 real(kind=rp) :: t_end
1793 real(kind=rp) :: min_jac
1794 integer :: output_freq
1795 integer :: step, n_steps
1796 integer :: nadv, nadv_sim
1798 logical :: mesh_preview_active
1799 character(len=128) :: log_buf
1801 mesh_preview_active = .false.
1803 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1804 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1805 mesh_preview_active)
1808 if (.not. mesh_preview_active)
return
1810 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1812 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1814 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1816 call json_get(json, &
1817 'case.fluid.ale.mesh_preview.output_freq', &
1820 call neko_log%section(
"ALE Mesh Preview")
1821 call neko_log%message(
"Executing mesh motion preview...")
1823 n_steps = int((t_end - t_start) / dt)
1824 call json_get(json,
'case.numerics.time_order', nadv_sim)
1826 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1827 call neko_log%message(log_buf)
1828 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1829 call neko_log%message(log_buf)
1830 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1831 call neko_log%message(log_buf)
1832 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1833 call neko_log%message(log_buf)
1834 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1835 call neko_log%message(log_buf)
1836 call neko_log%message(
'')
1839 call dummy_field%init(coef%dof,
"mesh_preview")
1840 call field_rzero(dummy_field)
1842 call fout%init(rp,
"mesh_preview", 1)
1843 call fout%fields%assign_to_field(1, dummy_field)
1844 select type (ft => fout%file_%file_type)
1845 type is (fld_file_t)
1846 ft%write_mesh = .true.
1847 ft%skip_pressure = .false.
1860 if (neko_bcknd_device .eq. 1)
then
1861 min_jac = device_glmin(coef%jac_d, n)
1863 min_jac = glmin(coef%jac, n)
1867 call fout%sample(t_state%t)
1869 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1870 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1871 t_state%t,
" | Min Jac: ", min_jac
1873 call neko_log%message(trim(log_buf))
1874 call this%update_mesh_velocity(coef, t_state)
1876 do step = 1, n_steps
1877 t_state%tstep = step
1878 t_state%t = t_start + (step * dt)
1879 nadv = min(step, nadv_sim)
1881 call this%advance_mesh(coef, t_state, nadv)
1882 call coef%recompute_metrics()
1885 if (neko_bcknd_device .eq. 1)
then
1886 min_jac = device_glmin(coef%jac_d, n)
1888 min_jac = glmin(coef%jac, n)
1891 if (min_jac .le. 0.0_rp)
then
1892 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1893 "Negative Jacobian detected (", min_jac,
") at t = ", &
1895 call neko_log%message(log_buf)
1898 call fout%sample(t_state%t)
1900 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1901 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1902 t_state%t,
" | Min Jac:", min_jac
1903 call neko_log%message(trim(log_buf))
1905 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1908 if (mod(step, output_freq) .eq. 0)
then
1911 call fout%sample(t_state%t)
1913 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1914 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1915 t_state%t,
" | Min Jac:", min_jac
1916 call neko_log%message(trim(log_buf))
1920 call this%update_mesh_velocity(coef, t_state)
1924 call dummy_field%free()
1926 call neko_log%end_section()
1927 call neko_log%message(
"Mesh preview complete.")
1928 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1933 type(fld_file_output_t) :: fout
1934 type(coef_t),
intent(inout) :: coef
1935 type(field_t),
intent(inout) :: dummy_field
1939 if (neko_bcknd_device .eq. 1)
then
1940 call device_copy(dummy_field%x_d, coef%B_d, n)
1942 call copy(dummy_field%x, coef%B, n)
1945 if (neko_bcknd_device .eq. 1)
then
1946 associate(
mesh => coef%dof)
1947 call device_memcpy(
mesh%x%x,
mesh%x%x_d,
mesh%size(), &
1948 device_to_host, sync = .false.)
1949 call device_memcpy(
mesh%y%x,
mesh%y%x_d,
mesh%size(), &
1950 device_to_host, sync = .false.)
1951 call device_memcpy(
mesh%z%x,
mesh%z%x_d,
mesh%size(), &
1952 device_to_host, sync = .false.)
1962 real(kind=rp),
intent(in) :: initial_pos(3)
1963 integer,
intent(in) :: body_id
1965 type(point_tracker_t),
allocatable :: tmp(:)
1968 if (.not. this%active)
return
1969 if (.not. this%has_moving_boundary)
return
1971 if (.not.
allocated(this%trackers))
then
1972 allocate(this%trackers(30))
1974 elseif (this%n_trackers .ge.
size(this%trackers))
then
1975 allocate(tmp(
size(this%trackers) + 30))
1976 tmp(1:
size(this%trackers)) = this%trackers
1977 deallocate(this%trackers)
1978 call move_alloc(tmp, this%trackers)
1980 this%n_trackers = this%n_trackers + 1
1981 handle = this%n_trackers
1983 this%trackers(handle)%pos = initial_pos
1984 this%trackers(handle)%body_id = body_id
1985 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
1990 integer,
intent(in) :: handle
1991 real(kind=rp) :: pos(3)
1993 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
1994 pos = this%trackers(handle)%pos
2004 integer,
intent(in) :: body_idx
2005 type(time_state_t),
intent(in) :: time
2007 real(kind=rp) :: p(3), gx(3), gy(3)
2008 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
2010 if (.not. this%active)
return
2011 if (.not. this%has_moving_boundary)
return
2014 h_x = this%ghost_handles(1, body_idx)
2015 h_y = this%ghost_handles(2, body_idx)
2017 p = this%ale_pivot(body_idx)%pos
2018 gx = this%get_tracker_pos(h_x)
2019 gy = this%get_tracker_pos(h_y)
2023 u = u / sqrt(sum(u**2))
2027 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2028 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2029 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2030 w = w / sqrt(sum(w**2))
2033 v(1) = w(2)*u(3) - w(3)*u(2)
2034 v(2) = w(3)*u(1) - w(1)*u(3)
2035 v(3) = w(1)*u(2) - w(2)*u(1)
2037 this%body_rot_matrices(:, 1, body_idx) = u
2038 this%body_rot_matrices(:, 2, body_idx) = v
2039 this%body_rot_matrices(:, 3, body_idx) = w
2049 type(time_state_t),
intent(in) :: time
2050 integer,
optional,
intent(in) :: body_idxs(:)
2052 integer :: i, idx, n_log
2053 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2054 real(kind=rp) :: r(3,3)
2055 character(len=256) :: log_buf
2056 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2058 if (.not. this%active)
return
2059 if (.not. this%has_moving_boundary)
return
2061 if (
present(body_idxs))
then
2062 n_log =
size(body_idxs)
2064 n_log = this%config%nbodies
2067 call neko_log%message(
" ")
2068 call neko_log%message(
"---------Rotation log---------")
2069 call neko_log%message(
"variable, time step, time, body, " // &
2070 "x_val, y_val, z_val")
2075 if (
present(body_idxs))
then
2081 r = this%body_rot_matrices(:, :, idx)
2084 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2085 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2086 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2089 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2090 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2091 trim(this%config%bodies(idx)%name),
" ", &
2092 roll_deg, pitch_deg, yaw_deg
2093 call neko_log%message(trim(log_buf))
2104 type(time_state_t),
intent(in) :: time
2105 integer,
optional,
intent(in) :: body_idxs(:)
2106 integer :: i, idx, n_log
2107 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2108 character(len=256) :: log_buf
2110 if (.not. this%active)
return
2111 if (.not. this%has_moving_boundary)
return
2113 if (
present(body_idxs))
then
2114 n_log =
size(body_idxs)
2116 n_log = this%config%nbodies
2119 call neko_log%message(
" ")
2120 call neko_log%message(
"----------Pivot Log-----------")
2121 call neko_log%message(
"variable, time step, time, body, " // &
2122 "x_val, y_val, z_val")
2127 if (
present(body_idxs))
then
2133 pivot_pos = this%ale_pivot(idx)%pos
2134 pivot_vel = this%ale_pivot(idx)%vel
2137 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2138 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2139 trim(this%config%bodies(idx)%name),
" ", &
2140 this%ale_pivot(idx)%pos
2141 call neko_log%message(trim(log_buf))
2144 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2145 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2146 trim(this%config%bodies(idx)%name),
" ", &
2147 this%ale_pivot(idx)%vel
2148 call neko_log%message(trim(log_buf))
2155 type(body_kinematics_t),
intent(in) :: kin_object
2156 type(time_state_t),
intent(in) :: time_s
2157 integer,
intent(in) :: nadv
2158 integer,
intent(in) :: body_idx
2160 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2162 if (.not. this%active)
return
2163 if (.not. this%has_moving_boundary)
return
2165 if (
allocated(this%trackers))
then
2166 do t = 1, this%n_trackers
2167 if (this%trackers(t)%body_id .eq. &
2168 this%config%bodies(body_idx)%id)
then
2169 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2170 t .eq. this%ghost_handles(2, body_idx))
then
2173 rel_pos = this%trackers(t)%pos - kin_object%center
2176 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2177 kin_object%vel_ang(3) * rel_pos(2)
2178 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2179 kin_object%vel_ang(1) * rel_pos(3)
2180 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2181 kin_object%vel_ang(2) * rel_pos(1)
2184 p_vel = kin_object%vel_trans + v_tan
2186 if (time_s%tstep .gt. 0)
then
2187 call ab_integrate_point_pos(this%trackers(t)%pos, &
2188 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2200 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
2202 type(json_file),
intent(inout) :: json
2203 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2204 character(len=:),
allocatable,
intent(inout) :: precon_type
2205 type(json_file),
intent(inout) :: precon_params
2206 real(kind=rp),
intent(out) :: abstol
2207 integer,
intent(out) :: ksp_max_iter
2208 logical,
intent(out) :: res_monitor
2209 logical,
intent(out) :: import_base_shapes
2210 logical :: tmp_logical
2211 character(len=:),
allocatable :: tmp_str
2213 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2214 if (
allocated(precon_type))
deallocate(precon_type)
2216 call json_get_or_default(json, &
2217 'case.fluid.ale.solver.import_base_shape', &
2218 import_base_shapes, .false.)
2220 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2223 call json_get_or_default(json, &
2224 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2226 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2227 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2231 call json_get_or_default(json, &
2232 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2233 call json_get_or_default(json,
'case.fluid.ale.solver.monitor', &
2234 res_monitor, .false.)
2235 call json_get_or_default(json,
'case.fluid.ale.solver.max_iterations', &
2236 ksp_max_iter, 10000)
2238 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2239 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2240 this%config%if_output_phi = tmp_logical
2242 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2243 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2244 this%config%if_output_stiffness = tmp_logical
2248 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2249 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2250 this%config%stiffness_type = tmp_str
2251 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2252 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2262 type(coef_t),
target,
intent(inout) :: coef
2263 type(chkp_t),
intent(inout) :: checkpoint
2264 type(checkpoint_payload_t),
pointer :: payload
2266 if (.not. this%active)
return
2269 call payload%add_field(this%wm_x)
2270 call payload%add_field(this%wm_y)
2271 call payload%add_field(this%wm_z)
2272 call payload%add_series(this%wm_x_lag)
2273 call payload%add_series(this%wm_y_lag)
2274 call payload%add_series(this%wm_z_lag)
2275 call payload%add_mesh_array(
"mesh_x", coef%dof%x%x, coef%msh, coef%Xh, &
2277 call payload%add_mesh_array(
"mesh_y", coef%dof%y%x, coef%msh, coef%Xh, &
2279 call payload%add_mesh_array(
"mesh_z", coef%dof%z%x, coef%msh, coef%Xh, &
2281 call payload%add_mesh_array(
"B_lag", coef%Blag, coef%msh, coef%Xh, &
2283 call payload%add_mesh_array(
"B_laglag", coef%Blaglag, coef%msh, &
2284 coef%Xh, coef%Blaglag_d)
2285 call payload%add_array(
"pivot_position", this%global_pivot_pos, &
2286 replicated = .true.)
2287 call payload%add_array(
"pivot_velocity_lag", &
2288 this%global_pivot_vel_lag, replicated = .true.)
2289 call payload%add_array(
"basis_position", this%global_basis_pos, &
2290 replicated = .true.)
2291 call payload%add_array(
"basis_velocity_lag", &
2292 this%global_basis_vel_lag, replicated = .true.)
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.
Format-independent checkpoint payloads.
Defines format-independent checkpoint registration and restart state.
type(mpi_comm), public neko_comm
MPI communicator.
Jacobi preconditioner accelerator backend.
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
real(kind=rp) function, public device_glmin(a_d, n, strm)
Min of a vector of length n.
Device abstraction, common interface for various accelerators.
integer, parameter, public host_to_device
integer, parameter, public device_to_host
Defines a mapping of the degrees of freedom.
subroutine, public field_rzero(a, n)
Zero a real vector.
subroutine, public field_add2(a, b, n)
Vector addition .
subroutine, public field_cmult(a, c, n)
Multiplication by constant c .
Contains the field_serties_t type.
Module for file I/O operations.
Implements fld_file_output_t.
Importation of fields from fld files.
Utilities for retrieving parameters from the case files.
Implements the base abstract type for Krylov solvers plus helper types.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
real(kind=rp), parameter, public pi
subroutine, public copy(a, b, n)
Copy a vector .
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
integer, parameter neko_bcknd_hip
integer, parameter neko_bcknd_device
integer, parameter neko_bcknd_cuda
integer, parameter, public dp
integer, parameter, public rp
Global precision used in computations.
Hybrid ph-multigrid preconditioner.
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Defines a registry for storing solution fields.
type(registry_t), target, public neko_registry
Global field registry.
Implements scalar_projector_t.
Defines a function space.
Jacobi preconditioner SX-Aurora backend.
Module with things related to the simulation time.
Interfaces for user interaction with NEKO.
subroutine, public dummy_user_ale_mesh_velocity(wm_x, wm_y, wm_z, coef, x_ref, y_ref, z_ref, base_shapes, time)
subroutine, public dummy_user_ale_base_shapes(base_shapes)
subroutine, public dummy_user_ale_rigid_kinematics(body_id, time, vel_trans, vel_ang)
Defines a zero-valued Dirichlet boundary condition.
Base abstract type for computing the advection operator.
Global ALE Configuration.
Calculated Kinematics for a body at current time.
State history for time-integration of pivots.
Type for a tracked point linked to a body.
Base type for a matrix-vector product providing .
A list of allocatable `bc_t`. Follows the standard interface of lists.
Collection of live simulation data registered for checkpointing.
A named collection of live fields to checkpoint together.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Defines a jacobi preconditioner.
Stores a series (sequence) of fields, logically connected to a base field, and arranged according to ...
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Interface for NEKTON fld files.
A simple output saving a list of fields to a .fld file.
Defines a jacobi preconditioner.
Type for storing initial and final residuals in a Krylov solver.
Base abstract type for a canonical Krylov method, solving .
Defines a canonical Krylov preconditioner.
Projector for scalar boundary conditions.
The function space for the SEM solution fields.
Defines a jacobi preconditioner for SX-Aurora.
A struct that contains all info about the time, expand as needed.
A type collecting all the overridable user routines and flag to suppress type injection from custom m...
Zero-valued Dirichlet boundary condition. Used for no-slip walls, but also for various auxillary cond...