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, solver_params
185 integer,
allocatable :: zone_indices(:)
186 integer :: time_order
187 integer :: n_moving_zones
188 integer :: z, tmp_int
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 :: 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, import_base_shapes, solver_params)
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 solver_params, precon_type, precon_params)
805 if (.not. json%valid_path(
'case.restart_file'))
then
809 call this%update_mesh_velocity(coef, t_init)
812 call this%wm_x_lag%init(this%wm_x, 2)
813 call this%wm_y_lag%init(this%wm_y, 2)
814 call this%wm_z_lag%init(this%wm_z, 2)
816 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
817 if (
allocated(bc_type))
deallocate(bc_type)
818 if (
allocated(zone_indices))
deallocate(zone_indices)
819 if (
allocated(ksp_solver))
deallocate(ksp_solver)
820 if (
allocated(precon_type))
deallocate(precon_type)
821 if (
allocated(tmp_str))
deallocate(tmp_str)
822 if (
allocated(tmp_vec))
deallocate(tmp_vec)
825 call this%mesh_preview(coef, json)
828 call this%register_checkpoint_fields(coef, chkp)
838 import_base_shapes, solver_params, precon_type, precon_params)
840 class(
ax_t),
allocatable :: Ax
841 class(
ksp_t),
allocatable :: ksp
842 class(
pc_t),
allocatable :: pc
843 type(
coef_t),
intent(inout) :: coef
844 type(json_file),
intent(inout) :: json
845 logical,
intent(in) :: import_base_shapes
846 type(json_file),
intent(inout) :: solver_params
847 character(len=*),
intent(in) :: precon_type
848 type(json_file),
intent(inout) :: precon_params
850 type(
field_t),
pointer :: phi_ptr => null()
854 real(kind=
rp) :: sample_start_time, sample_end_time
855 real(kind=
rp) :: sample_time
856 character(len=LOG_SIZE) :: log_buf
857 integer :: n, i, m, k, ierr, body_idx, z_idx
859 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
860 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
865 type(json_file) :: body_sub
866 character(len=256) :: phi_fname
867 character(len=:),
allocatable :: tmp_str
870 if (.not. this%active)
return
871 if (.not. this%has_moving_boundary)
return
872 if (this%config%nbodies .eq. 0)
return
874 if (import_base_shapes)
then
876 call neko_log%message(
"Importing ALE base shapes" // &
877 " (skipping Laplace solve)...")
879 do body_idx = 1, this%config%nbodies
884 call json_get(body_sub,
'base_shape_import_file', tmp_str)
887 phi_ptr => this%base_shapes(body_idx)
892 call neko_log%message(
" Loaded: " // &
895 trim(this%config%bodies(body_idx)%name))
902 call neko_log%message(
"Starting base mesh motion solve ...")
905 call ax_helm_allocator(ax, type_name =
"standard")
914 call rhs_field%init(coef%dof)
915 call corr_field%init(coef%dof)
919 if (.not.
associated(this%user_ale_base_shapes, &
921 call neko_log%message(
" Using user-defined base shapes " // &
922 "(skipping Laplace solve)")
925 call this%user_ale_base_shapes(this%base_shapes)
928 if (this%config%nbodies .gt. 1)
then
930 do body_idx = 1, this%config%nbodies
931 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
936 if (this%config%if_output_phi)
then
938 do body_idx = 1, this%config%nbodies
939 call phi_file%init(
'phi_' // &
940 trim(this%config%bodies(body_idx)%name) //
'.fld', &
942 select type (ft => phi_file%file_type)
944 ft%skip_pressure = .false.
946 call phi_file%write(this%base_shapes(body_idx))
949 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
953 if (this%config%nbodies .gt. 1)
then
954 call neko_log%message(
" phi_total.fld saved.")
955 select type (ft => phi_file%file_type)
957 ft%skip_pressure = .false.
959 call phi_file%init(
'phi_total.fld', precision =
rp)
960 call phi_file%write(this%phi_total)
971 if (this%config%if_output_stiffness)
then
972 rhs_field%x = coef%h1
973 call phi_file%init(
'stiffness.fld')
974 call phi_file%write(rhs_field)
980 do body_idx = 1, this%config%nbodies
982 sample_start_time = mpi_wtime()
983 call neko_log%message(
" Solving laplace for body: " // &
984 trim(this%config%bodies(body_idx)%name))
986 call bc_active_body%init_from_components(coef)
987 call bc_inactive_body%init_from_components(coef)
990 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
991 z_idx = this%config%bodies(body_idx)%zone_indices(j)
992 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
995 do i = 1, this%config%nbodies
996 if (i /= body_idx)
then
997 do j = 1,
size(this%config%bodies(i)%zone_indices)
998 z_idx = this%config%bodies(i)%zone_indices(j)
999 call bc_inactive_body%mark_zone(&
1000 coef%msh%labeled_zones(z_idx))
1005 call bc_active_body%finalize()
1006 call bc_inactive_body%finalize()
1009 call bc_projector%mark(this%bc_fixed)
1010 call bc_projector%mark(bc_active_body)
1011 call bc_projector%mark(bc_inactive_body)
1014 call bc_projector_zeros_only%mark(this%bc_fixed)
1015 call bc_projector_zeros_only%mark(bc_inactive_body)
1018 this%base_shapes(body_idx)%x = 0.0_rp
1019 rhs_field%x = 0.0_rp
1020 corr_field%x = 0.0_rp
1027 m = bc_active_body%msk(0)
1029 k = bc_active_body%msk(i)
1030 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1041 call bc_projector_zeros_only%apply(this%base_shapes(body_idx)%x, n)
1045 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1046 coef, coef%msh, coef%Xh)
1051 call bc_projector%apply(rhs_field%x, n)
1052 call coef%gs_h%op(rhs_field, gs_op_add)
1057 monitor(1) = ksp%solve(ax, corr_field, &
1058 rhs_field%x, n, coef, bc_projector, coef%gs_h)
1061 call field_add2(this%base_shapes(body_idx), corr_field, n)
1065 if (this%config%nbodies .gt. 1)
then
1066 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1070 sample_end_time = mpi_wtime()
1071 sample_time = sample_end_time - sample_start_time
1072 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1073 trim(this%config%bodies(body_idx)%name),
"' took ", &
1078 call bc_active_body%free()
1079 call bc_inactive_body%free()
1080 call bc_projector%free()
1081 call bc_projector_zeros_only%free()
1091 if (this%config%if_output_phi)
then
1092 call phi_file%init(
'phi_' // &
1093 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1095 select type (ft => phi_file%file_type)
1097 ft%skip_pressure = .false.
1099 call phi_file%write(this%base_shapes(body_idx))
1100 call phi_file%free()
1102 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1106 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1109 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1113 call neko_log%message(
" phi_total.fld saved.")
1114 call phi_file%init(
'phi_total.fld', precision =
rp)
1115 select type (ft => phi_file%file_type)
1117 ft%skip_pressure = .false.
1119 call phi_file%write(this%phi_total)
1120 call phi_file%free()
1124 call rhs_field%free()
1125 call corr_field%free()
1126 if (this%config%nbodies > 1)
then
1127 call this%phi_total%free()
1131 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1132 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1138 if (
allocated(h1_restore))
deallocate(h1_restore)
1139 if (
allocated(h2_restore))
deallocate(h2_restore)
1140 if (
allocated(ax))
then
1144 if (
allocated(ksp))
then
1148 if (
allocated(pc))
then
1159 type(
coef_t),
intent(in) :: coef
1163 real(kind=
rp) :: rot_mat(3,3)
1164 real(kind=
rp) :: initial_rot_center(3)
1166 if (.not. this%active)
return
1167 if (.not. this%has_moving_boundary)
return
1174 do i = 1, this%config%nbodies
1178 this%config%bodies(i), time_s)
1181 if (.not.
associated(this%user_ale_rigid_kinematics, &
1183 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1185 current_kin%vel_trans, &
1186 current_kin%vel_ang)
1189 current_kin%center = this%ale_pivot(i)%pos
1190 this%ale_pivot(i)%vel = current_kin%vel_trans
1192 this%body_kin(i)%center = this%ale_pivot(i)%pos
1193 this%body_kin(i)%vel_trans = current_kin%vel_trans
1194 this%body_kin(i)%vel_ang = current_kin%vel_ang
1197 call this%compute_rotation_matrix(i, time_s)
1198 rot_mat = this%body_rot_matrices(:,:,i)
1199 initial_rot_center = this%config%bodies(i)%rot_center
1203 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1204 this%base_shapes(i), coef, current_kin, rot_mat, &
1208 call this%prep_checkpoint(i)
1214 if (.not.
associated(this%user_ale_mesh_vel, &
1216 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1217 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1227 type(
coef_t),
intent(inout) :: coef
1229 integer,
intent(in) :: nadv
1232 if (.not. this%active)
return
1233 if (.not. this%has_moving_boundary)
return
1235 do i = 1, this%config%nbodies
1240 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1243 this%ale_pivot(i)%pos, &
1244 this%ale_pivot(i)%vel, &
1247 this%config%bodies(i))
1251 call coef%update_B_history()
1255 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1259 call this%wm_x_lag%update()
1260 call this%wm_y_lag%update()
1261 call this%wm_z_lag%update()
1267 type(
coef_t),
intent(inout) :: coef
1269 integer :: i, n, b, ierr
1270 integer,
allocatable :: cheap_map(:)
1271 integer :: n_cheap, map_idx
1272 real(kind=
rp) :: x, y, z
1273 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1274 real(kind=
rp) :: cx, cy, cz
1275 real(kind=
rp) :: arg, decay, gain, norm_dist
1276 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1277 type(
field_t),
allocatable :: dist_fields(:)
1278 character(len=128) :: log_buf
1283 allocate(cheap_map(params%nbodies))
1287 do b = 1, params%nbodies
1288 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1289 n_cheap = n_cheap + 1
1290 cheap_map(b) = n_cheap
1295 if (n_cheap > 0)
then
1296 allocate(dist_fields(n_cheap))
1298 do b = 1, params%nbodies
1299 map_idx = cheap_map(b)
1300 if (map_idx .gt. 0)
then
1302 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1305 call neko_log%message(
" Start: cheap dist calculation " // &
1306 "for body '" // trim(params%bodies(b)%name) //
"'")
1309 sample_start_time = mpi_wtime()
1313 coef%msh, params%bodies(b)%zone_indices, &
1314 copy_to_host = .true.)
1317 coef%msh, params%bodies(b)%zone_indices)
1321 sample_end_time = mpi_wtime()
1322 sample_time = sample_end_time - sample_start_time
1324 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1325 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1333 select case (trim(params%stiffness_type))
1336 do concurrent(i = 1:n)
1337 x = coef%dof%x%x(i, 1, 1, 1)
1338 y = coef%dof%y%x(i, 1, 1, 1)
1339 z = coef%dof%z%x(i, 1, 1, 1)
1341 max_added_stiff = 0.0_rp
1344 do b = 1, params%nbodies
1345 gain = params%bodies(b)%stiff_geom%gain
1346 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1347 decay = params%bodies(b)%stiff_geom%stiff_dist
1349 decay = params%bodies(b)%stiff_geom%radius
1353 cx = params%bodies(b)%stiff_geom%center(1)
1354 cy = params%bodies(b)%stiff_geom%center(2)
1355 cz = params%bodies(b)%stiff_geom%center(3)
1357 raw_dist = huge(0.0_rp)
1360 select case (trim(params%bodies(b)%stiff_geom%type))
1362 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1366 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1372 map_idx = cheap_map(b)
1373 if (map_idx .gt. 0)
then
1374 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1379 body_stiff_val = 0.0_rp
1380 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1383 arg = -(raw_dist**2) / (decay**2)
1384 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1385 body_stiff_val = gain * exp(arg)
1389 norm_dist = (raw_dist / decay)
1390 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1391 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1394 if (body_stiff_val .gt. max_added_stiff)
then
1395 max_added_stiff = body_stiff_val
1399 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1400 coef%h2(i, 1, 1, 1) = 0.0_rp
1404 call neko_error(
"ALE Manager: Unknown stiffness type")
1414 if (
allocated(dist_fields))
then
1415 do i = 1,
size(dist_fields)
1416 call dist_fields(i)%free()
1418 deallocate(dist_fields)
1420 if (
allocated(cheap_map))
deallocate(cheap_map)
1426 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1427 type(
field_t),
intent(inout) :: wx, wy, wz
1428 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1429 type(
field_t),
intent(in) :: phi
1430 type(
coef_t),
intent(in) :: coef
1432 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1433 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1436 x_ref, y_ref, z_ref, &
1437 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1440 x_ref, y_ref, z_ref, &
1441 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1447 wm_z_lag, time, nadv, scheme_)
1448 type(
coef_t),
intent(inout) :: c_xh
1449 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1452 integer,
intent(in) :: nadv
1453 character(len=*),
intent(in) :: scheme_
1456 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1459 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1468 if (.not. this%active)
return
1470 call this%bc_moving%free()
1471 call this%bc_fixed%free()
1472 call this%bc_list%free()
1474 if (
allocated(this%base_shapes))
then
1475 do i = 1,
size(this%base_shapes)
1476 call this%base_shapes(i)%free()
1478 deallocate(this%base_shapes)
1481 call this%wm_x_lag%free()
1482 call this%wm_y_lag%free()
1483 call this%wm_z_lag%free()
1484 call this%x_ref%free()
1485 call this%y_ref%free()
1486 call this%z_ref%free()
1488 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1489 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1490 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1491 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1492 if (
associated(this%global_pivot_vel_lag)) &
1493 deallocate(this%global_pivot_vel_lag)
1494 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1495 if (
associated(this%global_basis_vel_lag)) &
1496 deallocate(this%global_basis_vel_lag)
1497 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1498 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1499 if (
allocated(this%trackers))
deallocate(this%trackers)
1506 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1507 class(
ksp_t),
target,
intent(inout) :: ksp
1508 type(
coef_t),
target,
intent(in) :: coef
1509 type(
bc_list_t),
target,
intent(inout) :: bclst
1510 character(len=*),
intent(in) :: pctype
1511 type(json_file),
intent(inout) :: json
1513 call precon_factory(pc, pctype, coef, bclst, json)
1520 real(kind=
dp),
intent(in) :: time_restart
1522 integer :: i, idx, handle_1, handle_2, offset_base
1524 time_state_dummy%t = time_restart
1528 do i = 1, this%config%nbodies
1531 this%config%bodies(i), time_state_dummy)
1534 if (.not.
associated(this%user_ale_rigid_kinematics, &
1536 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1538 kin_restart%vel_trans, &
1539 kin_restart%vel_ang)
1542 this%ale_pivot(i)%vel = kin_restart%vel_trans
1546 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1547 this%body_kin(i)%center = this%ale_pivot(i)%pos
1548 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1549 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1552 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1553 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1556 offset_base = (i-1)*6
1557 handle_1 = this%ghost_handles(1, i)
1558 handle_2 = this%ghost_handles(2, i)
1560 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1561 this%trackers(handle_1)%pos = &
1562 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1565 this%trackers(handle_1)%vel_lag = &
1566 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1569 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1570 this%trackers(handle_2)%pos = &
1571 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1574 this%trackers(handle_2)%vel_lag = &
1575 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1585 type(
coef_t),
intent(inout) :: coef
1586 type(
space_t),
intent(inout) :: Xh
1587 type(
chkp_t),
intent(in) :: chkp
1588 type(
gs_t),
intent(inout) :: gs_Xh
1592 if (.not. this%active)
return
1594 if (
allocated(chkp%previous_mesh%elements))
then
1596 "The current mesh has a different number " // &
1597 "of elements than the checkpoint.")
1601 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1603 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1604 do concurrent(j = 1:n)
1606 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1607 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1608 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1612 do i = 1, this%wm_x_lag%size()
1613 do concurrent(j = 1:n)
1614 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1615 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1616 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1617 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1618 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1619 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1629 call this%wm_x_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1630 call this%wm_x_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1632 call this%wm_y_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1633 call this%wm_y_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1635 call this%wm_z_lag%lf(1)%copy_from(
host_to_device, sync = .false.)
1636 call this%wm_z_lag%lf(2)%copy_from(
host_to_device, sync = .false.)
1638 if (c_associated(coef%dof%x%x_d))
then
1644 if (c_associated(coef%Blag_d))
then
1645 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1649 if (c_associated(coef%Blaglag_d))
then
1657 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1658 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1659 call gs_xh%op(this%wm_x, gs_op_add)
1660 call gs_xh%op(this%wm_y, gs_op_add)
1661 call gs_xh%op(this%wm_z, gs_op_add)
1662 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1664 do i = 1, this%wm_x_lag%size()
1665 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1666 this%wm_z_lag%lf(i)%x, 1, coef)
1667 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1668 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1669 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
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, 0, coef)
1676 call this%set_pivot_restart(chkp%t)
1677 call coef%recompute_metrics()
1684 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1686 coef%Blaglag = coef%B
1688 if (c_associated(coef%Blag_d))
then
1692 if (c_associated(coef%Blaglag_d))
then
1700 call adv%recompute_metrics(coef, .true.)
1705 integer,
intent(in) :: body_idx
1706 integer :: idx, offset_base, h1, h2
1708 if (.not. this%active)
return
1709 if (.not. this%has_moving_boundary)
return
1711 idx = (body_idx - 1) * 3
1712 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1713 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1714 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1716 h1 = this%ghost_handles(1, body_idx)
1717 h2 = this%ghost_handles(2, body_idx)
1719 offset_base = (body_idx-1)*6
1722 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1723 this%get_tracker_pos(h1)
1724 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1725 this%get_tracker_pos(h2)
1728 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1729 this%trackers(h1)%vel_lag
1732 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1733 this%trackers(h2)%vel_lag
1738 integer,
allocatable,
intent(inout) :: arr(:)
1739 integer,
intent(inout) :: n
1740 integer,
intent(in) :: val
1741 integer,
allocatable :: tmp(:)
1745 if (arr(k) .eq. val)
return
1748 allocate(tmp(n + 1))
1749 if (n .gt. 0) tmp(1:n) = arr(1:n)
1752 if (
allocated(arr))
deallocate(arr)
1753 call move_alloc(tmp, arr)
1761 type(coef_t),
intent(inout) :: coef
1762 type(json_file),
intent(inout) :: json
1763 type(fld_file_output_t) :: fout
1764 type(field_t) :: dummy_field
1765 type(time_state_t) :: t_state
1766 type(file_t) :: out_file
1767 real(kind=rp) :: t_start
1768 real(kind=rp) :: t_end
1770 real(kind=rp) :: min_jac
1771 integer :: output_freq
1772 integer :: step, n_steps
1773 integer :: nadv, nadv_sim
1775 logical :: mesh_preview_active
1776 character(len=128) :: log_buf
1778 mesh_preview_active = .false.
1780 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1781 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1782 mesh_preview_active)
1785 if (.not. mesh_preview_active)
return
1787 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1789 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1791 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1793 call json_get(json, &
1794 'case.fluid.ale.mesh_preview.output_freq', &
1797 call neko_log%section(
"ALE Mesh Preview")
1798 call neko_log%message(
"Executing mesh motion preview...")
1800 n_steps = int((t_end - t_start) / dt)
1801 call json_get(json,
'case.numerics.time_order', nadv_sim)
1803 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1804 call neko_log%message(log_buf)
1805 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1806 call neko_log%message(log_buf)
1807 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1808 call neko_log%message(log_buf)
1809 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1810 call neko_log%message(log_buf)
1811 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1812 call neko_log%message(log_buf)
1813 call neko_log%message(
'')
1816 call dummy_field%init(coef%dof,
"mesh_preview")
1817 call field_rzero(dummy_field)
1819 call fout%init(rp,
"mesh_preview", 1)
1820 call fout%fields%assign_to_field(1, dummy_field)
1821 select type (ft => fout%file_%file_type)
1822 type is (fld_file_t)
1823 ft%write_mesh = .true.
1824 ft%skip_pressure = .false.
1837 if (neko_bcknd_device .eq. 1)
then
1838 min_jac = device_glmin(coef%jac_d, n)
1840 min_jac = glmin(coef%jac, n)
1844 call fout%sample(t_state%t)
1846 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1847 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1848 t_state%t,
" | Min Jac: ", min_jac
1850 call neko_log%message(trim(log_buf))
1851 call this%update_mesh_velocity(coef, t_state)
1853 do step = 1, n_steps
1854 t_state%tstep = step
1855 t_state%t = t_start + (step * dt)
1856 nadv = min(step, nadv_sim)
1858 call this%advance_mesh(coef, t_state, nadv)
1859 call coef%recompute_metrics()
1862 if (neko_bcknd_device .eq. 1)
then
1863 min_jac = device_glmin(coef%jac_d, n)
1865 min_jac = glmin(coef%jac, n)
1868 if (min_jac .le. 0.0_rp)
then
1869 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1870 "Negative Jacobian detected (", min_jac,
") at t = ", &
1872 call neko_log%message(log_buf)
1875 call fout%sample(t_state%t)
1877 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1878 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1879 t_state%t,
" | Min Jac:", min_jac
1880 call neko_log%message(trim(log_buf))
1882 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1885 if (mod(step, output_freq) .eq. 0)
then
1888 call fout%sample(t_state%t)
1890 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1891 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1892 t_state%t,
" | Min Jac:", min_jac
1893 call neko_log%message(trim(log_buf))
1897 call this%update_mesh_velocity(coef, t_state)
1901 call dummy_field%free()
1903 call neko_log%end_section()
1904 call neko_log%message(
"Mesh preview complete.")
1905 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1910 type(fld_file_output_t) :: fout
1911 type(coef_t),
intent(inout) :: coef
1912 type(field_t),
intent(inout) :: dummy_field
1916 if (neko_bcknd_device .eq. 1)
then
1917 call device_copy(dummy_field%x_d, coef%B_d, n)
1919 call copy(dummy_field%x, coef%B, n)
1922 if (neko_bcknd_device .eq. 1)
then
1923 associate(
mesh => coef%dof)
1924 call device_memcpy(
mesh%x%x,
mesh%x%x_d,
mesh%size(), &
1925 device_to_host, sync = .false.)
1926 call device_memcpy(
mesh%y%x,
mesh%y%x_d,
mesh%size(), &
1927 device_to_host, sync = .false.)
1928 call device_memcpy(
mesh%z%x,
mesh%z%x_d,
mesh%size(), &
1929 device_to_host, sync = .false.)
1939 real(kind=rp),
intent(in) :: initial_pos(3)
1940 integer,
intent(in) :: body_id
1942 type(point_tracker_t),
allocatable :: tmp(:)
1945 if (.not. this%active)
return
1946 if (.not. this%has_moving_boundary)
return
1948 if (.not.
allocated(this%trackers))
then
1949 allocate(this%trackers(30))
1951 elseif (this%n_trackers .ge.
size(this%trackers))
then
1952 allocate(tmp(
size(this%trackers) + 30))
1953 tmp(1:
size(this%trackers)) = this%trackers
1954 deallocate(this%trackers)
1955 call move_alloc(tmp, this%trackers)
1957 this%n_trackers = this%n_trackers + 1
1958 handle = this%n_trackers
1960 this%trackers(handle)%pos = initial_pos
1961 this%trackers(handle)%body_id = body_id
1962 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
1967 integer,
intent(in) :: handle
1968 real(kind=rp) :: pos(3)
1970 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
1971 pos = this%trackers(handle)%pos
1981 integer,
intent(in) :: body_idx
1982 type(time_state_t),
intent(in) :: time
1984 real(kind=rp) :: p(3), gx(3), gy(3)
1985 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
1987 if (.not. this%active)
return
1988 if (.not. this%has_moving_boundary)
return
1991 h_x = this%ghost_handles(1, body_idx)
1992 h_y = this%ghost_handles(2, body_idx)
1994 p = this%ale_pivot(body_idx)%pos
1995 gx = this%get_tracker_pos(h_x)
1996 gy = this%get_tracker_pos(h_y)
2000 u = u / sqrt(sum(u**2))
2004 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2005 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2006 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2007 w = w / sqrt(sum(w**2))
2010 v(1) = w(2)*u(3) - w(3)*u(2)
2011 v(2) = w(3)*u(1) - w(1)*u(3)
2012 v(3) = w(1)*u(2) - w(2)*u(1)
2014 this%body_rot_matrices(:, 1, body_idx) = u
2015 this%body_rot_matrices(:, 2, body_idx) = v
2016 this%body_rot_matrices(:, 3, body_idx) = w
2026 type(time_state_t),
intent(in) :: time
2027 integer,
optional,
intent(in) :: body_idxs(:)
2029 integer :: i, idx, n_log
2030 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2031 real(kind=rp) :: r(3,3)
2032 character(len=256) :: log_buf
2033 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2035 if (.not. this%active)
return
2036 if (.not. this%has_moving_boundary)
return
2038 if (
present(body_idxs))
then
2039 n_log =
size(body_idxs)
2041 n_log = this%config%nbodies
2044 call neko_log%message(
" ")
2045 call neko_log%message(
"---------Rotation log---------")
2046 call neko_log%message(
"variable, time step, time, body, " // &
2047 "x_val, y_val, z_val")
2052 if (
present(body_idxs))
then
2058 r = this%body_rot_matrices(:, :, idx)
2061 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2062 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2063 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2066 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2067 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2068 trim(this%config%bodies(idx)%name),
" ", &
2069 roll_deg, pitch_deg, yaw_deg
2070 call neko_log%message(trim(log_buf))
2081 type(time_state_t),
intent(in) :: time
2082 integer,
optional,
intent(in) :: body_idxs(:)
2083 integer :: i, idx, n_log
2084 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2085 character(len=256) :: log_buf
2087 if (.not. this%active)
return
2088 if (.not. this%has_moving_boundary)
return
2090 if (
present(body_idxs))
then
2091 n_log =
size(body_idxs)
2093 n_log = this%config%nbodies
2096 call neko_log%message(
" ")
2097 call neko_log%message(
"----------Pivot Log-----------")
2098 call neko_log%message(
"variable, time step, time, body, " // &
2099 "x_val, y_val, z_val")
2104 if (
present(body_idxs))
then
2110 pivot_pos = this%ale_pivot(idx)%pos
2111 pivot_vel = this%ale_pivot(idx)%vel
2114 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2115 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2116 trim(this%config%bodies(idx)%name),
" ", &
2117 this%ale_pivot(idx)%pos
2118 call neko_log%message(trim(log_buf))
2121 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2122 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2123 trim(this%config%bodies(idx)%name),
" ", &
2124 this%ale_pivot(idx)%vel
2125 call neko_log%message(trim(log_buf))
2132 type(body_kinematics_t),
intent(in) :: kin_object
2133 type(time_state_t),
intent(in) :: time_s
2134 integer,
intent(in) :: nadv
2135 integer,
intent(in) :: body_idx
2137 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2139 if (.not. this%active)
return
2140 if (.not. this%has_moving_boundary)
return
2142 if (
allocated(this%trackers))
then
2143 do t = 1, this%n_trackers
2144 if (this%trackers(t)%body_id .eq. &
2145 this%config%bodies(body_idx)%id)
then
2146 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2147 t .eq. this%ghost_handles(2, body_idx))
then
2150 rel_pos = this%trackers(t)%pos - kin_object%center
2153 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2154 kin_object%vel_ang(3) * rel_pos(2)
2155 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2156 kin_object%vel_ang(1) * rel_pos(3)
2157 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2158 kin_object%vel_ang(2) * rel_pos(1)
2161 p_vel = kin_object%vel_trans + v_tan
2163 if (time_s%tstep .gt. 0)
then
2164 call ab_integrate_point_pos(this%trackers(t)%pos, &
2165 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2177 precon_params, abstol, import_base_shapes, solver_params)
2179 type(json_file),
intent(inout) :: json
2180 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2181 character(len=:),
allocatable,
intent(inout) :: precon_type
2182 type(json_file),
intent(inout) :: precon_params
2183 real(kind=rp),
intent(out) :: abstol
2184 logical,
intent(out) :: import_base_shapes
2185 type(json_file),
intent(inout) :: solver_params
2186 logical :: tmp_logical
2187 character(len=:),
allocatable :: tmp_str
2189 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2190 if (
allocated(precon_type))
deallocate(precon_type)
2192 call json_get_or_default(json, &
2193 'case.fluid.ale.solver.import_base_shape', &
2194 import_base_shapes, .false.)
2196 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2199 call json_get_or_default(json, &
2200 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2202 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2203 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2207 call json_get_or_default(json, &
2208 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2210 call json_get(json,
'case.fluid.ale.solver', solver_params)
2212 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2213 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2214 this%config%if_output_phi = tmp_logical
2216 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2217 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2218 this%config%if_output_stiffness = tmp_logical
2222 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2223 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2224 this%config%stiffness_type = tmp_str
2225 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2226 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2236 type(coef_t),
target,
intent(inout) :: coef
2237 type(chkp_t),
intent(inout) :: checkpoint
2238 type(checkpoint_payload_t),
pointer :: payload
2240 if (.not. this%active)
return
2243 call payload%add_field(this%wm_x)
2244 call payload%add_field(this%wm_y)
2245 call payload%add_field(this%wm_z)
2246 call payload%add_series(this%wm_x_lag)
2247 call payload%add_series(this%wm_y_lag)
2248 call payload%add_series(this%wm_z_lag)
2249 call payload%add_mesh_array(
"mesh_x", coef%dof%x%x, coef%msh, coef%Xh, &
2251 call payload%add_mesh_array(
"mesh_y", coef%dof%y%x, coef%msh, coef%Xh, &
2253 call payload%add_mesh_array(
"mesh_z", coef%dof%z%x, coef%msh, coef%Xh, &
2255 call payload%add_mesh_array(
"B_lag", coef%Blag, coef%msh, coef%Xh, &
2257 call payload%add_mesh_array(
"B_laglag", coef%Blaglag, coef%msh, &
2258 coef%Xh, coef%Blaglag_d)
2259 call payload%add_array(
"pivot_position", this%global_pivot_pos, &
2260 replicated = .true.)
2261 call payload%add_array(
"pivot_velocity_lag", &
2262 this%global_pivot_vel_lag, replicated = .true.)
2263 call payload%add_array(
"basis_position", this%global_basis_pos, &
2264 replicated = .true.)
2265 call payload%add_array(
"basis_velocity_lag", &
2266 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.
Factory for Krylov solvers. Both creates and initializes the object, either from its parameters or fr...
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 solve_base_mesh_displacement(this, coef, json, import_base_shapes, solver_params, precon_type, precon_params)
Solves the Laplace equation to determine the base shape (phi) for each body. It finds a smooth blendi...
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 get_ale_solver_params_json(this, json, ksp_solver, precon_type, precon_params, abstol, import_base_shapes, solver_params)
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 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)
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...