36 use json_module,
only : json_file
64 use mpi_f08,
only : mpi_wtime, mpi_barrier
84 use,
intrinsic :: iso_c_binding, only : c_associated
96 logical :: active = .false.
97 logical :: has_moving_boundary = .false.
129 real(kind=
rp),
pointer :: global_pivot_pos(:) => null()
130 real(kind=
rp),
pointer :: global_pivot_vel_lag(:, :) => null()
133 real(kind=
rp),
pointer :: global_basis_pos(:) => null()
135 real(kind=
rp),
pointer :: global_basis_vel_lag(:, :) => null()
137 integer,
allocatable :: ghost_handles(:,:)
139 real(kind=
rp),
allocatable :: body_rot_matrices(:,:,:)
142 integer :: n_trackers = 0
145 user_ale_mesh_vel => null()
147 user_ale_base_shapes => null()
149 user_ale_rigid_kinematics => null()
178 type(
coef_t),
target,
intent(inout) :: coef
179 type(json_file),
intent(inout) :: json
180 type(
user_t),
intent(in) :: user
181 type(
chkp_t),
intent(inout) :: chkp
182 type(json_file) :: body_sub, bc_subdict
183 type(json_file) :: precon_params
185 integer,
allocatable :: zone_indices(:)
186 integer :: time_order
187 integer :: n_moving_zones
188 integer :: z, tmp_int, ksp_max_iter
189 integer,
allocatable :: moving_zone_ids(:)
190 integer :: i, j, k, n_bcs, n, n_bodies
191 real(kind=
rp),
allocatable :: tmp_vec(:)
192 real(kind=
rp) :: tmp_val, abstol
193 character(len=128) :: log_buf
194 character(len=256) :: log_buf_l
195 character(len=:),
allocatable :: bc_type
196 character(len=:),
allocatable :: tmp_str
197 character(len=:),
allocatable :: ksp_solver
198 character(len=:),
allocatable :: precon_type
199 logical :: tmp_logical, oifs
201 logical :: found_zone
202 logical :: has_user_rigid_kin, has_user_mesh_vel
203 logical :: has_builtin_osc, has_builtin_rot, is_rot_active
204 logical :: res_monitor, import_base_shapes
206 if (json%valid_path(
'case.fluid.ale'))
then
207 call json_get(json,
'case.fluid.ale.enabled', this%active)
211 if (.not. this%active)
then
214 else if (this%active)
then
216 call coef%msh%all_deformed()
222 "supported only with HIP or CUDA backend.")
226 call neko_error(
"ALE not currently supported with OIFS.")
231 call neko_log%section(
"ALE Initialization")
235 call neko_log%message(
"Initializing ALE " // &
236 "with device backend (HIP).")
238 call neko_log%message(
"Initializing ALE " // &
239 "with device backend (CUDA).")
241 call neko_log%message(
"Initializing ALE " // &
245 tmp_logical = .false.
248 call this%x_ref%init(coef%dof,
"x_ref")
249 call this%y_ref%init(coef%dof,
"y_ref")
250 call this%z_ref%init(coef%dof,
"z_ref")
252 call copy(this%x_ref%x, coef%dof%x%x, n)
253 call copy(this%y_ref%x, coef%dof%y%x, n)
254 call copy(this%z_ref%x, coef%dof%z%x, n)
264 this%user_ale_mesh_vel =>
user%ale_mesh_velocity
265 this%user_ale_base_shapes =>
user%ale_base_shapes
266 this%user_ale_rigid_kinematics =>
user%ale_rigid_kinematics
269 has_user_rigid_kin = .not.
associated(this%user_ale_rigid_kinematics, &
271 has_user_mesh_vel = .not.
associated(this%user_ale_mesh_vel, &
275 call coef%enable_B_history()
276 call json_get(json,
'case.numerics.time_order', time_order)
280 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
281 allocate(moving_zone_ids(0))
292 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
295 call this%bc_moving%init_from_components(coef)
296 call this%bc_fixed%init_from_components(coef)
298 if (json%valid_path(
'case.fluid.boundary_conditions'))
then
299 call json%info(
'case.fluid.boundary_conditions', n_children = n_bcs)
305 if (
allocated(bc_type))
deallocate(bc_type)
306 call json_get(bc_subdict,
'type', bc_type)
308 if (
allocated(zone_indices))
deallocate(zone_indices)
309 call json_get(bc_subdict,
'zone_indices', zone_indices)
312 if (trim(bc_type) .eq.
'no_slip')
then
317 do j = 1,
size(zone_indices)
321 call this%bc_moving%mark_zone(coef%msh%labeled_zones(&
324 this%has_moving_boundary = .true.
326 do j = 1,
size(zone_indices)
327 call this%bc_fixed%mark_zone(coef%msh%labeled_zones(&
334 call this%bc_moving%finalize()
335 call this%bc_fixed%finalize()
336 call this%bc_list%init()
337 call this%bc_list%append(this%bc_moving)
338 call this%bc_list%append(this%bc_fixed)
341 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
342 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
343 this%config%stiffness_type = tmp_str
344 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
345 call neko_error(
"ALE: stiffness_type must be 'built-in'")
349 if (
associated(this%user_ale_base_shapes, &
351 call neko_log%message(
'Solver Type : (' // &
352 trim(ksp_solver) //
', ' // trim(precon_type) //
')')
353 write(log_buf,
'(A,ES13.6)')
'Abs tol :', abstol
355 call neko_log%message(
'Mesh Stiffness : ' // &
356 trim(this%config%stiffness_type))
361 if (json%valid_path(
'case.fluid.ale.bodies'))
then
362 call json%info(
'case.fluid.ale.bodies', n_children = n_bodies)
363 this%config%nbodies = n_bodies
364 allocate(this%config%bodies(n_bodies))
365 allocate(this%ale_pivot(n_bodies))
366 allocate(this%body_kin(n_bodies))
367 allocate(this%base_shapes(n_bodies))
368 allocate(this%global_pivot_pos(3 * this%config%nbodies))
369 allocate(this%global_pivot_vel_lag(3 * this%config%nbodies, 3))
370 allocate(this%global_basis_pos(6 * this%config%nbodies))
371 allocate(this%ghost_handles(2, this%config%nbodies))
372 allocate(this%global_basis_vel_lag(6 * this%config%nbodies, 3))
373 allocate(this%body_rot_matrices(3, 3, this%config%nbodies))
375 this%global_pivot_pos = 0.0_rp
376 this%global_pivot_vel_lag = 0.0_rp
377 this%global_basis_pos = 0.0_rp
378 this%global_basis_vel_lag = 0.0_rp
379 this%body_rot_matrices = 0.0_rp
382 this%body_rot_matrices(1, 1, i) = 1.0_rp
383 this%body_rot_matrices(2, 2, i) = 1.0_rp
384 this%body_rot_matrices(3, 3, i) = 1.0_rp
389 this%config%bodies(i)%id = i
391 if (body_sub%valid_path(
'name'))
then
392 call json_get(body_sub,
'name', tmp_str)
393 this%config%bodies(i)%name = tmp_str
395 write(this%config%bodies(i)%name,
'(A,I0)')
'body_', i
398 if (body_sub%valid_path(
'zone_indices'))
then
399 call json_get(body_sub,
'zone_indices', zone_indices)
400 this%config%bodies(i)%zone_indices = zone_indices
403 trim(this%config%bodies(i)%name) // &
404 " must have 'zone_indices'")
408 this%config%bodies(i)%osc_amp = 0.0_rp
409 this%config%bodies(i)%osc_freq = 0.0_rp
410 if (body_sub%valid_path(
'oscillation'))
then
411 call json_get(body_sub,
'oscillation.amplitude', tmp_vec, &
413 this%config%bodies(i)%osc_amp = tmp_vec
414 call json_get(body_sub,
'oscillation.frequency', tmp_vec, &
416 this%config%bodies(i)%osc_freq = tmp_vec
420 if (body_sub%valid_path(
'rotation'))
then
422 if (.not. body_sub%valid_path(
'pivot'))
then
423 call neko_error(
"ale.bodies.pivot is missing " // &
424 "from the case file.")
427 call json_get(body_sub,
'rotation.type', tmp_str)
428 this%config%bodies(i)%rotation_type = tmp_str
430 select case (trim(tmp_str))
432 call json_get(body_sub,
'rotation.amplitude_deg', tmp_vec, &
434 this%config%bodies(i)%rot_amp_degree = tmp_vec
436 call json_get(body_sub,
'rotation.frequency', tmp_vec, &
438 this%config%bodies(i)%rot_freq = tmp_vec
442 call json_get(body_sub,
'rotation.ramp_t0', tmp_vec, &
444 this%config%bodies(i)%ramp_t0 = tmp_vec
446 call json_get(body_sub,
'rotation.ramp_omega0', tmp_vec, &
448 this%config%bodies(i)%ramp_omega0 = tmp_vec
454 if (tmp_int .ge. 1 .and. tmp_int .le. 3)
then
455 this%config%bodies(i)%rotation_axis = tmp_int
457 call neko_error(
"ALE: rotation.axis must be (integer) " // &
458 "1 -> x, 2 -> y, or 3 -> z")
460 call json_get(body_sub,
'rotation.step_control_times', &
461 tmp_vec, expected_size = 4)
462 this%config%bodies(i)%step_control_times = tmp_vec
464 call json_get(body_sub,
'rotation.target_angle_deg', tmp_val)
465 this%config%bodies(i)%target_rot_angle_deg = tmp_val
468 call neko_error(
"ALE: rotation.type must be 'harmonic', " // &
469 "'ramp', or 'smooth_step'")
474 if (body_sub%valid_path(
'pivot'))
then
477 this%config%bodies(i)%rotation_center_type = tmp_str
478 call json_get(body_sub,
'pivot.value', tmp_vec, expected_size = 3)
479 this%config%bodies(i)%rot_center = tmp_vec
482 tmp_str = this%config%bodies(i)%rotation_center_type
483 if (trim(tmp_str) /=
'relative' .and. &
484 trim(tmp_str) /=
'relative_sin')
then
485 call neko_error(
"ALE: pivot.type must be " // &
486 "'relative', or 'relative_sin'.")
491 if (body_sub%valid_path(
'stiff_geom'))
then
492 call json_get(body_sub,
'stiff_geom.type', tmp_str)
493 this%config%bodies(i)%stiff_geom%type = tmp_str
494 call json_get(body_sub,
'stiff_geom.gain', &
495 this%config%bodies(i)%stiff_geom%gain)
496 call json_get(body_sub,
'stiff_geom.decay_profile', tmp_str)
497 this%config%bodies(i)%stiff_geom%decay_profile = tmp_str
499 select case (trim(this%config%bodies(i)%stiff_geom%decay_profile))
502 'stiff_geom.cutoff_coef', &
503 this%config%bodies(i)%stiff_geom%cutoff_coef, 9.0_rp)
506 'stiff_geom.cutoff_coef', &
507 this%config%bodies(i)%stiff_geom%cutoff_coef, 3.5_rp)
509 call neko_error(
"ALE: Invalid stiff_geom.decay_profile: " // &
510 trim(this%config%bodies(i)%stiff_geom%decay_profile))
513 select case (trim(this%config%bodies(i)%stiff_geom%type))
514 case (
'cylinder',
'sphere')
515 call json_get(body_sub,
'stiff_geom.center', tmp_vec, &
517 this%config%bodies(i)%stiff_geom%center = tmp_vec
519 call json_get(body_sub,
'stiff_geom.radius', &
520 this%config%bodies(i)%stiff_geom%radius)
522 call json_get(body_sub,
'stiff_geom.stiff_dist', &
523 this%config%bodies(i)%stiff_geom%stiff_dist)
525 call neko_error(
"ALE: stiff_geom.type 'box' not yet" // &
528 call neko_error(
"ALE: Invalid stiff_geom.type: " // &
529 trim(this%config%bodies(i)%stiff_geom%type))
531 elseif (import_base_shapes)
then
535 trim(this%config%bodies(i)%name) // &
536 "' must have 'stiff_geom' definition.")
542 call this%base_shapes(i)%init(coef%dof, &
543 "phi_" // trim(this%config%bodies(i)%name))
549 this%ghost_handles(1, i) = this%request_tracker( &
550 this%config%bodies(i)%rot_center + [1.0_rp, 0.0_rp, 0.0_rp], &
551 this%config%bodies(i)%id)
553 this%ghost_handles(2, i) = this%request_tracker( &
554 this%config%bodies(i)%rot_center + [0.0_rp, 1.0_rp, 0.0_rp], &
555 this%config%bodies(i)%id)
557 call neko_log%message(
'Registered Body : ' // &
558 trim(this%config%bodies(i)%name))
562 if (
associated(this%user_ale_base_shapes, &
564 (.not. import_base_shapes))
then
565 write(log_buf,
'(A,A)')
' Stiff Type : ', &
566 trim(this%config%bodies(i)%stiff_geom%type)
568 write(log_buf,
'(A,ES18.11,A,A,A,ES10.4)')
' Gain : ', &
569 this%config%bodies(i)%stiff_geom%gain,
' | Profile: ', &
570 trim(this%config%bodies(i)%stiff_geom%decay_profile), &
571 ' | Cutoff: ', this%config%bodies(i)%stiff_geom%cutoff_coef
573 select case (trim(this%config%bodies(i)%stiff_geom%type))
574 case (
'cylinder',
'sphere')
575 write(log_buf,
'(A,3(ES23.15,1X))')
' Center :', &
576 this%config%bodies(i)%stiff_geom%center
578 write(log_buf,
'(A,ES23.15)')
' Radius :', &
579 this%config%bodies(i)%stiff_geom%radius
582 write(log_buf,
'(A,ES23.15)')
' Stiff Dist:', &
583 this%config%bodies(i)%stiff_geom%stiff_dist
590 has_builtin_osc = any(abs(this%config%bodies(i)%osc_amp) .gt. 0.0_rp)
592 if (has_builtin_osc)
then
593 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
594 call neko_log%message(
' Oscillation : ' // &
595 'X(t) = Amp*sin(2*pi*Freq*t) + User')
596 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
597 this%config%bodies(i)%osc_amp
599 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
600 this%config%bodies(i)%osc_freq
603 call neko_log%message(
' Oscillation : ' // &
604 'X(t) = Amp*sin(2*pi*Freq*t)')
605 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
606 this%config%bodies(i)%osc_amp
608 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
609 this%config%bodies(i)%osc_freq
613 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
614 call neko_log%message(
' Oscillation : User-defined')
616 call neko_log%message(
' Oscillation : None')
622 has_builtin_rot = (trim(this%config%bodies(i)%rotation_type) &
625 if (trim(this%config%bodies(i)%rotation_type) .eq.
'user')
then
627 call neko_log%message(
' Rotation Type: User-defined')
629 elseif (has_builtin_rot)
then
632 is_rot_active = .false.
633 select case (trim(this%config%bodies(i)%rotation_type))
635 is_rot_active = any(abs(this%config%bodies(i)%rot_amp_degree) &
638 is_rot_active = any(abs(this%config%bodies(i)%ramp_omega0) &
642 (abs(this%config%bodies(i)%target_rot_angle_deg) &
646 if (is_rot_active)
then
648 if (trim(this%config%bodies(i)%rotation_type) &
649 .eq.
'harmonic')
then
650 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
651 call neko_log%message(
' Rotation : ' // &
652 'Theta(t) = Amp*sin(2*pi*Freq*t) + User')
654 call neko_log%message(
' Rotation : ' // &
655 'Theta(t) = Amp*sin(2*pi*Freq*t)')
657 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp (deg) :', &
658 this%config%bodies(i)%rot_amp_degree
660 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
661 this%config%bodies(i)%rot_freq
665 elseif (trim(this%config%bodies(i)%rotation_type) &
667 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
668 call neko_log%message(
' Rotation : ' // &
669 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0)) + User')
671 call neko_log%message(
' Rotation : ' // &
672 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0))')
674 write(log_buf,
'(A,3(ES18.11,1X))')
' Omega0 :', &
675 this%config%bodies(i)%ramp_omega0
677 write(log_buf,
'(A,3(ES18.11,1X))')
' t0 :', &
678 this%config%bodies(i)%ramp_t0
682 elseif (trim(this%config%bodies(i)%rotation_type) &
683 .eq.
'smooth_step')
then
684 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
685 call neko_log%message(
' Rotation : ' // &
686 'Smooth Step Control + User')
688 call neko_log%message(
' Rotation : ' // &
689 'Smooth Step Control')
691 write(log_buf,
'(A,I10)')
' Rotation Axis :', &
692 this%config%bodies(i)%rotation_axis
694 write(log_buf,
'(A,ES18.11)')
' Target Rot ' // &
696 this%config%bodies(i)%target_rot_angle_deg
698 write(log_buf,
'(A,4(ES18.11,1X))') &
699 ' Control Times [t0, t1, t2, t3] :', &
700 this%config%bodies(i)%step_control_times
704 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
705 call neko_log%message(
' Rotation Type: User-defined')
707 call neko_log%message(
' Rotation Type: None')
715 call neko_log%message(
' Pivot Type : ' // &
716 trim(this%config%bodies(i)%rotation_center_type))
718 write(log_buf,
'(A,3(ES18.11,1X))')
' Init Pivot:', &
719 this%config%bodies(i)%rot_center
725 call neko_error(
"ALE: No 'ale bodies' found in case file!")
728 if (this%config%nbodies .gt. 1 .and. (.not. import_base_shapes))
then
729 call this%phi_total%init(coef%dof,
"phi_total")
734 do i = 1, n_moving_zones
735 z = moving_zone_ids(i)
738 do while ((.not. found_zone) .and. (j .le. this%config%nbodies))
739 if (any(this%config%bodies(j)%zone_indices .eq. z))
then
744 if (.not. found_zone)
then
745 write(log_buf_l,
'(A,I0,A)') &
746 "ALE: zone index ", z, &
747 " has BC no_slip with moving: true, " // &
748 "but it is not registered in ALE bodies."
755 do j = 1, this%config%nbodies
756 if (
allocated(this%config%bodies(j)%zone_indices))
then
757 do i = 1,
size(this%config%bodies(j)%zone_indices)
758 z = this%config%bodies(j)%zone_indices(i)
760 if (n_moving_zones .gt. 0)
then
761 if (any(moving_zone_ids(1:n_moving_zones) .eq. z))
then
765 if (.not. found_zone)
then
766 write(log_buf_l,
'(A,I0,A,A)') &
767 "ALE: zone index ", z, &
768 " is registered in ALE bodies, ", &
769 "but the BC is not no_slip with moving: true."
777 do j = 1, this%config%nbodies
778 if (
allocated(this%config%bodies(j)%zone_indices))
then
779 do i = 1,
size(this%config%bodies(j)%zone_indices)
780 z = this%config%bodies(j)%zone_indices(i)
782 do k = j + 1, this%config%nbodies
783 if (
allocated(this%config%bodies(k)%zone_indices))
then
784 if (any(this%config%bodies(k)%zone_indices .eq. z))
then
785 write(log_buf_l,
'(A,I0,A,A,A,A,A)') &
786 "ALE: zone index ", z, &
787 " is assigned to multiple bodies ('", &
788 trim(this%config%bodies(j)%name),
"' and '", &
789 trim(this%config%bodies(k)%name),
"')."
800 call this%solve_base_mesh_displacement(coef, json, import_base_shapes, &
801 abstol, ksp_solver, ksp_max_iter, &
802 precon_type, precon_params, res_monitor)
806 if (.not. json%valid_path(
'case.restart_file'))
then
810 call this%update_mesh_velocity(coef, t_init)
813 call this%wm_x_lag%init(this%wm_x, 2)
814 call this%wm_y_lag%init(this%wm_y, 2)
815 call this%wm_z_lag%init(this%wm_z, 2)
817 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
818 if (
allocated(bc_type))
deallocate(bc_type)
819 if (
allocated(zone_indices))
deallocate(zone_indices)
820 if (
allocated(ksp_solver))
deallocate(ksp_solver)
821 if (
allocated(precon_type))
deallocate(precon_type)
822 if (
allocated(tmp_str))
deallocate(tmp_str)
823 if (
allocated(tmp_vec))
deallocate(tmp_vec)
826 call this%mesh_preview(coef, json)
829 call this%register_checkpoint_fields(coef, chkp)
839 import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, &
840 precon_params, res_monitor)
842 class(
ax_t),
allocatable :: Ax
843 class(
ksp_t),
allocatable :: ksp
844 class(
pc_t),
allocatable :: pc
845 type(
coef_t),
intent(inout) :: coef
846 type(json_file),
intent(inout) :: json
847 logical,
intent(in) :: import_base_shapes
848 real(kind=
rp),
intent(in) :: abstol
849 logical,
intent(in) :: res_monitor
850 character(len=*),
intent(in) :: ksp_solver, precon_type
851 integer,
intent(in) :: ksp_max_iter
852 type(json_file),
intent(inout) :: precon_params
854 type(
field_t),
pointer :: phi_ptr => null()
858 real(kind=
rp) :: sample_start_time, sample_end_time
859 real(kind=
rp) :: sample_time
860 character(len=LOG_SIZE) :: log_buf
861 integer :: n, i, m, k, ierr, body_idx, z_idx
863 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
864 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
869 type(json_file) :: body_sub
870 character(len=256) :: phi_fname
871 character(len=:),
allocatable :: tmp_str
874 if (.not. this%active)
return
875 if (.not. this%has_moving_boundary)
return
876 if (this%config%nbodies .eq. 0)
return
878 if (import_base_shapes)
then
880 call neko_log%message(
"Importing ALE base shapes" // &
881 " (skipping Laplace solve)...")
883 do body_idx = 1, this%config%nbodies
888 call json_get(body_sub,
'base_shape_import_file', tmp_str)
891 phi_ptr => this%base_shapes(body_idx)
896 call neko_log%message(
" Loaded: " // &
899 trim(this%config%bodies(body_idx)%name))
906 call neko_log%message(
"Starting base mesh motion solve ...")
909 call ax_helm_allocator(ax, type_name =
"standard")
910 call krylov_solver_factory(ksp, n, ksp_solver, &
911 ksp_max_iter, abstol, monitor = res_monitor)
919 call rhs_field%init(coef%dof)
920 call corr_field%init(coef%dof)
924 if (.not.
associated(this%user_ale_base_shapes, &
926 call neko_log%message(
" Using user-defined base shapes " // &
927 "(skipping Laplace solve)")
930 call this%user_ale_base_shapes(this%base_shapes)
933 if (this%config%nbodies .gt. 1)
then
935 do body_idx = 1, this%config%nbodies
936 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
941 if (this%config%if_output_phi)
then
943 do body_idx = 1, this%config%nbodies
944 call phi_file%init(
'phi_' // &
945 trim(this%config%bodies(body_idx)%name) //
'.fld', &
947 select type (ft => phi_file%file_type)
949 ft%skip_pressure = .false.
951 call phi_file%write(this%base_shapes(body_idx))
954 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
958 if (this%config%nbodies .gt. 1)
then
959 call neko_log%message(
" phi_total.fld saved.")
960 select type (ft => phi_file%file_type)
962 ft%skip_pressure = .false.
964 call phi_file%init(
'phi_total.fld', precision =
rp)
965 call phi_file%write(this%phi_total)
976 if (this%config%if_output_stiffness)
then
977 rhs_field%x = coef%h1
978 call phi_file%init(
'stiffness.fld')
979 call phi_file%write(rhs_field)
985 do body_idx = 1, this%config%nbodies
987 sample_start_time = mpi_wtime()
988 call neko_log%message(
" Solving laplace for body: " // &
989 trim(this%config%bodies(body_idx)%name))
991 call bc_active_body%init_from_components(coef)
992 call bc_inactive_body%init_from_components(coef)
995 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
996 z_idx = this%config%bodies(body_idx)%zone_indices(j)
997 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
1000 do i = 1, this%config%nbodies
1001 if (i /= body_idx)
then
1002 do j = 1,
size(this%config%bodies(i)%zone_indices)
1003 z_idx = this%config%bodies(i)%zone_indices(j)
1004 call bc_inactive_body%mark_zone(&
1005 coef%msh%labeled_zones(z_idx))
1010 call bc_active_body%finalize()
1011 call bc_inactive_body%finalize()
1014 call bc_projector%mark(this%bc_fixed)
1015 call bc_projector%mark(bc_active_body)
1016 call bc_projector%mark(bc_inactive_body)
1019 call bc_projector_zeros_only%mark(this%bc_fixed)
1020 call bc_projector_zeros_only%mark(bc_inactive_body)
1023 this%base_shapes(body_idx)%x = 0.0_rp
1024 rhs_field%x = 0.0_rp
1025 corr_field%x = 0.0_rp
1032 m = bc_active_body%msk(0)
1034 k = bc_active_body%msk(i)
1035 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1046 call bc_projector_zeros_only%apply(this%base_shapes(body_idx)%x, n)
1050 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1051 coef, coef%msh, coef%Xh)
1056 call bc_projector%apply(rhs_field%x, n)
1057 call coef%gs_h%op(rhs_field, gs_op_add)
1062 monitor(1) = ksp%solve(ax, corr_field, &
1063 rhs_field%x, n, coef, bc_projector, coef%gs_h)
1066 call field_add2(this%base_shapes(body_idx), corr_field, n)
1070 if (this%config%nbodies .gt. 1)
then
1071 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1075 sample_end_time = mpi_wtime()
1076 sample_time = sample_end_time - sample_start_time
1077 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1078 trim(this%config%bodies(body_idx)%name),
"' took ", &
1083 call bc_active_body%free()
1084 call bc_inactive_body%free()
1085 call bc_projector%free()
1086 call bc_projector_zeros_only%free()
1096 if (this%config%if_output_phi)
then
1097 call phi_file%init(
'phi_' // &
1098 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1100 select type (ft => phi_file%file_type)
1102 ft%skip_pressure = .false.
1104 call phi_file%write(this%base_shapes(body_idx))
1105 call phi_file%free()
1107 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1111 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1114 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1118 call neko_log%message(
" phi_total.fld saved.")
1119 call phi_file%init(
'phi_total.fld', precision =
rp)
1120 select type (ft => phi_file%file_type)
1122 ft%skip_pressure = .false.
1124 call phi_file%write(this%phi_total)
1125 call phi_file%free()
1129 call rhs_field%free()
1130 call corr_field%free()
1131 if (this%config%nbodies > 1)
then
1132 call this%phi_total%free()
1136 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1137 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1143 if (
allocated(h1_restore))
deallocate(h1_restore)
1144 if (
allocated(h2_restore))
deallocate(h2_restore)
1145 if (
allocated(ax))
then
1149 if (
allocated(ksp))
then
1153 if (
allocated(pc))
then
1164 type(
coef_t),
intent(in) :: coef
1168 real(kind=
rp) :: rot_mat(3,3)
1169 real(kind=
rp) :: initial_rot_center(3)
1171 if (.not. this%active)
return
1172 if (.not. this%has_moving_boundary)
return
1179 do i = 1, this%config%nbodies
1183 this%config%bodies(i), time_s)
1186 if (.not.
associated(this%user_ale_rigid_kinematics, &
1188 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1190 current_kin%vel_trans, &
1191 current_kin%vel_ang)
1194 current_kin%center = this%ale_pivot(i)%pos
1195 this%ale_pivot(i)%vel = current_kin%vel_trans
1197 this%body_kin(i)%center = this%ale_pivot(i)%pos
1198 this%body_kin(i)%vel_trans = current_kin%vel_trans
1199 this%body_kin(i)%vel_ang = current_kin%vel_ang
1202 call this%compute_rotation_matrix(i, time_s)
1203 rot_mat = this%body_rot_matrices(:,:,i)
1204 initial_rot_center = this%config%bodies(i)%rot_center
1208 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1209 this%base_shapes(i), coef, current_kin, rot_mat, &
1213 call this%prep_checkpoint(i)
1219 if (.not.
associated(this%user_ale_mesh_vel, &
1221 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1222 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1232 type(
coef_t),
intent(inout) :: coef
1234 integer,
intent(in) :: nadv
1237 if (.not. this%active)
return
1238 if (.not. this%has_moving_boundary)
return
1240 do i = 1, this%config%nbodies
1245 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1248 this%ale_pivot(i)%pos, &
1249 this%ale_pivot(i)%vel, &
1252 this%config%bodies(i))
1256 call coef%update_B_history()
1260 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1264 call this%wm_x_lag%update()
1265 call this%wm_y_lag%update()
1266 call this%wm_z_lag%update()
1272 type(
coef_t),
intent(inout) :: coef
1274 integer :: i, n, b, ierr
1275 integer,
allocatable :: cheap_map(:)
1276 integer :: n_cheap, map_idx
1277 real(kind=
rp) :: x, y, z
1278 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1279 real(kind=
rp) :: cx, cy, cz
1280 real(kind=
rp) :: arg, decay, gain, norm_dist
1281 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1282 type(
field_t),
allocatable :: dist_fields(:)
1283 character(len=128) :: log_buf
1288 allocate(cheap_map(params%nbodies))
1292 do b = 1, params%nbodies
1293 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1294 n_cheap = n_cheap + 1
1295 cheap_map(b) = n_cheap
1300 if (n_cheap > 0)
then
1301 allocate(dist_fields(n_cheap))
1303 do b = 1, params%nbodies
1304 map_idx = cheap_map(b)
1305 if (map_idx .gt. 0)
then
1307 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1310 call neko_log%message(
" Start: cheap dist calculation " // &
1311 "for body '" // trim(params%bodies(b)%name) //
"'")
1314 sample_start_time = mpi_wtime()
1318 coef%msh, params%bodies(b)%zone_indices, &
1319 copy_to_host = .true.)
1322 coef%msh, params%bodies(b)%zone_indices)
1326 sample_end_time = mpi_wtime()
1327 sample_time = sample_end_time - sample_start_time
1329 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1330 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1338 select case (trim(params%stiffness_type))
1341 do concurrent(i = 1:n)
1342 x = coef%dof%x%x(i, 1, 1, 1)
1343 y = coef%dof%y%x(i, 1, 1, 1)
1344 z = coef%dof%z%x(i, 1, 1, 1)
1346 max_added_stiff = 0.0_rp
1349 do b = 1, params%nbodies
1350 gain = params%bodies(b)%stiff_geom%gain
1351 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1352 decay = params%bodies(b)%stiff_geom%stiff_dist
1354 decay = params%bodies(b)%stiff_geom%radius
1358 cx = params%bodies(b)%stiff_geom%center(1)
1359 cy = params%bodies(b)%stiff_geom%center(2)
1360 cz = params%bodies(b)%stiff_geom%center(3)
1362 raw_dist = huge(0.0_rp)
1365 select case (trim(params%bodies(b)%stiff_geom%type))
1367 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1371 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1377 map_idx = cheap_map(b)
1378 if (map_idx .gt. 0)
then
1379 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1384 body_stiff_val = 0.0_rp
1385 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1388 arg = -(raw_dist**2) / (decay**2)
1389 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1390 body_stiff_val = gain * exp(arg)
1394 norm_dist = (raw_dist / decay)
1395 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1396 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1399 if (body_stiff_val .gt. max_added_stiff)
then
1400 max_added_stiff = body_stiff_val
1404 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1405 coef%h2(i, 1, 1, 1) = 0.0_rp
1409 call neko_error(
"ALE Manager: Unknown stiffness type")
1419 if (
allocated(dist_fields))
then
1420 do i = 1,
size(dist_fields)
1421 call dist_fields(i)%free()
1423 deallocate(dist_fields)
1425 if (
allocated(cheap_map))
deallocate(cheap_map)
1431 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1432 type(
field_t),
intent(inout) :: wx, wy, wz
1433 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1434 type(
field_t),
intent(in) :: phi
1435 type(
coef_t),
intent(in) :: coef
1437 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1438 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1441 x_ref, y_ref, z_ref, &
1442 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1445 x_ref, y_ref, z_ref, &
1446 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1452 wm_z_lag, time, nadv, scheme_)
1453 type(
coef_t),
intent(inout) :: c_xh
1454 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1457 integer,
intent(in) :: nadv
1458 character(len=*),
intent(in) :: scheme_
1461 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1464 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1473 if (.not. this%active)
return
1475 call this%bc_moving%free()
1476 call this%bc_fixed%free()
1477 call this%bc_list%free()
1479 if (
allocated(this%base_shapes))
then
1480 do i = 1,
size(this%base_shapes)
1481 call this%base_shapes(i)%free()
1483 deallocate(this%base_shapes)
1486 call this%wm_x_lag%free()
1487 call this%wm_y_lag%free()
1488 call this%wm_z_lag%free()
1489 call this%x_ref%free()
1490 call this%y_ref%free()
1491 call this%z_ref%free()
1493 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1494 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1495 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1496 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1497 if (
associated(this%global_pivot_vel_lag)) &
1498 deallocate(this%global_pivot_vel_lag)
1499 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1500 if (
associated(this%global_basis_vel_lag)) &
1501 deallocate(this%global_basis_vel_lag)
1502 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1503 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1504 if (
allocated(this%trackers))
deallocate(this%trackers)
1511 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1512 class(
ksp_t),
target,
intent(inout) :: ksp
1513 type(
coef_t),
target,
intent(in) :: coef
1514 type(
bc_list_t),
target,
intent(inout) :: bclst
1515 character(len=*),
intent(in) :: pctype
1516 type(json_file),
intent(inout) :: json
1518 call precon_factory(pc, pctype, coef, bclst, json)
1525 real(kind=
dp),
intent(in) :: time_restart
1527 integer :: i, idx, handle_1, handle_2, offset_base
1529 time_state_dummy%t = time_restart
1533 do i = 1, this%config%nbodies
1536 this%config%bodies(i), time_state_dummy)
1539 if (.not.
associated(this%user_ale_rigid_kinematics, &
1541 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1543 kin_restart%vel_trans, &
1544 kin_restart%vel_ang)
1547 this%ale_pivot(i)%vel = kin_restart%vel_trans
1551 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1552 this%body_kin(i)%center = this%ale_pivot(i)%pos
1553 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1554 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1557 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1558 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1561 offset_base = (i-1)*6
1562 handle_1 = this%ghost_handles(1, i)
1563 handle_2 = this%ghost_handles(2, i)
1565 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1566 this%trackers(handle_1)%pos = &
1567 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1570 this%trackers(handle_1)%vel_lag = &
1571 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1574 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1575 this%trackers(handle_2)%pos = &
1576 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1579 this%trackers(handle_2)%vel_lag = &
1580 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1590 type(
coef_t),
intent(inout) :: coef
1591 type(
space_t),
intent(inout) :: Xh
1592 type(
chkp_t),
intent(in) :: chkp
1593 type(
gs_t),
intent(inout) :: gs_Xh
1597 if (.not. this%active)
return
1599 if (
allocated(chkp%previous_mesh%elements))
then
1601 "The current mesh has a different number " // &
1602 "of elements than the checkpoint.")
1606 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1608 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1609 do concurrent(j = 1:n)
1611 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1612 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1613 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1617 do i = 1, this%wm_x_lag%size()
1618 do concurrent(j = 1:n)
1619 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1620 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1621 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1622 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1623 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1624 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1634 call this%wm_x_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1635 call this%wm_x_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1637 call this%wm_y_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1638 call this%wm_y_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1640 call this%wm_z_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1641 call this%wm_z_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1643 if (c_associated(coef%dof%x%x_d))
then
1649 if (c_associated(coef%Blag_d))
then
1650 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1654 if (c_associated(coef%Blaglag_d))
then
1662 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1663 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1664 call gs_xh%op(this%wm_x, gs_op_add)
1665 call gs_xh%op(this%wm_y, gs_op_add)
1666 call gs_xh%op(this%wm_z, gs_op_add)
1667 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1669 do i = 1, this%wm_x_lag%size()
1670 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1671 this%wm_z_lag%lf(i)%x, 1, coef)
1672 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1673 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1674 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
1675 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1676 this%wm_z_lag%lf(i)%x, 0, coef)
1681 call this%set_pivot_restart(chkp%t)
1682 call coef%recompute_metrics()
1689 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1691 coef%Blaglag = coef%B
1693 if (c_associated(coef%Blag_d))
then
1697 if (c_associated(coef%Blaglag_d))
then
1705 call adv%recompute_metrics(coef, .true.)
1710 integer,
intent(in) :: body_idx
1711 integer :: idx, offset_base, h1, h2
1713 if (.not. this%active)
return
1714 if (.not. this%has_moving_boundary)
return
1716 idx = (body_idx - 1) * 3
1717 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1718 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1719 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1721 h1 = this%ghost_handles(1, body_idx)
1722 h2 = this%ghost_handles(2, body_idx)
1724 offset_base = (body_idx-1)*6
1727 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1728 this%get_tracker_pos(h1)
1729 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1730 this%get_tracker_pos(h2)
1733 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1734 this%trackers(h1)%vel_lag
1737 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1738 this%trackers(h2)%vel_lag
1743 integer,
allocatable,
intent(inout) :: arr(:)
1744 integer,
intent(inout) :: n
1745 integer,
intent(in) :: val
1746 integer,
allocatable :: tmp(:)
1750 if (arr(k) .eq. val)
return
1753 allocate(tmp(n + 1))
1754 if (n .gt. 0) tmp(1:n) = arr(1:n)
1757 if (
allocated(arr))
deallocate(arr)
1758 call move_alloc(tmp, arr)
1766 type(coef_t),
intent(inout) :: coef
1767 type(json_file),
intent(inout) :: json
1768 type(fld_file_output_t) :: fout
1769 type(field_t) :: dummy_field
1770 type(time_state_t) :: t_state
1771 type(file_t) :: out_file
1772 real(kind=rp) :: t_start
1773 real(kind=rp) :: t_end
1775 real(kind=rp) :: min_jac
1776 integer :: output_freq
1777 integer :: step, n_steps
1778 integer :: nadv, nadv_sim
1780 logical :: mesh_preview_active
1781 character(len=128) :: log_buf
1783 mesh_preview_active = .false.
1785 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1786 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1787 mesh_preview_active)
1790 if (.not. mesh_preview_active)
return
1792 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1794 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1796 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1798 call json_get(json, &
1799 'case.fluid.ale.mesh_preview.output_freq', &
1802 call neko_log%section(
"ALE Mesh Preview")
1803 call neko_log%message(
"Executing mesh motion preview...")
1805 n_steps = int((t_end - t_start) / dt)
1806 call json_get(json,
'case.numerics.time_order', nadv_sim)
1808 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1809 call neko_log%message(log_buf)
1810 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1811 call neko_log%message(log_buf)
1812 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1813 call neko_log%message(log_buf)
1814 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1815 call neko_log%message(log_buf)
1816 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1817 call neko_log%message(log_buf)
1818 call neko_log%message(
'')
1821 call dummy_field%init(coef%dof,
"mesh_preview")
1822 call field_rzero(dummy_field)
1824 call fout%init(rp,
"mesh_preview", 1)
1825 call fout%fields%assign_to_field(1, dummy_field)
1826 select type (ft => fout%file_%file_type)
1827 type is (fld_file_t)
1828 ft%write_mesh = .true.
1829 ft%skip_pressure = .false.
1842 if (neko_bcknd_device .eq. 1)
then
1843 min_jac = device_glmin(coef%jac_d, n)
1845 min_jac = glmin(coef%jac, n)
1849 call fout%sample(t_state%t)
1851 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1852 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1853 t_state%t,
" | Min Jac: ", min_jac
1855 call neko_log%message(trim(log_buf))
1856 call this%update_mesh_velocity(coef, t_state)
1858 do step = 1, n_steps
1859 t_state%tstep = step
1860 t_state%t = t_start + (step * dt)
1861 nadv = min(step, nadv_sim)
1863 call this%advance_mesh(coef, t_state, nadv)
1864 call coef%recompute_metrics()
1867 if (neko_bcknd_device .eq. 1)
then
1868 min_jac = device_glmin(coef%jac_d, n)
1870 min_jac = glmin(coef%jac, n)
1873 if (min_jac .le. 0.0_rp)
then
1874 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1875 "Negative Jacobian detected (", min_jac,
") at t = ", &
1877 call neko_log%message(log_buf)
1880 call fout%sample(t_state%t)
1882 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1883 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1884 t_state%t,
" | Min Jac:", min_jac
1885 call neko_log%message(trim(log_buf))
1887 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1890 if (mod(step, output_freq) .eq. 0)
then
1893 call fout%sample(t_state%t)
1895 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1896 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1897 t_state%t,
" | Min Jac:", min_jac
1898 call neko_log%message(trim(log_buf))
1902 call this%update_mesh_velocity(coef, t_state)
1906 call dummy_field%free()
1908 call neko_log%end_section()
1909 call neko_log%message(
"Mesh preview complete.")
1910 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1915 type(fld_file_output_t) :: fout
1916 type(coef_t),
intent(inout) :: coef
1917 type(field_t),
intent(inout) :: dummy_field
1921 if (neko_bcknd_device .eq. 1)
then
1922 call device_copy(dummy_field%x_d, coef%B_d, n)
1924 call copy(dummy_field%x, coef%B, n)
1927 if (neko_bcknd_device .eq. 1)
then
1928 associate(
mesh => coef%dof)
1929 call device_memcpy(
mesh%x%x,
mesh%x%x_d,
mesh%size(), &
1930 device_to_host, sync = .false.)
1931 call device_memcpy(
mesh%y%x,
mesh%y%x_d,
mesh%size(), &
1932 device_to_host, sync = .false.)
1933 call device_memcpy(
mesh%z%x,
mesh%z%x_d,
mesh%size(), &
1934 device_to_host, sync = .false.)
1944 real(kind=rp),
intent(in) :: initial_pos(3)
1945 integer,
intent(in) :: body_id
1947 type(point_tracker_t),
allocatable :: tmp(:)
1950 if (.not. this%active)
return
1951 if (.not. this%has_moving_boundary)
return
1953 if (.not.
allocated(this%trackers))
then
1954 allocate(this%trackers(30))
1956 elseif (this%n_trackers .ge.
size(this%trackers))
then
1957 allocate(tmp(
size(this%trackers) + 30))
1958 tmp(1:
size(this%trackers)) = this%trackers
1959 deallocate(this%trackers)
1960 call move_alloc(tmp, this%trackers)
1962 this%n_trackers = this%n_trackers + 1
1963 handle = this%n_trackers
1965 this%trackers(handle)%pos = initial_pos
1966 this%trackers(handle)%body_id = body_id
1967 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
1972 integer,
intent(in) :: handle
1973 real(kind=rp) :: pos(3)
1975 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
1976 pos = this%trackers(handle)%pos
1986 integer,
intent(in) :: body_idx
1987 type(time_state_t),
intent(in) :: time
1989 real(kind=rp) :: p(3), gx(3), gy(3)
1990 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
1992 if (.not. this%active)
return
1993 if (.not. this%has_moving_boundary)
return
1996 h_x = this%ghost_handles(1, body_idx)
1997 h_y = this%ghost_handles(2, body_idx)
1999 p = this%ale_pivot(body_idx)%pos
2000 gx = this%get_tracker_pos(h_x)
2001 gy = this%get_tracker_pos(h_y)
2005 u = u / sqrt(sum(u**2))
2009 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2010 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2011 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2012 w = w / sqrt(sum(w**2))
2015 v(1) = w(2)*u(3) - w(3)*u(2)
2016 v(2) = w(3)*u(1) - w(1)*u(3)
2017 v(3) = w(1)*u(2) - w(2)*u(1)
2019 this%body_rot_matrices(:, 1, body_idx) = u
2020 this%body_rot_matrices(:, 2, body_idx) = v
2021 this%body_rot_matrices(:, 3, body_idx) = w
2031 type(time_state_t),
intent(in) :: time
2032 integer,
optional,
intent(in) :: body_idxs(:)
2034 integer :: i, idx, n_log
2035 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2036 real(kind=rp) :: r(3,3)
2037 character(len=256) :: log_buf
2038 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2040 if (.not. this%active)
return
2041 if (.not. this%has_moving_boundary)
return
2043 if (
present(body_idxs))
then
2044 n_log =
size(body_idxs)
2046 n_log = this%config%nbodies
2049 call neko_log%message(
" ")
2050 call neko_log%message(
"---------Rotation log---------")
2051 call neko_log%message(
"variable, time step, time, body, " // &
2052 "x_val, y_val, z_val")
2057 if (
present(body_idxs))
then
2063 r = this%body_rot_matrices(:, :, idx)
2066 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2067 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2068 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2071 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2072 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2073 trim(this%config%bodies(idx)%name),
" ", &
2074 roll_deg, pitch_deg, yaw_deg
2075 call neko_log%message(trim(log_buf))
2086 type(time_state_t),
intent(in) :: time
2087 integer,
optional,
intent(in) :: body_idxs(:)
2088 integer :: i, idx, n_log
2089 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2090 character(len=256) :: log_buf
2092 if (.not. this%active)
return
2093 if (.not. this%has_moving_boundary)
return
2095 if (
present(body_idxs))
then
2096 n_log =
size(body_idxs)
2098 n_log = this%config%nbodies
2101 call neko_log%message(
" ")
2102 call neko_log%message(
"----------Pivot Log-----------")
2103 call neko_log%message(
"variable, time step, time, body, " // &
2104 "x_val, y_val, z_val")
2109 if (
present(body_idxs))
then
2115 pivot_pos = this%ale_pivot(idx)%pos
2116 pivot_vel = this%ale_pivot(idx)%vel
2119 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2120 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2121 trim(this%config%bodies(idx)%name),
" ", &
2122 this%ale_pivot(idx)%pos
2123 call neko_log%message(trim(log_buf))
2126 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2127 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2128 trim(this%config%bodies(idx)%name),
" ", &
2129 this%ale_pivot(idx)%vel
2130 call neko_log%message(trim(log_buf))
2137 type(body_kinematics_t),
intent(in) :: kin_object
2138 type(time_state_t),
intent(in) :: time_s
2139 integer,
intent(in) :: nadv
2140 integer,
intent(in) :: body_idx
2142 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2144 if (.not. this%active)
return
2145 if (.not. this%has_moving_boundary)
return
2147 if (
allocated(this%trackers))
then
2148 do t = 1, this%n_trackers
2149 if (this%trackers(t)%body_id .eq. &
2150 this%config%bodies(body_idx)%id)
then
2151 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2152 t .eq. this%ghost_handles(2, body_idx))
then
2155 rel_pos = this%trackers(t)%pos - kin_object%center
2158 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2159 kin_object%vel_ang(3) * rel_pos(2)
2160 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2161 kin_object%vel_ang(1) * rel_pos(3)
2162 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2163 kin_object%vel_ang(2) * rel_pos(1)
2166 p_vel = kin_object%vel_trans + v_tan
2168 if (time_s%tstep .gt. 0)
then
2169 call ab_integrate_point_pos(this%trackers(t)%pos, &
2170 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2182 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
2184 type(json_file),
intent(inout) :: json
2185 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2186 character(len=:),
allocatable,
intent(inout) :: precon_type
2187 type(json_file),
intent(inout) :: precon_params
2188 real(kind=rp),
intent(out) :: abstol
2189 integer,
intent(out) :: ksp_max_iter
2190 logical,
intent(out) :: res_monitor
2191 logical,
intent(out) :: import_base_shapes
2192 logical :: tmp_logical
2193 character(len=:),
allocatable :: tmp_str
2195 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2196 if (
allocated(precon_type))
deallocate(precon_type)
2198 call json_get_or_default(json, &
2199 'case.fluid.ale.solver.import_base_shape', &
2200 import_base_shapes, .false.)
2202 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2205 call json_get_or_default(json, &
2206 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2208 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2209 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2213 call json_get_or_default(json, &
2214 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2215 call json_get_or_default(json,
'case.fluid.ale.solver.monitor', &
2216 res_monitor, .false.)
2217 call json_get_or_default(json,
'case.fluid.ale.solver.max_iterations', &
2218 ksp_max_iter, 10000)
2220 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2221 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2222 this%config%if_output_phi = tmp_logical
2224 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2225 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2226 this%config%if_output_stiffness = tmp_logical
2230 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2231 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2232 this%config%stiffness_type = tmp_str
2233 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2234 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2244 type(coef_t),
target,
intent(inout) :: coef
2245 type(chkp_t),
intent(inout) :: checkpoint
2246 type(checkpoint_payload_t),
pointer :: payload
2248 if (.not. this%active)
return
2251 call payload%add_field(this%wm_x)
2252 call payload%add_field(this%wm_y)
2253 call payload%add_field(this%wm_z)
2254 call payload%add_series(this%wm_x_lag)
2255 call payload%add_series(this%wm_y_lag)
2256 call payload%add_series(this%wm_z_lag)
2257 call payload%add_mesh_array(
"mesh_x", coef%dof%x%x, coef%msh, coef%Xh, &
2259 call payload%add_mesh_array(
"mesh_y", coef%dof%y%x, coef%msh, coef%Xh, &
2261 call payload%add_mesh_array(
"mesh_z", coef%dof%z%x, coef%msh, coef%Xh, &
2263 call payload%add_mesh_array(
"B_lag", coef%Blag, coef%msh, coef%Xh, &
2265 call payload%add_mesh_array(
"B_laglag", coef%Blaglag, coef%msh, &
2266 coef%Xh, coef%Blaglag_d)
2267 call payload%add_array(
"pivot_position", this%global_pivot_pos, &
2268 replicated = .true.)
2269 call payload%add_array(
"pivot_velocity_lag", &
2270 this%global_pivot_vel_lag, replicated = .true.)
2271 call payload%add_array(
"basis_position", this%global_basis_pos, &
2272 replicated = .true.)
2273 call payload%add_array(
"basis_velocity_lag", &
2274 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...
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 ale_precon_factory(pc, ksp, coef, bclst, pctype, json)
Factory for ALE Preconditioner.
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.
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.
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.
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,...
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.
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.
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...