From 7e9f5e0a55570482f273c7d0ee35bae434f5dd12 Mon Sep 17 00:00:00 2001 From: Zhi Chen <62574124+zhichen3@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:30:36 -0400 Subject: [PATCH 1/3] address 2d spherical transverse correction (#2961) This adds the necessary pressure correction during transverse correction since our usual flux doesn't contain pressure in spherical2d --- Source/hydro/trans.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Source/hydro/trans.cpp b/Source/hydro/trans.cpp index acbc4947df..18dd50c2e0 100644 --- a/Source/hydro/trans.cpp +++ b/Source/hydro/trans.cpp @@ -101,6 +101,8 @@ Castro::actual_trans_single(const Box& bx, // NOLINT(readability-convert-member #if AMREX_SPACEDIM == 2 int coord = geom.Coord(); + const auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); #endif bool reset_density = transverse_reset_density; @@ -292,9 +294,17 @@ Castro::actual_trans_single(const Box& bx, // NOLINT(readability-convert-member // // in cylindrical coords -- note that the p term is not // in a divergence for UMX in the x-direction, so there - // are no area factors. For this geometry, we do not + // are no area factors. + // + // Similarly for Spherical2D geometry, we have: + // d(rho u)/dt + d(rho u v)/(rdtheta) = -1/r^2 d(r^2 rho u u)/dr - dp/dr + // d(rho v)/dt + d(rho u v)/dr = -1/(r sin(theta)) d(sin(theta) rho v v)/dtheta - 1/r dp/dtheta + // + // For these non-cartesian geometries, we do not // include p in our definition of the flux in the - // x-direction, for we need to fix this now. + // x-direction for Cylindrical2D or both x- and y-direction for spherical 2D + // So we need to fix this now. + Real runewn = run - hdt * (area_t(ir,jr,kr) * flux_t(ir,jr,kr,UMX) - area_t(il,jl,kl) * flux_t(il,jl,kl,UMX)) * volinv; if (idir_t == 0 && !mom_flux_has_p(0, idir_t, coord)) { @@ -302,6 +312,10 @@ Castro::actual_trans_single(const Box& bx, // NOLINT(readability-convert-member } Real rvnewn = rvn - hdt * (area_t(ir,jr,kr) * flux_t(ir,jr,kr,UMY) - area_t(il,jl,kl) * flux_t(il,jl,kl,UMY)) * volinv; + if (idir_t == 1 && !mom_flux_has_p(1, idir_t, coord)) { + Real r = problo[0] + static_cast(il + 0.5_rt) * dx[0]; + rvnewn = rvnewn - cdtdx / r * (pgp - pgm); + } Real rwnewn = rwn - hdt * (area_t(ir,jr,kr) * flux_t(ir,jr,kr,UMZ) - area_t(il,jl,kl) * flux_t(il,jl,kl,UMZ)) * volinv; Real renewn = ren - hdt * (area_t(ir,jr,kr) * flux_t(ir,jr,kr,UEDEN) - From 327fba883d0a3510b139f307ceb56388bc480022 Mon Sep 17 00:00:00 2001 From: Michael Zingale Date: Thu, 19 Sep 2024 11:49:24 -0400 Subject: [PATCH 2/3] update the shock detection algorithm for r-theta (#2959) --- Source/hydro/advection_util.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Source/hydro/advection_util.cpp b/Source/hydro/advection_util.cpp index 869ec477b8..e17e4d0326 100644 --- a/Source/hydro/advection_util.cpp +++ b/Source/hydro/advection_util.cpp @@ -113,7 +113,6 @@ Castro::shock(const Box& bx, #endif #endif -#if AMREX_SPACEDIM == 1 } else if (coord_type == 2) { // 1-d spherical @@ -122,6 +121,15 @@ Castro::shock(const Box& bx, Real rp = (i + 1 + 0.5_rt) * dx[0]; div_u += 0.5_rt * (rp * rp * q_arr(i+1,j,k,QU) - rm * rm * q_arr(i-1,j,k,QU)) / (rc * rc * dx[0]); +#if AMREX_SPACEDIM == 2 + + Real thetac = (j + 0.5_rt) * dx[1]; + Real thetam = (j - 1 + 0.5_rt) * dx[1]; + Real thetap = (j + 1 + 0.5_rt) * dx[1]; + + div_u += 0.5_rt * (std::sin(thetap) * q_arr(i,j+1,k,QV) - + std::sin(thetam) * q_arr(i,j-1,k,QV)) / + (rc * sin(thetac) * dx[1]); #endif #ifndef AMREX_USE_GPU @@ -134,7 +142,14 @@ Castro::shock(const Box& bx, // now compute (grad P - rho g) . dx // We subtract off the hydrostatic force, since the pressure that - // balances that is not available to make a shock. + // balances that is not available to make a shock. We compute this + // as: + // + // P'_{i+1} = P_{i+1} - [ P_i + \int_{x_i}^{x_{i+1}} rho g dx ] + // + // where the term in the [ ] is the hydrostatic pressure in i+1 + // computed by integrating from x_i to x_{i+1} + // // We'll use a centered diff for the pressure gradient. Real dP_x = 0.5_rt * (q_arr(i+1,j,k,QPRES) - q_arr(i-1,j,k,QPRES)); if (shock_detection_include_sources == 1) { @@ -145,7 +160,13 @@ Castro::shock(const Box& bx, #if AMREX_SPACEDIM >= 2 dP_y = 0.5_rt * (q_arr(i,j+1,k,QPRES) - q_arr(i,j-1,k,QPRES)); if (shock_detection_include_sources == 1) { - dP_y += -0.25_rt * dx[1] * (U_src_arr(i,j+1,k,UMY) + 2.0_rt * U_src_arr(i,j,k,UMY) + U_src_arr(i,j-1,k,UMY)); + Real dy{dx[1]}; + if (coord_type == 2) { + // dx[1] is just dtheta + Real rc = (i + 0.5_rt) * dx[0]; + dy *= rc; + } + dP_y += -0.25_rt * dy * (U_src_arr(i,j+1,k,UMY) + 2.0_rt * U_src_arr(i,j,k,UMY) + U_src_arr(i,j-1,k,UMY)); } #endif #if AMREX_SPACEDIM == 3 From fb34ee127216bb5b44fa51d415150482d1e9454f Mon Sep 17 00:00:00 2001 From: Zhi Chen <62574124+zhichen3@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:49:50 -0400 Subject: [PATCH 3/3] address timestep and cfl violation for Spherical2D (#2962) Change timestep and cfl_violation so we use rdtheta, rdx[1], which is the physical cell length instead of just dx[1] for cell length in theta direction for spherical 2d. --- Source/driver/timestep.cpp | 38 ++++++++++++++++++++++++++++++++++- Source/hydro/Castro_hydro.cpp | 8 ++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Source/driver/timestep.cpp b/Source/driver/timestep.cpp index a7b5936e4e..fd7e029a4b 100644 --- a/Source/driver/timestep.cpp +++ b/Source/driver/timestep.cpp @@ -35,6 +35,9 @@ Castro::estdt_cfl (int is_new) // Courant-condition limited timestep const auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); + const auto coord = geom.Coord(); + amrex::ignore_unused(problo, coord); const MultiFab& stateMF = is_new ? get_new_data(State_Type) : get_old_data(State_Type); @@ -82,6 +85,11 @@ Castro::estdt_cfl (int is_new) Real dt2; #if AMREX_SPACEDIM >= 2 dt2 = dx[1]/(c + std::abs(uy)); + if (coord == 2) { + // dx[1] in Spherical2D is just dtheta, need rdtheta for physical length + // so just multiply by the smallest r + dt2 *= problo[0] + 0.5_rt * dx[0]; + } #else dt2 = dt1; #endif @@ -127,6 +135,9 @@ Castro::estdt_mhd (int is_new) // MHD timestep limiter const auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); + const auto coord = geom.Coord(); + amrex::ignore_unused(problo, coord); const MultiFab& U_state = is_new ? get_new_data(State_Type) : get_old_data(State_Type); @@ -206,6 +217,9 @@ Castro::estdt_mhd (int is_new) Real dt2; #if AMREX_SPACEDIM >= 2 dt2 = dx[1]/(cy + std::abs(uy)); + if (coord == 2) { + dt2 *= problo[0] + 0.5_rt * dx[0]; + } #else dt2 = dt1; #endif @@ -238,6 +252,9 @@ Castro::estdt_temp_diffusion (int is_new) // where D = k/(rho c_v), and k is the conductivity const auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); + const auto coord = geom.Coord(); + amrex::ignore_unused(problo, coord); const MultiFab& stateMF = is_new ? get_new_data(State_Type) : get_old_data(State_Type); @@ -287,6 +304,10 @@ Castro::estdt_temp_diffusion (int is_new) Real dt2; #if AMREX_SPACEDIM >= 2 dt2 = 0.5_rt * dx[1]*dx[1] / D; + if (coord == 2) { + Real r = problo[0] + 0.5_rt * dx[0]; + dt2 *= r * r; + } #else dt2 = dt1; #endif @@ -320,6 +341,9 @@ Castro::estdt_burning (int is_new) } const auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); + const auto coord = geom.Coord(); + amrex::ignore_unused(problo, coord); MultiFab& stateMF = is_new ? get_new_data(State_Type) : get_old_data(State_Type); @@ -368,7 +392,13 @@ Castro::estdt_burning (int is_new) #if AMREX_SPACEDIM == 1 burn_state.dx = dx[0]; #else - burn_state.dx = amrex::min(AMREX_D_DECL(dx[0], dx[1], dx[2])); + Real dx1 = dx[1]; +#if AMREX_SPACEDIM >= 2 + if (coord == 2) { + dx1 *= problo[0] + 0.5_rt * dx[0]; + } +#endif + burn_state.dx = amrex::min(AMREX_D_DECL(dx[0], dx1, dx[2])); #endif burn_state.rho = S(i,j,k,URHO); @@ -464,6 +494,9 @@ Real Castro::estdt_rad (int is_new) { auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); + const auto coord = geom.Coord(); + amrex::ignore_unused(problo, coord); const MultiFab& stateMF = is_new ? get_new_data(State_Type) : get_old_data(State_Type); const MultiFab& radMF = is_new ? get_new_data(Rad_Type) : get_old_data(Rad_Type); @@ -523,6 +556,9 @@ Castro::estdt_rad (int is_new) Real dt1 = dx[0] / (c + std::abs(ux)); #if AMREX_SPACEDIM >= 2 Real dt2 = dx[1] / (c + std::abs(uy)); + if (coord == 2) { + dt2 *= problo[0] + 0.5_rt * dx[0]; + } #else Real dt2 = std::numeric_limits::max(); #endif diff --git a/Source/hydro/Castro_hydro.cpp b/Source/hydro/Castro_hydro.cpp index 0dedbc17aa..0e2250ed20 100644 --- a/Source/hydro/Castro_hydro.cpp +++ b/Source/hydro/Castro_hydro.cpp @@ -237,12 +237,20 @@ Castro::check_for_cfl_violation(const MultiFab& State, const Real dt) int cfl_violation = 0; auto dx = geom.CellSizeArray(); + const auto problo = geom.ProbLoArray(); + const auto coord = geom.Coord(); + amrex::ignore_unused(problo, coord); Real dtdx = dt / dx[0]; Real dtdy = 0.0_rt; if (AMREX_SPACEDIM >= 2) { dtdy = dt / dx[1]; + if (coord == 2) { + // dx[1] in Spherical2D is just rdtheta, need rdtheta for physical length + // Just choose to divide by the smallest r + dtdy /= problo[0] + 0.5_rt * dx[0]; + } } Real dtdz = 0.0_rt;