Began porting the mapping system

This commit is contained in:
2026-09-20 14:37:11 -04:00
parent f69fac8f1e
commit 08a8f231d2
46 changed files with 1336 additions and 115 deletions

View File

@@ -1,154 +1,346 @@
#pragma once
/**
* @file dimensions.hpp
* @author Emily M. Boudreaux
*
* @brief File containing prue dimensions. Note that this is not intended to be (nor does it
* have the capability to be) a general dimensional analysis library. There is no
* understanding here that, for example, a dimension of length^2 is an area. Rather,
* the purpose of this is to force developers to be explicit about what values they
* are passing to what functions. Further, most of this system is built to be compile
* time constant. This means that the compiler can still apply many optimizations. Note
* that the dimensions here do not contain a value, rather these are *just* the concept
* of a dimension. To store a value you must use a @ref Quantity and @ref QuantityValue.
*/
#include <string_view>
#include "serif/dimensions/quantities.hpp"
namespace serif::dimensions {
/**
* @struct Dimensionless
*
* @brief Non dimensional type.
*/
struct Dimensionless final : PhysicalQuantity {
static constexpr std::string_view identifier = "dimensionless";
};
/**
* @struct Mass
*
* @brief Dimension of mass
*/
struct Mass final : PhysicalQuantity {
static constexpr std::string_view identifier = "mass";
};
/**
* @struct Length
*
* @brief Dimension of Length
*/
struct Length final : PhysicalQuantity {
static constexpr std::string_view identifier = "length";
};
/**
* @struct Time
*
* @brief Dimension of Time
*/
struct Time final : PhysicalQuantity {
static constexpr std::string_view identifier = "time";
};
/**
* @struct Area
*
* @brief Dimension of Area
*/
struct Area final : PhysicalQuantity {
static constexpr std::string_view identifier = "area";
};
/**
* @struct Volume
*
* @brief Dimension of Volume
*/
struct Volume final : PhysicalQuantity {
static constexpr std::string_view identifier = "volume";
};
struct Density final : ThermodynamicQuantity {
/**
* @struct MassDensity
*
* @brief Dimension of Mass Density
*/
struct MassDensity final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "density";
};
struct SurfaceDensity final : PhysicalQuantity {
static constexpr std::string_view identifier = "surface_density";
};
/**
* @struct NumberDensity
*
* @brief Dimension of Number Density
*/
struct NumberDensity final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "number_density";
};
/**
* @struct Pressure
*
* @brief Dimension of Pressure
*/
struct Pressure final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "pressure";
};
/**
* @struct Temperature
*
* @brief Dimension of Temperature
*/
struct Temperature final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "temperature";
};
/**
* @struct Entropy
*
* @brief Dimension of Entropy
*/
struct Entropy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "entropy";
};
/**
* @struct SpecificEntropy
*
* @brief Dimension of Specific Entropy
*/
struct SpecificEntropy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_entropy";
};
/**
* @struct ChemicalPotential
*
* @brief Dimension of Chemical Potential
*/
struct ChemicalPotential final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "chemical_potential";
};
/**
* @struct Energy
*
* @brief Dimension of Energy
*/
struct Energy final : PhysicalQuantity {
static constexpr std::string_view identifier = "energy";
};
/**
* @struct InternalEnergy
*
* @brief Dimension of Internal Energy
*/
struct InternalEnergy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "internal_energy";
};
/**
* @struct SpecificEnergy
*
* @brief Dimension of Specific Energy
*/
struct SpecificEnergy final : PhysicalQuantity {
static constexpr std::string_view identifier = "specific_energy";
};
/**
* @struct SpecificInternalEnergy
*
* @brief Dimension of Specific Internal Energy
*/
struct SpecificInternalEnergy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_internal_energy";
};
/**
* @struct SpecificEnthalpy
*
* @brief Dimension of Specific Enthalpy
*/
struct SpecificEnthalpy final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "specific_enthalpy";
};
/**
* @struct EnergyDensity
*
* @brief Dimension of Energy Density
*/
struct EnergyDensity final : ThermodynamicQuantity {
static constexpr std::string_view identifier = "energy_density";
};
/**
* @struct GravitationalPotential
*
* @brief Dimension of Gravitational Potential
*/
struct GravitationalPotential final : PhysicalQuantity {
static constexpr std::string_view identifier = "gravitational_potential";
};
/**
* @struct Velocity
*
* @brief Dimension of Velocity
*/
struct Velocity final : PhysicalQuantity {
static constexpr std::string_view identifier = "velocity";
};
/**
* @struct Acceleration
*
* @brief Dimension of Acceleration
*/
struct Acceleration final : PhysicalQuantity {
static constexpr std::string_view identifier = "acceleration";
};
/**
* @struct Frequency
*
* @brief Dimension of Frequency
*/
struct Frequency final : PhysicalQuantity {
static constexpr std::string_view identifier = "frequency";
};
/**
* @struct AngularVelocity
*
* @brief Dimension of Angular Velocity
*/
struct AngularVelocity final : PhysicalQuantity {
static constexpr std::string_view identifier = "angular_velocity";
};
/**
* @struct Momentum
*
* @brief Dimension of Momentum
*/
struct Momentum final : PhysicalQuantity {
static constexpr std::string_view identifier = "momentum";
};
/**
* @struct AngularMomentum
*
* @brief Dimension of Angular Momentum
*/
struct AngularMomentum final : PhysicalQuantity {
static constexpr std::string_view identifier = "angular_momentum";
};
/**
* @struct MomentOfInertia
*
* @brief Dimension of Moment Of Inertia
*/
struct MomentOfInertia final : PhysicalQuantity {
static constexpr std::string_view identifier = "moment_of_inertia";
};
/**
* @struct Force
*
* @brief Dimension of Force
*/
struct Force final : PhysicalQuantity {
static constexpr std::string_view identifier = "force";
};
/**
* @struct Torque
*
* @brief Dimension of Torque
*/
struct Torque final : PhysicalQuantity {
static constexpr std::string_view identifier = "torque";
};
/**
* @struct Power
*
* @brief Dimension of Power
*/
struct Power final : PhysicalQuantity {
static constexpr std::string_view identifier = "power";
};
/**
* @struct Luminosity
*
* @brief Dimension of Luminosity
*/
struct Luminosity final : PhysicalQuantity {
static constexpr std::string_view identifier = "luminosity";
};
/**
* @struct MassFlowRate
*
* @brief Dimension of Mass Flow Rate
*/
struct MassFlowRate final : PhysicalQuantity {
static constexpr std::string_view identifier = "mass_flow_rate";
};
/**
* @struct Opacity
*
* @brief Dimension of Opacity
* @note we are not currently using this in the code since we are still using a polytropic
* eos. However, when we actually get to using this we will likely want to break this out
* into more specific and meaningful opacity dimensions (RMO, per unit wavelength, etc...)
*/
struct Opacity final : PhysicalQuantity {
static constexpr std::string_view identifier = "opacity";
};
/**
* @struct DynamicViscosity
*
* @brief Dimension of Dynamic Viscosity
*/
struct DynamicViscosity final : PhysicalQuantity {
static constexpr std::string_view identifier = "dynamic_viscosity";
};
/**
* @struct KinematicViscosity
*
* @brief Dimension of Kinematic Viscosity
*/
struct KinematicViscosity final : PhysicalQuantity {
static constexpr std::string_view identifier = "kinematic_viscosity";
};
/**
* @struct MagneticFluxDensity
*
* @brief Dimension of Magnetic Flux Density
*/
struct MagneticFluxDensity final : PhysicalQuantity {
static constexpr std::string_view identifier = "magnetic_flux_density";
};

View File

@@ -1,21 +1,78 @@
#pragma once
/**
* @file partial.hpp
* @author Emily M. Boudreaux
*
* @brief Compile time tools to represent a partial derivative of one quantity wrt. another quantity.
* Note that this system is not responsible for computing partials or in fact derivatives of any kind.
* Rather, it is responsible for forcing the developer --- or compiler at least --- to ask
* for a specific, explicit, partial and have to spell out what that is. That in turn gives
* the compiler enough information to do a lot of downstream things. A motivating example would be automatic verification
* of the provided EOS against all partials that might be needed to ensure they are all exported
* by the EOS.
*/
#include "serif/dimensions/quantities.hpp"
#include "serif/utils/misc/concepts/numeric.hpp"
namespace serif::dimensions {
/**
* @struct WithRespectTo
*
* @tparam Quantity A quantity satisfying @ref ThermodynamicQuantityType
* @brief A type that is empty at runtime but allows for the developer
* to specify to the compiler what quantity the partial is with respect to.
*/
template <ThermodynamicQuantityType Quantity>
struct WithRespectTo final {};
/**
* @class PartialDerivative
*
* @tparam OutputQuantity
* @tparam InputQuantity
*
* @brief Class to represent a compile time derivative relation between two quantities. Note that
* this class does not, in fact cannot, compute any derivatives itself. Rather, this is a way
* for the compiler to understand higher level mathematical relations. Unless you are really
* in the weeds of the development team you will likely not need to interact with this
* directly. Further note that this class does include (unlike the more basic dimension system)
* some basic dimensional analysis. Specifically, there are some overloaded operators that
* allow for certain specializations of PartialDerivative to operate on one and other
* conditioned on what their input and output types are. This does not do any thing like
* convert area to length^2. However, it will do more basic things like ensure that you
* can only add two partials which agree on their dimensions exactly. Or that while you can
* multiple a partial by any scalar, you cannot multiply arbitrary partials.
*/
template <ThermodynamicQuantityType OutputQuantity, ThermodynamicQuantityType InputQuantity>
class PartialDerivative final {
public:
explicit constexpr PartialDerivative(const double value) noexcept : m_value(value){}
/**
* @brief Get the underlying value as a compile time constant if possible. This
* allows the compiler, where the constructor may be determined at compile time,
* to fully optimize PartialDerivative operations as if they were doubles.
*
* @note calling value gets the underlying numeric value directly thereby bypassing
* the limitations on what a valid operation are (e.g. what the operator overloads
* enforce).
*
* @return m_value: This is whatever was passed at constructor time since there is
* no way to modify this value after construction without some truly horrific C++ tricks
*/
[[nodiscard]] constexpr double value() const noexcept {
return m_value;
}
/**
* @brief Overload the + operator between two partials which share the exact same input
* and output types
* @param lhs One partial
* @param rhs Other Partial
* @return A new partial with the same input and output types where m_value = lhs.m_value + rhs.m_value
*/
friend constexpr PartialDerivative<OutputQuantity, InputQuantity> operator+(
const PartialDerivative<OutputQuantity, InputQuantity>& lhs,
const PartialDerivative<OutputQuantity, InputQuantity>& rhs
@@ -23,6 +80,13 @@ namespace serif::dimensions {
return PartialDerivative<OutputQuantity, InputQuantity>{lhs.m_value + rhs.m_value};
}
/**
* @brief Overload the - operator between two partials which share the exact same input
* and output types
* @param lhs One partial
* @param rhs Other Partial
* @return A new partial with the same input and output types where m_value = lhs.m_value - rhs.m_value
*/
friend constexpr PartialDerivative<OutputQuantity, InputQuantity> operator-(
const PartialDerivative<OutputQuantity, InputQuantity>& lhs,
const PartialDerivative<OutputQuantity, InputQuantity>& rhs
@@ -30,6 +94,14 @@ namespace serif::dimensions {
return PartialDerivative<OutputQuantity, InputQuantity>{lhs.m_value - rhs.m_value};
}
/**
* @brief Overload of the * operator for a left partial and a right scalar
* and output types
* @tparam Scalar Any value satisfying the @ref IsNumeric concept (integral types and float types)
* @param lhs Partial with some input and some output type
* @param rhs Some numeric quantity
* @return A new partial with the same input and output types where m_value = lhs.m_value * rhs
*/
template <utils::misc::concepts::IsNumeric Scalar>
friend constexpr PartialDerivative<OutputQuantity, InputQuantity> operator*(
const PartialDerivative<OutputQuantity, InputQuantity>& lhs,
@@ -38,6 +110,14 @@ namespace serif::dimensions {
return PartialDerivative<OutputQuantity, InputQuantity>{lhs.m_value * rhs};
}
/**
* @brief Overload of the * operator for a right partial and a left scalar
* and output types
* @tparam Scalar Any value satisfying the @ref IsNumeric concept (integral types and float types)
* @param lhs Some numeric quantity
* @param rhs Partial with some input and some output type
* @return A new partial with the same input and output types where m_value = lhs * rhs.m_value
*/
template <utils::misc::concepts::IsNumeric Scalar>
friend constexpr PartialDerivative<OutputQuantity, InputQuantity> operator*(
const Scalar& lhs,
@@ -46,6 +126,14 @@ namespace serif::dimensions {
return PartialDerivative<OutputQuantity, InputQuantity>{lhs * rhs.m_value};
}
/**
* @brief Overload of the / operator for a left partial and a right scalar
* and output types
* @tparam Scalar Any value satisfying the @ref IsNumeric concept (integral types and float types)
* @param lhs Partial with some input and some output type
* @param rhs Some numeric quantity
* @return A new partial with the same input and output types where m_value = lhs.m_value / rhs
*/
template <utils::misc::concepts::IsNumeric Scalar>
friend constexpr PartialDerivative<OutputQuantity, InputQuantity> operator/(
const PartialDerivative<OutputQuantity, InputQuantity>& lhs,
@@ -54,6 +142,13 @@ namespace serif::dimensions {
return PartialDerivative<OutputQuantity, InputQuantity>{lhs.m_value / rhs};
}
/**
* @brief Partial ordering overload to compare a left partial and a right scalar
* @tparam Scalar Any value satisfying the @ref IsNumeric concept (integral types and float types)
* @param lhs Some numeric quantity
* @param rhs Some partial with an input and output type
* @return partial ordering comparing rhs.m_value to lhs
*/
template <utils::misc::concepts::IsNumeric Scalar>
friend constexpr std::partial_ordering operator<=>(
const PartialDerivative<OutputQuantity, InputQuantity>& lhs,
@@ -62,6 +157,13 @@ namespace serif::dimensions {
return lhs.m_value <=> rhs;
}
/**
* @brief Partial ordering overload to compare a right partial and a left scalar
* @tparam Scalar Any value satisfying the @ref IsNumeric concept (integral types and float types)
* @param lhs Some numeric quantity
* @param rhs Some partial with an input and output type
* @return partial ordering comparing rhs.m_value to lhs
*/
template <utils::misc::concepts::IsNumeric Scalar>
friend constexpr std::partial_ordering operator<=>(
Scalar lhs,
@@ -70,6 +172,12 @@ namespace serif::dimensions {
return lhs <=> rhs.m_value;
}
/**
* @brief Partial ordering comparing two partials with exactly the same input and output types
* @param lhs Some Partial
* @param rhs Other Partial
* @return Partial ordering comparing lhs.m_value to rhs.m_value
*/
friend constexpr std::partial_ordering operator<=>(
const PartialDerivative<OutputQuantity, InputQuantity> &lhs,
const PartialDerivative<OutputQuantity, InputQuantity> &rhs
@@ -78,6 +186,6 @@ namespace serif::dimensions {
}
private:
double m_value;
double m_value; ///< Numeric value associated with the partial. If this is known at compile time then the compiler can optimize operations with partial.value() to be equivalent to compile time double operations.
};
}

View File

@@ -1,4 +1,11 @@
#pragma once
/**
* @file quantities.hpp
* @author Emily M. Boudreaux
*
* @brief This file contains the code to associate numeric data to a dimension. We call
* this a Quantity and a QuantityValue.
*/
#include <type_traits>
#include <compare>
@@ -14,19 +21,60 @@ namespace serif::dimensions {
using utils::misc::concepts::IsNumeric;
/**
* @struct PhysicalQuantity
*
* @breif General type for any physical quantity.
*/
struct PhysicalQuantity { };
/**
* @struct ThermodynamicQuantity
*
* @breif Slightly more specific type for thermodynamic types. Note both of these
* are empty at runtime, these are only useful as compile time tools to control
* what code the compiler generates.
*/
struct ThermodynamicQuantity: PhysicalQuantity { };
/**
* @concept PhysicalQuantityType
*
* @tparam QuantityCandidate The type that will be validated
*
* @brief Is compile-time true of the QuantityCandidate can have any const / volatile stripped
* and if its derived from PhysicalQuantity. Note all ThermodynamicQuantities will also
* satisfy this concept.
*/
template <typename QuantityCandidate>
concept PhysicalQuantityType =
std::same_as<QuantityCandidate, NeitherConstNorVolatile<QuantityCandidate>> &&
std::derived_from<QuantityCandidate, PhysicalQuantity>;
/**
* @concept ThermodynamicQuantityType
*
* @tparam QuantityCandidate
*
* @brief Is compile-time true of the QuantityCandidate can have any const / volatile stripped
* and if its derived from PhysicalQuantity (both enforced through checking @ref PhysicalQuantityType)
* and then that is is also derived from ThermodynamicQuantity. Note not all physical quanties will
* satisfy this.
*/
template <typename QuantityCandidate>
concept ThermodynamicQuantityType =
PhysicalQuantityType<QuantityCandidate> &&
std::derived_from<QuantityCandidate, ThermodynamicQuantity>;
/**
* @class QuantityValue
* @tparam Quantity Some valid PhysicalQuantityType. Note all the dimensions in @ref dimensions.hpp
* are of type PhysicalQuantity. There should be no other dimensions in the code.
*
* @brief This is the non derivative equivalent to @ref PartialDerivative. This associates
* a dimension with a value and, if that value can be determined at compile time, can be
* decomposed to a transparent double through .value()
*/
template <PhysicalQuantityType Quantity>
class QuantityValue final {
public:
@@ -36,11 +84,25 @@ namespace serif::dimensions {
return m_value;
}
/**
* @breif Default comparison operator for two QuantityValues. Note that there is
* an implicit requirement these be of the same specialization. E.g. each have the same
* PhysicalQuantityType Quantity type parameter. Because this is the default and this
* class has only one trivially comparable member this just checks if m_value == m_value.
* @return true if the values in both are equal.
*/
[[nodiscard]] friend constexpr bool operator==(
const QuantityValue &,
const QuantityValue &
) noexcept = default;
/**
* @breif overload of + operator for two quantities with the same PhysicalQuantityType
* @param lhs One Quantity
* @param rhs Other Quantity
* @return a new quantity with the same PhysicalQuantityType but with a value = lhs.m_value + rhs.m_value
*/
friend constexpr QuantityValue operator+(
const QuantityValue &lhs,
const QuantityValue &rhs
@@ -48,6 +110,12 @@ namespace serif::dimensions {
return QuantityValue{lhs.m_value + rhs.m_value};
}
/**
* @breif overload of - operator for two quantities with the same PhysicalQuantityType
* @param lhs One Quantity
* @param rhs Other Quantity
* @return a new quantity with the same PhysicalQuantityType but with a value = lhs.m_value - rhs.m_value
*/
friend constexpr QuantityValue operator-(
const QuantityValue &lhs,
const QuantityValue &rhs
@@ -55,6 +123,13 @@ namespace serif::dimensions {
return QuantityValue{lhs.m_value - rhs.m_value};
}
/**
* @breif Overload of the * operator for a left quantity and some right numeric, scalar, value.
* @tparam Scalar A value satisfying @ref IsNumeric
* @param lhs some quantity value
* @param rhs some scalar value
* @return some quantity value with the same type as lhs but with value = lhs.m_value * scalar
*/
template <IsNumeric Scalar>
friend constexpr QuantityValue operator*(
const QuantityValue &lhs,
@@ -63,6 +138,13 @@ namespace serif::dimensions {
return QuantityValue{lhs.m_value * static_cast<double>(rhs)};
}
/**
* @breif Overload of the * operator for a right quantity and some left numeric, scalar, value.
* @tparam Scalar A value satisfying @ref IsNumeric
* @param lhs some scalar value
* @param rhs some quantity value
* @return some quantity value with the same type as lhs but with value = scalar * lhs.m_value
*/
template <IsNumeric Scalar>
friend constexpr QuantityValue operator*(
const Scalar lhs,
@@ -71,6 +153,13 @@ namespace serif::dimensions {
return QuantityValue{static_cast<double>(lhs) * rhs.m_value};
}
/**
* @breif Overload of the / operator for a left quantity and some right numeric, scalar, value.
* @tparam Scalar A value satisfying @ref IsNumeric
* @param lhs some quantity value
* @param rhs some scalar value
* @return some quantity value with the same type as lhs but with value = lhs.m_value / scalar
*/
template <IsNumeric Scalar>
friend constexpr QuantityValue operator/(
const QuantityValue &lhs,
@@ -79,6 +168,13 @@ namespace serif::dimensions {
return QuantityValue{lhs.m_value / static_cast<double>(rhs)};
}
/**
* @breif Partial ordering overload for some left quantity and right scalar
* @tparam Scalar A value satisfying @ref IsNumeric
* @param lhs some quantity value
* @param rhs some scalar value
* @return The partial ordering comparing lhs.m_value to scalar
*/
template <IsNumeric Scalar>
friend constexpr std::partial_ordering operator<=>(
const QuantityValue &lhs,
@@ -87,6 +183,13 @@ namespace serif::dimensions {
return lhs.m_value <=> static_cast<double>(rhs);
}
/**
* @breif Partial ordering overload for some right quantity and left scalar
* @tparam Scalar A value satisfying @ref IsNumeric
* @param lhs some scalar value
* @param rhs some quantity value
* @return The partial ordering comparing scalar to lhs.m_value
*/
template <IsNumeric Scalar>
friend constexpr std::partial_ordering operator<=>(
const Scalar lhs,
@@ -95,6 +198,12 @@ namespace serif::dimensions {
return static_cast<double>(lhs) <=> rhs.m_value;
}
/**
* @breif partial ordering overload to compare two quantity values of the same type
* @param lhs Some quantity value
* @param rhs Other quantity value
* @return the partial ordering of lhs.m_value <=> rhs.m_value
*/
friend constexpr std::partial_ordering operator<=>(
const QuantityValue &lhs,
const QuantityValue &rhs
@@ -103,19 +212,43 @@ namespace serif::dimensions {
}
private:
double m_value;
double m_value; ///< Numeric value associated with the dimension of QuantityValue.
};
/**
* @struct IsQuantityValue
* @tparam Candidate some type that may be a QuantityValue
*
* @breif Most general specialization, defaults to compile time false.
*/
template <typename Candidate>
struct IsQuantityValue : std::false_type { };
/**
* @struct IsQuantityValue
* @tparam Quantity Some quantity that satisfies the @ref PhysicalQuantityType concept
*
* @breif More specific so if a type satisfies this the compiler will select it first. This evaluates
* to compile time true if Quantity satisfies the PhysicalQuantityType concept which then
* creats a specialization of IsQuantityValue that is compile time true for any Quantity of that set.
*/
template <PhysicalQuantityType Quantity>
struct IsQuantityValue<QuantityValue<Quantity>> : std::true_type { };
/**
* @concept QuantityValueType
* @tparam Candidate Some type that might be a quantity value type
*
* @brief Turn those compile time structs into a concept that can be used to constrain
* a template parameter
*/
template <typename Candidate>
concept QuantityValueType = IsQuantityValue<std::remove_cvref_t<Candidate>>::value;
/**
* @struct QuantityOf
* @tparam Candidate Some type that may be able to report what its dimension is
*/
template <typename Candidate>
struct QuantityOf;

View File

@@ -1,4 +1,13 @@
#pragma once
/**
* @file concepts.hpp
* @author Emily M. Boudreaux
*
* @brief Runtime concept for a type that can be projected to a runtime type.
* This is useful when converting from the compile time type system to something
* that can be inspected at runtime.
*/
#include <string_view>
#include <type_traits>
@@ -6,12 +15,25 @@
#include "serif/dimensions/runtime/runtime.hpp"
namespace serif::dimensions::runtime {
/**
* @concept RuntimeIdentifiedThermodynamicQuantity
* @breif Concept to limit template arguments such that they are compatible with the expected
* ThermodynamicQuantity interface. Specifically, a valid type must contain a member
* identifier which can be converted to std::string_view and that member, when converted
* to a string_view must be longer than 0 length.
*/
template <typename Quantity>
concept RuntimeIdentifiedThermodynamicQuantity =
ThermodynamicQuantityType<Quantity> &&
requires {{Quantity::identifier} -> std::convertible_to<std::string_view>; } &&
(std::string_view{Quantity::identifier}.size() > 0);
/**
* @brief Extract a compile time identifier from a thermodynamic quantity and project it into a runtime
* string_view
* @tparam Quantity Type which @ref RuntimeIdentifiedThermodynamicQuantity allows
*/
template <RuntimeIdentifiedThermodynamicQuantity Quantity>
inline constexpr ThermodynamicQuantityID thermodynamicQuantityID{std::string_view{Quantity::identifier}};
}

View File

@@ -1,13 +1,30 @@
#pragma once
/**
* @file runtime.hpp
* @author Emily M. Boudreaux
*
* @brief runtime usable types representing the compile time dimension type system.
* Note that generally this is not a dimensional analysis library. Though perhaps
* in the future it will grow to something like that. Rather, this system
* is intended to ensure that developers are explicit which what numeric values mean.
* There is more detail on this in the file comment for @ref dimensions.hpp and @ref quantities.hpp
*/
#include <string_view>
#include <span>
#include <cstdint>
namespace serif::dimensions::runtime {
/**
* @class ThermodynamicQuantityID
*
* @brief Runtime resolvable ID for a thermodynamic quantity. Used in conjunction with
* concepts to resolve compile time thermodynamic types to runtime values.
*/
class ThermodynamicQuantityID final {
public:
explicit constexpr ThermodynamicQuantityID(std::string_view name) noexcept : m_name(name) {};
explicit constexpr ThermodynamicQuantityID(const std::string_view name) noexcept : m_name(name) {};
[[nodiscard]] constexpr std::string_view name() const noexcept {
return m_name;
@@ -18,9 +35,17 @@ namespace serif::dimensions::runtime {
std::string_view m_name; // We can use a string view here since the constructor is constexpr and the string view will be valid for the lifetime of the program.
};
/**
* @struct RuntimeQuantityValue
*
* @brief Runtime resolved type for a quantity value. This holds both an ID and a value. This is the runtime
* equivalent to a @ref QuantityValue. Note that where these differ is that QuantityValue
* is built with template types. This allows the compiler to resolve it to a plain numeric type and still do optimizations
* That is generally not the case with RuntimeQuantityValue
*/
struct RuntimeQuantityValue final {
ThermodynamicQuantityID id;
double value;
double value{};
};
// TODO: This should be refactored into the eos module rather than the dimensions module

View File

@@ -10,8 +10,7 @@ namespace serif::dimensions {
using TimeValue = QuantityValue<Time>;
using AreaValue = QuantityValue<Area>;
using VolumeValue = QuantityValue<Volume>;
using DensityValue = QuantityValue<Density>;
using SurfaceDensityValue = QuantityValue<SurfaceDensity>;
using DensityValue = QuantityValue<MassDensity>;
using NumberDensityValue = QuantityValue<NumberDensity>;
using PressureValue = QuantityValue<Pressure>;
using TemperatureValue = QuantityValue<Temperature>;

View File

@@ -27,7 +27,7 @@ namespace serif::discretization::blocks {
using FunctionalSpace = functional_space::DiscreteFunctionalSpace<functional_space::L2, 2, 0>; // second order scalar L2 space
using Support = domain::StellarDomains;
using Quantity = dimensions::Density;
using Quantity = dimensions::MassDensity;
static constexpr std::string_view symbol = "ρ";
struct value final : value_block_base {};

View File

@@ -39,7 +39,7 @@ namespace serif::eos::models {
[[nodiscard]] dimensions::SpecificEnthalpyValue evaluate(relations::SpecificEnthalpyFromPressure, dimensions::PressureValue pressure) const;
[[nodiscard]] dimensions::DensityValue evaluate(relations::DensityFromSpecificEnthalpy, dimensions::SpecificEnthalpyValue specific_enthalpy) const;
[[nodiscard]] dimensions::PartialDerivative<dimensions::Density, dimensions::SpecificEnthalpy> partial_derivative(
[[nodiscard]] dimensions::PartialDerivative<dimensions::MassDensity, dimensions::SpecificEnthalpy> partial_derivative(
relations::DensityFromSpecificEnthalpy,
dimensions::WithRespectTo<dimensions::SpecificEnthalpy>,
dimensions::SpecificEnthalpyValue specific_enthalpy
@@ -51,9 +51,9 @@ namespace serif::eos::models {
dimensions::SpecificEnthalpyValue specific_enthalpy
) const;
[[nodiscard]] dimensions::PartialDerivative<dimensions::Pressure, dimensions::Density> partial_derivative(
[[nodiscard]] dimensions::PartialDerivative<dimensions::Pressure, dimensions::MassDensity> partial_derivative(
relations::PressureFromDensity,
dimensions::WithRespectTo<dimensions::Density>,
dimensions::WithRespectTo<dimensions::MassDensity>,
dimensions::DensityValue density
) const;

View File

@@ -6,7 +6,7 @@
namespace serif::eos::relations {
using PressureFromDensity = Relation<
dimensions::Pressure,
dimensions::Density>;
dimensions::MassDensity>;
using PressureFromSpecificEnthalpy = Relation<
dimensions::Pressure,
@@ -14,13 +14,13 @@ namespace serif::eos::relations {
using SpecificEnthalpyFromDensity = Relation<
dimensions::SpecificEnthalpy,
dimensions::Density>;
dimensions::MassDensity>;
using SpecificEnthalpyFromPressure = Relation<
dimensions::SpecificEnthalpy,
dimensions::Pressure>;
using DensityFromSpecificEnthalpy = Relation<
dimensions::Density,
dimensions::MassDensity,
dimensions::SpecificEnthalpy>;
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <string_view>
#include "serif/mapping/status.hpp"
#include "serif/mapping/compactification/input_result.hpp"
#include "serif/mapping/compactification/variation.hpp"
namespace serif::mapping::compactification {
class ExteriorDomainMap {
public:
virtual ~ExteriorDomainMap() = default;
[[nodiscard]] virtual bool is_affine_in_displacement() const noexcept;
[[nodiscard]] virtual MappingStatus evaluate(
const ExteriorMapInput &input,
ExteriorMapResult &result
) const = 0;
[[nodiscard]] virtual MappingStatus evaluate_variation(
const ExteriorMapInput &input,
const ExteriorMapResult &result,
const ExteriorMapDirection &direction,
ExteriorMapVariation &variation
) const = 0;
[[nodiscard]] virtual std::string_view get_name() const noexcept = 0;
};
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "mfem/linalg/vector.hpp"
#include "mfem/linalg/densemat.hpp"
namespace serif::mapping::compactification {
struct ExteriorMapInput {
const mfem::Vector &reference_position;
const mfem::Vector &displaced_position;
const mfem::DenseMatrix &displacement_jacobian;
const mfem::Vector &compactification_coordinate_gradient;
double compactification_coordinate;
};
struct ExteriorMapResult {
mfem::Vector physical_position;
mfem::DenseMatrix mapping_jacobian;
};
}

View File

@@ -0,0 +1,62 @@
#pragma once
#include <string_view>
#include "mfem/linalg/vector.hpp"
#include "serif/mapping/status.hpp"
#include "serif/mapping/compactification/compactification.hpp"
#include "serif/utils/user_options/mapping/compactification/kelvin.hpp"
namespace serif::mapping::compactification {
class KelvinCompactification final : public ExteriorDomainMap {
public:
explicit KelvinCompactification(const utils::user_options::KelvinCompactificationOptions& options);
[[nodiscard]] bool is_affine_in_displacement() const noexcept override;
[[nodiscard]] MappingStatus evaluate(
const ExteriorMapInput& input,
ExteriorMapResult& result
) const override;
[[nodiscard]] MappingStatus evaluate_variation(
const ExteriorMapInput& input,
const ExteriorMapResult& result,
const ExteriorMapDirection& direction,
ExteriorMapVariation& variation
) const override;
[[nodiscard]] std::string_view get_name() const noexcept override;
[[nodiscard]] double get_reference_stellar_radius() const noexcept;
[[nodiscard]] double get_reference_infinity_radius() const noexcept;
[[nodiscard]] double get_coordinate_tolerance() const noexcept;
[[nodiscard]] MappingStatus evaluate_jacobian_variation_factors(
double compactification_coordinate,
const mfem::Vector &coordinateGradient,
double &scale,
mfem::Vector &scaleGradient
) const;
private:
struct RadialFactors {
double compactification_coordinate;
double computational_radius;
double scale;
double scale_derivative;
};
private:
[[nodiscard]] MappingStatus compute_radial_factors(
double compactification_coordinate,
RadialFactors &radial_factors
) const;
private:
utils::user_options::KelvinCompactificationOptions m_options;
const std::string_view m_name = "KelvinCompactification";
};
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "mfem/linalg/vector.hpp"
#include "mfem/linalg/densemat.hpp"
namespace serif::mapping::compactification {
struct ExteriorMapDirection {
const mfem::Vector &displaced_position_variation;
const mfem::DenseMatrix &displacement_jacobian_variation;
};
struct ExteriorMapVariation {
mfem::Vector physical_position_variation;
mfem::DenseMatrix mapping_jacobian_variation;
};
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include "mfem/linalg/densemat.hpp"
#include "mfem/linalg/vector.hpp"
namespace serif::mapping {
struct VolumeQuadratureContext {
mfem::DenseMatrix J_inv;
double detJ;
double weight;
};
struct FaceQuadratureContext {
mfem::Vector normal;
double ds;
double v_dot_n_scale;
};
struct MappingPointContext {
mfem::Vector reference_position;
mfem::Vector displaced_position;
mfem::Vector physical_position;
mfem::DenseMatrix displacement_jacobian;
mfem::DenseMatrix mapping_jacobian;
mfem::DenseMatrix inverse_mapping_jacobian;
double mapping_determinate{0.0};
bool compactified{false};
};
struct VolumeMappingContext {
MappingPointContext mapping;
VolumeQuadratureContext quadrature;
};
struct FaceMappingContext {
MappingPointContext mapping;
FaceQuadratureContext quadrature;
mfem::Vector reference_normal;
double reference_surface_weight{0.0};
double physical_surface_weight{0.0};
};
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include <unordered_map>
#include <cstdint>
#include <utility>
#include "serif/utils/error/codes.hpp"
#include "serif/meta/enums.hpp"
namespace serif::mapping
{
enum class MappingStatus : uint16_t {
VALID,
// Start this at 400 so this is parallel to the mapping error codes. There must be a better way to
// do this but it is not worth the time to sort out now
INVALID_DIMENSION = 400,
NON_FINITE_MAPPING_INPUT,
INVALID_REFERENCE_RADIUS,
AT_COMPACTIFIED_INFINITY,
OUTSIDE_REFERENCE_DOMAIN,
NON_FINITE_MAPPING_RESULT,
NON_POSITIVE_DETERMINATE
};
static auto MappingStatus_enum_string_map = meta::enum_to_enum_string_map<MappingStatus>();
static auto MappingStatus_string_enum_map = meta::enum_to_string_enum_map<MappingStatus>();
inline std::unordered_map<MappingStatus, utils::errors::SERiFErrorCode> make_MappingStatus_SERiFErrorCode_map() {
std::unordered_map<MappingStatus, utils::errors::SERiFErrorCode> ret;
for (const auto& [MS, MS_name] : MappingStatus_enum_string_map) {
if (std::to_underlying(MS) < 400) {
continue; // Skip VALID since it is not in the error code set
}
ret.insert({MS, utils::errors::SERiFErrorCodeNameToTypeMap.at(MS_name)});
}
return ret;
}
inline std::unordered_map<utils::errors::SERiFErrorCode, MappingStatus> make_SERIFErrorCode_MappingStatus_map() {
std::unordered_map<utils::errors::SERiFErrorCode, MappingStatus> ret;
for (const auto& [MS, MS_name] : MappingStatus_enum_string_map) {
if (std::to_underlying(MS) < 400) {
continue; // Skip VALID since it is not in the error code set
}
ret.insert({utils::errors::SERiFErrorCodeNameToTypeMap.at(MS_name), MS});
}
return ret;
}
static auto MappingStatus_SERiFErrorCode_map = make_MappingStatus_SERiFErrorCode_map();
static auto SERiFErrorCode_MappingStatus_map = make_SERIFErrorCode_MappingStatus_map();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "mfem/linalg/densemat.hpp"
#include "mfem/linalg/vector.hpp"
namespace serif::mapping {
struct MappingPointVariation {
mfem::Vector displacement_variation;
mfem::Vector physical_position_variation;
mfem::DenseMatrix displacement_jacobian_variation;
mfem::DenseMatrix mapping_jacobian_variation;
mfem::DenseMatrix inverse_mapping_jacobian_variation;
double mapping_determinate_variation{0.0};
};
struct VolumeMappingVariation {
MappingPointVariation mapping;
mfem::DenseMatrix inverse_element_jacobian_variation;
double weight_variation{0.0};
};
struct FaceMappingVariation {
MappingPointVariation mapping;
mfem::Vector physical_normal_variation;
double physical_surface_weight_variation{0.0};
double normal_flux_scale_variation{0.0};
};
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <cmath>
#include "mfem/linalg/vector.hpp"
#include "mfem/linalg/densemat.hpp"
namespace serif::utils::checks {
// If we have a new backend / new vector and matrix type in the future we can add new overloads
inline bool is_finite(const mfem::Vector& vector) {
for (int i = 0; i < vector.Size(); ++i) {
if (!std::isfinite(vector(i))) {
return false;
}
}
return true;
}
inline bool is_finite(const mfem::DenseMatrix& matrix) {
for (int i = 0; i < matrix.Height(); ++i) {
for (int j = 0; j < matrix.Width(); ++j) {
if (!std::isfinite(matrix(i, j))) {
return false;
}
}
}
return true;
}
}

View File

@@ -42,6 +42,18 @@ namespace serif::utils::errors {
EOS_NONFINITE_RESULT,
EOS_INVALID_THERMODYNAMIC_INPUT,
// Mapping Errors
INVALID_DIMENSION = 400,
NON_FINITE_MAPPING_INPUT,
INVALID_REFERENCE_RADIUS,
AT_COMPACTIFIED_INFINITY,
OUTSIDE_REFERENCE_DOMAIN,
NON_FINITE_MAPPING_RESULT,
NON_POSITIVE_DETERMINATE,
IMPROPERLY_ORDERED_REFERENCE_RADII = 450,
INVALID_COORDINATE_TOLERANCE,
// COMPILE TIME FAILURES (>1000)
// Type Invariant Failures
FAILED_TYPE_INVARIANT = 1000

View File

@@ -0,0 +1,7 @@
#pragma once
#include "serif/utils/types/tensor/tensor.hpp"
namespace serif::utils::types::backend::mfem {
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <cstddef>
namespace serif::utils::types {
template <typename T>
struct VectorBase {
using Type = T;
};
template <typename T>
struct DenseMatrixBase {
using Type = T;
};
template <typename T>
struct SparseMatrixBase{
using Type = T;
};
template <typename T, std::size_t Rank>
struct DenseTensorBase {
using Type = T;
static constexpr std::size_t rank = Rank;
};
template <typename T, std::size_t Rank>
struct SparseTensorBase {
using Type = T;
static constexpr std::size_t rank = Rank;
};
}

View File

@@ -0,0 +1,11 @@
#pragma once
namespace serif::utils::user_options {
struct KelvinCompactificationOptions
{
double r_star_ref{1.0};
double r_inf_ref{2.0};
double coordinate_tolerance{1.0e-12};
};
}