@@ -741,6 +741,10 @@ void ProblemInitPackageData(ParameterInput *pin, StateDescriptor *pkg) {
741741 pin->GetOrAddReal (" precipitator" , " source_diag_min_hse_dv_kms" ,
742742 100.0 ),
743743 parthenon::Params::Mutability::Restart);
744+ pkg->AddParam <>(" density_contrast_stop_threshold" ,
745+ pin->GetOrAddReal (" precipitator" ,
746+ " density_contrast_stop_threshold" , 10.0 ),
747+ parthenon::Params::Mutability::Restart);
744748
745749 pkg->AddParam <>(" outer_sponge_inner_radius" ,
746750 pin->GetOrAddReal (" precipitator" , " outer_sponge_inner_radius" ,
@@ -1331,6 +1335,78 @@ void AddSplitSrcTerms(MeshData<Real> *md, const parthenon::SimTime, const Real d
13311335 });
13321336}
13331337
1338+ Real MaxDensityContrastOverRadialMean (Mesh *mesh) {
1339+ auto md = mesh->mesh_data .Get ();
1340+ auto pmb = md->GetBlockData (0 )->GetBlockPointer ();
1341+ auto pkg = pmb->packages .Get (" Hydro" );
1342+
1343+ const int num_bins = pkg->Param <int >(" radial_profile_bins" );
1344+ const Real rmin = pkg->Param <Real>(" radial_profile_min" );
1345+ const Real rmax = pkg->Param <Real>(" radial_profile_max" );
1346+ const Real nominal_outer_radius = pkg->Param <Real>(" nominal_outer_radius" );
1347+ const Real inv_dr =
1348+ (num_bins > 1 && rmax > rmin) ? static_cast <Real>(num_bins) / (rmax - rmin) : 0.0 ;
1349+
1350+ parthenon::ParArray1D<Real> rho_bar (" rho_bar_stop_check" , num_bins);
1351+ auto prim_pack = md->PackVariables (std::vector<std::string>{" prim" });
1352+ ComputeRadialAverageProfile (
1353+ rho_bar, md.get (), rmin, rmax,
1354+ KOKKOS_LAMBDA (const int b, const int k, const int j, const int i, const Real) {
1355+ return prim_pack (b)(IDN , k, j, i);
1356+ });
1357+
1358+ IndexRange ib = md->GetBlockData (0 )->GetBoundsI (IndexDomain::interior);
1359+ IndexRange jb = md->GetBlockData (0 )->GetBoundsJ (IndexDomain::interior);
1360+ IndexRange kb = md->GetBlockData (0 )->GetBoundsK (IndexDomain::interior);
1361+
1362+ Real max_contrast = -std::numeric_limits<Real>::infinity ();
1363+ parthenon::par_reduce (
1364+ DEFAULT_LOOP_PATTERN , " SphericalPrecipMaxDensityContrast" ,
1365+ parthenon::DevExecSpace (), 0 , prim_pack.GetDim (5 ) - 1 , kb.s , kb.e , jb.s , jb.e ,
1366+ ib.s , ib.e ,
1367+ KOKKOS_LAMBDA (const int b, const int k, const int j, const int i,
1368+ Real &local_max) {
1369+ const auto &coords = prim_pack.GetCoords (b);
1370+ const auto &prim = prim_pack (b);
1371+ const Real radius = Radius (coords.Xc <1 >(i), coords.Xc <2 >(j), coords.Xc <3 >(k));
1372+ if (radius > nominal_outer_radius) return ;
1373+ const Real rho_avg = SampleRadialProfile (rho_bar, num_bins, radius, rmin, inv_dr);
1374+ const Real contrast =
1375+ (rho_avg > 0.0 ) ? (prim (IDN , k, j, i) - rho_avg) / rho_avg : 0.0 ;
1376+ if (contrast > local_max) local_max = contrast;
1377+ },
1378+ Kokkos::Max<Real>(max_contrast));
1379+
1380+ #ifdef MPI_PARALLEL
1381+ PARTHENON_MPI_CHECK (MPI_Allreduce (MPI_IN_PLACE , &max_contrast, 1 ,
1382+ MPI_PARTHENON_REAL , MPI_MAX , MPI_COMM_WORLD ));
1383+ #endif
1384+
1385+ return max_contrast;
1386+ }
1387+
1388+ void PostStepMeshUserWorkInLoop (Mesh *mesh, ParameterInput *,
1389+ const parthenon::SimTime &tm) {
1390+ auto md = mesh->mesh_data .Get ();
1391+ auto pmb = md->GetBlockData (0 )->GetBlockPointer ();
1392+ auto pkg = pmb->packages .Get (" Hydro" );
1393+ const Real threshold = pkg->Param <Real>(" density_contrast_stop_threshold" );
1394+ if (!(threshold > 0.0 )) return ;
1395+
1396+ const Real max_contrast = MaxDensityContrastOverRadialMean (mesh);
1397+ if (max_contrast > threshold) {
1398+ auto &mutable_tm = const_cast <parthenon::SimTime &>(tm);
1399+ mutable_tm.tlim = std::min (mutable_tm.tlim , mutable_tm.time + mutable_tm.dt );
1400+ mutable_tm.nlim = (mutable_tm.nlim < 0 ) ? mutable_tm.ncycle + 1
1401+ : std::min (mutable_tm.nlim , tm.ncycle + 1 );
1402+ if (parthenon::Globals::my_rank == 0 ) {
1403+ std::cout << " Stopping precipitator_spherical: max "
1404+ " delta_rho_over_rho_bar="
1405+ << max_contrast << " exceeds " << threshold << std::endl;
1406+ }
1407+ }
1408+ }
1409+
13341410void UserMeshWorkBeforeOutput (Mesh *mesh, ParameterInput *pin,
13351411 const parthenon::SimTime &) {
13361412 auto md = mesh->mesh_data .Get ();
0 commit comments