|
| 1 | +//============================================================================== |
| 2 | +// TwoMomentRad - a radiation transport library for patch-based AMR codes |
| 3 | +// Copyright 2020 Benjamin Wibking. |
| 4 | +// Released under the MIT license. See LICENSE file included in the GitHub repo. |
| 5 | +//============================================================================== |
| 6 | +/// \file testDensityFloorUnit.cpp |
| 7 | +/// \brief Unit test for spatially varying density floors. |
| 8 | +/// |
| 9 | + |
| 10 | +#include "AMReX_Geometry.H" |
| 11 | +#include "AMReX_Math.H" |
| 12 | +#include "AMReX_ParallelDescriptor.H" |
| 13 | +#include "AMReX_ParmParse.H" |
| 14 | +#include "AMReX_Parser.H" |
| 15 | +#include "AMReX_REAL.H" |
| 16 | +#include "AMReX_Reduce.H" |
| 17 | + |
| 18 | +#include "eos.H" |
| 19 | +#include "extern_parameters.H" |
| 20 | +#include "fundamental_constants.H" |
| 21 | +#include "hydro/hydro_system.hpp" |
| 22 | + |
| 23 | +struct DensityFloorUnitProblem { |
| 24 | +}; |
| 25 | + |
| 26 | +template <> struct quokka::EOS_Traits<DensityFloorUnitProblem> { |
| 27 | + static constexpr double gamma = 5. / 3.; |
| 28 | + static constexpr double mean_molecular_weight = C::m_u; |
| 29 | +}; |
| 30 | + |
| 31 | +template <> struct Physics_Traits<DensityFloorUnitProblem> { |
| 32 | + static constexpr bool is_self_gravity_enabled = false; |
| 33 | + static constexpr bool is_hydro_enabled = true; |
| 34 | + static constexpr int numMassScalars = 0; |
| 35 | + static constexpr int numPassiveScalars = numMassScalars + 0; |
| 36 | + static constexpr bool is_radiation_enabled = false; |
| 37 | + static constexpr bool is_dust_enabled = false; |
| 38 | + static constexpr bool is_mhd_enabled = false; |
| 39 | + static constexpr int nGroups = 1; |
| 40 | + static constexpr int nDustGroups = 1; |
| 41 | + static constexpr UnitSystem unit_system = UnitSystem::CGS; |
| 42 | +}; |
| 43 | + |
| 44 | +auto problem_main() -> int |
| 45 | +{ |
| 46 | + init_extern_parameters(); |
| 47 | + amrex::Real small_temp = 1.0e-10; |
| 48 | + amrex::Real small_dens = 1.0e-100; |
| 49 | + eos_init(small_temp, small_dens); |
| 50 | + |
| 51 | + amrex::ParmParse pp; |
| 52 | + amrex::Real base_density_floor = 0.0; |
| 53 | + pp.query("density_floor", base_density_floor); |
| 54 | + |
| 55 | + std::string density_floor_expr; |
| 56 | + pp.query("density_floor_expr", density_floor_expr); |
| 57 | + if (density_floor_expr.empty()) { |
| 58 | + amrex::Print() << "density_floor_expr must be set for DensityFloorUnit test.\n"; |
| 59 | + return 1; |
| 60 | + } |
| 61 | + |
| 62 | + amrex::Parser parser(density_floor_expr); |
| 63 | + parser.registerVariables({"x", "y", "z", "base_density_floor"}); |
| 64 | + auto const parser_exe = parser.compile<4>(); |
| 65 | + |
| 66 | + constexpr int nx = 4; |
| 67 | + constexpr int ny = 1; |
| 68 | + constexpr int nz = 1; |
| 69 | + amrex::IntVect const dom_lo(AMREX_D_DECL(0, 0, 0)); |
| 70 | + amrex::IntVect const dom_hi(AMREX_D_DECL(nx - 1, ny - 1, nz - 1)); |
| 71 | + amrex::Box const domain(dom_lo, dom_hi); |
| 72 | + amrex::RealBox const real_box({AMREX_D_DECL(0.0, 0.0, 0.0)}, {AMREX_D_DECL(1.0, 1.0, 1.0)}); |
| 73 | + amrex::Array<int, AMREX_SPACEDIM> const is_periodic{AMREX_D_DECL(0, 0, 0)}; |
| 74 | + amrex::Geometry const geom(domain, &real_box, amrex::CoordSys::cartesian, is_periodic.data()); |
| 75 | + |
| 76 | + amrex::BoxArray ba(domain); |
| 77 | + ba.maxSize(domain.size()); |
| 78 | + amrex::DistributionMapping const dm(ba); |
| 79 | + int const ncomp = Physics_Indices<DensityFloorUnitProblem>::nvarTotal_cc; |
| 80 | + amrex::MultiFab state(ba, dm, ncomp, 0); |
| 81 | + |
| 82 | + state.setVal(0.0); |
| 83 | + |
| 84 | + amrex::Real const rho_init = 0.5 * base_density_floor; |
| 85 | + amrex::Real const Tgas_init = 1.0; |
| 86 | + amrex::Real const Eint_init = quokka::EOS<DensityFloorUnitProblem>::ComputeEintFromTgas(rho_init, Tgas_init); |
| 87 | + state.setVal(rho_init, HydroSystem<DensityFloorUnitProblem>::density_index, 1, 0); |
| 88 | + state.setVal(Eint_init, HydroSystem<DensityFloorUnitProblem>::energy_index, 1, 0); |
| 89 | + state.setVal(Eint_init, HydroSystem<DensityFloorUnitProblem>::internalEnergy_index, 1, 0); |
| 90 | + |
| 91 | + auto const density_floor_func = [=] AMREX_GPU_HOST_DEVICE(amrex::Real x, amrex::Real y, amrex::Real z, |
| 92 | + amrex::Real base_floor) -> amrex::Real { return parser_exe(x, y, z, base_floor); }; |
| 93 | + |
| 94 | + HydroSystem<DensityFloorUnitProblem>::EnforceLimits(base_density_floor, 0.0, state, geom.data(), density_floor_func); |
| 95 | + |
| 96 | + amrex::ReduceOps<amrex::ReduceOpMax> reduce_op; |
| 97 | + amrex::ReduceData<amrex::Real> reduce_data(reduce_op); |
| 98 | + auto const *const prob_lo = geom.ProbLo(); |
| 99 | + auto const *const dx = geom.CellSize(); |
| 100 | + |
| 101 | + for (amrex::MFIter mfi(state); mfi.isValid(); ++mfi) { |
| 102 | + amrex::Box const &bx = mfi.validbox(); |
| 103 | + auto const &data = state.array(mfi); |
| 104 | + |
| 105 | + reduce_op.eval(bx, reduce_data, |
| 106 | + [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept -> amrex::GpuTuple<amrex::Real> { |
| 107 | + amrex::Real const x = prob_lo[0] + (static_cast<amrex::Real>(i) + 0.5) * dx[0]; |
| 108 | +#if (AMREX_SPACEDIM >= 2) |
| 109 | + amrex::Real const y = prob_lo[1] + (static_cast<amrex::Real>(j) + 0.5) * dx[1]; |
| 110 | +#else |
| 111 | + amrex::Real const y = 0.0; |
| 112 | +#endif |
| 113 | +#if (AMREX_SPACEDIM == 3) |
| 114 | + amrex::Real const z = prob_lo[2] + (static_cast<amrex::Real>(k) + 0.5) * dx[2]; |
| 115 | +#else |
| 116 | + amrex::Real const z = 0.0; |
| 117 | +#endif |
| 118 | + amrex::Real const expected = parser_exe(x, y, z, base_density_floor); |
| 119 | + amrex::Real const actual = data(i, j, k, HydroSystem<DensityFloorUnitProblem>::density_index); |
| 120 | + return {amrex::Math::abs(actual - expected)}; |
| 121 | + }); |
| 122 | + } |
| 123 | + |
| 124 | + auto [max_err] = reduce_data.value(); |
| 125 | + amrex::ParallelDescriptor::ReduceRealMax(max_err); |
| 126 | + |
| 127 | + amrex::Real const tol = 1.0e-12; |
| 128 | + int status = 0; |
| 129 | + if (!(max_err <= tol)) { |
| 130 | + amrex::Print() << "Max density floor error = " << max_err << "\n"; |
| 131 | + status = 1; |
| 132 | + } |
| 133 | + |
| 134 | + return status; |
| 135 | +} |
0 commit comments