Skip to content

Commit e7139bc

Browse files
Update terminal output and add limiting factor to adaptive output (#1757)
Co-authored-by: Spencer Bryngelson <sbryngelson@gmail.com>
1 parent da39d1f commit e7139bc

11 files changed

Lines changed: 149 additions & 42 deletions

File tree

docs/documentation/case.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ This is enabled by adding ``'elliptic_smoothing': "T",`` and ``'elliptic_smoothi
369369
| `coefficient_of_restitution` | Real | A number 0 to 1 describing how elastic IB collisions are |
370370
| `collision_model` | Integer | Integer to select the collision model being used for IB collisions. |
371371
| `collision_time` | Real | Amount of simulation time used to resolve collisions |
372+
| `collision_temporal_resolution` | Integer | Minimum number of adaptive time steps used to resolve each collision |
372373
| `ib_coefficient_of_friction` | Real | Coefficient of friction used in IB collisions |
373374

374375
These parameters should be prepended with `patch_ib(j)%` where $j$ is the patch index.
@@ -419,6 +420,8 @@ Additional details on this specification can be found in [NACA airfoil](https://
419420

420421
- `collision_time` is approximately the amount of simulation time used to resolve collisions. This is handled by modifying the spring constant used to apply collision forces.
421422

423+
- `collision_temporal_resolution` restricts the adaptive time step (`cfl_adap_dt`) to at most `collision_time / collision_temporal_resolution` while any collision is occurring, so that each collision is resolved with at least that many time steps. Pairing it with `ramp_ratio` limits how quickly the time step grows back once the collision ends.
424+
422425
- `ib_coefficient_of_friction` is the coefficient of friction used in IB collisions.
423426

424427
- `ib_neighborhood_radius` controls the size of the neighborhood size. A value of $r$ indicates that any given rank is aware of IBs up to $r$ ranks away. This value defaults to 0, which leaves the radius unset so that it is selected automatically. This parameter is required to strong-scale a case when IBs eventually grow to be larger than one full processor domain wide.
@@ -543,6 +546,7 @@ See @ref equations "Equations" for the mathematical models these parameters cont
543546
| `cfl_const_dt` | Logical | CFL based non-adaptive time-stepping |
544547
| `cfl_dt` | Logical | Enable CFL-based time stepping |
545548
| `cfl_target` | Real | Specified CFL value |
549+
| `ramp_ratio` | Real | Maximum factor by which the adaptive time step may grow per time step |
546550
| `n_start` | Integer | Save file from which to start simulation |
547551
| `t_save` | Real | Time duration between data output |
548552
| `t_stop` | Real | Simulation stop time |
@@ -707,6 +711,8 @@ restart data being resumed from. Pass `-t pre_process` explicitly (as in the res
707711

708712
- `cfl_target` specifies the target CFL value
709713

714+
- `ramp_ratio` limits how much the adaptive time step can grow from one time step to the next: `dt` is capped at `ramp_ratio` times the previous `dt`. Must be at least 1. When unset, the time step growth is unlimited.
715+
710716
- `n_start` specifies the save file to start at
711717

712718
- `t_save` specifies the time interval between data output during the simulation

src/common/m_mpi_common.fpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,22 @@ contains
441441

442442
end subroutine s_mpi_allreduce_min
443443

444+
!> Reduce a local real vector to its elementwise global minimum across all MPI ranks.
445+
impure subroutine s_mpi_allreduce_min_vec(var_loc, var_glb)
446+
447+
real(wp), dimension(:), intent(in) :: var_loc
448+
real(wp), dimension(:), intent(out) :: var_glb
449+
450+
#ifdef MFC_MPI
451+
integer :: ierr !< Generic flag used to identify and report MPI errors
452+
453+
call MPI_ALLREDUCE(var_loc, var_glb, size(var_loc), mpi_p, MPI_MIN, MPI_COMM_WORLD, ierr)
454+
#else
455+
var_glb = var_loc
456+
#endif
457+
458+
end subroutine s_mpi_allreduce_min_vec
459+
444460
!> Reduce a local real value to its global maximum across all MPI ranks.
445461
impure subroutine s_mpi_allreduce_max(var_loc, var_glb)
446462

src/post_process/m_start_up.fpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,18 @@ contains
138138
eta_hh = int(eta_sec)/3600
139139
eta_mm = mod(int(eta_sec), 3600)/60
140140
eta_ss = mod(int(eta_sec), 60)
141-
print '(" [", I3, "%] Saving ", I8, " of ", I0, " Time Avg = ", ES16.6, " Time/step = ", ES12.6, " ETA (HH:MM:SS) = ", I0, ":", I2.2, ":", I2.2)', &
142-
& int(ceiling(100._wp*(real(t_step - n_start)/(n_save)))), t_step, n_save, wall_time_avg, wall_time, eta_hh, &
141+
print '(" [", I3, "%] Saving ", I0, " of ", I0, " t/step ", ES9.2, "s (avg ", ES9.2, "s) ETA ", I0, ":", I2.2, ":", I2.2)', &
142+
& int(ceiling(100._wp*(real(t_step - n_start)/(n_save)))), t_step, n_save, wall_time, wall_time_avg, eta_hh, &
143143
& eta_mm, eta_ss
144144
else
145145
eta_sec = wall_time_avg*real((t_step_stop - t_step)/t_step_save, wp)
146146
eta_hh = int(eta_sec)/3600
147147
eta_mm = mod(int(eta_sec), 3600)/60
148148
eta_ss = mod(int(eta_sec), 60)
149-
print '(" [", I3, "%] Saving ", I8, " of ", I0, " @ t_step = ", I8, " Time Avg = ", ES16.6, " Time/step = ", ES12.6, " ETA (HH:MM:SS) = ", I0, ":", I2.2, ":", I2.2)', &
149+
print '(" [", I3, "%] Saving ", I0, " of ", I0, " (t_step ", I0, ") t/step ", ES9.2, "s (avg ", ES9.2, "s) ETA ", I0, ":", I2.2, ":", I2.2)', &
150150
& int(ceiling(100._wp*(real(t_step - t_step_start)/(t_step_stop - t_step_start + 1)))), &
151-
& (t_step - t_step_start)/t_step_save + 1, (t_step_stop - t_step_start)/t_step_save + 1, t_step, &
152-
& wall_time_avg, wall_time, eta_hh, eta_mm, eta_ss
151+
& (t_step - t_step_start)/t_step_save + 1, (t_step_stop - t_step_start)/t_step_save + 1, t_step, wall_time, &
152+
& wall_time_avg, eta_hh, eta_mm, eta_ss
153153
end if
154154
end if
155155

src/simulation/m_collisions.fpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ module m_collisions
2121
implicit none
2222

2323
private; public :: s_apply_collision_forces, s_initialize_collisions_module, s_finalize_collisions_module, &
24-
& f_local_rank_owns_location, f_neighborhood_ranks_own_location, ib_gbl_idx_lookup
24+
& f_local_rank_owns_location, f_neighborhood_ranks_own_location, ib_gbl_idx_lookup, collisions_active
2525
! overlap distances for computing collisions
2626
integer, allocatable, dimension(:,:) :: collision_lookup
2727
real(wp), allocatable, dimension(:,:) :: wall_overlap_distances
@@ -32,6 +32,9 @@ module m_collisions
3232
integer, dimension(:), allocatable :: ib_gbl_idx_lookup
3333
$:GPU_DECLARE(create='[ib_gbl_idx_lookup]')
3434

35+
!> true when any IB-IB or IB-wall contact was detected on this rank since the last adaptive-dt computation
36+
logical :: collisions_active
37+
3538
contains
3639

3740
subroutine s_initialize_collisions_module()
@@ -47,6 +50,7 @@ contains
4750
@:ALLOCATE(wall_overlap_distances(num_local_ibs_max*27, 6))
4851

4952
wall_overlap_distances = 0
53+
collisions_active = .false.
5054
$:GPU_UPDATE(device='[wall_overlap_distances]')
5155
$:GPU_UPDATE(device='[ib_coefficient_of_friction]')
5256

@@ -59,15 +63,19 @@ contains
5963
type(integer_field), intent(in) :: ib_markers
6064
real(wp), dimension(num_ibs, 3), intent(inout) :: forces, torques
6165
integer :: num_considered_collisions
66+
logical :: any_wall_collision
6267

6368
! return if no collisions
6469

6570
if (collision_model == 0) return
6671

6772
! get is distance used in the force calculation with each IB and each wall
68-
call s_detect_wall_collisions()
73+
call s_detect_wall_collisions(any_wall_collision)
6974
call s_detect_ib_collisions(ghost_points, ib_markers, num_gps, num_considered_collisions)
7075

76+
! accumulate across RK stages; consumed (and reset) by s_compute_dt once per time step
77+
collisions_active = collisions_active .or. any_wall_collision .or. (num_considered_collisions > 0)
78+
7179
select case (collision_model)
7280
case (1) ! soft sphere model
7381
call s_apply_wall_collision_forces_soft_sphere(forces, torques)
@@ -335,12 +343,14 @@ contains
335343
end subroutine s_detect_ib_collisions
336344

337345
!> @brief uses boundary conditions and particle locations to check for wall conditions
338-
subroutine s_detect_wall_collisions()
346+
subroutine s_detect_wall_collisions(any_wall_collision)
339347

340-
integer :: gp_idx, i, j, k, patch_id
341-
real(wp) :: edge_location, overlap_distance
348+
logical, intent(out) :: any_wall_collision
349+
integer :: gp_idx, i, j, k, patch_id
350+
real(wp) :: edge_location, overlap_distance, max_overlap
342351

343-
$:GPU_PARALLEL_LOOP(private='[patch_id, edge_location, overlap_distance]')
352+
max_overlap = 0._wp
353+
$:GPU_PARALLEL_LOOP(private='[patch_id, edge_location, overlap_distance]', reduction='[[max_overlap]]', reductionOp='[max]')
344354
do patch_id = 1, num_ibs
345355
#:for X, DIR, IDX in [('x', 1, 1), ('y', 2, 3), ('z', 3, 5)]
346356
! check if the boundaries are either of the two conditions we should compute collisions with
@@ -355,6 +365,7 @@ contains
355365
overlap_distance = 0._wp
356366
end if
357367
wall_overlap_distances(patch_id, ${IDX}$) = overlap_distance
368+
max_overlap = max(max_overlap, overlap_distance)
358369
end if
359370

360371
if (ib_bc_${X}$%end == BC_SLIP_WALL .or. ib_bc_${X}$%end == BC_NO_SLIP_WALL) then
@@ -365,11 +376,14 @@ contains
365376
overlap_distance = 0._wp
366377
end if
367378
wall_overlap_distances(patch_id, ${IDX}$ + 1) = overlap_distance
379+
max_overlap = max(max_overlap, overlap_distance)
368380
end if
369381
#:endfor
370382
end do
371383
$:END_GPU_PARALLEL_LOOP()
372384

385+
any_wall_collision = max_overlap > 0._wp
386+
373387
end subroutine s_detect_wall_collisions
374388

375389
!> @brief function checks if this local MPI processor owns this specific collision

src/simulation/m_global_parameters.fpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ contains
356356
dt = dflt_real
357357
cfl_dt = .false.
358358
cfl_target = dflt_real
359+
ramp_ratio = dflt_real
359360

360361
t_step_stop = dflt_int
361362
t_step_save = dflt_int
@@ -508,6 +509,7 @@ contains
508509
! Immersed Boundaries (sim-specific extras)
509510
ib_neighborhood_radius = 0
510511
collision_model = 0
512+
collision_temporal_resolution = 0
511513
coefficient_of_restitution = dflt_real
512514
collision_time = dflt_real
513515
ib_coefficient_of_friction = dflt_real

src/simulation/m_sim_helpers.fpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ module m_sim_helpers
1414

1515
implicit none
1616

17-
private; public :: s_compute_cell_state, s_compute_stability_from_dt, s_compute_dt_from_cfl
17+
private; public :: s_compute_cell_state, s_compute_stability_from_dt, s_compute_dt_from_cfl, dt_limiter, dt_limiter_names
18+
19+
!> Criterion currently limiting the adaptive time step (ICFL, VCFL, CCFL, the collision cap, or the ramp limiter)
20+
character(len=4) :: dt_limiter = 'none'
21+
character(len=4), dimension(4), parameter :: dt_limiter_names = (/'ICFL', 'VCFL', 'CCFL', 'COLL'/)
1822

1923
contains
2024

@@ -174,18 +178,22 @@ contains
174178
175179
end subroutine s_compute_stability_from_dt
176180
177-
!> Computes dt for a specified CFL number
181+
!> Computes the candidate dts for a specified CFL number: max_dt(1) from the inviscid, max_dt(2) the viscous, and max_dt(3) the
182+
!! capillary criterion (huge where the criterion is inactive)
178183
subroutine s_compute_dt_from_cfl(vel, c, max_dt, rho, Re_l, j, k, l)
179184
180185
$:GPU_ROUTINE(parallelism='[seq]')
181186
real(wp), dimension(num_vels), intent(in) :: vel
182187
real(wp), intent(in) :: c, rho
183-
real(wp), intent(inout) :: max_dt
188+
real(wp), dimension(3), intent(out) :: max_dt
184189
real(wp), dimension(2), intent(in) :: Re_l
185190
integer, intent(in) :: j, k, l
186191
real(wp) :: vcfl_dt, ccfl_dt
187192
real(wp) :: fltr_dtheta
188193
194+
max_dt(2) = huge(1._wp)
195+
max_dt(3) = huge(1._wp)
196+
189197
! Inviscid CFL calculation
190198
! The multi-dimensional CFL terms are written out here rather than
191199
! obtained from a shared helper procedure: NVHPC 25.5's fort2 segfaults
@@ -195,15 +203,15 @@ contains
195203
#:if not MFC_CASE_OPTIMIZATION or num_dims > 2
196204
if (grid_geometry == 3) then
197205
fltr_dtheta = f_compute_filtered_dtheta(k, l)
198-
max_dt = cfl_target*min(dx(j)/(abs(vel(1)) + c), dy(k)/(abs(vel(2)) + c), fltr_dtheta/(abs(vel(3)) + c))
206+
max_dt(1) = cfl_target*min(dx(j)/(abs(vel(1)) + c), dy(k)/(abs(vel(2)) + c), fltr_dtheta/(abs(vel(3)) + c))
199207
else
200-
max_dt = cfl_target*min(dx(j)/(abs(vel(1)) + c), dy(k)/(abs(vel(2)) + c), dz(l)/(abs(vel(3)) + c))
208+
max_dt(1) = cfl_target*min(dx(j)/(abs(vel(1)) + c), dy(k)/(abs(vel(2)) + c), dz(l)/(abs(vel(3)) + c))
201209
end if
202210
#:endif
203211
else if (n > 0) then
204-
max_dt = cfl_target*min(dx(j)/(abs(vel(1)) + c), dy(k)/(abs(vel(2)) + c))
212+
max_dt(1) = cfl_target*min(dx(j)/(abs(vel(1)) + c), dy(k)/(abs(vel(2)) + c))
205213
else
206-
max_dt = cfl_target*(dx(j)/(abs(vel(1)) + c))
214+
max_dt(1) = cfl_target*(dx(j)/(abs(vel(1)) + c))
207215
end if
208216

209217
! Viscous calculations
@@ -220,7 +228,7 @@ contains
220228
else
221229
vcfl_dt = cfl_target*(dx(j)**2._wp)/maxval(1/(rho*Re_l))
222230
end if
223-
max_dt = min(max_dt, vcfl_dt)
231+
max_dt(2) = vcfl_dt
224232
end if
225233

226234
! Capillary CFL calculations
@@ -239,7 +247,7 @@ contains
239247
else
240248
ccfl_dt = cfl_target*sqrt(rho*dx(j)**3._wp/(2._wp*pi*sigma))
241249
end if
242-
max_dt = min(max_dt, ccfl_dt)
250+
max_dt(3) = ccfl_dt
243251
end if
244252

245253
end subroutine s_compute_dt_from_cfl

src/simulation/m_start_up.fpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ contains
573573
real(wp), intent(inout) :: time_avg
574574
integer :: i, eta_hh, eta_mm, eta_ss
575575
real(wp) :: eta_sec
576+
real(wp) :: dt_floor
577+
character(len=8) :: lim_str !< Time-step limiter tag, e.g. ' (ICFL)'
576578

577579
if (cfl_dt) then
578580
if (cfl_const_dt .and. t_step == 0) call s_compute_dt()
@@ -581,7 +583,14 @@ contains
581583

582584
if (t_step == 0) dt_init = dt
583585

584-
if (dt < 1.e-3_wp*dt_init .and. cfl_adap_dt .and. proc_rank == 0) then
586+
! the collision restriction deliberately drops dt to collision_time/collision_temporal_resolution, so lower the
587+
! runaway-dt abort threshold below that cap when it is enabled
588+
dt_floor = 1.e-3_wp*dt_init
589+
if (collision_model > 0 .and. collision_temporal_resolution > 0) then
590+
dt_floor = min(dt_floor, 1.e-3_wp*collision_time/real(collision_temporal_resolution, wp))
591+
end if
592+
593+
if (dt < dt_floor .and. cfl_adap_dt .and. proc_rank == 0) then
585594
print *, "Delta t = ", dt
586595
call s_mpi_abort("Delta t has become too small")
587596
end if
@@ -605,18 +614,21 @@ contains
605614
eta_hh = int(eta_sec)/3600
606615
eta_mm = mod(int(eta_sec), 3600)/60
607616
eta_ss = mod(int(eta_sec), 60)
608-
print '(" [", I3, "%] Time ", ES16.6, " dt = ", ES16.6, " @ Time Step = ", I8, " Time Avg = ", ES16.6, " Time/step = ", ES12.6, " ETA (HH:MM:SS) = ", I0, ":", I2.2, ":", I2.2)', &
609-
& int(ceiling(100._wp*(mytime/t_stop))), mytime, dt, t_step, wall_time_avg, wall_time, eta_hh, eta_mm, eta_ss
617+
lim_str = ''
618+
if (cfl_adap_dt) lim_str = ' (' // dt_limiter // ')'
619+
print '(" [", I3, "%] t = ", ES11.4, " dt = ", ES11.4, A, " @ step ", I0, " t/step ", ES9.2, "s (avg ", ES9.2, "s) ETA ", I0, ":", I2.2, ":", I2.2)', &
620+
& int(ceiling(100._wp*(mytime/t_stop))), mytime, dt, trim(lim_str), t_step, wall_time, wall_time_avg, eta_hh, &
621+
& eta_mm, eta_ss
610622
end if
611623
else
612624
if (proc_rank == 0 .and. mod(t_step - t_step_start, t_step_print) == 0) then
613625
eta_sec = wall_time_avg*real(t_step_stop - t_step, wp)
614626
eta_hh = int(eta_sec)/3600
615627
eta_mm = mod(int(eta_sec), 3600)/60
616628
eta_ss = mod(int(eta_sec), 60)
617-
print '(" [", I3, "%] Time step ", I8, " of ", I0, " @ t_step = ", I8, " Time Avg = ", ES12.6, " Time/step= ", ES12.6, " ETA (HH:MM:SS) = ", I0, ":", I2.2, ":", I2.2)', &
629+
print '(" [", I3, "%] step ", I0, " of ", I0, " (t_step ", I0, ") t/step ", ES9.2, "s (avg ", ES9.2, "s) ETA ", I0, ":", I2.2, ":", I2.2)', &
618630
& int(ceiling(100._wp*(real(t_step - t_step_start)/(t_step_stop - t_step_start + 1)))), &
619-
& t_step - t_step_start + 1, t_step_stop - t_step_start + 1, t_step, wall_time_avg, wall_time, eta_hh, &
631+
& t_step - t_step_start + 1, t_step_stop - t_step_start + 1, t_step, wall_time, wall_time_avg, eta_hh, &
620632
& eta_mm, eta_ss
621633
end if
622634
end if

0 commit comments

Comments
 (0)