@@ -684,6 +684,7 @@ contains
684684 real (wp), dimension (5 ) :: dt_candidates_glb !< Global dt candidates (ICFL, VCFL, CCFL, TCFL, collision cap)
685685 real (wp) :: dt_prev
686686 logical :: is_fluid_cell !< Cell lies outside every immersed boundary
687+ integer :: bad_cell !< 1 + linear index of a fluid cell with no valid dt, 0 if none
687688 integer :: j, k, l !< Generic loop iterators
688689 integer :: fl !< Fluid loop iterator
689690
@@ -697,9 +698,10 @@ contains
697698 ccfl_dt_local = huge (1.0_wp )
698699 tcfl_dt_local = huge (1.0_wp )
699700 coll_dt_local = huge (1.0_wp )
701+ bad_cell = 0
700702 $:GPU_PARALLEL_LOOP(collapse= 3 , private= ' [vel, alpha, alpha_rho, Re, rho, vel_sum, pres, gamma, pi_inf, c, qv, fl, &
701703 & max_dt, is_fluid_cell]' , reduction= ' [[icfl_dt_local, vcfl_dt_local, ccfl_dt_local, &
702- & tcfl_dt_local]] ' , reductionOp= ' [min]' )
704+ & tcfl_dt_local], [bad_cell]] ' , reductionOp= ' [min, max ]' )
703705 do l = 0 , p
704706 do k = 0 , n
705707 do j = 0 , m
@@ -733,6 +735,10 @@ contains
733735
734736 call s_compute_dt_from_cfl(vel, c, max_dt, rho, Re, alpha, alpha_rho, j, k, l)
735737
738+ ! min () drops a NaN candidate, so a cell with a NaN or non- positive dt would otherwise vanish from
739+ ! the reduction and dt would come from the cells still valid.
740+ if (.not. (max_dt(1 ) > 0._wp )) bad_cell = max (bad_cell, 1 + j + (m + 1 )* (k + (n + 1 )* l))
741+
736742 icfl_dt_local = min (icfl_dt_local, max_dt(1 ))
737743 vcfl_dt_local = min (vcfl_dt_local, max_dt(2 ))
738744 ccfl_dt_local = min (ccfl_dt_local, max_dt(3 ))
@@ -743,6 +749,8 @@ contains
743749 end do
744750 $:END_GPU_PARALLEL_LOOP()
745751
752+ if (bad_cell > 0 ) call s_abort_on_bad_dt_cell(bad_cell - 1 )
753+
746754 ! restrict the time step so an ongoing collision spans at least collision_temporal_resolution time steps; the collision
747755 ! flag is rank- local, so the cap enters as a candidate before the global elementwise min propagates it to all ranks
748756 if (collision_model > 0 .and. collision_temporal_resolution > 0 ) then
@@ -775,6 +783,27 @@ contains
775783
776784 end subroutine s_compute_dt
777785
786+ !> Abort with the location of a fluid cell whose state admits no valid time step (NaN or non- positive inviscid dt).
787+ impure subroutine s_abort_on_bad_dt_cell (idx )
788+
789+ integer , intent (in ) :: idx !< Rank- local linear index j + (m+1 )* (k + (n+1 )* l)
790+ integer :: j, k, l
791+ real (wp) :: loc(3 )
792+ character (len= 256 ) :: msg
793+
794+ j = mod (idx, m + 1 )
795+ k = mod (idx/ (m + 1 ), n + 1 )
796+ l = idx/ ((m + 1 )* (n + 1 ))
797+ loc = 0._wp
798+ loc(1 ) = x_cc(j)
799+ if (n > 0 ) loc(2 ) = y_cc(k)
800+ if (p > 0 ) loc(3 ) = z_cc(l)
801+ write (msg, ' (A,I0,A,3(I0,1X),A,3(ES12.4,1X),A)' ) ' No valid time step: rank ' , proc_rank, ' , local cell (j,k,l) = ' , j, &
802+ & k, l, ' , x = ' , loc, ' . Its state is NaN or unphysical.'
803+ call s_mpi_abort(trim (msg))
804+
805+ end subroutine s_abort_on_bad_dt_cell
806+
778807 !> Apply the body forces source term at each Runge- Kutta stage
779808 subroutine s_apply_bodyforces (q_cons_vf , q_prim_vf_in , rhs_vf_in , ldt )
780809
0 commit comments