perf(jacobian-action): major updates to jacobian action application by removing redudant quadrature work. ~5x increase in speed

This commit is contained in:
2026-09-02 17:01:50 -04:00
parent 85500fef3b
commit 25510008dd
74 changed files with 8967 additions and 814 deletions

View File

@@ -91,10 +91,10 @@ export namespace mean_field::eos {
template <typename Candidate>
concept BarotropicClosureEquationOfState =
EquationOfStateModel<Candidate> && SupportsRelation<Candidate, DensityFromSpecificEnthalpy> &&
SupportsPartialDerivative<Candidate, DensityFromSpecificEnthalpy, quantity::SpecificEnthalpy>;
SupportsPartialDerivative<Candidate, DensityFromSpecificEnthalpy, dimensions::quantity::SpecificEnthalpy>;
template <typename Candidate>
concept PressureForceEquationOfState =
EquationOfStateModel<Candidate> && SupportsRelation<Candidate, PressureFromSpecificEnthalpy> &&
SupportsPartialDerivative<Candidate, PressureFromSpecificEnthalpy, quantity::SpecificEnthalpy>;
SupportsPartialDerivative<Candidate, PressureFromSpecificEnthalpy, dimensions::quantity::SpecificEnthalpy>;
} // namespace mean_field::eos

View File

@@ -8,6 +8,11 @@ export import :eos.evaluation;
export namespace mean_field::eos {
class Polytrope final {
public:
struct Parameters final {
double n;
double K;
};
using Relations = RelationCatalog<
PressureFromDensity,
PressureFromSpecificEnthalpy,
@@ -15,6 +20,13 @@ export namespace mean_field::eos {
SpecificEnthalpyFromPressure,
DensityFromSpecificEnthalpy>;
explicit Polytrope(const Parameters parameters)
: Polytrope(
parameters.n,
parameters.K
) {
}
Polytrope(
const double polytropic_index,
const double polytropic_constant
@@ -56,125 +68,131 @@ export namespace mean_field::eos {
return m_enthalpy_scale;
}
[[nodiscard]] PressureValue evaluate(
[[nodiscard]] dimensions::PressureValue evaluate(
PressureFromDensity,
const DensityValue density
const dimensions::DensityValue density
) const {
validate_nonnegativity(density.value(), "density");
if (density.value() == 0.0) {
return PressureValue{0.0};
return dimensions::PressureValue{0.0};
}
return PressureValue{m_polytropic_constant * std::pow(density.value(), 1.0 + 1.0 / m_polytropic_index)};
return dimensions::PressureValue{
m_polytropic_constant * std::pow(density.value(), 1.0 + 1.0 / m_polytropic_index)
};
}
[[nodiscard]] SpecificEnthalpyValue evaluate(
[[nodiscard]] dimensions::SpecificEnthalpyValue evaluate(
SpecificEnthalpyFromDensity,
const DensityValue density
const dimensions::DensityValue density
) const {
validate_nonnegativity(density.value(), "density");
if (density.value() == 0.0) {
return SpecificEnthalpyValue{0.0};
return dimensions::SpecificEnthalpyValue{0.0};
}
return SpecificEnthalpyValue{m_enthalpy_scale * std::pow(density.value(), 1.0 / m_polytropic_index)};
return dimensions::SpecificEnthalpyValue{
m_enthalpy_scale * std::pow(density.value(), 1.0 / m_polytropic_index)
};
}
[[nodiscard]] DensityValue evaluate(
[[nodiscard]] dimensions::DensityValue evaluate(
DensityFromSpecificEnthalpy,
const SpecificEnthalpyValue specificEnthalpy
const dimensions::SpecificEnthalpyValue specificEnthalpy
) const {
validate_finite(specificEnthalpy.value(), "specific enthalpy");
if (specificEnthalpy.value() <= 0.0) {
return DensityValue{0.0};
return dimensions::DensityValue{0.0};
}
return DensityValue{std::pow(specificEnthalpy.value() / m_enthalpy_scale, m_polytropic_index)};
return dimensions::DensityValue{std::pow(specificEnthalpy.value() / m_enthalpy_scale, m_polytropic_index)};
}
[[nodiscard]] PressureValue evaluate(
[[nodiscard]] dimensions::PressureValue evaluate(
PressureFromSpecificEnthalpy,
const SpecificEnthalpyValue specificEnthalpy
const dimensions::SpecificEnthalpyValue specificEnthalpy
) const {
const DensityValue density = evaluate(DensityFromSpecificEnthalpy{}, specificEnthalpy);
const dimensions::DensityValue density = evaluate(DensityFromSpecificEnthalpy{}, specificEnthalpy);
if (specificEnthalpy.value() <= 0.0) {
return PressureValue{0.0};
return dimensions::PressureValue{0.0};
}
return PressureValue{density.value() * specificEnthalpy.value() / (m_polytropic_index + 1.0)};
return dimensions::PressureValue{density.value() * specificEnthalpy.value() / (m_polytropic_index + 1.0)};
}
[[nodiscard]] SpecificEnthalpyValue evaluate(
[[nodiscard]] dimensions::SpecificEnthalpyValue evaluate(
SpecificEnthalpyFromPressure,
const PressureValue pressure
const dimensions::PressureValue pressure
) const {
validate_nonnegativity(pressure.value(), "pressure");
if (pressure.value() == 0.0) {
return SpecificEnthalpyValue{0.0};
return dimensions::SpecificEnthalpyValue{0.0};
}
const double indexPlusOne = m_polytropic_index + 1.0;
return SpecificEnthalpyValue{
return dimensions::SpecificEnthalpyValue{
indexPlusOne * std::pow(m_polytropic_constant, m_polytropic_index / indexPlusOne) *
std::pow(pressure.value(), 1.0 / indexPlusOne)
};
}
[[nodiscard]] PartialDerivative<
quantity::Density,
quantity::SpecificEnthalpy>
dimensions::quantity::Density,
dimensions::quantity::SpecificEnthalpy>
partialDerivative(
DensityFromSpecificEnthalpy,
WithRespectTo<quantity::SpecificEnthalpy>,
const SpecificEnthalpyValue specificEnthalpy
WithRespectTo<dimensions::quantity::SpecificEnthalpy>,
const dimensions::SpecificEnthalpyValue specificEnthalpy
) const {
validate_finite(specificEnthalpy.value(), "specific enthalpy");
if (specificEnthalpy.value() < 0.0) {
return PartialDerivative<quantity::Density, quantity::SpecificEnthalpy>{0.0};
return PartialDerivative<dimensions::quantity::Density, dimensions::quantity::SpecificEnthalpy>{0.0};
}
if (specificEnthalpy.value() == 0.0) {
return PartialDerivative<quantity::Density, quantity::SpecificEnthalpy>{
return PartialDerivative<dimensions::quantity::Density, dimensions::quantity::SpecificEnthalpy>{
m_polytropic_index == 1.0 ? 1.0 / m_enthalpy_scale : 0.0
};
}
return PartialDerivative<quantity::Density, quantity::SpecificEnthalpy>{
return PartialDerivative<dimensions::quantity::Density, dimensions::quantity::SpecificEnthalpy>{
m_polytropic_index / m_enthalpy_scale *
std::pow(specificEnthalpy.value() / m_enthalpy_scale, m_polytropic_index - 1.0)
};
}
[[nodiscard]] PartialDerivative<
quantity::Pressure,
quantity::SpecificEnthalpy>
dimensions::quantity::Pressure,
dimensions::quantity::SpecificEnthalpy>
partialDerivative(
PressureFromSpecificEnthalpy,
WithRespectTo<quantity::SpecificEnthalpy>,
const SpecificEnthalpyValue specificEnthalpy
WithRespectTo<dimensions::quantity::SpecificEnthalpy>,
const dimensions::SpecificEnthalpyValue specificEnthalpy
) const {
const DensityValue density = evaluate(DensityFromSpecificEnthalpy{}, specificEnthalpy);
const dimensions::DensityValue density = evaluate(DensityFromSpecificEnthalpy{}, specificEnthalpy);
return PartialDerivative<quantity::Pressure, quantity::SpecificEnthalpy>{density.value()};
return PartialDerivative<dimensions::quantity::Pressure, dimensions::quantity::SpecificEnthalpy>{
density.value()
};
}
[[nodiscard]] PartialDerivative<
quantity::Pressure,
quantity::Density>
dimensions::quantity::Pressure,
dimensions::quantity::Density>
partialDerivative(
PressureFromDensity,
WithRespectTo<quantity::Density>,
const DensityValue density
WithRespectTo<dimensions::quantity::Density>,
const dimensions::DensityValue density
) const {
validate_nonnegativity(density.value(), "density");
if (density.value() == 0.0) {
return PartialDerivative<quantity::Pressure, quantity::Density>{0.0};
return PartialDerivative<dimensions::quantity::Pressure, dimensions::quantity::Density>{0.0};
}
return PartialDerivative<quantity::Pressure, quantity::Density>{
return PartialDerivative<dimensions::quantity::Pressure, dimensions::quantity::Density>{
m_polytropic_constant * (1.0 + 1.0 / m_polytropic_index) *
std::pow(density.value(), 1.0 / m_polytropic_index)
};

View File

@@ -13,10 +13,10 @@ export namespace mean_field::eos {
ThermodynamicQuantityType InputQuantity,
typename SurfaceState>
[[nodiscard]] constexpr auto pressureSurfaceRelationInput(
const PressureValue targetPressure,
const dimensions::PressureValue targetPressure,
const SurfaceState &state
) {
if constexpr (std::same_as<InputQuantity, quantity::Pressure>) {
if constexpr (std::same_as<InputQuantity, dimensions::quantity::Pressure>) {
return targetPressure;
} else {
return state.value(InputQuantity{});
@@ -30,9 +30,9 @@ export namespace mean_field::eos {
template <
typename EquationOfState,
typename SurfaceState>
[[nodiscard]] static QuantityValue<CarrierQuantity> requiredCarrierValue(
[[nodiscard]] static dimensions::QuantityValue<CarrierQuantity> requiredCarrierValue(
const EquationOfState &equationOfState,
const PressureValue targetPressure,
const dimensions::PressureValue targetPressure,
const SurfaceState &state
) {
return evaluate<CarrierQuantity>(
@@ -47,11 +47,11 @@ export namespace mean_field::eos {
typename SurfaceVariation>
[[nodiscard]] static double inputJacobianContribution(
const EquationOfState &equationOfState,
const PressureValue targetPressure,
const dimensions::PressureValue targetPressure,
const SurfaceState &state,
const SurfaceVariation &variation
) {
if constexpr (std::same_as<InputQuantity, quantity::Pressure>) {
if constexpr (std::same_as<InputQuantity, dimensions::quantity::Pressure>) {
return 0.0;
} else {
const auto derivative = partialDerivative<CarrierQuantity, InputQuantity>(
@@ -67,7 +67,7 @@ export namespace mean_field::eos {
typename SurfaceVariation>
[[nodiscard]] static double carrierCorrectionJacobianAction(
const EquationOfState &equationOfState,
const PressureValue targetPressure,
const dimensions::PressureValue targetPressure,
const SurfaceState &state,
const SurfaceVariation &variation
) {
@@ -92,18 +92,18 @@ export namespace mean_field::eos {
ResolvedPressureSurfaceRelation(
const EquationOfState &equationOfState,
const PressureValue targetPressure
const dimensions::PressureValue targetPressure
) noexcept
: m_equationOfState(std::addressof(equationOfState)),
m_targetPressure(targetPressure) {
}
[[nodiscard]] PressureValue targetPressure() const noexcept {
[[nodiscard]] dimensions::PressureValue targetPressure() const noexcept {
return m_targetPressure;
}
template <typename SurfaceState>
[[nodiscard]] QuantityValue<CarrierQuantity> requiredCarrierValue(const SurfaceState &state) const {
[[nodiscard]] dimensions::QuantityValue<CarrierQuantity> requiredCarrierValue(const SurfaceState &state) const {
return detail::PressureSurfaceRelationOperations<RelationType>::requiredCarrierValue(
*m_equationOfState, m_targetPressure, state
);
@@ -123,6 +123,6 @@ export namespace mean_field::eos {
private:
const EquationOfState *m_equationOfState;
PressureValue m_targetPressure;
dimensions::PressureValue m_targetPressure;
};
} // namespace mean_field::eos

View File

@@ -2,132 +2,42 @@ module;
#include <compare>
#include <concepts>
#include <string_view>
#include <type_traits>
export module mean_field:eos.quantities;
export import :dimensions.quantities;
export namespace mean_field::eos {
struct ThermodynamicQuantity { };
// Compatibility names for the thermodynamic subset now owned by the
// general dimensions partition.
using ThermodynamicQuantity = dimensions::ThermodynamicQuantity;
template <typename Candidate>
concept ThermodynamicQuantityType =
std::same_as<Candidate, std::remove_cv_t<Candidate>> && std::derived_from<Candidate, ThermodynamicQuantity>;
concept ThermodynamicQuantityType = dimensions::ThermodynamicQuantityType<Candidate>;
namespace quantity {
struct Density final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "density";
};
struct Pressure final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "pressure";
};
struct SpecificEnthalpy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_enthalpy";
};
using Density = dimensions::quantity::Density;
using Pressure = dimensions::quantity::Pressure;
using SpecificEnthalpy = dimensions::quantity::SpecificEnthalpy;
} // namespace quantity
template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
concept Numeric = dimensions::Numeric<T>;
template <ThermodynamicQuantityType Quantity> class QuantityValue final {
public:
explicit constexpr QuantityValue(const double value) noexcept : m_value(value) {
}
template <ThermodynamicQuantityType Quantity> using QuantityValue = dimensions::QuantityValue<Quantity>;
[[nodiscard]] constexpr double value() const noexcept {
return m_value;
}
using DensityValue = dimensions::DensityValue;
using PressureValue = dimensions::PressureValue;
using SpecificEnthalpyValue = dimensions::SpecificEnthalpyValue;
[[nodiscard]] friend constexpr bool operator==(
const QuantityValue &,
const QuantityValue &
) noexcept = default;
friend constexpr QuantityValue<Quantity> operator+(
const QuantityValue<Quantity> &lhs,
const QuantityValue<Quantity> &rhs
) noexcept {
return QuantityValue<Quantity>{lhs.m_value + rhs.m_value};
}
friend constexpr QuantityValue<Quantity> operator-(
const QuantityValue<Quantity> &lhs,
const QuantityValue<Quantity> &rhs
) noexcept {
return QuantityValue<Quantity>{lhs.m_value - rhs.m_value};
}
template <Numeric rhsT>
friend constexpr QuantityValue<Quantity> operator*(
const QuantityValue<Quantity> &lhs,
rhsT rhs
) noexcept {
return QuantityValue<Quantity>{lhs.m_value * static_cast<double>(rhs)};
}
template <Numeric lhsT>
friend constexpr QuantityValue<Quantity> operator*(
lhsT lhs,
const QuantityValue<Quantity> &rhs
) noexcept {
return QuantityValue<Quantity>{static_cast<double>(lhs) * rhs.m_value};
}
template <Numeric rhsT>
friend constexpr QuantityValue<Quantity> operator/(
const QuantityValue<Quantity> &lhs,
rhsT rhs
) noexcept {
return QuantityValue<Quantity>{lhs.m_value / static_cast<double>(rhs)};
}
template <Numeric compT>
friend constexpr std::partial_ordering operator<=>(
const QuantityValue<Quantity> &lhs,
compT rhs
) noexcept {
return lhs.m_value <=> static_cast<double>(rhs);
}
template <Numeric compT>
friend constexpr std::partial_ordering operator<=>(
compT lhs,
const QuantityValue<Quantity> &rhs
) noexcept {
return static_cast<double>(lhs) <=> rhs.m_value;
}
friend constexpr std::partial_ordering operator<=>(
const QuantityValue<Quantity> &lhs,
const QuantityValue<Quantity> &rhs
) noexcept {
return lhs.m_value <=> rhs.m_value;
}
private:
double m_value;
};
using DensityValue = QuantityValue<quantity::Density>;
using PressureValue = QuantityValue<quantity::Pressure>;
using SpecificEnthalpyValue = QuantityValue<quantity::SpecificEnthalpy>;
template <typename Candidate> struct IsQuantityValue : std::false_type { };
template <ThermodynamicQuantityType Quantity> struct IsQuantityValue<QuantityValue<Quantity>> : std::true_type { };
template <typename Candidate> using IsQuantityValue = dimensions::IsQuantityValue<Candidate>;
template <typename Candidate>
concept QuantityValueType = IsQuantityValue<std::remove_cvref_t<Candidate>>::value;
concept QuantityValueType =
dimensions::QuantityValueType<Candidate> && ThermodynamicQuantityType<dimensions::QuantityOfT<Candidate>>;
template <typename Candidate> struct QuantityOf;
template <typename Candidate> using QuantityOf = dimensions::QuantityOf<Candidate>;
template <ThermodynamicQuantityType Quantity> struct QuantityOf<QuantityValue<Quantity>> {
using Type = Quantity;
};
template <QuantityValueType Value> using QuantityOfT = typename QuantityOf<std::remove_cvref_t<Value>>::Type;
template <QuantityValueType Value> using QuantityOfT = dimensions::QuantityOfT<Value>;
template <ThermodynamicQuantityType OutputQuantity, ThermodynamicQuantityType InputQuantity>
class PartialDerivative final {
@@ -163,7 +73,7 @@ export namespace mean_field::eos {
InputQuantity> &rhs
) noexcept;
template <Numeric rhsT>
template <Numeric Scalar>
friend constexpr PartialDerivative<
OutputQuantity,
InputQuantity>
@@ -171,21 +81,21 @@ export namespace mean_field::eos {
const PartialDerivative<
OutputQuantity,
InputQuantity> &,
rhsT
Scalar
) noexcept;
template <Numeric lhsT>
template <Numeric Scalar>
friend constexpr PartialDerivative<
OutputQuantity,
InputQuantity>
operator*(
lhsT,
Scalar,
const PartialDerivative<
OutputQuantity,
InputQuantity> &
) noexcept;
template <Numeric rhsT>
template <Numeric Scalar>
friend constexpr PartialDerivative<
OutputQuantity,
InputQuantity>
@@ -193,22 +103,22 @@ export namespace mean_field::eos {
const PartialDerivative<
OutputQuantity,
InputQuantity> &,
rhsT
Scalar
) noexcept;
template <Numeric cmpT>
template <Numeric Scalar>
friend constexpr std::partial_ordering operator<=>(
const PartialDerivative<
OutputQuantity,
InputQuantity> &lhs,
cmpT rhs
Scalar rhs
) noexcept {
return lhs.m_value <=> static_cast<double>(rhs);
}
template <Numeric cmpT>
template <Numeric Scalar>
friend constexpr std::partial_ordering operator<=>(
cmpT lhs,
Scalar lhs,
const PartialDerivative<
OutputQuantity,
InputQuantity> &rhs

View File

@@ -85,9 +85,11 @@ export namespace mean_field::eos {
template <std::size_t Index, ThermodynamicRelationType RelationType>
using RelationInputT = typename detail::QuantityAt<Index, typename RelationType::InputQuantities>::Type;
using PressureFromDensity = Relation<quantity::Pressure, quantity::Density>;
using PressureFromSpecificEnthalpy = Relation<quantity::Pressure, quantity::SpecificEnthalpy>;
using SpecificEnthalpyFromDensity = Relation<quantity::SpecificEnthalpy, quantity::Density>;
using SpecificEnthalpyFromPressure = Relation<quantity::SpecificEnthalpy, quantity::Pressure>;
using DensityFromSpecificEnthalpy = Relation<quantity::Density, quantity::SpecificEnthalpy>;
using PressureFromDensity = Relation<dimensions::quantity::Pressure, dimensions::quantity::Density>;
using PressureFromSpecificEnthalpy =
Relation<dimensions::quantity::Pressure, dimensions::quantity::SpecificEnthalpy>;
using SpecificEnthalpyFromDensity = Relation<dimensions::quantity::SpecificEnthalpy, dimensions::quantity::Density>;
using SpecificEnthalpyFromPressure =
Relation<dimensions::quantity::SpecificEnthalpy, dimensions::quantity::Pressure>;
using DensityFromSpecificEnthalpy = Relation<dimensions::quantity::Density, dimensions::quantity::SpecificEnthalpy>;
} // namespace mean_field::eos