#include #include #include #include #include import mean_field; import test_helpers; TEST_CASE( "Polytropic EOS Satisfies Its Analytic Identities", tags::barotrope_eos_unit ) { using namespace mean_field::eos; constexpr double polytropic_index = 3.0; constexpr double polytropic_constant = 1.5; const Polytrope barotrope(polytropic_index, polytropic_constant); using densityV = DensityValue; using pressureV = PressureValue; using enthalpyV = SpecificEnthalpyValue; constexpr std::array densities{ densityV{1.0e-6}, densityV{1.0e-3}, densityV{0.1}, densityV{0.7}, densityV{2.0} }; for (const densityV density : densities) { const pressureV pressure = evaluate(barotrope, density); const enthalpyV enthalpy = evaluate(barotrope, density); const densityV reconstructed_density = evaluate(barotrope, enthalpy); const pressureV reconstructed_pressure = evaluate(barotrope, enthalpy); const enthalpyV reconstructed_enthalpy = evaluate(barotrope, pressure); CHECK_THAT(reconstructed_density.value(), Catch::Matchers::WithinRel(density.value(), 2.0e-14)); CHECK_THAT(reconstructed_pressure.value(), Catch::Matchers::WithinRel(pressure.value(), 2.0e-14)); CHECK_THAT(reconstructed_enthalpy.value(), Catch::Matchers::WithinRel(enthalpy.value(), 2.0e-14)); CHECK_THAT( pressure.value(), Catch::Matchers::WithinRel(density.value() * enthalpy.value() / (polytropic_index + 1.0), 2.0e-14) ); CHECK_THAT( (mean_field::eos::partialDerivative< mean_field::eos::quantity::Pressure, mean_field::eos::quantity::SpecificEnthalpy>( barotrope, mean_field::eos::SpecificEnthalpyValue{enthalpy} ) .value()), Catch::Matchers::WithinRel(density.value(), 2.0e-14) ); CHECK_THAT( (mean_field::eos::partialDerivative< mean_field::eos::quantity::Pressure, mean_field::eos::quantity::Density>( barotrope, mean_field::eos::DensityValue{density} ) .value()), Catch::Matchers::WithinRel(enthalpy.value() / polytropic_index, 2.0e-14) ); } } TEST_CASE( "Polytropic EOS Derivatives Match Centered Differences", tags::barotrope_eos_jacobian ) { using namespace mean_field::eos; const Polytrope barotrope(3.0, 1.5); using densityV = DensityValue; using pressureV = PressureValue; using enthalpyV = SpecificEnthalpyValue; constexpr std::array enthalpies{enthalpyV{0.05}, enthalpyV{0.2}, enthalpyV{0.7}, enthalpyV{1.4}}; for (const enthalpyV enthalpy : enthalpies) { const enthalpyV step = enthalpyV{1.0e-6} * std::max(1.0, enthalpy.value()); const densityV density_difference = (evaluate(barotrope, enthalpy + step) - evaluate(barotrope, enthalpy - step)) / (2.0 * step.value()); const pressureV pressure_difference = (evaluate(barotrope, enthalpy + step) - evaluate(barotrope, enthalpy - step)) / (2.0 * step.value()); CHECK_THAT( density_difference.value(), Catch::Matchers::WithinRel( mean_field::eos::partialDerivative< mean_field::eos::quantity::Density, mean_field::eos::quantity::SpecificEnthalpy>( barotrope, enthalpy ) .value(), 5.0e-10 ) ); CHECK_THAT( pressure_difference.value(), Catch::Matchers::WithinRel( mean_field::eos::partialDerivative< mean_field::eos::quantity::Pressure, mean_field::eos::quantity::SpecificEnthalpy>( barotrope, enthalpy ) .value(), 5.0e-10 ) ); } } TEST_CASE( "Polytropic EOS Has An Exact Zero Density Surface", tags::barotrope_eos_unit ) { const mean_field::eos::Polytrope barotrope(3.0, 1.5); CHECK( mean_field::eos::evaluate( barotrope, mean_field::eos::SpecificEnthalpyValue{-1.0} ) .value() == 0.0 ); CHECK( mean_field::eos::evaluate( barotrope, mean_field::eos::SpecificEnthalpyValue{0.0} ) .value() == 0.0 ); CHECK( mean_field::eos::evaluate( barotrope, mean_field::eos::SpecificEnthalpyValue{-1.0} ) .value() == 0.0 ); CHECK( mean_field::eos::evaluate( barotrope, mean_field::eos::SpecificEnthalpyValue{0.0} ) .value() == 0.0 ); CHECK( (mean_field::eos::partialDerivative< mean_field::eos::quantity::Density, mean_field::eos::quantity::SpecificEnthalpy>( barotrope, mean_field::eos::SpecificEnthalpyValue{-1.0} ) .value() == 0.0) ); CHECK( (mean_field::eos::partialDerivative< mean_field::eos::quantity::Density, mean_field::eos::quantity::SpecificEnthalpy>( barotrope, mean_field::eos::SpecificEnthalpyValue{0.0} ) .value() == 0.0) ); CHECK( (mean_field::eos::partialDerivative< mean_field::eos::quantity::Pressure, mean_field::eos::quantity::SpecificEnthalpy>( barotrope, mean_field::eos::SpecificEnthalpyValue{0.0} ) .value() == 0.0) ); } TEST_CASE( "Polytropic EOS Rejects Invalid Material Parameters", tags::barotrope_eos_unit ) { CHECK_THROWS_AS(mean_field::eos::Polytrope(0.5, 1.0), std::invalid_argument); CHECK_THROWS_AS(mean_field::eos::Polytrope(3.0, 0.0), std::invalid_argument); CHECK_THROWS_AS(mean_field::eos::Polytrope(std::numeric_limits::infinity(), 1.0), std::invalid_argument); const mean_field::eos::Polytrope barotrope(3.0, 1.0); CHECK_THROWS_AS( mean_field::eos::evaluate(barotrope, mean_field::eos::DensityValue{-1.0}), std::domain_error ); CHECK_THROWS_AS( mean_field::eos::evaluate( barotrope, mean_field::eos::DensityValue{-1.0} ), std::domain_error ); CHECK_THROWS_AS( mean_field::eos::evaluate( barotrope, mean_field::eos::PressureValue{-1.0} ), std::domain_error ); }