36 use json_module,
only : json_file
43 use precon,
only :
pc_t, precon_allocator, precon_destroy
68 use mpi_f08,
only : mpi_wtime, mpi_barrier
86 use,
intrinsic :: iso_c_binding, only : c_associated
98 logical :: active = .false.
99 logical :: has_moving_boundary = .false.
131 real(kind=
rp),
pointer :: global_pivot_pos(:) => null()
132 real(kind=
rp),
pointer :: global_pivot_vel_lag(:, :) => null()
135 real(kind=
rp),
pointer :: global_basis_pos(:) => null()
137 real(kind=
rp),
pointer :: global_basis_vel_lag(:, :) => null()
139 integer,
allocatable :: ghost_handles(:,:)
141 real(kind=
rp),
allocatable :: body_rot_matrices(:,:,:)
144 integer :: n_trackers = 0
147 user_ale_mesh_vel => null()
149 user_ale_base_shapes => null()
151 user_ale_rigid_kinematics => null()
180 type(
coef_t),
intent(inout) :: coef
181 type(json_file),
intent(inout) :: json
182 type(
user_t),
intent(in) :: user
183 type(
chkp_t),
intent(inout) :: chkp
184 type(json_file) :: body_sub, bc_subdict
185 type(json_file) :: precon_params
187 integer,
allocatable :: zone_indices(:)
188 integer :: time_order
189 integer :: n_moving_zones
190 integer :: z, tmp_int, ksp_max_iter
191 integer,
allocatable :: moving_zone_ids(:)
192 integer :: i, j, k, n_bcs, n, n_bodies
193 real(kind=
rp),
allocatable :: tmp_vec(:)
194 real(kind=
rp) :: tmp_val, abstol
195 character(len=128) :: log_buf
196 character(len=256) :: log_buf_l
197 character(len=:),
allocatable :: bc_type
198 character(len=:),
allocatable :: tmp_str
199 character(len=:),
allocatable :: ksp_solver
200 character(len=:),
allocatable :: precon_type
201 logical :: tmp_logical, oifs
203 logical :: found_zone
204 logical :: has_user_rigid_kin, has_user_mesh_vel
205 logical :: has_builtin_osc, has_builtin_rot, is_rot_active
206 logical :: res_monitor, import_base_shapes
208 if (json%valid_path(
'case.fluid.ale'))
then
209 call json_get(json,
'case.fluid.ale.enabled', this%active)
213 if (.not. this%active)
then
216 else if (this%active)
then
218 call coef%msh%all_deformed()
224 "supported only with HIP or CUDA backend.")
228 call neko_error(
"ALE not currently supported with OIFS.")
230 if (json%valid_path(
'case.checkpoint_format'))
then
231 call json_get(json,
'case.checkpoint_format', tmp_str)
232 if (trim(tmp_str) /=
'chkp')
then
233 call neko_error(
"ALE is not supported with the '" // &
235 "' checkpoint format. Please use 'chkp'.")
241 call neko_log%section(
"ALE Initialization")
245 call neko_log%message(
"Initializing ALE " // &
246 "with device backend (HIP).")
248 call neko_log%message(
"Initializing ALE " // &
249 "with device backend (CUDA).")
251 call neko_log%message(
"Initializing ALE " // &
255 tmp_logical = .false.
258 call this%x_ref%init(coef%dof,
"x_ref")
259 call this%y_ref%init(coef%dof,
"y_ref")
260 call this%z_ref%init(coef%dof,
"z_ref")
262 call copy(this%x_ref%x, coef%dof%x, n)
263 call copy(this%y_ref%x, coef%dof%y, n)
264 call copy(this%z_ref%x, coef%dof%z, n)
274 this%user_ale_mesh_vel =>
user%ale_mesh_velocity
275 this%user_ale_base_shapes =>
user%ale_base_shapes
276 this%user_ale_rigid_kinematics =>
user%ale_rigid_kinematics
279 has_user_rigid_kin = .not.
associated(this%user_ale_rigid_kinematics, &
281 has_user_mesh_vel = .not.
associated(this%user_ale_mesh_vel, &
285 call coef%enable_B_history()
286 call json_get(json,
'case.numerics.time_order', time_order)
290 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
291 allocate(moving_zone_ids(0))
302 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
305 call this%bc_moving%init_from_components(coef)
306 call this%bc_fixed%init_from_components(coef)
308 if (json%valid_path(
'case.fluid.boundary_conditions'))
then
309 call json%info(
'case.fluid.boundary_conditions', n_children = n_bcs)
315 if (
allocated(bc_type))
deallocate(bc_type)
316 call json_get(bc_subdict,
'type', bc_type)
318 if (
allocated(zone_indices))
deallocate(zone_indices)
319 call json_get(bc_subdict,
'zone_indices', zone_indices)
322 if (trim(bc_type) .eq.
'no_slip')
then
327 do j = 1,
size(zone_indices)
331 call this%bc_moving%mark_zone(coef%msh%labeled_zones(&
334 this%has_moving_boundary = .true.
336 do j = 1,
size(zone_indices)
337 call this%bc_fixed%mark_zone(coef%msh%labeled_zones(&
344 call this%bc_moving%finalize()
345 call this%bc_fixed%finalize()
346 call this%bc_list%init()
347 call this%bc_list%append(this%bc_moving)
348 call this%bc_list%append(this%bc_fixed)
351 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
352 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
353 this%config%stiffness_type = tmp_str
354 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
355 call neko_error(
"ALE: stiffness_type must be 'built-in'")
359 if (
associated(this%user_ale_base_shapes, &
361 call neko_log%message(
'Solver Type : (' // &
362 trim(ksp_solver) //
', ' // trim(precon_type) //
')')
363 write(log_buf,
'(A,ES13.6)')
'Abs tol :', abstol
365 call neko_log%message(
'Mesh Stiffness : ' // &
366 trim(this%config%stiffness_type))
371 if (json%valid_path(
'case.fluid.ale.bodies'))
then
372 call json%info(
'case.fluid.ale.bodies', n_children = n_bodies)
373 this%config%nbodies = n_bodies
374 allocate(this%config%bodies(n_bodies))
375 allocate(this%ale_pivot(n_bodies))
376 allocate(this%body_kin(n_bodies))
377 allocate(this%base_shapes(n_bodies))
378 allocate(this%global_pivot_pos(3 * this%config%nbodies))
379 allocate(this%global_pivot_vel_lag(3 * this%config%nbodies, 3))
380 allocate(this%global_basis_pos(6 * this%config%nbodies))
381 allocate(this%ghost_handles(2, this%config%nbodies))
382 allocate(this%global_basis_vel_lag(6 * this%config%nbodies, 3))
383 allocate(this%body_rot_matrices(3, 3, this%config%nbodies))
385 this%global_pivot_pos = 0.0_rp
386 this%global_pivot_vel_lag = 0.0_rp
387 this%global_basis_pos = 0.0_rp
388 this%global_basis_vel_lag = 0.0_rp
389 this%body_rot_matrices = 0.0_rp
392 this%body_rot_matrices(1, 1, i) = 1.0_rp
393 this%body_rot_matrices(2, 2, i) = 1.0_rp
394 this%body_rot_matrices(3, 3, i) = 1.0_rp
399 this%config%bodies(i)%id = i
401 if (body_sub%valid_path(
'name'))
then
402 call json_get(body_sub,
'name', tmp_str)
403 this%config%bodies(i)%name = tmp_str
405 write(this%config%bodies(i)%name,
'(A,I0)')
'body_', i
408 if (body_sub%valid_path(
'zone_indices'))
then
409 call json_get(body_sub,
'zone_indices', zone_indices)
410 this%config%bodies(i)%zone_indices = zone_indices
413 trim(this%config%bodies(i)%name) // &
414 " must have 'zone_indices'")
418 this%config%bodies(i)%osc_amp = 0.0_rp
419 this%config%bodies(i)%osc_freq = 0.0_rp
420 if (body_sub%valid_path(
'oscillation'))
then
421 call json_get(body_sub,
'oscillation.amplitude', tmp_vec, &
423 this%config%bodies(i)%osc_amp = tmp_vec
424 call json_get(body_sub,
'oscillation.frequency', tmp_vec, &
426 this%config%bodies(i)%osc_freq = tmp_vec
430 if (body_sub%valid_path(
'rotation'))
then
432 if (.not. body_sub%valid_path(
'pivot'))
then
433 call neko_error(
"ale.bodies.pivot is missing " // &
434 "from the case file.")
437 call json_get(body_sub,
'rotation.type', tmp_str)
438 this%config%bodies(i)%rotation_type = tmp_str
440 select case (trim(tmp_str))
442 call json_get(body_sub,
'rotation.amplitude_deg', tmp_vec, &
444 this%config%bodies(i)%rot_amp_degree = tmp_vec
446 call json_get(body_sub,
'rotation.frequency', tmp_vec, &
448 this%config%bodies(i)%rot_freq = tmp_vec
452 call json_get(body_sub,
'rotation.ramp_t0', tmp_vec, &
454 this%config%bodies(i)%ramp_t0 = tmp_vec
456 call json_get(body_sub,
'rotation.ramp_omega0', tmp_vec, &
458 this%config%bodies(i)%ramp_omega0 = tmp_vec
464 if (tmp_int .ge. 1 .and. tmp_int .le. 3)
then
465 this%config%bodies(i)%rotation_axis = tmp_int
467 call neko_error(
"ALE: rotation.axis must be (integer) " // &
468 "1 -> x, 2 -> y, or 3 -> z")
470 call json_get(body_sub,
'rotation.step_control_times', &
471 tmp_vec, expected_size = 4)
472 this%config%bodies(i)%step_control_times = tmp_vec
474 call json_get(body_sub,
'rotation.target_angle_deg', tmp_val)
475 this%config%bodies(i)%target_rot_angle_deg = tmp_val
478 call neko_error(
"ALE: rotation.type must be 'harmonic', " // &
479 "'ramp', or 'smooth_step'")
484 if (body_sub%valid_path(
'pivot'))
then
487 this%config%bodies(i)%rotation_center_type = tmp_str
488 call json_get(body_sub,
'pivot.value', tmp_vec, expected_size = 3)
489 this%config%bodies(i)%rot_center = tmp_vec
492 tmp_str = this%config%bodies(i)%rotation_center_type
493 if (trim(tmp_str) /=
'relative' .and. &
494 trim(tmp_str) /=
'relative_sin')
then
495 call neko_error(
"ALE: pivot.type must be " // &
496 "'relative', or 'relative_sin'.")
501 if (body_sub%valid_path(
'stiff_geom'))
then
502 call json_get(body_sub,
'stiff_geom.type', tmp_str)
503 this%config%bodies(i)%stiff_geom%type = tmp_str
504 call json_get(body_sub,
'stiff_geom.gain', &
505 this%config%bodies(i)%stiff_geom%gain)
506 call json_get(body_sub,
'stiff_geom.decay_profile', tmp_str)
507 this%config%bodies(i)%stiff_geom%decay_profile = tmp_str
509 select case (trim(this%config%bodies(i)%stiff_geom%decay_profile))
512 'stiff_geom.cutoff_coef', &
513 this%config%bodies(i)%stiff_geom%cutoff_coef, 9.0_rp)
516 'stiff_geom.cutoff_coef', &
517 this%config%bodies(i)%stiff_geom%cutoff_coef, 3.5_rp)
519 call neko_error(
"ALE: Invalid stiff_geom.decay_profile: " // &
520 trim(this%config%bodies(i)%stiff_geom%decay_profile))
523 select case (trim(this%config%bodies(i)%stiff_geom%type))
524 case (
'cylinder',
'sphere')
525 call json_get(body_sub,
'stiff_geom.center', tmp_vec, &
527 this%config%bodies(i)%stiff_geom%center = tmp_vec
529 call json_get(body_sub,
'stiff_geom.radius', &
530 this%config%bodies(i)%stiff_geom%radius)
532 call json_get(body_sub,
'stiff_geom.stiff_dist', &
533 this%config%bodies(i)%stiff_geom%stiff_dist)
535 call neko_error(
"ALE: stiff_geom.type 'box' not yet" // &
538 call neko_error(
"ALE: Invalid stiff_geom.type: " // &
539 trim(this%config%bodies(i)%stiff_geom%type))
541 elseif (import_base_shapes)
then
545 trim(this%config%bodies(i)%name) // &
546 "' must have 'stiff_geom' definition.")
552 call this%base_shapes(i)%init(coef%dof, &
553 "phi_" // trim(this%config%bodies(i)%name))
559 this%ghost_handles(1, i) = this%request_tracker( &
560 this%config%bodies(i)%rot_center + [1.0_rp, 0.0_rp, 0.0_rp], &
561 this%config%bodies(i)%id)
563 this%ghost_handles(2, i) = this%request_tracker( &
564 this%config%bodies(i)%rot_center + [0.0_rp, 1.0_rp, 0.0_rp], &
565 this%config%bodies(i)%id)
567 call neko_log%message(
'Registered Body : ' // &
568 trim(this%config%bodies(i)%name))
572 if (
associated(this%user_ale_base_shapes, &
574 (.not. import_base_shapes))
then
575 write(log_buf,
'(A,A)')
' Stiff Type : ', &
576 trim(this%config%bodies(i)%stiff_geom%type)
578 write(log_buf,
'(A,ES18.11,A,A,A,ES10.4)')
' Gain : ', &
579 this%config%bodies(i)%stiff_geom%gain,
' | Profile: ', &
580 trim(this%config%bodies(i)%stiff_geom%decay_profile), &
581 ' | Cutoff: ', this%config%bodies(i)%stiff_geom%cutoff_coef
583 select case (trim(this%config%bodies(i)%stiff_geom%type))
584 case (
'cylinder',
'sphere')
585 write(log_buf,
'(A,3(ES23.15,1X))')
' Center :', &
586 this%config%bodies(i)%stiff_geom%center
588 write(log_buf,
'(A,ES23.15)')
' Radius :', &
589 this%config%bodies(i)%stiff_geom%radius
592 write(log_buf,
'(A,ES23.15)')
' Stiff Dist:', &
593 this%config%bodies(i)%stiff_geom%stiff_dist
600 has_builtin_osc = any(abs(this%config%bodies(i)%osc_amp) .gt. 0.0_rp)
602 if (has_builtin_osc)
then
603 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
604 call neko_log%message(
' Oscillation : ' // &
605 'X(t) = Amp*sin(2*pi*Freq*t) + User')
606 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
607 this%config%bodies(i)%osc_amp
609 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
610 this%config%bodies(i)%osc_freq
613 call neko_log%message(
' Oscillation : ' // &
614 'X(t) = Amp*sin(2*pi*Freq*t)')
615 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp :', &
616 this%config%bodies(i)%osc_amp
618 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
619 this%config%bodies(i)%osc_freq
623 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
624 call neko_log%message(
' Oscillation : User-defined')
626 call neko_log%message(
' Oscillation : None')
632 has_builtin_rot = (trim(this%config%bodies(i)%rotation_type) &
635 if (trim(this%config%bodies(i)%rotation_type) .eq.
'user')
then
637 call neko_log%message(
' Rotation Type: User-defined')
639 elseif (has_builtin_rot)
then
642 is_rot_active = .false.
643 select case (trim(this%config%bodies(i)%rotation_type))
645 is_rot_active = any(abs(this%config%bodies(i)%rot_amp_degree) &
648 is_rot_active = any(abs(this%config%bodies(i)%ramp_omega0) &
652 (abs(this%config%bodies(i)%target_rot_angle_deg) &
656 if (is_rot_active)
then
658 if (trim(this%config%bodies(i)%rotation_type) &
659 .eq.
'harmonic')
then
660 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
661 call neko_log%message(
' Rotation : ' // &
662 'Theta(t) = Amp*sin(2*pi*Freq*t) + User')
664 call neko_log%message(
' Rotation : ' // &
665 'Theta(t) = Amp*sin(2*pi*Freq*t)')
667 write(log_buf,
'(A,3(ES18.11,1X))')
' Amp (deg) :', &
668 this%config%bodies(i)%rot_amp_degree
670 write(log_buf,
'(A,3(ES18.11,1X))')
' Freq :', &
671 this%config%bodies(i)%rot_freq
675 elseif (trim(this%config%bodies(i)%rotation_type) &
677 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
678 call neko_log%message(
' Rotation : ' // &
679 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0)) + User')
681 call neko_log%message(
' Rotation : ' // &
682 'Omega(t) = Omega0*(1 - exp(-4.6*t/t0))')
684 write(log_buf,
'(A,3(ES18.11,1X))')
' Omega0 :', &
685 this%config%bodies(i)%ramp_omega0
687 write(log_buf,
'(A,3(ES18.11,1X))')
' t0 :', &
688 this%config%bodies(i)%ramp_t0
692 elseif (trim(this%config%bodies(i)%rotation_type) &
693 .eq.
'smooth_step')
then
694 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
695 call neko_log%message(
' Rotation : ' // &
696 'Smooth Step Control + User')
698 call neko_log%message(
' Rotation : ' // &
699 'Smooth Step Control')
701 write(log_buf,
'(A,I10)')
' Rotation Axis :', &
702 this%config%bodies(i)%rotation_axis
704 write(log_buf,
'(A,ES18.11)')
' Target Rot ' // &
706 this%config%bodies(i)%target_rot_angle_deg
708 write(log_buf,
'(A,4(ES18.11,1X))') &
709 ' Control Times [t0, t1, t2, t3] :', &
710 this%config%bodies(i)%step_control_times
714 if (has_user_rigid_kin .or. has_user_mesh_vel)
then
715 call neko_log%message(
' Rotation Type: User-defined')
717 call neko_log%message(
' Rotation Type: None')
725 call neko_log%message(
' Pivot Type : ' // &
726 trim(this%config%bodies(i)%rotation_center_type))
728 write(log_buf,
'(A,3(ES18.11,1X))')
' Init Pivot:', &
729 this%config%bodies(i)%rot_center
735 call neko_error(
"ALE: No 'ale bodies' found in case file!")
738 if (this%config%nbodies .gt. 1 .and. (.not. import_base_shapes))
then
739 call this%phi_total%init(coef%dof,
"phi_total")
744 do i = 1, n_moving_zones
745 z = moving_zone_ids(i)
748 do while ((.not. found_zone) .and. (j .le. this%config%nbodies))
749 if (any(this%config%bodies(j)%zone_indices .eq. z))
then
754 if (.not. found_zone)
then
755 write(log_buf_l,
'(A,I0,A)') &
756 "ALE: zone index ", z, &
757 " has BC no_slip with moving: true, " // &
758 "but it is not registered in ALE bodies."
765 do j = 1, this%config%nbodies
766 if (
allocated(this%config%bodies(j)%zone_indices))
then
767 do i = 1,
size(this%config%bodies(j)%zone_indices)
768 z = this%config%bodies(j)%zone_indices(i)
770 if (n_moving_zones .gt. 0)
then
771 if (any(moving_zone_ids(1:n_moving_zones) .eq. z))
then
775 if (.not. found_zone)
then
776 write(log_buf_l,
'(A,I0,A,A)') &
777 "ALE: zone index ", z, &
778 " is registered in ALE bodies, ", &
779 "but the BC is not no_slip with moving: true."
787 do j = 1, this%config%nbodies
788 if (
allocated(this%config%bodies(j)%zone_indices))
then
789 do i = 1,
size(this%config%bodies(j)%zone_indices)
790 z = this%config%bodies(j)%zone_indices(i)
792 do k = j + 1, this%config%nbodies
793 if (
allocated(this%config%bodies(k)%zone_indices))
then
794 if (any(this%config%bodies(k)%zone_indices .eq. z))
then
795 write(log_buf_l,
'(A,I0,A,A,A,A,A)') &
796 "ALE: zone index ", z, &
797 " is assigned to multiple bodies ('", &
798 trim(this%config%bodies(j)%name),
"' and '", &
799 trim(this%config%bodies(k)%name),
"')."
810 call this%solve_base_mesh_displacement(coef, json, import_base_shapes, &
811 abstol, ksp_solver, ksp_max_iter, &
812 precon_type, precon_params, res_monitor)
816 if (.not. json%valid_path(
'case.restart_file'))
then
820 call this%update_mesh_velocity(coef, t_init)
823 call this%wm_x_lag%init(this%wm_x, 2)
824 call this%wm_y_lag%init(this%wm_y, 2)
825 call this%wm_z_lag%init(this%wm_z, 2)
827 if (
allocated(moving_zone_ids))
deallocate(moving_zone_ids)
828 if (
allocated(bc_type))
deallocate(bc_type)
829 if (
allocated(zone_indices))
deallocate(zone_indices)
830 if (
allocated(ksp_solver))
deallocate(ksp_solver)
831 if (
allocated(precon_type))
deallocate(precon_type)
832 if (
allocated(tmp_str))
deallocate(tmp_str)
833 if (
allocated(tmp_vec))
deallocate(tmp_vec)
836 call this%mesh_preview(coef, json)
839 call this%register_checkpoint_fields(coef, chkp)
849 import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, &
850 precon_params, res_monitor)
852 class(
ax_t),
allocatable :: Ax
853 class(
ksp_t),
allocatable :: ksp
854 class(
pc_t),
allocatable :: pc
855 type(
coef_t),
intent(inout) :: coef
856 type(json_file),
intent(inout) :: json
857 logical,
intent(in) :: import_base_shapes
858 real(kind=
rp),
intent(in) :: abstol
859 logical,
intent(in) :: res_monitor
860 character(len=*),
intent(in) :: ksp_solver, precon_type
861 integer,
intent(in) :: ksp_max_iter
862 type(json_file),
intent(inout) :: precon_params
864 type(
field_t),
pointer :: phi_ptr => null()
868 real(kind=
rp) :: sample_start_time, sample_end_time
869 real(kind=
rp) :: sample_time
870 character(len=LOG_SIZE) :: log_buf
871 integer :: n, i, m, k, ierr, body_idx, z_idx
873 real(kind=
rp),
allocatable :: h1_restore(:, :, :, :)
874 real(kind=
rp),
allocatable :: h2_restore(:, :, :, :)
879 type(json_file) :: body_sub
880 character(len=256) :: phi_fname
881 character(len=:),
allocatable :: tmp_str
884 if (.not. this%active)
return
885 if (.not. this%has_moving_boundary)
return
886 if (this%config%nbodies .eq. 0)
return
888 if (import_base_shapes)
then
890 call neko_log%message(
"Importing ALE base shapes" // &
891 " (skipping Laplace solve)...")
893 do body_idx = 1, this%config%nbodies
898 call json_get(body_sub,
'base_shape_import_file', tmp_str)
901 phi_ptr => this%base_shapes(body_idx)
906 call neko_log%message(
" Loaded: " // &
909 trim(this%config%bodies(body_idx)%name))
916 call neko_log%message(
"Starting base mesh motion solve ...")
919 call ax_helm_factory(ax, full_formulation = .false.)
920 call krylov_solver_factory(ksp, n, ksp_solver, &
921 ksp_max_iter, abstol, monitor = res_monitor)
923 coef%gs_h, this%bc_list, precon_type, precon_params)
929 call rhs_field%init(coef%dof)
930 call corr_field%init(coef%dof)
934 if (.not.
associated(this%user_ale_base_shapes, &
936 call neko_log%message(
" Using user-defined base shapes " // &
937 "(skipping Laplace solve)")
940 call this%user_ale_base_shapes(this%base_shapes)
943 if (this%config%nbodies .gt. 1)
then
945 do body_idx = 1, this%config%nbodies
946 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
951 if (this%config%if_output_phi)
then
953 do body_idx = 1, this%config%nbodies
954 call phi_file%init(
'phi_' // &
955 trim(this%config%bodies(body_idx)%name) //
'.fld', &
957 select type (ft => phi_file%file_type)
959 ft%skip_pressure = .false.
961 call phi_file%write(this%base_shapes(body_idx))
964 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
968 if (this%config%nbodies .gt. 1)
then
969 call neko_log%message(
" phi_total.fld saved.")
970 select type (ft => phi_file%file_type)
972 ft%skip_pressure = .false.
974 call phi_file%init(
'phi_total.fld', precision =
rp)
975 call phi_file%write(this%phi_total)
986 if (this%config%if_output_stiffness)
then
987 rhs_field%x = coef%h1
988 call phi_file%init(
'stiffness.fld')
989 call phi_file%write(rhs_field)
995 do body_idx = 1, this%config%nbodies
997 sample_start_time = mpi_wtime()
998 call neko_log%message(
" Solving laplace for body: " // &
999 trim(this%config%bodies(body_idx)%name))
1001 call bc_active_body%init_from_components(coef)
1002 call bc_inactive_body%init_from_components(coef)
1005 do j = 1,
size(this%config%bodies(body_idx)%zone_indices)
1006 z_idx = this%config%bodies(body_idx)%zone_indices(j)
1007 call bc_active_body%mark_zone(coef%msh%labeled_zones(z_idx))
1010 do i = 1, this%config%nbodies
1011 if (i /= body_idx)
then
1012 do j = 1,
size(this%config%bodies(i)%zone_indices)
1013 z_idx = this%config%bodies(i)%zone_indices(j)
1014 call bc_inactive_body%mark_zone(&
1015 coef%msh%labeled_zones(z_idx))
1020 call bc_active_body%finalize()
1021 call bc_inactive_body%finalize()
1025 call bcloc%append(this%bc_fixed)
1026 call bcloc%append(bc_active_body)
1027 call bcloc%append(bc_inactive_body)
1030 call bcloc_zeros_only%init()
1031 call bcloc_zeros_only%append(this%bc_fixed)
1032 call bcloc_zeros_only%append(bc_inactive_body)
1035 this%base_shapes(body_idx)%x = 0.0_rp
1036 rhs_field%x = 0.0_rp
1037 corr_field%x = 0.0_rp
1044 m = bc_active_body%msk(0)
1046 k = bc_active_body%msk(i)
1047 this%base_shapes(body_idx)%x(k, 1, 1, 1) = 1.0_rp
1058 call bcloc_zeros_only%apply_scalar(this%base_shapes(body_idx)%x, n)
1062 call ax%compute(rhs_field%x, this%base_shapes(body_idx)%x, &
1063 coef, coef%msh, coef%Xh)
1068 call bcloc%apply_scalar(rhs_field%x, n)
1069 call coef%gs_h%op(rhs_field, gs_op_add)
1074 monitor(1) = ksp%solve(ax, corr_field, &
1075 rhs_field%x, n, coef, bcloc, coef%gs_h)
1078 call field_add2(this%base_shapes(body_idx), corr_field, n)
1082 if (this%config%nbodies .gt. 1)
then
1083 call field_add2(this%phi_total, this%base_shapes(body_idx), n)
1087 sample_end_time = mpi_wtime()
1088 sample_time = sample_end_time - sample_start_time
1089 write(log_buf,
'(A, A, A, ES11.4, A)')
" Laplace solve for '", &
1090 trim(this%config%bodies(body_idx)%name),
"' took ", &
1095 call bc_active_body%free()
1096 call bc_inactive_body%free()
1098 call bcloc_zeros_only%free()
1108 if (this%config%if_output_phi)
then
1109 call phi_file%init(
'phi_' // &
1110 trim(this%config%bodies(body_idx)%name) //
'.fld', &
1112 select type (ft => phi_file%file_type)
1114 ft%skip_pressure = .false.
1116 call phi_file%write(this%base_shapes(body_idx))
1117 call phi_file%free()
1119 trim(this%config%bodies(body_idx)%name) //
'.fld saved.')
1123 if (this%config%if_output_phi .and. (this%config%nbodies .gt. 1))
then
1126 call device_memcpy(this%phi_total%x, this%phi_total%x_d, n, &
1130 call neko_log%message(
" phi_total.fld saved.")
1131 call phi_file%init(
'phi_total.fld', precision =
rp)
1132 select type (ft => phi_file%file_type)
1134 ft%skip_pressure = .false.
1136 call phi_file%write(this%phi_total)
1137 call phi_file%free()
1141 call rhs_field%free()
1142 call corr_field%free()
1143 if (this%config%nbodies > 1)
then
1144 call this%phi_total%free()
1148 coef%h1(:,:,:,:) = h1_restore(:,:,:,:)
1149 coef%h2(:,:,:,:) = h2_restore(:,:,:,:)
1155 if (
allocated(h1_restore))
deallocate(h1_restore)
1156 if (
allocated(h2_restore))
deallocate(h2_restore)
1157 if (
allocated(ax))
deallocate(ax)
1158 if (
allocated(ksp))
then
1162 if (
allocated(pc))
then
1163 call precon_destroy(pc)
1173 type(
coef_t),
intent(in) :: coef
1177 real(kind=
rp) :: rot_mat(3,3)
1178 real(kind=
rp) :: initial_rot_center(3)
1180 if (.not. this%active)
return
1181 if (.not. this%has_moving_boundary)
return
1188 do i = 1, this%config%nbodies
1192 this%config%bodies(i), time_s)
1195 if (.not.
associated(this%user_ale_rigid_kinematics, &
1197 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1199 current_kin%vel_trans, &
1200 current_kin%vel_ang)
1203 current_kin%center = this%ale_pivot(i)%pos
1204 this%ale_pivot(i)%vel = current_kin%vel_trans
1206 this%body_kin(i)%center = this%ale_pivot(i)%pos
1207 this%body_kin(i)%vel_trans = current_kin%vel_trans
1208 this%body_kin(i)%vel_ang = current_kin%vel_ang
1211 call this%compute_rotation_matrix(i, time_s)
1212 rot_mat = this%body_rot_matrices(:,:,i)
1213 initial_rot_center = this%config%bodies(i)%rot_center
1217 this%wm_z, this%x_ref, this%y_ref, this%z_ref , &
1218 this%base_shapes(i), coef, current_kin, rot_mat, &
1222 call this%prep_checkpoint(i)
1228 if (.not.
associated(this%user_ale_mesh_vel, &
1230 call this%user_ale_mesh_vel(this%wm_x, this%wm_y, this%wm_z, &
1231 coef, this%x_ref, this%y_ref, this%z_ref, this%base_shapes, time_s)
1241 type(
coef_t),
intent(inout) :: coef
1243 integer,
intent(in) :: nadv
1246 if (.not. this%active)
return
1247 if (.not. this%has_moving_boundary)
return
1249 do i = 1, this%config%nbodies
1254 call this%ghost_tracker_coord_step(this%body_kin(i), time, nadv, i)
1257 this%ale_pivot(i)%pos, &
1258 this%ale_pivot(i)%vel, &
1261 this%config%bodies(i))
1265 call coef%update_B_history()
1269 this%wm_x_lag, this%wm_y_lag, this%wm_z_lag, &
1273 call this%wm_x_lag%update()
1274 call this%wm_y_lag%update()
1275 call this%wm_z_lag%update()
1281 type(
coef_t),
intent(inout) :: coef
1283 integer :: i, n, b, ierr
1284 integer,
allocatable :: cheap_map(:)
1285 integer :: n_cheap, map_idx
1286 real(kind=
rp) :: x, y, z
1287 real(kind=
rp) :: raw_dist, body_stiff_val, max_added_stiff
1288 real(kind=
rp) :: cx, cy, cz
1289 real(kind=
rp) :: arg, decay, gain, norm_dist
1290 real(kind=
rp) :: sample_start_time, sample_end_time, sample_time
1291 type(
field_t),
allocatable :: dist_fields(:)
1292 character(len=128) :: log_buf
1297 allocate(cheap_map(params%nbodies))
1301 do b = 1, params%nbodies
1302 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1303 n_cheap = n_cheap + 1
1304 cheap_map(b) = n_cheap
1309 if (n_cheap > 0)
then
1310 allocate(dist_fields(n_cheap))
1312 do b = 1, params%nbodies
1313 map_idx = cheap_map(b)
1314 if (map_idx .gt. 0)
then
1316 call dist_fields(map_idx)%init(coef%dof,
"tmp_cheap_dist")
1319 call neko_log%message(
" Start: cheap dist calculation " // &
1320 "for body '" // trim(params%bodies(b)%name) //
"'")
1323 sample_start_time = mpi_wtime()
1327 coef%msh, params%bodies(b)%zone_indices, &
1328 copy_to_host = .true.)
1331 coef%msh, params%bodies(b)%zone_indices)
1335 sample_end_time = mpi_wtime()
1336 sample_time = sample_end_time - sample_start_time
1338 write(log_buf,
'(A, A, A, ES11.4, A)')
" cheap dist for '", &
1339 trim(params%bodies(b)%name),
"' took ", sample_time,
" (s)"
1347 select case (trim(params%stiffness_type))
1350 do concurrent(i = 1:n)
1351 x = coef%dof%x(i, 1, 1, 1)
1352 y = coef%dof%y(i, 1, 1, 1)
1353 z = coef%dof%z(i, 1, 1, 1)
1355 max_added_stiff = 0.0_rp
1358 do b = 1, params%nbodies
1359 gain = params%bodies(b)%stiff_geom%gain
1360 if (trim(params%bodies(b)%stiff_geom%type) .eq.
'cheap_dist')
then
1361 decay = params%bodies(b)%stiff_geom%stiff_dist
1363 decay = params%bodies(b)%stiff_geom%radius
1367 cx = params%bodies(b)%stiff_geom%center(1)
1368 cy = params%bodies(b)%stiff_geom%center(2)
1369 cz = params%bodies(b)%stiff_geom%center(3)
1371 raw_dist = huge(0.0_rp)
1374 select case (trim(params%bodies(b)%stiff_geom%type))
1376 raw_dist = sqrt((x - cx)**2 + (y - cy)**2 + (z - cz)**2)
1380 raw_dist = sqrt((x - cx)**2 + (y - cy)**2)
1386 map_idx = cheap_map(b)
1387 if (map_idx .gt. 0)
then
1388 raw_dist = dist_fields(map_idx)%x(i, 1, 1, 1)
1393 body_stiff_val = 0.0_rp
1394 select case (trim(params%bodies(b)%stiff_geom%decay_profile))
1397 arg = -(raw_dist**2) / (decay**2)
1398 arg = arg * params%bodies(b)%stiff_geom%cutoff_coef
1399 body_stiff_val = gain * exp(arg)
1403 norm_dist = (raw_dist / decay)
1404 norm_dist = norm_dist * params%bodies(b)%stiff_geom%cutoff_coef
1405 body_stiff_val = gain * (1.0_rp - tanh(norm_dist))
1408 if (body_stiff_val .gt. max_added_stiff)
then
1409 max_added_stiff = body_stiff_val
1413 coef%h1(i, 1, 1, 1) = 1.0_rp + max_added_stiff
1414 coef%h2(i, 1, 1, 1) = 0.0_rp
1418 call neko_error(
"ALE Manager: Unknown stiffness type")
1428 if (
allocated(dist_fields))
then
1429 do i = 1,
size(dist_fields)
1430 call dist_fields(i)%free()
1432 deallocate(dist_fields)
1434 if (
allocated(cheap_map))
deallocate(cheap_map)
1440 x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
1441 type(
field_t),
intent(inout) :: wx, wy, wz
1442 type(
field_t),
intent(in) :: x_ref, y_ref, z_ref
1443 type(
field_t),
intent(in) :: phi
1444 type(
coef_t),
intent(in) :: coef
1446 real(kind=
rp),
intent(in) :: initial_pivot_loc(3)
1447 real(kind=
rp),
intent(in) :: rot_mat(3,3)
1450 x_ref, y_ref, z_ref, &
1451 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1454 x_ref, y_ref, z_ref, &
1455 phi, coef, kinematics, rot_mat, initial_pivot_loc)
1461 wm_z_lag, time, nadv, scheme_)
1462 type(
coef_t),
intent(inout) :: c_xh
1463 type(
field_t),
intent(in) :: wm_x, wm_y, wm_z
1466 integer,
intent(in) :: nadv
1467 character(len=*),
intent(in) :: scheme_
1470 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1473 wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
1482 if (.not. this%active)
return
1484 call this%bc_moving%free()
1485 call this%bc_fixed%free()
1486 call this%bc_list%free()
1488 if (
allocated(this%base_shapes))
then
1489 do i = 1,
size(this%base_shapes)
1490 call this%base_shapes(i)%free()
1492 deallocate(this%base_shapes)
1495 call this%wm_x_lag%free()
1496 call this%wm_y_lag%free()
1497 call this%wm_z_lag%free()
1498 call this%x_ref%free()
1499 call this%y_ref%free()
1500 call this%z_ref%free()
1502 if (
allocated(this%ale_pivot))
deallocate(this%ale_pivot)
1503 if (
allocated(this%config%bodies))
deallocate(this%config%bodies)
1504 if (
allocated(this%body_kin))
deallocate(this%body_kin)
1505 if (
associated(this%global_pivot_pos))
deallocate(this%global_pivot_pos)
1506 if (
associated(this%global_pivot_vel_lag)) &
1507 deallocate(this%global_pivot_vel_lag)
1508 if (
associated(this%global_basis_pos))
deallocate(this%global_basis_pos)
1509 if (
associated(this%global_basis_vel_lag)) &
1510 deallocate(this%global_basis_vel_lag)
1511 if (
allocated(this%ghost_handles))
deallocate(this%ghost_handles)
1512 if (
allocated(this%body_rot_matrices))
deallocate(this%body_rot_matrices)
1513 if (
allocated(this%trackers))
deallocate(this%trackers)
1520 class(
pc_t),
allocatable,
target,
intent(inout) :: pc
1521 class(
ksp_t),
target,
intent(inout) :: ksp
1522 type(
coef_t),
target,
intent(in) :: coef
1523 type(
dofmap_t),
target,
intent(in) :: dof
1524 type(
gs_t),
target,
intent(inout) :: gs
1525 type(
bc_list_t),
target,
intent(inout) :: bclst
1526 character(len=*),
intent(in) :: pctype
1527 type(json_file),
intent(inout) :: params
1528 call precon_allocator(pc, pctype)
1529 select type (pcp => pc)
1531 call pcp%init(coef, dof, gs)
1533 call pcp%init(coef, dof, gs)
1535 call pcp%init(coef, dof, gs)
1537 call pcp%init(coef, bclst, params)
1539 call pcp%init(coef, bclst, params)
1547 real(kind=
dp),
intent(in) :: time_restart
1549 integer :: i, idx, handle_1, handle_2, offset_base
1551 time_state_dummy%t = time_restart
1555 do i = 1, this%config%nbodies
1558 this%config%bodies(i), time_state_dummy)
1561 if (.not.
associated(this%user_ale_rigid_kinematics, &
1563 call this%user_ale_rigid_kinematics(this%config%bodies(i)%id, &
1565 kin_restart%vel_trans, &
1566 kin_restart%vel_ang)
1569 this%ale_pivot(i)%vel = kin_restart%vel_trans
1573 this%ale_pivot(i)%pos(1:3) = this%global_pivot_pos(idx + 1:idx + 3)
1574 this%body_kin(i)%center = this%ale_pivot(i)%pos
1575 this%body_kin(i)%vel_trans = kin_restart%vel_trans
1576 this%body_kin(i)%vel_ang = kin_restart%vel_ang
1579 this%ale_pivot(i)%vel_lag(1:3, 1:3) = &
1580 this%global_pivot_vel_lag(idx + 1:idx + 3, :)
1583 offset_base = (i-1)*6
1584 handle_1 = this%ghost_handles(1, i)
1585 handle_2 = this%ghost_handles(2, i)
1587 if ((handle_1 .gt. 0) .and. (handle_1 .le. this%n_trackers))
then
1588 this%trackers(handle_1)%pos = &
1589 this%global_basis_pos(offset_base + 1 : offset_base + 3)
1592 this%trackers(handle_1)%vel_lag = &
1593 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :)
1596 if ((handle_2 .gt. 0) .and. (handle_2 .le. this%n_trackers))
then
1597 this%trackers(handle_2)%pos = &
1598 this%global_basis_pos(offset_base + 4 : offset_base + 6)
1601 this%trackers(handle_2)%vel_lag = &
1602 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :)
1612 type(
coef_t),
intent(inout) :: coef
1613 type(
space_t),
intent(inout) :: Xh
1614 type(
chkp_t),
intent(in) :: chkp
1615 type(
gs_t),
intent(inout) :: gs_Xh
1619 if (.not. this%active)
return
1621 if (
allocated(chkp%previous_mesh%elements))
then
1623 "The current mesh has a different number " // &
1624 "of elements than the checkpoint.")
1628 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1630 associate(wm_x => this%wm_x, wm_y => this%wm_y, wm_z => this%wm_z)
1631 do concurrent(j = 1:n)
1633 wm_x%x(j,1,1,1) = wm_x%x(j,1,1,1) * coef%mult(j,1,1,1)
1634 wm_y%x(j,1,1,1) = wm_y%x(j,1,1,1) * coef%mult(j,1,1,1)
1635 wm_z%x(j,1,1,1) = wm_z%x(j,1,1,1) * coef%mult(j,1,1,1)
1639 do i = 1, this%wm_x_lag%size()
1640 do concurrent(j = 1:n)
1641 this%wm_x_lag%lf(i)%x(j,1,1,1) = &
1642 this%wm_x_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1643 this%wm_y_lag%lf(i)%x(j,1,1,1) = &
1644 this%wm_y_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1645 this%wm_z_lag%lf(i)%x(j,1,1,1) = &
1646 this%wm_z_lag%lf(i)%x(j,1,1,1) * coef%mult(j,1,1,1)
1671 if (c_associated(coef%dof%x_d))
then
1680 if (c_associated(coef%Blag_d))
then
1681 call device_memcpy(coef%Blag, coef%Blag_d,
size(coef%Blag), &
1685 if (c_associated(coef%Blaglag_d))
then
1693 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1694 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 1, coef)
1695 call gs_xh%op(this%wm_x, gs_op_add)
1696 call gs_xh%op(this%wm_y, gs_op_add)
1697 call gs_xh%op(this%wm_z, gs_op_add)
1698 call rotate_cyc(this%wm_x%x, this%wm_y%x, this%wm_z%x, 0, coef)
1700 do i = 1, this%wm_x_lag%size()
1701 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1702 this%wm_z_lag%lf(i)%x, 1, coef)
1703 call gs_xh%op(this%wm_x_lag%lf(i), gs_op_add)
1704 call gs_xh%op(this%wm_y_lag%lf(i), gs_op_add)
1705 call gs_xh%op(this%wm_z_lag%lf(i), gs_op_add)
1706 call rotate_cyc(this%wm_x_lag%lf(i)%x, this%wm_y_lag%lf(i)%x, &
1707 this%wm_z_lag%lf(i)%x, 0, coef)
1712 call this%set_pivot_restart(chkp%t)
1713 call coef%recompute_metrics()
1720 if (chkp%previous_Xh%lx .ne. xh%lx)
then
1722 coef%Blaglag = coef%B
1724 if (c_associated(coef%Blag_d))
then
1728 if (c_associated(coef%Blaglag_d))
then
1736 call adv%recompute_metrics(coef, .true.)
1741 integer,
intent(in) :: body_idx
1742 integer :: idx, offset_base, h1, h2
1744 if (.not. this%active)
return
1745 if (.not. this%has_moving_boundary)
return
1747 idx = (body_idx - 1) * 3
1748 this%global_pivot_pos(idx + 1:idx + 3) = this%ale_pivot(body_idx)%pos(1:3)
1749 this%global_pivot_vel_lag(idx + 1:idx + 3, :) = &
1750 this%ale_pivot(body_idx)%vel_lag(1:3, 1:3)
1752 h1 = this%ghost_handles(1, body_idx)
1753 h2 = this%ghost_handles(2, body_idx)
1755 offset_base = (body_idx-1)*6
1758 this%global_basis_pos(offset_base + 1 : offset_base + 3) = &
1759 this%get_tracker_pos(h1)
1760 this%global_basis_pos(offset_base + 4 : offset_base + 6) = &
1761 this%get_tracker_pos(h2)
1764 this%global_basis_vel_lag(offset_base + 1 : offset_base + 3, :) = &
1765 this%trackers(h1)%vel_lag
1768 this%global_basis_vel_lag(offset_base + 4 : offset_base + 6, :) = &
1769 this%trackers(h2)%vel_lag
1774 integer,
allocatable,
intent(inout) :: arr(:)
1775 integer,
intent(inout) :: n
1776 integer,
intent(in) :: val
1777 integer,
allocatable :: tmp(:)
1781 if (arr(k) .eq. val)
return
1784 allocate(tmp(n + 1))
1785 if (n .gt. 0) tmp(1:n) = arr(1:n)
1788 if (
allocated(arr))
deallocate(arr)
1789 call move_alloc(tmp, arr)
1797 type(coef_t),
intent(inout) :: coef
1798 type(json_file),
intent(inout) :: json
1799 type(fld_file_output_t) :: fout
1800 type(field_t) :: dummy_field
1801 type(time_state_t) :: t_state
1802 type(file_t) :: out_file
1803 real(kind=rp) :: t_start
1804 real(kind=rp) :: t_end
1806 real(kind=rp) :: min_jac
1807 integer :: output_freq
1808 integer :: step, n_steps
1809 integer :: nadv, nadv_sim
1811 logical :: mesh_preview_active
1812 character(len=128) :: log_buf
1814 mesh_preview_active = .false.
1816 if (json%valid_path(
'case.fluid.ale.mesh_preview.enabled'))
then
1817 call json%get(
'case.fluid.ale.mesh_preview.enabled', &
1818 mesh_preview_active)
1821 if (.not. mesh_preview_active)
return
1823 call json_get_or_default(json,
'case.fluid.ale.mesh_preview.start_time', &
1825 call json_get(json,
'case.fluid.ale.mesh_preview.end_time', &
1827 call json_get(json,
'case.fluid.ale.mesh_preview.dt', &
1829 call json_get(json, &
1830 'case.fluid.ale.mesh_preview.output_freq', &
1833 call neko_log%section(
"ALE Mesh Preview")
1834 call neko_log%message(
"Executing mesh motion preview...")
1836 n_steps = int((t_end - t_start) / dt)
1837 call json_get(json,
'case.numerics.time_order', nadv_sim)
1839 write(log_buf,
'(A, ES23.15)')
' Start Time : ', t_start
1840 call neko_log%message(log_buf)
1841 write(log_buf,
'(A, ES23.15)')
' End Time : ', t_end
1842 call neko_log%message(log_buf)
1843 write(log_buf,
'(A, ES23.15)')
' dt : ', dt
1844 call neko_log%message(log_buf)
1845 write(log_buf,
'(A, I0)')
' Num Steps : ', n_steps
1846 call neko_log%message(log_buf)
1847 write(log_buf,
'(A, I0)')
' Output Freq: ', output_freq
1848 call neko_log%message(log_buf)
1849 call neko_log%message(
'')
1852 call dummy_field%init(coef%dof,
"mesh_preview")
1853 call field_rzero(dummy_field)
1855 call fout%init(rp,
"mesh_preview", 1)
1856 call fout%fields%assign_to_field(1, dummy_field)
1857 select type (ft => fout%file_%file_type)
1858 type is (fld_file_t)
1859 ft%write_mesh = .true.
1860 ft%skip_pressure = .false.
1873 if (neko_bcknd_device .eq. 1)
then
1874 min_jac = device_glmin(coef%jac_d, n)
1876 min_jac = glmin(coef%jac, n)
1880 call fout%sample(t_state%t)
1882 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1883 "Initial Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1884 t_state%t,
" | Min Jac: ", min_jac
1886 call neko_log%message(trim(log_buf))
1887 call this%update_mesh_velocity(coef, t_state)
1889 do step = 1, n_steps
1890 t_state%tstep = step
1891 t_state%t = t_start + (step * dt)
1892 nadv = min(step, nadv_sim)
1894 call this%advance_mesh(coef, t_state, nadv)
1895 call coef%recompute_metrics()
1898 if (neko_bcknd_device .eq. 1)
then
1899 min_jac = device_glmin(coef%jac_d, n)
1901 min_jac = glmin(coef%jac, n)
1904 if (min_jac .le. 0.0_rp)
then
1905 write(log_buf,
'(A, ES18.11, A, ES23.15)') &
1906 "Negative Jacobian detected (", min_jac,
") at t = ", &
1908 call neko_log%message(log_buf)
1911 call fout%sample(t_state%t)
1913 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1914 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1915 t_state%t,
" | Min Jac:", min_jac
1916 call neko_log%message(trim(log_buf))
1918 call neko_error(
"ALE Mesh Preview Aborted: Negative Jacobian found.")
1921 if (mod(step, output_freq) .eq. 0)
then
1924 call fout%sample(t_state%t)
1926 write(log_buf,
'(A,I0, A,ES23.15, A,ES18.11)') &
1927 "Mesh and Mass matrix saved! Step: ", step,
" | Time:", &
1928 t_state%t,
" | Min Jac:", min_jac
1929 call neko_log%message(trim(log_buf))
1933 call this%update_mesh_velocity(coef, t_state)
1937 call dummy_field%free()
1939 call neko_log%end_section()
1940 call neko_log%message(
"Mesh preview complete.")
1941 call neko_error(
"ALE Mesh Preview Finished Successfully.")
1946 type(fld_file_output_t) :: fout
1947 type(coef_t),
intent(inout) :: coef
1948 type(field_t),
intent(inout) :: dummy_field
1952 if (neko_bcknd_device .eq. 1)
then
1953 call device_copy(dummy_field%x_d, coef%B_d, n)
1955 call copy(dummy_field%x, coef%B, n)
1958 if (neko_bcknd_device .eq. 1)
then
1959 associate(
mesh => coef%dof)
1961 device_to_host, sync = .false.)
1963 device_to_host, sync = .false.)
1965 device_to_host, sync = .false.)
1975 real(kind=rp),
intent(in) :: initial_pos(3)
1976 integer,
intent(in) :: body_id
1978 type(point_tracker_t),
allocatable :: tmp(:)
1981 if (.not. this%active)
return
1982 if (.not. this%has_moving_boundary)
return
1984 if (.not.
allocated(this%trackers))
then
1985 allocate(this%trackers(30))
1987 elseif (this%n_trackers .ge.
size(this%trackers))
then
1988 allocate(tmp(
size(this%trackers) + 30))
1989 tmp(1:
size(this%trackers)) = this%trackers
1990 deallocate(this%trackers)
1991 call move_alloc(tmp, this%trackers)
1993 this%n_trackers = this%n_trackers + 1
1994 handle = this%n_trackers
1996 this%trackers(handle)%pos = initial_pos
1997 this%trackers(handle)%body_id = body_id
1998 this%trackers(handle)%vel_lag = this%ale_pivot(body_id)%vel_lag
2003 integer,
intent(in) :: handle
2004 real(kind=rp) :: pos(3)
2006 if (handle .gt. 0 .and. handle .le. this%n_trackers)
then
2007 pos = this%trackers(handle)%pos
2017 integer,
intent(in) :: body_idx
2018 type(time_state_t),
intent(in) :: time
2020 real(kind=rp) :: p(3), gx(3), gy(3)
2021 real(kind=rp) :: u(3), v(3), w(3), v_temp(3)
2023 if (.not. this%active)
return
2024 if (.not. this%has_moving_boundary)
return
2027 h_x = this%ghost_handles(1, body_idx)
2028 h_y = this%ghost_handles(2, body_idx)
2030 p = this%ale_pivot(body_idx)%pos
2031 gx = this%get_tracker_pos(h_x)
2032 gy = this%get_tracker_pos(h_y)
2036 u = u / sqrt(sum(u**2))
2040 w(1) = u(2)*v_temp(3) - u(3)*v_temp(2)
2041 w(2) = u(3)*v_temp(1) - u(1)*v_temp(3)
2042 w(3) = u(1)*v_temp(2) - u(2)*v_temp(1)
2043 w = w / sqrt(sum(w**2))
2046 v(1) = w(2)*u(3) - w(3)*u(2)
2047 v(2) = w(3)*u(1) - w(1)*u(3)
2048 v(3) = w(1)*u(2) - w(2)*u(1)
2050 this%body_rot_matrices(:, 1, body_idx) = u
2051 this%body_rot_matrices(:, 2, body_idx) = v
2052 this%body_rot_matrices(:, 3, body_idx) = w
2062 type(time_state_t),
intent(in) :: time
2063 integer,
optional,
intent(in) :: body_idxs(:)
2065 integer :: i, idx, n_log
2066 real(kind=rp) :: roll_deg, pitch_deg, yaw_deg
2067 real(kind=rp) :: r(3,3)
2068 character(len=256) :: log_buf
2069 real(kind=rp),
parameter :: rad_to_deg = 180.0_rp / pi
2071 if (.not. this%active)
return
2072 if (.not. this%has_moving_boundary)
return
2074 if (
present(body_idxs))
then
2075 n_log =
size(body_idxs)
2077 n_log = this%config%nbodies
2080 call neko_log%message(
" ")
2081 call neko_log%message(
"---------Rotation log---------")
2082 call neko_log%message(
"variable, time step, time, body, " // &
2083 "x_val, y_val, z_val")
2088 if (
present(body_idxs))
then
2094 r = this%body_rot_matrices(:,:,idx)
2097 yaw_deg = atan2(r(2,1), r(1,1)) * rad_to_deg
2098 pitch_deg = atan2(-r(3,1), sqrt(r(3,2)**2 + r(3,3)**2)) * rad_to_deg
2099 roll_deg = atan2(r(3,2), r(3,3)) * rad_to_deg
2102 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2103 "Total_Rot_deg ", time%tstep,
" ", time%t,
" ", &
2104 trim(this%config%bodies(idx)%name),
" ", &
2105 roll_deg, pitch_deg, yaw_deg
2106 call neko_log%message(trim(log_buf))
2117 type(time_state_t),
intent(in) :: time
2118 integer,
optional,
intent(in) :: body_idxs(:)
2119 integer :: i, idx, n_log
2120 real(kind=rp) :: pivot_pos(3), pivot_vel(3)
2121 character(len=256) :: log_buf
2123 if (.not. this%active)
return
2124 if (.not. this%has_moving_boundary)
return
2126 if (
present(body_idxs))
then
2127 n_log =
size(body_idxs)
2129 n_log = this%config%nbodies
2132 call neko_log%message(
" ")
2133 call neko_log%message(
"----------Pivot Log-----------")
2134 call neko_log%message(
"variable, time step, time, body, " // &
2135 "x_val, y_val, z_val")
2140 if (
present(body_idxs))
then
2146 pivot_pos = this%ale_pivot(idx)%pos
2147 pivot_vel = this%ale_pivot(idx)%vel
2150 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2151 "Total_Pivot_pos ", time%tstep,
" ", time%t,
" ", &
2152 trim(this%config%bodies(idx)%name),
" ", &
2153 this%ale_pivot(idx)%pos
2154 call neko_log%message(trim(log_buf))
2157 write(log_buf,
'(A, I0, A, ES13.6, A, A, A, 3(ES17.10, :, 2X))') &
2158 "Total_Pivot_vel ", time%tstep,
" ", time%t,
" ", &
2159 trim(this%config%bodies(idx)%name),
" ", &
2160 this%ale_pivot(idx)%vel
2161 call neko_log%message(trim(log_buf))
2168 type(body_kinematics_t),
intent(in) :: kin_object
2169 type(time_state_t),
intent(in) :: time_s
2170 integer,
intent(in) :: nadv
2171 integer,
intent(in) :: body_idx
2173 real(kind=rp) :: p_vel(3), rel_pos(3), v_tan(3)
2175 if (.not. this%active)
return
2176 if (.not. this%has_moving_boundary)
return
2178 if (
allocated(this%trackers))
then
2179 do t = 1, this%n_trackers
2180 if (this%trackers(t)%body_id .eq. &
2181 this%config%bodies(body_idx)%id)
then
2182 if (t .eq. this%ghost_handles(1, body_idx) .or. &
2183 t .eq. this%ghost_handles(2, body_idx))
then
2186 rel_pos = this%trackers(t)%pos - kin_object%center
2189 v_tan(1) = kin_object%vel_ang(2) * rel_pos(3) - &
2190 kin_object%vel_ang(3) * rel_pos(2)
2191 v_tan(2) = kin_object%vel_ang(3) * rel_pos(1) - &
2192 kin_object%vel_ang(1) * rel_pos(3)
2193 v_tan(3) = kin_object%vel_ang(1) * rel_pos(2) - &
2194 kin_object%vel_ang(2) * rel_pos(1)
2197 p_vel = kin_object%vel_trans + v_tan
2199 if (time_s%tstep .gt. 0)
then
2200 call ab_integrate_point_pos(this%trackers(t)%pos, &
2201 this%trackers(t)%vel_lag, p_vel, time_s, nadv)
2213 precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
2215 type(json_file),
intent(inout) :: json
2216 character(len=:),
allocatable,
intent(inout) :: ksp_solver
2217 character(len=:),
allocatable,
intent(inout) :: precon_type
2218 type(json_file),
intent(inout) :: precon_params
2219 real(kind=rp),
intent(out) :: abstol
2220 integer,
intent(out) :: ksp_max_iter
2221 logical,
intent(out) :: res_monitor
2222 logical,
intent(out) :: import_base_shapes
2223 logical :: tmp_logical
2224 character(len=:),
allocatable :: tmp_str
2226 if (
allocated(ksp_solver))
deallocate(ksp_solver)
2227 if (
allocated(precon_type))
deallocate(precon_type)
2229 call json_get_or_default(json, &
2230 'case.fluid.ale.solver.import_base_shape', &
2231 import_base_shapes, .false.)
2233 call json_get_or_default(json,
'case.fluid.ale.solver.type', &
2236 call json_get_or_default(json, &
2237 'case.fluid.ale.solver.preconditioner.type', precon_type,
'jacobi')
2239 if (json%valid_path(
'case.fluid.ale.solver.preconditioner'))
then
2240 call json_get(json,
'case.fluid.ale.solver.preconditioner', &
2244 call json_get_or_default(json, &
2245 'case.fluid.ale.solver.absolute_tolerance', abstol, 1.0e-10_rp)
2246 call json_get_or_default(json,
'case.fluid.ale.solver.monitor', &
2247 res_monitor, .false.)
2248 call json_get_or_default(json,
'case.fluid.ale.solver.max_iterations', &
2249 ksp_max_iter, 10000)
2251 if (json%valid_path(
'case.fluid.ale.solver.output_base_shape'))
then
2252 call json%get(
'case.fluid.ale.solver.output_base_shape', tmp_logical)
2253 this%config%if_output_phi = tmp_logical
2255 if (json%valid_path(
'case.fluid.ale.solver.output_stiffness'))
then
2256 call json%get(
'case.fluid.ale.solver.output_stiffness', tmp_logical)
2257 this%config%if_output_stiffness = tmp_logical
2261 if (json%valid_path(
'case.fluid.ale.solver.mesh_stiffness.type'))
then
2262 call json%get(
'case.fluid.ale.solver.mesh_stiffness.type', tmp_str)
2263 this%config%stiffness_type = tmp_str
2264 if (.not. (trim(tmp_str) .eq.
'built-in'))
then
2265 call neko_error(
"ALE: stiffness_type must be 'built-in'")
2273 type(coef_t),
intent(inout) :: coef
2274 type(chkp_t),
intent(inout) :: checkpoint
2277 if (.not. this%active)
return
2280 call checkpoint%add_ale(coef%dof%x, coef%dof%y, &
2281 coef%dof%z, coef%dof%x_d, coef%dof%y_d, &
2283 coef%Blag, coef%Blaglag, coef%Blag_d, coef%Blaglag_d, &
2284 this%wm_x, this%wm_y, this%wm_z, &
2285 this%wm_x_lag, this%wm_y_lag, &
2287 this%global_pivot_pos, &
2288 this%global_pivot_vel_lag, &
2289 this%global_basis_pos, &
2290 this%global_basis_vel_lag)
Copy data between host and device (or device and device)
Synchronize a device or stream.
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
Apply cyclic boundary condition to a vector field.
Abstract interface for user defined ALE base shapes.
Abstract interface for user defined ALE mesh velocity.
Abstract interface for user defined ALE rigid body kinematics.
Subroutines to add advection terms to the RHS of a transport equation.
ALE Manager: Handles Mesh Motion.
type(ale_manager_t), pointer, public neko_ale
subroutine ale_manager_free(this)
subroutine, public log_pivot(this, time, body_idxs)
Logs pivot positions for all or selected bodies. can be called in usercompute. eg: call neko_alelog_p...
subroutine ale_precon_factory(pc, ksp, coef, dof, gs, bclst, pctype, params)
Factory for ALE Preconditioner.
real(kind=rp) function, dimension(3) get_tracker_pos(this, handle)
subroutine set_pivot_basis_for_checkpoint(this, body_idx)
subroutine compute_rotation_matrix(this, body_idx, time)
Computes Rotation Matrix.
subroutine, public update_ale_mesh(c_xh, wm_x, wm_y, wm_z, wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_)
subroutine, public add_kinematics_to_mesh_velocity(wx, wy, wz, x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, initial_pivot_loc)
subroutine update_mesh_velocity(this, coef, time_s)
Updates the mesh velocity field based on current time and kinematics Sums contributions from all bodi...
subroutine set_pivot_restart(this, time_restart)
subroutine, public compute_stiffness_ale(coef, params)
subroutine solve_base_mesh_displacement(this, coef, json, import_base_shapes, abstol, ksp_solver, ksp_max_iter, precon_type, precon_params, res_monitor)
Solves the Laplace equation to determine the base shape (phi) for each body. It finds a smooth blendi...
subroutine mesh_preview(this, coef, json)
Performs a preview of the mesh motion to verify quality/topology.
subroutine sync_mesh_preview_step(coef, dummy_field)
subroutine append_unique_int(arr, n, val)
subroutine get_ale_solver_params_json(this, json, ksp_solver, precon_type, precon_params, abstol, ksp_max_iter, res_monitor, import_base_shapes)
integer function request_tracker(this, initial_pos, body_id)
subroutine, public log_rot_angles(this, time, body_idxs)
Logs rotation angles for all or selected bodies. can be called in usercompute. eg: call neko_alelog_r...
subroutine register_checkpoint_fields(this, coef, checkpoint)
subroutine ale_manager_init(this, coef, json, user, chkp)
Initialize ALE Manager Sets up solver, registers fields, solves for base shape, etc.
subroutine ghost_tracker_coord_step(this, kin_object, time_s, nadv, body_idx)
subroutine advance_mesh(this, coef, time, nadv)
Main routine to advance the mesh in time.
subroutine sync_chkp(this, coef, xh, adv, chkp, gs_xh)
Defines data structures and algorithms for configuring, calculating, and time-integrating the rigid-b...
subroutine, public compute_body_kinematics_built_in(kinematics, body_conf, time)
Compute built-in kinematics for a body. Uses inputs from JSON. CPU-only.
subroutine, public ab_integrate_point_pos(pos, vel_lag, current_vel, time, nadv)
Advance a single point position (x,y,z) from the point's velocity using AB time-integration.
subroutine, public init_pivot_state(pivot, body_conf)
Initialize pivot state.
subroutine, public update_pivot_location(pivot, pivot_loc, pivot_vel, time, nadv, body_conf)
Updates pivot location.
subroutine, public add_kinematics_to_mesh_velocity_cpu(wx, wy, wz, x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, inital_pivot_loc)
Adds kinematics to mesh velocity (CPU)
subroutine, public compute_cheap_dist_v2_cpu(dist_field, coef, msh, zone_indices)
Compute cheap_dist field by passing distance information throughout an entire local element before do...
subroutine, public update_ale_mesh_cpu(c_xh, wm_x, wm_y, wm_z, wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_type)
Updates mesh position by integrating mesh velocity in time using AB (CPU)
subroutine, public add_kinematics_to_mesh_velocity_device(wx, wy, wz, x_ref, y_ref, z_ref, phi, coef, kinematics, rot_mat, inital_pivot_loc)
Add Kinematics to Mesh Velocity.
subroutine, public compute_cheap_dist_device(dist_field, coef, msh, zone_indices, copy_to_host)
Cheap dist device implementation.
subroutine, public update_ale_mesh_device(c_xh, wm_x, wm_y, wm_z, wm_x_lag, wm_y_lag, wm_z_lag, time, nadv, scheme_type)
Update ALE Mesh.
Defines a Matrix-vector product.
type(mpi_comm), public neko_comm
MPI communicator.
Jacobi preconditioner accelerator backend.
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
real(kind=rp) function, public device_glmin(a_d, n, strm)
Min of a vector of length n.
Device abstraction, common interface for various accelerators.
integer, parameter, public host_to_device
integer, parameter, public device_to_host
Defines a mapping of the degrees of freedom.
subroutine, public field_rzero(a, n)
Zero a real vector.
subroutine, public field_add2(a, b, n)
Vector addition .
subroutine, public field_cmult(a, c, n)
Multiplication by constant c .
Contains the field_serties_t type.
Module for file I/O operations.
Implements fld_file_output_t.
Importation of fields from fld files.
Utilities for retrieving parameters from the case files.
Implements the base abstract type for Krylov solvers plus helper types.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
real(kind=rp), parameter, public pi
subroutine, public copy(a, b, n)
Copy a vector .
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
integer, parameter neko_bcknd_hip
integer, parameter neko_bcknd_device
integer, parameter neko_bcknd_cuda
integer, parameter, public dp
integer, parameter, public rp
Global precision used in computations.
Hybrid ph-multigrid preconditioner.
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Defines a registry for storing solution fields.
type(registry_t), target, public neko_registry
Global field registry.
Defines a function space.
Jacobi preconditioner SX-Aurora backend.
Module with things related to the simulation time.
Interfaces for user interaction with NEKO.
subroutine, public dummy_user_ale_mesh_velocity(wm_x, wm_y, wm_z, coef, x_ref, y_ref, z_ref, base_shapes, time)
subroutine, public dummy_user_ale_base_shapes(base_shapes)
subroutine, public dummy_user_ale_rigid_kinematics(body_id, time, vel_trans, vel_ang)
Defines a zero-valued Dirichlet boundary condition.
Base abstract type for computing the advection operator.
Global ALE Configuration.
Calculated Kinematics for a body at current time.
State history for time-integration of pivots.
Type for a tracked point linked to a body.
Base type for a matrix-vector product providing .
A list of allocatable `bc_t`. Follows the standard interface of lists.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Defines a jacobi preconditioner.
Stores a series (sequence) of fields, logically connected to a base field, and arranged according to ...
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Interface for NEKTON fld files.
A simple output saving a list of fields to a .fld file.
Defines a jacobi preconditioner.
Type for storing initial and final residuals in a Krylov solver.
Base abstract type for a canonical Krylov method, solving .
Defines a canonical Krylov preconditioner.
The function space for the SEM solution fields.
Defines a jacobi preconditioner for SX-Aurora.
A struct that contains all info about the time, expand as needed.
A type collecting all the overridable user routines and flag to suppress type injection from custom m...
Zero-valued Dirichlet boundary condition. Used for no-slip walls, but also for various auxillary cond...