Files

313 lines
13 KiB
C++

module;
#include <compare>
#include <concepts>
#include <string_view>
#include <type_traits>
export module mean_field:dimensions.quantities;
export namespace mean_field::dimensions {
/*
* QuantityValue provides semantic strong typing for scalar physical
* values expressed in the unit system selected by a model. It does not
* perform dimensional algebra or unit conversion.
*/
struct PhysicalQuantity { };
struct ThermodynamicQuantity : PhysicalQuantity { };
template <typename Candidate>
concept PhysicalQuantityType =
std::same_as<Candidate, std::remove_cv_t<Candidate>> && std::derived_from<Candidate, PhysicalQuantity>;
template <typename Candidate>
concept ThermodynamicQuantityType =
PhysicalQuantityType<Candidate> && std::derived_from<Candidate, ThermodynamicQuantity>;
namespace quantity {
struct Dimensionless final : PhysicalQuantity {
static constexpr std::string_view identifier = "dimensionless";
};
struct Mass final : PhysicalQuantity {
static constexpr std::string_view identifier = "mass";
};
struct Length final : PhysicalQuantity {
static constexpr std::string_view identifier = "length";
};
struct Time final : PhysicalQuantity {
static constexpr std::string_view identifier = "time";
};
struct Area final : PhysicalQuantity {
static constexpr std::string_view identifier = "area";
};
struct Volume final : PhysicalQuantity {
static constexpr std::string_view identifier = "volume";
};
struct Density final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "density";
};
struct SurfaceDensity final : PhysicalQuantity {
static constexpr std::string_view identifier = "surface_density";
};
struct NumberDensity final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "number_density";
};
struct Pressure final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "pressure";
};
struct Temperature final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "temperature";
};
struct Entropy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "entropy";
};
struct SpecificEntropy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_entropy";
};
struct ChemicalPotential final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "chemical_potential";
};
struct Energy final : PhysicalQuantity {
static constexpr std::string_view identifier = "energy";
};
struct InternalEnergy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "internal_energy";
};
struct SpecificEnergy final : PhysicalQuantity {
static constexpr std::string_view identifier = "specific_energy";
};
struct SpecificInternalEnergy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_internal_energy";
};
struct SpecificEnthalpy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_enthalpy";
};
struct EnergyDensity final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "energy_density";
};
struct GravitationalPotential final : PhysicalQuantity {
static constexpr std::string_view identifier = "gravitational_potential";
};
struct Velocity final : PhysicalQuantity {
static constexpr std::string_view identifier = "velocity";
};
struct Acceleration final : PhysicalQuantity {
static constexpr std::string_view identifier = "acceleration";
};
struct Frequency final : PhysicalQuantity {
static constexpr std::string_view identifier = "frequency";
};
struct AngularVelocity final : PhysicalQuantity {
static constexpr std::string_view identifier = "angular_velocity";
};
struct Momentum final : PhysicalQuantity {
static constexpr std::string_view identifier = "momentum";
};
struct AngularMomentum final : PhysicalQuantity {
static constexpr std::string_view identifier = "angular_momentum";
};
struct MomentOfInertia final : PhysicalQuantity {
static constexpr std::string_view identifier = "moment_of_inertia";
};
struct Force final : PhysicalQuantity {
static constexpr std::string_view identifier = "force";
};
struct Torque final : PhysicalQuantity {
static constexpr std::string_view identifier = "torque";
};
struct Power final : PhysicalQuantity {
static constexpr std::string_view identifier = "power";
};
struct Luminosity final : PhysicalQuantity {
static constexpr std::string_view identifier = "luminosity";
};
struct MassFlowRate final : PhysicalQuantity {
static constexpr std::string_view identifier = "mass_flow_rate";
};
struct Opacity final : PhysicalQuantity {
static constexpr std::string_view identifier = "opacity";
};
struct DynamicViscosity final : PhysicalQuantity {
static constexpr std::string_view identifier = "dynamic_viscosity";
};
struct KinematicViscosity final : PhysicalQuantity {
static constexpr std::string_view identifier = "kinematic_viscosity";
};
struct MagneticFluxDensity final : PhysicalQuantity {
static constexpr std::string_view identifier = "magnetic_flux_density";
};
} // namespace quantity
template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template <PhysicalQuantityType Quantity> class QuantityValue final {
public:
explicit constexpr QuantityValue(const double value) noexcept : m_value(value) {
}
[[nodiscard]] constexpr double value() const noexcept {
return m_value;
}
[[nodiscard]] friend constexpr bool operator==(
const QuantityValue &,
const QuantityValue &
) noexcept = default;
friend constexpr QuantityValue operator+(
const QuantityValue &lhs,
const QuantityValue &rhs
) noexcept {
return QuantityValue{lhs.m_value + rhs.m_value};
}
friend constexpr QuantityValue operator-(
const QuantityValue &lhs,
const QuantityValue &rhs
) noexcept {
return QuantityValue{lhs.m_value - rhs.m_value};
}
template <Numeric Scalar>
friend constexpr QuantityValue operator*(
const QuantityValue &lhs,
const Scalar rhs
) noexcept {
return QuantityValue{lhs.m_value * static_cast<double>(rhs)};
}
template <Numeric Scalar>
friend constexpr QuantityValue operator*(
const Scalar lhs,
const QuantityValue &rhs
) noexcept {
return QuantityValue{static_cast<double>(lhs) * rhs.m_value};
}
template <Numeric Scalar>
friend constexpr QuantityValue operator/(
const QuantityValue &lhs,
const Scalar rhs
) noexcept {
return QuantityValue{lhs.m_value / static_cast<double>(rhs)};
}
template <Numeric Scalar>
friend constexpr std::partial_ordering operator<=>(
const QuantityValue &lhs,
const Scalar rhs
) noexcept {
return lhs.m_value <=> static_cast<double>(rhs);
}
template <Numeric Scalar>
friend constexpr std::partial_ordering operator<=>(
const Scalar lhs,
const QuantityValue &rhs
) noexcept {
return static_cast<double>(lhs) <=> rhs.m_value;
}
friend constexpr std::partial_ordering operator<=>(
const QuantityValue &lhs,
const QuantityValue &rhs
) noexcept {
return lhs.m_value <=> rhs.m_value;
}
private:
double m_value;
};
template <typename Candidate> struct IsQuantityValue : std::false_type { };
template <PhysicalQuantityType Quantity> struct IsQuantityValue<QuantityValue<Quantity>> : std::true_type { };
template <typename Candidate>
concept QuantityValueType = IsQuantityValue<std::remove_cvref_t<Candidate>>::value;
template <typename Candidate> struct QuantityOf;
template <PhysicalQuantityType Quantity> struct QuantityOf<QuantityValue<Quantity>> {
using Type = Quantity;
};
template <QuantityValueType Value> using QuantityOfT = typename QuantityOf<std::remove_cvref_t<Value>>::Type;
using DimensionlessValue = QuantityValue<quantity::Dimensionless>;
using MassValue = QuantityValue<quantity::Mass>;
using LengthValue = QuantityValue<quantity::Length>;
using TimeValue = QuantityValue<quantity::Time>;
using AreaValue = QuantityValue<quantity::Area>;
using VolumeValue = QuantityValue<quantity::Volume>;
using DensityValue = QuantityValue<quantity::Density>;
using SurfaceDensityValue = QuantityValue<quantity::SurfaceDensity>;
using NumberDensityValue = QuantityValue<quantity::NumberDensity>;
using PressureValue = QuantityValue<quantity::Pressure>;
using TemperatureValue = QuantityValue<quantity::Temperature>;
using EntropyValue = QuantityValue<quantity::Entropy>;
using SpecificEntropyValue = QuantityValue<quantity::SpecificEntropy>;
using ChemicalPotentialValue = QuantityValue<quantity::ChemicalPotential>;
using EnergyValue = QuantityValue<quantity::Energy>;
using InternalEnergyValue = QuantityValue<quantity::InternalEnergy>;
using SpecificEnergyValue = QuantityValue<quantity::SpecificEnergy>;
using SpecificInternalEnergyValue = QuantityValue<quantity::SpecificInternalEnergy>;
using SpecificEnthalpyValue = QuantityValue<quantity::SpecificEnthalpy>;
using EnergyDensityValue = QuantityValue<quantity::EnergyDensity>;
using GravitationalPotentialValue = QuantityValue<quantity::GravitationalPotential>;
using VelocityValue = QuantityValue<quantity::Velocity>;
using AccelerationValue = QuantityValue<quantity::Acceleration>;
using FrequencyValue = QuantityValue<quantity::Frequency>;
using AngularVelocityValue = QuantityValue<quantity::AngularVelocity>;
using MomentumValue = QuantityValue<quantity::Momentum>;
using AngularMomentumValue = QuantityValue<quantity::AngularMomentum>;
using MomentOfInertiaValue = QuantityValue<quantity::MomentOfInertia>;
using ForceValue = QuantityValue<quantity::Force>;
using TorqueValue = QuantityValue<quantity::Torque>;
using PowerValue = QuantityValue<quantity::Power>;
using LuminosityValue = QuantityValue<quantity::Luminosity>;
using MassFlowRateValue = QuantityValue<quantity::MassFlowRate>;
using OpacityValue = QuantityValue<quantity::Opacity>;
using DynamicViscosityValue = QuantityValue<quantity::DynamicViscosity>;
using KinematicViscosityValue = QuantityValue<quantity::KinematicViscosity>;
using MagneticFluxDensityValue = QuantityValue<quantity::MagneticFluxDensity>;
} // namespace mean_field::dimensions