feat(weak): major weak rate progress
Major weak rate progress which includes: A refactor of many of the public interfaces for GridFire Engines to use composition objects as opposed to raw abundance vectors. This helps prevent index mismatch errors. Further, the weak reaction class has been expanded with the majority of an implimentation, including an atomic_base derived class to allow for proper auto diff tracking of the interpolated table results. Some additional changes are that the version of fourdst and libcomposition have been bumped to versions with smarter caching of intermediate vectors and a few bug fixes.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -80,6 +80,7 @@ subprojects/libplugin/
|
|||||||
subprojects/minizip-ng-4.0.10/
|
subprojects/minizip-ng-4.0.10/
|
||||||
subprojects/cvode-*/
|
subprojects/cvode-*/
|
||||||
*.fbundle
|
*.fbundle
|
||||||
|
*.wraplock
|
||||||
|
|
||||||
*.csv
|
*.csv
|
||||||
*.dot
|
*.dot
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ namespace gridfire::diagnostics {
|
|||||||
void inspect_species_balance(
|
void inspect_species_balance(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const std::string& species_name,
|
const std::string& species_name,
|
||||||
const std::vector<double>& Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
|
|
||||||
void inspect_jacobian_stiffness(
|
void inspect_jacobian_stiffness(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const std::vector<double>& Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
template <IsArithmeticOrAD T>
|
template <IsArithmeticOrAD T>
|
||||||
struct StepDerivatives {
|
struct StepDerivatives {
|
||||||
std::vector<T> dydt; ///< Derivatives of abundances (dY/dt for each species).
|
std::map<fourdst::atomic::Species, T> dydt; ///< Derivatives of abundances (dY/dt for each species).
|
||||||
T nuclearEnergyGenerationRate = T(0.0); ///< Specific energy generation rate (e.g., erg/g/s).
|
T nuclearEnergyGenerationRate = T(0.0); ///< Specific energy generation rate (e.g., erg/g/s).
|
||||||
|
|
||||||
|
StepDerivatives() : dydt(), nuclearEnergyGenerationRate(T(0.0)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
using SparsityPattern = std::vector<std::pair<size_t, size_t>>;
|
using SparsityPattern = std::vector<std::pair<size_t, size_t>>;
|
||||||
@@ -107,7 +109,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Calculate the right-hand side (dY/dt) and energy generation.
|
* @brief Calculate the right-hand side (dY/dt) and energy generation.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current abundances for all species.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
||||||
@@ -117,7 +119,7 @@ namespace gridfire {
|
|||||||
* rate for the current state.
|
* rate for the current state.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
[[nodiscard]] virtual std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
@@ -142,7 +144,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Generate the Jacobian matrix for the current state.
|
* @brief Generate the Jacobian matrix for the current state.
|
||||||
*
|
*
|
||||||
* @param Y_dynamic Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
*
|
*
|
||||||
@@ -150,13 +152,13 @@ namespace gridfire {
|
|||||||
* for the current state. The matrix can then be accessed via getJacobianMatrixEntry().
|
* for the current state. The matrix can then be accessed via getJacobianMatrixEntry().
|
||||||
*/
|
*/
|
||||||
virtual void generateJacobianMatrix(
|
virtual void generateJacobianMatrix(
|
||||||
const std::vector<double>& Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
virtual void generateJacobianMatrix(
|
virtual void generateJacobianMatrix(
|
||||||
const std::vector<double>& Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho,
|
double rho,
|
||||||
const SparsityPattern& sparsityPattern
|
const SparsityPattern& sparsityPattern
|
||||||
@@ -167,15 +169,15 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Get an entry from the previously generated Jacobian matrix.
|
* @brief Get an entry from the previously generated Jacobian matrix.
|
||||||
*
|
*
|
||||||
* @param i Row index (species index).
|
* @param rowSpecies The species corresponding to the row index (i)
|
||||||
* @param j Column index (species index).
|
* @param colSpecies The species corresponding to the column index (j)
|
||||||
* @return Value of the Jacobian matrix at (i, j).
|
* @return Value of the Jacobian matrix at (i, j).
|
||||||
*
|
*
|
||||||
* The Jacobian must have been generated by generateJacobianMatrix() before calling this.
|
* The Jacobian must have been generated by generateJacobianMatrix() before calling this.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual double getJacobianMatrixEntry(
|
[[nodiscard]] virtual double getJacobianMatrixEntry(
|
||||||
int i,
|
const fourdst::atomic::Species& rowSpecies,
|
||||||
int j
|
const fourdst::atomic::Species& colSpecies
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
|
|
||||||
@@ -190,22 +192,22 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Get an entry from the stoichiometry matrix.
|
* @brief Get an entry from the stoichiometry matrix.
|
||||||
*
|
*
|
||||||
* @param speciesIndex Index of the species.
|
* @param species species to look up stoichiometry for.
|
||||||
* @param reactionIndex Index of the reaction.
|
* @param reaction reaction to find
|
||||||
* @return Stoichiometric coefficient for the species in the reaction.
|
* @return Stoichiometric coefficient for the species in the reaction.
|
||||||
*
|
*
|
||||||
* The stoichiometry matrix must have been generated by generateStoichiometryMatrix().
|
* The stoichiometry matrix must have been generated by generateStoichiometryMatrix().
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual int getStoichiometryMatrixEntry(
|
[[nodiscard]] virtual int getStoichiometryMatrixEntry(
|
||||||
int speciesIndex,
|
const fourdst::atomic::Species& species,
|
||||||
int reactionIndex
|
const reaction::Reaction& reaction
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculate the molar reaction flow for a given reaction.
|
* @brief Calculate the molar reaction flow for a given reaction.
|
||||||
*
|
*
|
||||||
* @param reaction The reaction for which to calculate the flow.
|
* @param reaction The reaction for which to calculate the flow.
|
||||||
* @param Y Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||||
@@ -215,7 +217,7 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual double calculateMolarReactionFlow(
|
[[nodiscard]] virtual double calculateMolarReactionFlow(
|
||||||
const reaction::Reaction& reaction,
|
const reaction::Reaction& reaction,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
@@ -223,7 +225,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Calculate the derivatives of the energy generation rate with respect to T and rho.
|
* @brief Calculate the derivatives of the energy generation rate with respect to T and rho.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return EnergyDerivatives containing dEps/dT and dEps/dRho.
|
* @return EnergyDerivatives containing dEps/dT and dEps/dRho.
|
||||||
@@ -232,9 +234,9 @@ namespace gridfire {
|
|||||||
* generation rate with respect to temperature and density for the current state.
|
* generation rate with respect to temperature and density for the current state.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual EnergyDerivatives calculateEpsDerivatives(
|
[[nodiscard]] virtual EnergyDerivatives calculateEpsDerivatives(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -249,7 +251,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Compute timescales for all species in the network.
|
* @brief Compute timescales for all species in the network.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Map from Species to their characteristic timescales (s).
|
* @return Map from Species to their characteristic timescales (s).
|
||||||
@@ -258,13 +260,13 @@ namespace gridfire {
|
|||||||
* which can be used for timestep control, diagnostics, and reaction network culling.
|
* which can be used for timestep control, diagnostics, and reaction network culling.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
[[nodiscard]] virtual std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
[[nodiscard]] virtual std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "cppad/cppad.hpp"
|
#include "cppad/cppad.hpp"
|
||||||
#include "cppad/utility/sparse_rc.hpp"
|
#include "cppad/utility/sparse_rc.hpp"
|
||||||
#include "cppad/speed/sparse_jac_fun.hpp"
|
#include "cppad/speed/sparse_jac_fun.hpp"
|
||||||
|
#include "gridfire/reaction/weak/weak_interpolator.h"
|
||||||
|
#include "gridfire/reaction/weak/weak_rate_library.h"
|
||||||
|
|
||||||
// PERF: The function getNetReactionStoichiometry returns a map of species to their stoichiometric coefficients for a given reaction.
|
// PERF: The function getNetReactionStoichiometry returns a map of species to their stoichiometric coefficients for a given reaction.
|
||||||
// this makes extra copies of the species, which is not ideal and could be optimized further.
|
// this makes extra copies of the species, which is not ideal and could be optimized further.
|
||||||
@@ -106,13 +108,13 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
explicit GraphEngine(
|
explicit GraphEngine(
|
||||||
const fourdst::composition::Composition &composition,
|
const fourdst::composition::Composition &composition,
|
||||||
const BuildDepthType = NetworkBuildDepth::Full
|
BuildDepthType = NetworkBuildDepth::Full
|
||||||
);
|
);
|
||||||
|
|
||||||
explicit GraphEngine(
|
explicit GraphEngine(
|
||||||
const fourdst::composition::Composition &composition,
|
const fourdst::composition::Composition &composition,
|
||||||
const partition::PartitionFunction& partitionFunction,
|
const partition::PartitionFunction& partitionFunction,
|
||||||
const BuildDepthType buildDepth = NetworkBuildDepth::Full
|
BuildDepthType buildDepth = NetworkBuildDepth::Full
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +130,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Calculates the right-hand side (dY/dt) and energy generation rate.
|
* @brief Calculates the right-hand side (dY/dt) and energy generation rate.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current abundances for all species.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
||||||
@@ -139,21 +141,21 @@ namespace gridfire {
|
|||||||
* @see StepDerivatives
|
* @see StepDerivatives
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates the Jacobian matrix for the current state.
|
* @brief Generates the Jacobian matrix for the current state.
|
||||||
*
|
*
|
||||||
* @param Y_dynamic Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
*
|
*
|
||||||
@@ -164,13 +166,13 @@ namespace gridfire {
|
|||||||
* @see getJacobianMatrixEntry()
|
* @see getJacobianMatrixEntry()
|
||||||
*/
|
*/
|
||||||
void generateJacobianMatrix(
|
void generateJacobianMatrix(
|
||||||
const std::vector<double>& Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
void generateJacobianMatrix(
|
void generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho,
|
double rho,
|
||||||
const SparsityPattern &sparsityPattern
|
const SparsityPattern &sparsityPattern
|
||||||
@@ -188,7 +190,7 @@ namespace gridfire {
|
|||||||
* @brief Calculates the molar reaction flow for a given reaction.
|
* @brief Calculates the molar reaction flow for a given reaction.
|
||||||
*
|
*
|
||||||
* @param reaction The reaction for which to calculate the flow.
|
* @param reaction The reaction for which to calculate the flow.
|
||||||
* @param Y Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||||
@@ -198,9 +200,9 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculateMolarReactionFlow(
|
[[nodiscard]] double calculateMolarReactionFlow(
|
||||||
const reaction::Reaction& reaction,
|
const reaction::Reaction& reaction,
|
||||||
const std::vector<double>&Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,8 +222,8 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the previously generated Jacobian matrix.
|
* @brief Gets an entry from the previously generated Jacobian matrix.
|
||||||
*
|
*
|
||||||
* @param i Row index (species index).
|
* @param rowSpecies Species corresponding to the row index (i).
|
||||||
* @param j Column index (species index).
|
* @param colSpecies Species corresponding to the column index (j).
|
||||||
* @return Value of the Jacobian matrix at (i, j).
|
* @return Value of the Jacobian matrix at (i, j).
|
||||||
*
|
*
|
||||||
* The Jacobian must have been generated by `generateJacobianMatrix()` before calling this.
|
* The Jacobian must have been generated by `generateJacobianMatrix()` before calling this.
|
||||||
@@ -229,8 +231,8 @@ namespace gridfire {
|
|||||||
* @see generateJacobianMatrix()
|
* @see generateJacobianMatrix()
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] double getJacobianMatrixEntry(
|
[[nodiscard]] double getJacobianMatrixEntry(
|
||||||
const int i,
|
const fourdst::atomic::Species& rowSpecies,
|
||||||
const int j
|
const fourdst::atomic::Species& colSpecies
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -246,8 +248,8 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the stoichiometry matrix.
|
* @brief Gets an entry from the stoichiometry matrix.
|
||||||
*
|
*
|
||||||
* @param speciesIndex Index of the species.
|
* @param species Species to look up stoichiometry for.
|
||||||
* @param reactionIndex Index of the reaction.
|
* @param reaction Reaction to find.
|
||||||
* @return Stoichiometric coefficient for the species in the reaction.
|
* @return Stoichiometric coefficient for the species in the reaction.
|
||||||
*
|
*
|
||||||
* The stoichiometry matrix must have been generated by `generateStoichiometryMatrix()`.
|
* The stoichiometry matrix must have been generated by `generateStoichiometryMatrix()`.
|
||||||
@@ -255,14 +257,14 @@ namespace gridfire {
|
|||||||
* @see generateStoichiometryMatrix()
|
* @see generateStoichiometryMatrix()
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||||
const int speciesIndex,
|
const fourdst::atomic::Species& species,
|
||||||
const int reactionIndex
|
const reaction::Reaction& reaction
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Computes timescales for all species in the network.
|
* @brief Computes timescales for all species in the network.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current abundances.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Map from Species to their characteristic timescales (s).
|
* @return Map from Species to their characteristic timescales (s).
|
||||||
@@ -271,13 +273,13 @@ namespace gridfire {
|
|||||||
* which can be used for timestep control or diagnostics.
|
* which can be used for timestep control or diagnostics.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -396,7 +398,7 @@ namespace gridfire {
|
|||||||
* @param reaction The reaction for which to calculate the reverse rate.
|
* @param reaction The reaction for which to calculate the reverse rate.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho
|
* @param rho
|
||||||
* @param Y
|
* @param comp Composition object containing current abundances.
|
||||||
* @return Reverse rate for the reaction (e.g., mol/g/s).
|
* @return Reverse rate for the reaction (e.g., mol/g/s).
|
||||||
*
|
*
|
||||||
* This method computes the reverse rate based on the forward rate and
|
* This method computes the reverse rate based on the forward rate and
|
||||||
@@ -404,7 +406,9 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculateReverseRate(
|
[[nodiscard]] double calculateReverseRate(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
double T9, double rho, const std::vector<double> &Y
|
double T9,
|
||||||
|
double rho,
|
||||||
|
const fourdst::composition::Composition& comp
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -428,8 +432,10 @@ namespace gridfire {
|
|||||||
|
|
||||||
[[nodiscard]] double calculateReverseRateTwoBodyDerivative(
|
[[nodiscard]] double calculateReverseRateTwoBodyDerivative(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const double T9,
|
double T9,
|
||||||
double rho, const std::vector<double> &Y, const double reverseRate
|
double rho,
|
||||||
|
const fourdst::composition::Composition& comp,
|
||||||
|
double reverseRate
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -577,12 +583,16 @@ namespace gridfire {
|
|||||||
|
|
||||||
constants m_constants;
|
constants m_constants;
|
||||||
|
|
||||||
|
rates::weak::WeakRateInterpolator m_weakRateInterpolator; ///< Interpolator for weak reaction rates.
|
||||||
|
|
||||||
reaction::ReactionSet m_reactions; ///< Set of REACLIB reactions in the network.
|
reaction::ReactionSet m_reactions; ///< Set of REACLIB reactions in the network.
|
||||||
std::unordered_map<std::string_view, reaction::Reaction*> m_reactionIDMap; ///< Map from reaction ID to REACLIBReaction. //PERF: This makes copies of REACLIBReaction and could be a performance bottleneck.
|
std::unordered_map<std::string_view, reaction::Reaction*> m_reactionIDMap; ///< Map from reaction ID to REACLIBReaction. //PERF: This makes copies of REACLIBReaction and could be a performance bottleneck.
|
||||||
|
|
||||||
std::vector<fourdst::atomic::Species> m_networkSpecies; ///< Vector of unique species in the network.
|
std::vector<fourdst::atomic::Species> m_networkSpecies; ///< Vector of unique species in the network.
|
||||||
std::unordered_map<std::string_view, fourdst::atomic::Species> m_networkSpeciesMap; ///< Map from species name to Species object.
|
std::unordered_map<std::string_view, fourdst::atomic::Species> m_networkSpeciesMap; ///< Map from species name to Species object.
|
||||||
std::unordered_map<fourdst::atomic::Species, size_t> m_speciesToIndexMap; ///< Map from species to their index in the stoichiometry matrix.
|
std::unordered_map<fourdst::atomic::Species, size_t> m_speciesToIndexMap; ///< Map from species to their index in the stoichiometry matrix.
|
||||||
|
std::unordered_map<size_t, fourdst::atomic::Species> m_indexToSpeciesMap; ///< Map from index to species in the stoichiometry matrix.
|
||||||
|
|
||||||
|
|
||||||
boost::numeric::ublas::compressed_matrix<int> m_stoichiometryMatrix; ///< Stoichiometry matrix (species x reactions).
|
boost::numeric::ublas::compressed_matrix<int> m_stoichiometryMatrix; ///< Stoichiometry matrix (species x reactions).
|
||||||
|
|
||||||
@@ -680,10 +690,11 @@ namespace gridfire {
|
|||||||
|
|
||||||
|
|
||||||
[[nodiscard]] StepDerivatives<double> calculateAllDerivativesUsingPrecomputation(
|
[[nodiscard]] StepDerivatives<double> calculateAllDerivativesUsingPrecomputation(
|
||||||
const std::vector<double> &Y_in,
|
const fourdst::composition::Composition &comp,
|
||||||
const std::vector<double>& bare_rates,
|
const std::vector<double>& bare_rates,
|
||||||
const std::vector<double> &bare_reverse_rates,
|
const std::vector<double> &bare_reverse_rates,
|
||||||
double T9, double rho
|
double T9,
|
||||||
|
double rho
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -691,9 +702,11 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @tparam T The numeric type to use for the calculation.
|
* @tparam T The numeric type to use for the calculation.
|
||||||
* @param reaction The reaction for which to calculate the flow.
|
* @param reaction The reaction for which to calculate the flow.
|
||||||
* @param Y Vector of current abundances.
|
* @param Y Vector of molar abundances for all species in the network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
|
* @param Ye
|
||||||
|
* @param mue
|
||||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||||
*
|
*
|
||||||
* This method computes the net rate at which the given reaction proceeds
|
* This method computes the net rate at which the given reaction proceeds
|
||||||
@@ -702,17 +715,17 @@ namespace gridfire {
|
|||||||
template <IsArithmeticOrAD T>
|
template <IsArithmeticOrAD T>
|
||||||
T calculateMolarReactionFlow(
|
T calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<T> &Y,
|
const std::vector<T>& Y,
|
||||||
const T T9,
|
const T T9,
|
||||||
const T rho
|
const T rho, T Ye, T mue
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
template<IsArithmeticOrAD T>
|
template<IsArithmeticOrAD T>
|
||||||
T calculateReverseMolarReactionFlow(
|
T calculateReverseMolarReactionFlow(
|
||||||
T T9,
|
const T T9,
|
||||||
T rho,
|
const T rho,
|
||||||
std::vector<T> screeningFactors,
|
std::vector<T> screeningFactors,
|
||||||
std::vector<T> Y,
|
const std::vector<T>& Y,
|
||||||
size_t reactionIndex,
|
size_t reactionIndex,
|
||||||
const reaction::Reaction &reaction
|
const reaction::Reaction &reaction
|
||||||
) const;
|
) const;
|
||||||
@@ -721,9 +734,11 @@ namespace gridfire {
|
|||||||
* @brief Calculates all derivatives (dY/dt) and the energy generation rate.
|
* @brief Calculates all derivatives (dY/dt) and the energy generation rate.
|
||||||
*
|
*
|
||||||
* @tparam T The numeric type to use for the calculation.
|
* @tparam T The numeric type to use for the calculation.
|
||||||
* @param Y_in Vector of current abundances for all species.
|
* @param Y_in Vector of molar abundances for all species in the network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
|
* @param Ye
|
||||||
|
* @param mue
|
||||||
* @return StepDerivatives<T> containing dY/dt and energy generation rate.
|
* @return StepDerivatives<T> containing dY/dt and energy generation rate.
|
||||||
*
|
*
|
||||||
* This method calculates the time derivatives of all species and the
|
* This method calculates the time derivatives of all species and the
|
||||||
@@ -731,46 +746,46 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
template<IsArithmeticOrAD T>
|
template<IsArithmeticOrAD T>
|
||||||
[[nodiscard]] StepDerivatives<T> calculateAllDerivatives(
|
[[nodiscard]] StepDerivatives<T> calculateAllDerivatives(
|
||||||
const std::vector<T> &Y_in,
|
const std::vector<T>& Y_in,
|
||||||
T T9,
|
T T9,
|
||||||
T rho
|
T rho, T Ye, T mue
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Calculates all derivatives (dY/dt) and the energy generation rate (double precision).
|
// * @brief Calculates all derivatives (dY/dt) and the energy generation rate (double precision).
|
||||||
*
|
// *
|
||||||
* @param Y_in Vector of current abundances for all species.
|
// * @param Y Vector of molar abundances for all species in the network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
// * @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
// * @param rho Density in g/cm^3.
|
||||||
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
// * @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
||||||
*
|
// *
|
||||||
* This method calculates the time derivatives of all species and the
|
// * This method calculates the time derivatives of all species and the
|
||||||
* specific nuclear energy generation rate for the current state using
|
// * specific nuclear energy generation rate for the current state using
|
||||||
* double precision arithmetic.
|
// * double precision arithmetic.
|
||||||
*/
|
// */
|
||||||
[[nodiscard]] StepDerivatives<double> calculateAllDerivatives(
|
// [[nodiscard]] StepDerivatives<double> calculateAllDerivatives(
|
||||||
const std::vector<double>& Y_in,
|
// const std::vector<double>& Y,
|
||||||
const double T9,
|
// double T9,
|
||||||
const double rho
|
// double rho
|
||||||
) const;
|
// ) const;
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* @brief Calculates all derivatives (dY/dt) and the energy generation rate (automatic differentiation).
|
// * @brief Calculates all derivatives (dY/dt) and the energy generation rate (automatic differentiation).
|
||||||
*
|
// *
|
||||||
* @param Y_in Vector of current abundances for all species.
|
// * @param Y Vector of molar abundances for all species in the network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
// * @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
// * @param rho Density in g/cm^3.
|
||||||
* @return StepDerivatives<ADDouble> containing dY/dt and energy generation rate.
|
// * @return StepDerivatives<ADDouble> containing dY/dt and energy generation rate.
|
||||||
*
|
// *
|
||||||
* This method calculates the time derivatives of all species and the
|
// * This method calculates the time derivatives of all species and the
|
||||||
* specific nuclear energy generation rate for the current state using
|
// * specific nuclear energy generation rate for the current state using
|
||||||
* automatic differentiation.
|
// * automatic differentiation.
|
||||||
*/
|
// */
|
||||||
[[nodiscard]] StepDerivatives<ADDouble> calculateAllDerivatives(
|
// [[nodiscard]] StepDerivatives<ADDouble> calculateAllDerivatives(
|
||||||
const std::vector<ADDouble>& Y_in,
|
// const std::vector<ADDouble> &Y,
|
||||||
const ADDouble &T9,
|
// ADDouble T9,
|
||||||
const ADDouble &rho
|
// ADDouble rho
|
||||||
) const;
|
// ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -780,7 +795,7 @@ namespace gridfire {
|
|||||||
T T9,
|
T T9,
|
||||||
T rho,
|
T rho,
|
||||||
std::vector<T> screeningFactors,
|
std::vector<T> screeningFactors,
|
||||||
std::vector<T> Y,
|
const std::vector<T>& Y,
|
||||||
size_t reactionIndex,
|
size_t reactionIndex,
|
||||||
const reaction::Reaction &reaction
|
const reaction::Reaction &reaction
|
||||||
) const {
|
) const {
|
||||||
@@ -804,9 +819,15 @@ namespace gridfire {
|
|||||||
} else {
|
} else {
|
||||||
return reverseMolarFlow; // If no atomic function is available, return zero
|
return reverseMolarFlow; // If no atomic function is available, return zero
|
||||||
}
|
}
|
||||||
} else {
|
} else { // The case where T is of type double
|
||||||
// A,B If not calling with an AD type, calculate the reverse rate directly
|
// A,B If not calling with an AD type, calculate the reverse rate directly
|
||||||
reverseRateConstant = calculateReverseRate(reaction, T9, 0, {});
|
std::vector<std::string> symbols;
|
||||||
|
symbols.reserve(m_networkSpecies.size());
|
||||||
|
for (const auto& species : m_networkSpecies) {
|
||||||
|
symbols.emplace_back(species.name());
|
||||||
|
}
|
||||||
|
fourdst::composition::Composition comp(symbols, Y);
|
||||||
|
reverseRateConstant = calculateReverseRate(reaction, T9, rho, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// C. Get product multiplicities
|
// C. Get product multiplicities
|
||||||
@@ -824,7 +845,7 @@ namespace gridfire {
|
|||||||
// E. Calculate the abundance term
|
// E. Calculate the abundance term
|
||||||
T productAbundanceTerm = static_cast<T>(1.0);
|
T productAbundanceTerm = static_cast<T>(1.0);
|
||||||
for (const auto& [species, count] : productCounts) {
|
for (const auto& [species, count] : productCounts) {
|
||||||
const unsigned long speciesIndex = m_speciesToIndexMap.at(species);
|
const size_t speciesIndex = m_speciesToIndexMap.at(species);
|
||||||
productAbundanceTerm *= CppAD::pow(Y[speciesIndex], count);
|
productAbundanceTerm *= CppAD::pow(Y[speciesIndex], count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,7 +865,12 @@ namespace gridfire {
|
|||||||
|
|
||||||
template<IsArithmeticOrAD T>
|
template<IsArithmeticOrAD T>
|
||||||
StepDerivatives<T> GraphEngine::calculateAllDerivatives(
|
StepDerivatives<T> GraphEngine::calculateAllDerivatives(
|
||||||
const std::vector<T> &Y_in, T T9, T rho) const {
|
const std::vector<T>& Y_in,
|
||||||
|
const T T9,
|
||||||
|
const T rho,
|
||||||
|
const T Ye,
|
||||||
|
const T mue
|
||||||
|
) const {
|
||||||
std::vector<T> screeningFactors = m_screeningModel->calculateScreeningFactors(
|
std::vector<T> screeningFactors = m_screeningModel->calculateScreeningFactors(
|
||||||
m_reactions,
|
m_reactions,
|
||||||
m_networkSpecies,
|
m_networkSpecies,
|
||||||
@@ -854,8 +880,10 @@ namespace gridfire {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// --- Setup output derivatives structure ---
|
// --- Setup output derivatives structure ---
|
||||||
StepDerivatives<T> result;
|
StepDerivatives<T> result{};
|
||||||
result.dydt.resize(m_networkSpecies.size(), static_cast<T>(0.0));
|
for (const auto& species : m_networkSpecies) {
|
||||||
|
result.dydt[species] = static_cast<T>(0.0); // default the change in abundance to zero
|
||||||
|
}
|
||||||
|
|
||||||
// --- AD Pre-setup (flags to control conditionals in an AD safe / branch aware manner) ---
|
// --- AD Pre-setup (flags to control conditionals in an AD safe / branch aware manner) ---
|
||||||
// ----- Constants for AD safe calculations ---
|
// ----- Constants for AD safe calculations ---
|
||||||
@@ -885,13 +913,16 @@ namespace gridfire {
|
|||||||
const T N_A = static_cast<T>(m_constants.Na); // Avogadro's number in mol^-1
|
const T N_A = static_cast<T>(m_constants.Na); // Avogadro's number in mol^-1
|
||||||
const T c = static_cast<T>(m_constants.c); // Speed of light in cm/s
|
const T c = static_cast<T>(m_constants.c); // Speed of light in cm/s
|
||||||
|
|
||||||
|
// TODO: It may be prudent to introduce assertions here which validate units but will be removed in release builds (to ensure that unit inconsistencies do not creep in during future development)
|
||||||
|
// libconstants already has units built in so this should be straightforward.
|
||||||
|
|
||||||
// --- SINGLE LOOP OVER ALL REACTIONS ---
|
// --- SINGLE LOOP OVER ALL REACTIONS ---
|
||||||
for (size_t reactionIndex = 0; reactionIndex < m_reactions.size(); ++reactionIndex) {
|
for (size_t reactionIndex = 0; reactionIndex < m_reactions.size(); ++reactionIndex) {
|
||||||
const auto& reaction = m_reactions[reactionIndex];
|
const auto& reaction = m_reactions[reactionIndex];
|
||||||
|
|
||||||
// 1. Calculate forward reaction rate
|
// 1. Calculate forward reaction rate
|
||||||
const T forwardMolarReactionFlow = screeningFactors[reactionIndex] *
|
const T forwardMolarReactionFlow = screeningFactors[reactionIndex] *
|
||||||
calculateMolarReactionFlow<T>(reaction, Y, T9, rho);
|
calculateMolarReactionFlow<T>(reaction, Y, T9, rho, Ye, mue);
|
||||||
|
|
||||||
// 2. Calculate reverse reaction rate
|
// 2. Calculate reverse reaction rate
|
||||||
T reverseMolarFlow = static_cast<T>(0.0);
|
T reverseMolarFlow = static_cast<T>(0.0);
|
||||||
@@ -910,15 +941,15 @@ namespace gridfire {
|
|||||||
const T molarReactionFlow = forwardMolarReactionFlow - reverseMolarFlow; // Net molar reaction flow
|
const T molarReactionFlow = forwardMolarReactionFlow - reverseMolarFlow; // Net molar reaction flow
|
||||||
|
|
||||||
// 3. Use the rate to update all relevant species derivatives (dY/dt)
|
// 3. Use the rate to update all relevant species derivatives (dY/dt)
|
||||||
for (size_t speciesIndex = 0; speciesIndex < m_networkSpecies.size(); ++speciesIndex) {
|
for (const auto& species: m_networkSpecies) {
|
||||||
const T nu_ij = static_cast<T>(m_stoichiometryMatrix(speciesIndex, reactionIndex));
|
const T nu_ij = static_cast<T>(reaction.stoichiometry(species));
|
||||||
result.dydt[speciesIndex] += threshold_flag * nu_ij * molarReactionFlow;
|
result.dydt[species] += threshold_flag * nu_ij * molarReactionFlow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T massProductionRate = static_cast<T>(0.0); // [mol][s^-1]
|
T massProductionRate = static_cast<T>(0.0); // [mol][s^-1]
|
||||||
for (const auto& [species, index] : m_speciesToIndexMap) {
|
for (const auto &species: m_speciesToIndexMap | std::views::keys) {
|
||||||
massProductionRate += result.dydt[index] * species.mass() * u;
|
massProductionRate += result.dydt.at(species) * species.mass() * u;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.nuclearEnergyGenerationRate = -massProductionRate * N_A * c * c; // [cm^2][s^-3] = [erg][s^-1][g^-1]
|
result.nuclearEnergyGenerationRate = -massProductionRate * N_A * c * c; // [cm^2][s^-3] = [erg][s^-1][g^-1]
|
||||||
@@ -930,9 +961,11 @@ namespace gridfire {
|
|||||||
template <IsArithmeticOrAD T>
|
template <IsArithmeticOrAD T>
|
||||||
T GraphEngine::calculateMolarReactionFlow(
|
T GraphEngine::calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<T> &Y,
|
const std::vector<T>& Y,
|
||||||
const T T9,
|
const T T9,
|
||||||
const T rho
|
const T rho,
|
||||||
|
const T Ye,
|
||||||
|
const T mue
|
||||||
) const {
|
) const {
|
||||||
|
|
||||||
// --- Pre-setup (flags to control conditionals in an AD safe / branch aware manner) ---
|
// --- Pre-setup (flags to control conditionals in an AD safe / branch aware manner) ---
|
||||||
@@ -940,7 +973,7 @@ namespace gridfire {
|
|||||||
const T zero = static_cast<T>(0.0);
|
const T zero = static_cast<T>(0.0);
|
||||||
|
|
||||||
// --- Calculate the molar reaction rate (in units of [s^-1][cm^3(N-1)][mol^(1-N)] for N reactants) ---
|
// --- Calculate the molar reaction rate (in units of [s^-1][cm^3(N-1)][mol^(1-N)] for N reactants) ---
|
||||||
const T k_reaction = reaction.calculate_rate(T9, rho, Y);
|
const T k_reaction = reaction.calculate_rate(T9, rho, Ye, mue, Y, m_indexToSpeciesMap);
|
||||||
|
|
||||||
// --- Cound the number of each reactant species to account for species multiplicity ---
|
// --- Cound the number of each reactant species to account for species multiplicity ---
|
||||||
std::unordered_map<std::string, int> reactant_counts;
|
std::unordered_map<std::string, int> reactant_counts;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include "gridfire/reaction/weak/weak_interpolator.h"
|
||||||
|
|
||||||
namespace gridfire {
|
namespace gridfire {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,6 +23,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param composition Mapping of isotopic species to their mass fractions; species with positive
|
* @param composition Mapping of isotopic species to their mass fractions; species with positive
|
||||||
* mass fraction seed the network.
|
* mass fraction seed the network.
|
||||||
|
* @param weakInterpolator
|
||||||
* @param maxLayers Variant specifying either a predefined NetworkBuildDepth or a custom integer depth;
|
* @param maxLayers Variant specifying either a predefined NetworkBuildDepth or a custom integer depth;
|
||||||
* negative depth (Full) collects all reactions, zero is invalid.
|
* negative depth (Full) collects all reactions, zero is invalid.
|
||||||
* @param reverse If true, collects reverse reactions (decays or back-reactions); if false, uses forward reactions.
|
* @param reverse If true, collects reverse reactions (decays or back-reactions); if false, uses forward reactions.
|
||||||
@@ -32,7 +35,7 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
reaction::ReactionSet build_reaclib_nuclear_network(
|
reaction::ReactionSet build_reaclib_nuclear_network(
|
||||||
const fourdst::composition::Composition &composition,
|
const fourdst::composition::Composition &composition,
|
||||||
BuildDepthType maxLayers = NetworkBuildDepth::Full,
|
const rates::weak::WeakRateInterpolator &weakInterpolator,
|
||||||
bool reverse = false
|
BuildDepthType maxLayers = NetworkBuildDepth::Full, bool reverse = false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param engine Engine providing the current set of network reactions and flow calculations.
|
* @param engine Engine providing the current set of network reactions and flow calculations.
|
||||||
* @param species The atomic species whose destruction rate is computed.
|
* @param species The atomic species whose destruction rate is computed.
|
||||||
* @param Y Vector of molar abundances for all species in the engine.
|
* @param composition Current composition providing abundances for all species.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density of the medium.
|
* @param rho Density of the medium.
|
||||||
* @pre Y.size() matches engine.getNetworkReactions().size() mapping species order.
|
* @pre Y.size() matches engine.getNetworkReactions().size() mapping species order.
|
||||||
@@ -47,7 +47,7 @@ namespace gridfire {
|
|||||||
double calculateDestructionRateConstant(
|
double calculateDestructionRateConstant(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const fourdst::atomic::Species& species,
|
const fourdst::atomic::Species& species,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& composition,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
@@ -60,7 +60,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param engine Engine providing the current set of network reactions and flow calculations.
|
* @param engine Engine providing the current set of network reactions and flow calculations.
|
||||||
* @param species The atomic species whose creation rate is computed.
|
* @param species The atomic species whose creation rate is computed.
|
||||||
* @param Y Vector of molar abundances for all species in the engine.
|
* @param composition Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density of the medium.
|
* @param rho Density of the medium.
|
||||||
* @pre Y.size() matches engine.getNetworkReactions().size() mapping species order.
|
* @pre Y.size() matches engine.getNetworkReactions().size() mapping species order.
|
||||||
@@ -70,7 +70,7 @@ namespace gridfire {
|
|||||||
double calculateCreationRate(
|
double calculateCreationRate(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const fourdst::atomic::Species& species,
|
const fourdst::atomic::Species& species,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& composition,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Calculates the right-hand side (dY/dt) and energy generation for the active species.
|
* @brief Calculates the right-hand side (dY/dt) and energy generation for the active species.
|
||||||
*
|
*
|
||||||
* @param Y_culled A vector of abundances for the active species.
|
* @param comp The current composition of the system.
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho The density in g/cm^3.
|
* @param rho The density in g/cm^3.
|
||||||
* @return A StepDerivatives struct containing the derivatives of the active species and the
|
* @return A StepDerivatives struct containing the derivatives of the active species and the
|
||||||
@@ -102,21 +102,29 @@ namespace gridfire {
|
|||||||
* @see AdaptiveEngineView::update()
|
* @see AdaptiveEngineView::update()
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param comp The current composition of the system.
|
||||||
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
|
* @param rho The density in g/cm^3.
|
||||||
|
* @return A struct containing the derivatives of the energy generation rate with respect to temperature and density.
|
||||||
|
*/
|
||||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates the Jacobian matrix for the active species.
|
* @brief Generates the Jacobian matrix for the active species.
|
||||||
*
|
*
|
||||||
* @param Y_dynamic A vector of abundances for the active species.
|
* @param comp The current composition of the system.
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho The density in g/cm^3.
|
* @param rho The density in g/cm^3.
|
||||||
*
|
*
|
||||||
@@ -127,16 +135,16 @@ namespace gridfire {
|
|||||||
* @see AdaptiveEngineView::update()
|
* @see AdaptiveEngineView::update()
|
||||||
*/
|
*/
|
||||||
void generateJacobianMatrix(
|
void generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the Jacobian matrix for the active species.
|
* @brief Gets an entry from the Jacobian matrix for the active species.
|
||||||
*
|
*
|
||||||
* @param i_culled The row index (species index) in the culled matrix.
|
* @param rowSpecies The species corresponding to the row index in the culled species list.
|
||||||
* @param j_culled The column index (species index) in the culled matrix.
|
* @param colSpecies The species corresponding to the column index in the culled species list
|
||||||
* @return The value of the Jacobian matrix at (i_culled, j_culled).
|
* @return The value of the Jacobian matrix at (i_culled, j_culled).
|
||||||
*
|
*
|
||||||
* This method maps the culled indices to the full network indices and calls the base engine
|
* This method maps the culled indices to the full network indices and calls the base engine
|
||||||
@@ -147,8 +155,8 @@ namespace gridfire {
|
|||||||
* @see AdaptiveEngineView::update()
|
* @see AdaptiveEngineView::update()
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] double getJacobianMatrixEntry(
|
[[nodiscard]] double getJacobianMatrixEntry(
|
||||||
const int i_culled,
|
const fourdst::atomic::Species& rowSpecies,
|
||||||
const int j_culled
|
const fourdst::atomic::Species& colSpecies
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,8 +173,8 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the stoichiometry matrix for the active species and reactions.
|
* @brief Gets an entry from the stoichiometry matrix for the active species and reactions.
|
||||||
*
|
*
|
||||||
* @param speciesIndex_culled The index of the species in the culled species list.
|
* @param species The species for which to get the stoichiometric coefficient.
|
||||||
* @param reactionIndex_culled The index of the reaction in the culled reaction list.
|
* @param reaction The reaction for which to get the stoichiometric coefficient.
|
||||||
* @return The stoichiometric coefficient for the given species and reaction.
|
* @return The stoichiometric coefficient for the given species and reaction.
|
||||||
*
|
*
|
||||||
* This method maps the culled indices to the full network indices and calls the base engine
|
* This method maps the culled indices to the full network indices and calls the base engine
|
||||||
@@ -177,15 +185,15 @@ namespace gridfire {
|
|||||||
* @see AdaptiveEngineView::update()
|
* @see AdaptiveEngineView::update()
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||||
const int speciesIndex_culled,
|
const fourdst::atomic::Species& species,
|
||||||
const int reactionIndex_culled
|
const reaction::Reaction& reaction
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculates the molar reaction flow for a given reaction in the active network.
|
* @brief Calculates the molar reaction flow for a given reaction in the active network.
|
||||||
*
|
*
|
||||||
* @param reaction The reaction for which to calculate the flow.
|
* @param reaction The reaction for which to calculate the flow.
|
||||||
* @param Y_culled Vector of current abundances for the active species.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||||
@@ -198,7 +206,7 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculateMolarReactionFlow(
|
[[nodiscard]] double calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -215,7 +223,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Computes timescales for all active species in the network.
|
* @brief Computes timescales for all active species in the network.
|
||||||
*
|
*
|
||||||
* @param Y_culled Vector of current abundances for the active species.
|
* @param comp Composition object containing current abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Map from Species to their characteristic timescales (s).
|
* @return Map from Species to their characteristic timescales (s).
|
||||||
@@ -226,13 +234,13 @@ namespace gridfire {
|
|||||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -391,21 +399,18 @@ namespace gridfire {
|
|||||||
* full network.
|
* full network.
|
||||||
*
|
*
|
||||||
* @param netIn The current network input, containing temperature, density, and composition.
|
* @param netIn The current network input, containing temperature, density, and composition.
|
||||||
* @param out_Y_Full A vector that will be populated with the molar abundances of all species in the full network.
|
* @return A pair with the first element a vector of ReactionFlow structs, each containing a pointer to a reaction and its calculated flow rate and the second being a composition object where species which were not present in netIn but are present in the definition of the base engine are registered but have 0 mass fraction.
|
||||||
* @return A vector of ReactionFlow structs, each containing a pointer to a reaction and its calculated flow rate.
|
|
||||||
*
|
*
|
||||||
* @par Algorithm:
|
* @par Algorithm:
|
||||||
* 1. Clears and reserves space in `out_Y_Full`.
|
* 1. Iterates through all species in the base engine's network.
|
||||||
* 2. Iterates through all species in the base engine's network.
|
* 2. For each species, it retrieves the molar abundance from `netIn.composition`. If the species is not found, its abundance is set to 0.0.
|
||||||
* 3. For each species, it retrieves the molar abundance from `netIn.composition`. If the species is not found, its abundance is set to 0.0.
|
* 3. Converts the temperature from Kelvin to T9.
|
||||||
* 4. Converts the temperature from Kelvin to T9.
|
* 4. Iterates through all reactions in the base engine's network.
|
||||||
* 5. Iterates through all reactions in the base engine's network.
|
* 5. For each reaction, it calls the base engine's `calculateMolarReactionFlow` to get the flow rate.
|
||||||
* 6. For each reaction, it calls the base engine's `calculateMolarReactionFlow` to get the flow rate.
|
* 6. Stores the reaction pointer and its flow rate in a `ReactionFlow` struct and adds it to the returned vector.
|
||||||
* 7. Stores the reaction pointer and its flow rate in a `ReactionFlow` struct and adds it to the returned vector.
|
|
||||||
*/
|
*/
|
||||||
std::vector<ReactionFlow> calculateAllReactionFlows(
|
std::pair<std::vector<ReactionFlow>, fourdst::composition::Composition> calculateAllReactionFlows(
|
||||||
const NetIn& netIn,
|
const NetIn& netIn
|
||||||
std::vector<double>& out_Y_Full
|
|
||||||
) const;
|
) const;
|
||||||
/**
|
/**
|
||||||
* @brief Finds all species that are reachable from the initial fuel through the reaction network.
|
* @brief Finds all species that are reachable from the initial fuel through the reaction network.
|
||||||
@@ -436,7 +441,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param allFlows A vector of all reactions and their flow rates.
|
* @param allFlows A vector of all reactions and their flow rates.
|
||||||
* @param reachableSpecies A set of all species reachable from the initial fuel.
|
* @param reachableSpecies A set of all species reachable from the initial fuel.
|
||||||
* @param Y_full A vector of molar abundances for all species in the full network.
|
* @param comp The current composition of the system.
|
||||||
* @param maxFlow The maximum reaction flow rate in the network.
|
* @param maxFlow The maximum reaction flow rate in the network.
|
||||||
* @return A vector of pointers to the reactions that have been kept after culling.
|
* @return A vector of pointers to the reactions that have been kept after culling.
|
||||||
*
|
*
|
||||||
@@ -450,15 +455,15 @@ namespace gridfire {
|
|||||||
[[nodiscard]] std::vector<const reaction::Reaction*> cullReactionsByFlow(
|
[[nodiscard]] std::vector<const reaction::Reaction*> cullReactionsByFlow(
|
||||||
const std::vector<ReactionFlow>& allFlows,
|
const std::vector<ReactionFlow>& allFlows,
|
||||||
const std::unordered_set<fourdst::atomic::Species>& reachableSpecies,
|
const std::unordered_set<fourdst::atomic::Species>& reachableSpecies,
|
||||||
const std::vector<double>& Y_full,
|
const fourdst::composition::Composition& comp,
|
||||||
double maxFlow
|
double maxFlow
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
typedef std::pair<std::unordered_set<const reaction::Reaction*>, std::unordered_set<fourdst::atomic::Species>> RescueSet;
|
typedef std::pair<std::unordered_set<const reaction::Reaction*>, std::unordered_set<fourdst::atomic::Species>> RescueSet;
|
||||||
[[nodiscard]] RescueSet rescueEdgeSpeciesDestructionChannel(
|
[[nodiscard]] RescueSet rescueEdgeSpeciesDestructionChannel(
|
||||||
const std::vector<double>& Y_full,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho,
|
double rho,
|
||||||
const std::vector<fourdst::atomic::Species>& activeSpecies,
|
const std::vector<fourdst::atomic::Species>& activeSpecies,
|
||||||
const reaction::ReactionSet& activeReactions
|
const reaction::ReactionSet& activeReactions
|
||||||
) const;
|
) const;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace gridfire{
|
|||||||
/**
|
/**
|
||||||
* @brief Calculates the right-hand side (dY/dt) and energy generation for the active species.
|
* @brief Calculates the right-hand side (dY/dt) and energy generation for the active species.
|
||||||
*
|
*
|
||||||
* @param Y_defined A vector of abundances for the active species.
|
* @param comp A Composition object containing the current composition of the system
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho The density in g/cm^3.
|
* @param rho The density in g/cm^3.
|
||||||
* @return A StepDerivatives struct containing the derivatives of the active species and the
|
* @return A StepDerivatives struct containing the derivatives of the active species and the
|
||||||
@@ -38,44 +38,44 @@ namespace gridfire{
|
|||||||
* @throws std::runtime_error If the view is stale (i.e., `update()` has not been called after `setNetworkFile()`).
|
* @throws std::runtime_error If the view is stale (i.e., `update()` has not been called after `setNetworkFile()`).
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||||
const std::vector<double>& Y_defined,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates the Jacobian matrix for the active species.
|
* @brief Generates the Jacobian matrix for the active species.
|
||||||
*
|
*
|
||||||
* @param Y_dynamic A vector of abundances for the active species.
|
* @param comp A Composition object containing the current composition of the system
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho The density in g/cm^3.
|
* @param rho The density in g/cm^3.
|
||||||
*
|
*
|
||||||
* @throws std::runtime_error If the view is stale.
|
* @throws std::runtime_error If the view is stale.
|
||||||
*/
|
*/
|
||||||
void generateJacobianMatrix(
|
void generateJacobianMatrix(
|
||||||
const std::vector<double>& Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const override;
|
) const override;
|
||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the Jacobian matrix for the active species.
|
* @brief Gets an entry from the Jacobian matrix for the active species.
|
||||||
*
|
*
|
||||||
* @param i_defined The row index (species index) in the defined matrix.
|
* @param rowSpecies The species corresponding to the row index.
|
||||||
* @param j_defined The column index (species index) in the defined matrix.
|
* @param colSpecies The species corresponding to the column index.
|
||||||
* @return The value of the Jacobian matrix at (i_defined, j_defined).
|
* @return The value of the Jacobian matrix at (row species index, col species index).
|
||||||
*
|
*
|
||||||
* @throws std::runtime_error If the view is stale.
|
* @throws std::runtime_error If the view is stale.
|
||||||
* @throws std::out_of_range If an index is out of bounds.
|
* @throws std::out_of_range If an index is out of bounds.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] double getJacobianMatrixEntry(
|
[[nodiscard]] double getJacobianMatrixEntry(
|
||||||
const int i_defined,
|
const fourdst::atomic::Species& rowSpecies,
|
||||||
const int j_defined
|
const fourdst::atomic::Species& colSpecies
|
||||||
) const override;
|
) const override;
|
||||||
/**
|
/**
|
||||||
* @brief Generates the stoichiometry matrix for the active reactions and species.
|
* @brief Generates the stoichiometry matrix for the active reactions and species.
|
||||||
@@ -86,22 +86,22 @@ namespace gridfire{
|
|||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the stoichiometry matrix for the active species and reactions.
|
* @brief Gets an entry from the stoichiometry matrix for the active species and reactions.
|
||||||
*
|
*
|
||||||
* @param speciesIndex_defined The index of the species in the defined species list.
|
* @param species The species for which to get the stoichiometric coefficient.
|
||||||
* @param reactionIndex_defined The index of the reaction in the defined reaction list.
|
* @param reaction The reaction for which to get the stoichiometric coefficient.
|
||||||
* @return The stoichiometric coefficient for the given species and reaction.
|
* @return The stoichiometric coefficient for the given species and reaction.
|
||||||
*
|
*
|
||||||
* @throws std::runtime_error If the view is stale.
|
* @throws std::runtime_error If the view is stale.
|
||||||
* @throws std::out_of_range If an index is out of bounds.
|
* @throws std::out_of_range If an index is out of bounds.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||||
const int speciesIndex_defined,
|
const fourdst::atomic::Species& species,
|
||||||
const int reactionIndex_defined
|
const reaction::Reaction& reaction
|
||||||
) const override;
|
) const override;
|
||||||
/**
|
/**
|
||||||
* @brief Calculates the molar reaction flow for a given reaction in the active network.
|
* @brief Calculates the molar reaction flow for a given reaction in the active network.
|
||||||
*
|
*
|
||||||
* @param reaction The reaction for which to calculate the flow.
|
* @param reaction The reaction for which to calculate the flow.
|
||||||
* @param Y_defined Vector of current abundances for the active species.
|
* @param comp A Composition object containing the current composition of the system
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||||
@@ -110,9 +110,9 @@ namespace gridfire{
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculateMolarReactionFlow(
|
[[nodiscard]] double calculateMolarReactionFlow(
|
||||||
const reaction::Reaction& reaction,
|
const reaction::Reaction& reaction,
|
||||||
const std::vector<double>& Y_defined,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
/**
|
/**
|
||||||
* @brief Gets the set of active logical reactions in the network.
|
* @brief Gets the set of active logical reactions in the network.
|
||||||
@@ -127,7 +127,7 @@ namespace gridfire{
|
|||||||
/**
|
/**
|
||||||
* @brief Computes timescales for all active species in the network.
|
* @brief Computes timescales for all active species in the network.
|
||||||
*
|
*
|
||||||
* @param Y_defined Vector of current abundances for the active species.
|
* @param comp A Composition object containing the current composition of the system
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Map from Species to their characteristic timescales (s).
|
* @return Map from Species to their characteristic timescales (s).
|
||||||
@@ -135,15 +135,15 @@ namespace gridfire{
|
|||||||
* @throws std::runtime_error If the view is stale.
|
* @throws std::runtime_error If the view is stale.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||||
const std::vector<double>& Y_defined,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||||
const std::vector<double>& Y_defined,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Calculates the right-hand side (dY/dt) and energy generation.
|
* @brief Calculates the right-hand side (dY/dt) and energy generation.
|
||||||
*
|
*
|
||||||
* @param Y_full Vector of current molar abundances for all species in the base engine.
|
* @param comp The current composition.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A `std::expected` containing `StepDerivatives<double>` on success, or a
|
* @return A `std::expected` containing `StepDerivatives<double>` on success, or a
|
||||||
@@ -231,21 +231,21 @@ namespace gridfire {
|
|||||||
* (T9, rho, Y_full). This indicates `update()` was not called recently enough.
|
* (T9, rho, Y_full). This indicates `update()` was not called recently enough.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates the Jacobian matrix for the current state.
|
* @brief Generates the Jacobian matrix for the current state.
|
||||||
*
|
*
|
||||||
* @param Y_full Vector of current molar abundances.
|
* @param comp The current composition.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
*
|
*
|
||||||
@@ -266,7 +266,7 @@ namespace gridfire {
|
|||||||
* without a valid partition.
|
* without a valid partition.
|
||||||
*/
|
*/
|
||||||
void generateJacobianMatrix(
|
void generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -274,8 +274,8 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the previously generated Jacobian matrix.
|
* @brief Gets an entry from the previously generated Jacobian matrix.
|
||||||
*
|
*
|
||||||
* @param i_full Row index (species index) in the full network.
|
* @param rowSpecies Species corresponding to the row index (i_full).
|
||||||
* @param j_full Column index (species index) in the full network.
|
* @param colSpecies Species corresponding to the column index (j_full).
|
||||||
* @return Value of the Jacobian matrix at (i_full, j_full).
|
* @return Value of the Jacobian matrix at (i_full, j_full).
|
||||||
*
|
*
|
||||||
* @par Purpose
|
* @par Purpose
|
||||||
@@ -289,8 +289,8 @@ namespace gridfire {
|
|||||||
* @pre `generateJacobianMatrix()` must have been called for the current state.
|
* @pre `generateJacobianMatrix()` must have been called for the current state.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] double getJacobianMatrixEntry(
|
[[nodiscard]] double getJacobianMatrixEntry(
|
||||||
int i_full,
|
const fourdst::atomic::Species& rowSpecies,
|
||||||
int j_full
|
const fourdst::atomic::Species& colSpecies
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -308,8 +308,8 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Gets an entry from the stoichiometry matrix.
|
* @brief Gets an entry from the stoichiometry matrix.
|
||||||
*
|
*
|
||||||
* @param speciesIndex Index of the species in the full network.
|
* @param species Species to look up stoichiometry for.
|
||||||
* @param reactionIndex Index of the reaction in the full network.
|
* @param reaction Reaction to find.
|
||||||
* @return Stoichiometric coefficient for the species in the reaction.
|
* @return Stoichiometric coefficient for the species in the reaction.
|
||||||
*
|
*
|
||||||
* @par Purpose
|
* @par Purpose
|
||||||
@@ -321,15 +321,15 @@ namespace gridfire {
|
|||||||
* @pre `generateStoichiometryMatrix()` must have been called.
|
* @pre `generateStoichiometryMatrix()` must have been called.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||||
int speciesIndex,
|
const fourdst::atomic::Species& species,
|
||||||
int reactionIndex
|
const reaction::Reaction& reaction
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculates the molar reaction flow for a given reaction.
|
* @brief Calculates the molar reaction flow for a given reaction.
|
||||||
*
|
*
|
||||||
* @param reaction The reaction for which to calculate the flow.
|
* @param reaction The reaction for which to calculate the flow.
|
||||||
* @param Y_full Vector of current molar abundances for the full network.
|
* @param comp The current composition.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||||
@@ -349,7 +349,7 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculateMolarReactionFlow(
|
[[nodiscard]] double calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -385,7 +385,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Computes timescales for all species in the network.
|
* @brief Computes timescales for all species in the network.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp The current composition.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A `std::expected` containing a map from `Species` to their characteristic
|
* @return A `std::expected` containing a map from `Species` to their characteristic
|
||||||
@@ -403,7 +403,7 @@ namespace gridfire {
|
|||||||
* @throws StaleEngineError If the QSE cache misses.
|
* @throws StaleEngineError If the QSE cache misses.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -411,7 +411,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Computes destruction timescales for all species in the network.
|
* @brief Computes destruction timescales for all species in the network.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp The current composition.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A `std::expected` containing a map from `Species` to their characteristic
|
* @return A `std::expected` containing a map from `Species` to their characteristic
|
||||||
@@ -429,7 +429,7 @@ namespace gridfire {
|
|||||||
* @throws StaleEngineError If the QSE cache misses.
|
* @throws StaleEngineError If the QSE cache misses.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition& comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
@@ -516,7 +516,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param timescale_pools A vector of vectors of species indices, where each inner vector
|
* @param timescale_pools A vector of vectors of species indices, where each inner vector
|
||||||
* represents a timescale pool.
|
* represents a timescale pool.
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp Vector of current molar abundances for the full network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A vector of vectors of species indices, where each inner vector represents a
|
* @return A vector of vectors of species indices, where each inner vector represents a
|
||||||
@@ -531,9 +531,9 @@ namespace gridfire {
|
|||||||
* It then finds the connected components within that graph using a Breadth-First Search (BFS).
|
* It then finds the connected components within that graph using a Breadth-First Search (BFS).
|
||||||
* The resulting components from all pools are collected and returned.
|
* The resulting components from all pools are collected and returned.
|
||||||
*/
|
*/
|
||||||
std::vector<std::vector<size_t>> analyzeTimescalePoolConnectivity(
|
std::vector<std::vector<fourdst::atomic::Species>> analyzeTimescalePoolConnectivity(
|
||||||
const std::vector<std::vector<size_t>> ×cale_pools,
|
const std::vector<std::vector<fourdst::atomic::Species>> ×cale_pools,
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const;
|
) const;
|
||||||
@@ -541,7 +541,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Partitions the network into dynamic and algebraic (QSE) groups based on timescales.
|
* @brief Partitions the network into dynamic and algebraic (QSE) groups based on timescales.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp Vector of current molar abundances for the full network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
*
|
*
|
||||||
@@ -567,7 +567,7 @@ namespace gridfire {
|
|||||||
* partitioning.
|
* partitioning.
|
||||||
*/
|
*/
|
||||||
void partitionNetwork(
|
void partitionNetwork(
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
@@ -605,9 +605,9 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
void exportToDot(
|
void exportToDot(
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition &Y,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -679,7 +679,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Equilibrates the network by partitioning and solving for QSE abundances.
|
* @brief Equilibrates the network by partitioning and solving for QSE abundances.
|
||||||
*
|
*
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp Vector of current molar abundances for the full network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A new composition object with the equilibrated abundances.
|
* @return A new composition object with the equilibrated abundances.
|
||||||
@@ -698,7 +698,7 @@ namespace gridfire {
|
|||||||
* @post The engine's internal partition is updated. A new composition object is returned.
|
* @post The engine's internal partition is updated. A new composition object is returned.
|
||||||
*/
|
*/
|
||||||
fourdst::composition::Composition equilibrateNetwork(
|
fourdst::composition::Composition equilibrateNetwork(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
@@ -730,11 +730,10 @@ namespace gridfire {
|
|||||||
* in quasi-steady-state equilibrium with each other.
|
* in quasi-steady-state equilibrium with each other.
|
||||||
*/
|
*/
|
||||||
struct QSEGroup {
|
struct QSEGroup {
|
||||||
std::set<size_t> species_indices; ///< Indices of all species in this group.
|
bool is_in_equilibrium = false; ///< Flag set by flux analysis.
|
||||||
bool is_in_equilibrium = false; ///< Flag set by flux analysis.
|
std::set<fourdst::atomic::Species> algebraic_species; ///< Algebraic species in this group.
|
||||||
std::set<size_t> algebraic_indices; ///< Indices of algebraic species in this group.
|
std::set<fourdst::atomic::Species> seed_species; ///< Dynamic species in this group.
|
||||||
std::set<size_t> seed_indices; ///< Indices of dynamic species in this group.
|
double mean_timescale; ///< Mean timescale of the group.
|
||||||
double mean_timescale; ///< Mean timescale of the group.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Less-than operator for QSEGroup, used for sorting.
|
* @brief Less-than operator for QSEGroup, used for sorting.
|
||||||
@@ -761,9 +760,7 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
bool operator!=(const QSEGroup& other) const;
|
bool operator!=(const QSEGroup& other) const;
|
||||||
|
|
||||||
std::string toString() const;
|
[[nodiscard]] [[maybe_unused]] std::string toString() const;
|
||||||
|
|
||||||
std::string toString(const DynamicEngine &engine) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -802,11 +799,11 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Indices of the species to solve for in the QSE group.
|
* @brief Indices of the species to solve for in the QSE group.
|
||||||
*/
|
*/
|
||||||
const std::vector<size_t>& m_qse_solve_indices;
|
const std::set<fourdst::atomic::Species>& m_qse_solve_species;
|
||||||
/**
|
/**
|
||||||
* @brief Initial abundances of all species in the full network.
|
* @brief Initial abundances of all species in the full network.
|
||||||
*/
|
*/
|
||||||
const std::vector<double>& m_Y_full_initial;
|
const fourdst::composition::Composition& m_initial_comp;
|
||||||
/**
|
/**
|
||||||
* @brief Temperature in units of 10^9 K.
|
* @brief Temperature in units of 10^9 K.
|
||||||
*/
|
*/
|
||||||
@@ -820,41 +817,49 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
const Eigen::VectorXd& m_Y_scale;
|
const Eigen::VectorXd& m_Y_scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mapping from species to their indices in the QSE solve vector.
|
||||||
|
*/
|
||||||
|
const std::unordered_map<fourdst::atomic::Species, size_t> m_qse_solve_species_index_map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructs an EigenFunctor.
|
* @brief Constructs an EigenFunctor.
|
||||||
*
|
*
|
||||||
* @param view The MultiscalePartitioningEngineView instance.
|
* @param view The MultiscalePartitioningEngineView instance.
|
||||||
* @param qse_solve_indices Indices of the species to solve for in the QSE group.
|
* @param qse_solve_species Species to solve for in the QSE group.
|
||||||
* @param Y_full_initial Initial abundances of all species.
|
* @param initial_comp Initial abundances of all species in the full network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @param Y_scale Scaling factors for the species abundances.
|
* @param Y_scale Scaling factors for the species abundances.
|
||||||
|
* @param qse_solve_species_index_map Mapping from species to their indices in the QSE solve vector.
|
||||||
*/
|
*/
|
||||||
EigenFunctor(
|
EigenFunctor(
|
||||||
MultiscalePartitioningEngineView& view,
|
MultiscalePartitioningEngineView& view,
|
||||||
const std::vector<size_t>& qse_solve_indices,
|
const std::set<fourdst::atomic::Species>& qse_solve_species,
|
||||||
const std::vector<double>& Y_full_initial,
|
const fourdst::composition::Composition& initial_comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho,
|
const double rho,
|
||||||
const Eigen::VectorXd& Y_scale
|
const Eigen::VectorXd& Y_scale,
|
||||||
|
const std::unordered_map<fourdst::atomic::Species, size_t>& qse_solve_species_index_map
|
||||||
) :
|
) :
|
||||||
m_view(&view),
|
m_view(&view),
|
||||||
m_qse_solve_indices(qse_solve_indices),
|
m_qse_solve_species(qse_solve_species),
|
||||||
m_Y_full_initial(Y_full_initial),
|
m_initial_comp(initial_comp),
|
||||||
m_T9(T9),
|
m_T9(T9),
|
||||||
m_rho(rho),
|
m_rho(rho),
|
||||||
m_Y_scale(Y_scale) {}
|
m_Y_scale(Y_scale),
|
||||||
|
m_qse_solve_species_index_map(qse_solve_species_index_map){}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the number of output values from the functor (size of the residual vector).
|
* @brief Gets the number of output values from the functor (size of the residual vector).
|
||||||
* @return The number of algebraic species being solved.
|
* @return The number of algebraic species being solved.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] size_t values() const { return m_qse_solve_indices.size(); }
|
[[nodiscard]] size_t values() const { return m_qse_solve_species.size(); }
|
||||||
/**
|
/**
|
||||||
* @brief Gets the number of input values to the functor (size of the variable vector).
|
* @brief Gets the number of input values to the functor (size of the variable vector).
|
||||||
* @return The number of algebraic species being solved.
|
* @return The number of algebraic species being solved.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] size_t inputs() const { return m_qse_solve_indices.size(); }
|
[[nodiscard]] size_t inputs() const { return m_qse_solve_species.size(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Evaluates the functor's residual vector `f_qse = dY_alg/dt`.
|
* @brief Evaluates the functor's residual vector `f_qse = dY_alg/dt`.
|
||||||
@@ -981,23 +986,15 @@ namespace gridfire {
|
|||||||
* @brief The simplified set of species presented to the solver (the "slow" species).
|
* @brief The simplified set of species presented to the solver (the "slow" species).
|
||||||
*/
|
*/
|
||||||
std::vector<fourdst::atomic::Species> m_dynamic_species;
|
std::vector<fourdst::atomic::Species> m_dynamic_species;
|
||||||
/**
|
|
||||||
* @brief Indices mapping the dynamic species back to the base engine's full species list.
|
|
||||||
*/
|
|
||||||
std::vector<size_t> m_dynamic_species_indices;
|
|
||||||
/**
|
/**
|
||||||
* @brief Species that are treated as algebraic (in QSE) in the QSE groups.
|
* @brief Species that are treated as algebraic (in QSE) in the QSE groups.
|
||||||
*/
|
*/
|
||||||
std::vector<fourdst::atomic::Species> m_algebraic_species;
|
std::vector<fourdst::atomic::Species> m_algebraic_species;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @breif Stateful storage of the current algebraic species abundances. This is updated every time the update method is called.
|
* @brief Map from species to their calculated abundances in the QSE state.
|
||||||
*/
|
*/
|
||||||
std::vector<double> m_Y_algebraic;
|
std::unordered_map<fourdst::atomic::Species, double> m_algebraic_abundances;
|
||||||
/**
|
|
||||||
* @brief Indices of algebraic species in the full network.
|
|
||||||
*/
|
|
||||||
std::vector<size_t> m_algebraic_species_indices;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Indices of all species considered active in the current partition (dynamic + algebraic).
|
* @brief Indices of all species considered active in the current partition (dynamic + algebraic).
|
||||||
@@ -1029,7 +1026,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Partitions the network by timescale.
|
* @brief Partitions the network by timescale.
|
||||||
*
|
*
|
||||||
* @param Y_full Vector of current molar abundances for all species.
|
* @param comp Vector of current molar abundances for all species.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A vector of vectors of species indices, where each inner vector represents a
|
* @return A vector of vectors of species indices, where each inner vector represents a
|
||||||
@@ -1044,8 +1041,8 @@ namespace gridfire {
|
|||||||
* a gap between consecutive timescales that is larger than a predefined threshold
|
* a gap between consecutive timescales that is larger than a predefined threshold
|
||||||
* (e.g., a factor of 100).
|
* (e.g., a factor of 100).
|
||||||
*/
|
*/
|
||||||
std::vector<std::vector<size_t>> partitionByTimescale(
|
std::vector<std::vector<fourdst::atomic::Species>> partitionByTimescale(
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const;
|
) const;
|
||||||
@@ -1054,7 +1051,7 @@ namespace gridfire {
|
|||||||
* @brief Validates candidate QSE groups using flux analysis.
|
* @brief Validates candidate QSE groups using flux analysis.
|
||||||
*
|
*
|
||||||
* @param candidate_groups A vector of candidate QSE groups.
|
* @param candidate_groups A vector of candidate QSE groups.
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp Vector of current molar abundances for the full network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A vector of validated QSE groups that meet the flux criteria.
|
* @return A vector of validated QSE groups that meet the flux criteria.
|
||||||
@@ -1074,7 +1071,7 @@ namespace gridfire {
|
|||||||
::
|
::
|
||||||
QSEGroup>> validateGroupsWithFluxAnalysis(
|
QSEGroup>> validateGroupsWithFluxAnalysis(
|
||||||
const std::vector<QSEGroup> &candidate_groups,
|
const std::vector<QSEGroup> &candidate_groups,
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const;
|
) const;
|
||||||
@@ -1082,7 +1079,7 @@ namespace gridfire {
|
|||||||
/**
|
/**
|
||||||
* @brief Solves for the QSE abundances of the algebraic species in a given state.
|
* @brief Solves for the QSE abundances of the algebraic species in a given state.
|
||||||
*
|
*
|
||||||
* @param Y_full Vector of current molar abundances for all species in the base engine.
|
* @param comp Vector of current molar abundances for all species in the base engine.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A vector of molar abundances for the algebraic species.
|
* @return A vector of molar abundances for the algebraic species.
|
||||||
@@ -1099,8 +1096,8 @@ namespace gridfire {
|
|||||||
* @pre The input state (Y_full, T9, rho) must be a valid physical state.
|
* @pre The input state (Y_full, T9, rho) must be a valid physical state.
|
||||||
* @post The algebraic species in the QSE cache are updated with the new equilibrium abundances.
|
* @post The algebraic species in the QSE cache are updated with the new equilibrium abundances.
|
||||||
*/
|
*/
|
||||||
std::vector<double> solveQSEAbundances(
|
fourdst::composition::Composition solveQSEAbundances(
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
@@ -1110,7 +1107,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param pools A vector of vectors of species indices, where each inner vector represents a
|
* @param pools A vector of vectors of species indices, where each inner vector represents a
|
||||||
* timescale pool.
|
* timescale pool.
|
||||||
* @param Y Vector of current molar abundances for the full network.
|
* @param comp Vector of current molar abundances for the full network.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return The index of the pool with the largest (slowest) mean destruction timescale.
|
* @return The index of the pool with the largest (slowest) mean destruction timescale.
|
||||||
@@ -1123,8 +1120,8 @@ namespace gridfire {
|
|||||||
* pool and returns the index of the pool with the maximum mean timescale.
|
* pool and returns the index of the pool with the maximum mean timescale.
|
||||||
*/
|
*/
|
||||||
size_t identifyMeanSlowestPool(
|
size_t identifyMeanSlowestPool(
|
||||||
const std::vector<std::vector<size_t>>& pools,
|
const std::vector<std::vector<fourdst::atomic::Species>>& pools,
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const;
|
) const;
|
||||||
@@ -1144,8 +1141,8 @@ namespace gridfire {
|
|||||||
* and one as a product), it adds edges between all reactants and products from
|
* and one as a product), it adds edges between all reactants and products from
|
||||||
* that reaction that are also in the pool.
|
* that reaction that are also in the pool.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<size_t, std::vector<size_t>> buildConnectivityGraph(
|
std::unordered_map<fourdst::atomic::Species, std::vector<fourdst::atomic::Species>> buildConnectivityGraph(
|
||||||
const std::vector<size_t>& species_pool
|
const std::vector<fourdst::atomic::Species>& species_pool
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1153,7 +1150,7 @@ namespace gridfire {
|
|||||||
*
|
*
|
||||||
* @param candidate_pools A vector of vectors of species indices, where each inner vector
|
* @param candidate_pools A vector of vectors of species indices, where each inner vector
|
||||||
* represents a connected pool of species with similar fast timescales.
|
* represents a connected pool of species with similar fast timescales.
|
||||||
* @param Y Vector of current molar abundances.
|
* @param comp Vector of current molar abundances.
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
* @param T9 Temperature in units of 10^9 K.
|
||||||
* @param rho Density in g/cm^3.
|
* @param rho Density in g/cm^3.
|
||||||
* @return A vector of `QSEGroup` structs, ready for flux validation.
|
* @return A vector of `QSEGroup` structs, ready for flux validation.
|
||||||
@@ -1168,8 +1165,8 @@ namespace gridfire {
|
|||||||
* @post A list of candidate `QSEGroup` objects is returned.
|
* @post A list of candidate `QSEGroup` objects is returned.
|
||||||
*/
|
*/
|
||||||
std::vector<QSEGroup> constructCandidateGroups(
|
std::vector<QSEGroup> constructCandidateGroups(
|
||||||
const std::vector<std::vector<size_t>>& candidate_pools,
|
const std::vector<std::vector<fourdst::atomic::Species>>& candidate_pools,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition &comp,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
) const;
|
) const;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <vector>
|
||||||
|
|
||||||
namespace gridfire::exceptions {
|
namespace gridfire::exceptions {
|
||||||
class EngineError : public std::exception {};
|
class EngineError : public std::exception {};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace gridfire::expectations {
|
namespace gridfire::expectations {
|
||||||
enum class EngineErrorTypes {
|
enum class EngineErrorTypes {
|
||||||
@@ -19,8 +20,8 @@ namespace gridfire::expectations {
|
|||||||
std::string m_message;
|
std::string m_message;
|
||||||
const EngineErrorTypes type = EngineErrorTypes::FAILURE;
|
const EngineErrorTypes type = EngineErrorTypes::FAILURE;
|
||||||
|
|
||||||
explicit EngineError(const std::string &message, const EngineErrorTypes type)
|
explicit EngineError(std::string message, const EngineErrorTypes type)
|
||||||
: m_message(message), type(type) {}
|
: m_message(std::move(message)), type(type) {}
|
||||||
|
|
||||||
virtual ~EngineError() = default;
|
virtual ~EngineError() = default;
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace gridfire::io {
|
|||||||
* ParsedNetworkData data = parser.parse("reactions.txt");
|
* ParsedNetworkData data = parser.parse("reactions.txt");
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
ParsedNetworkData parse(const std::string& filename) const override;
|
[[nodiscard]] ParsedNetworkData parse(const std::string& filename) const override;
|
||||||
private:
|
private:
|
||||||
using Config = fourdst::config::Config;
|
using Config = fourdst::config::Config;
|
||||||
using LogManager = fourdst::logging::LogManager;
|
using LogManager = fourdst::logging::LogManager;
|
||||||
@@ -139,7 +139,7 @@ namespace gridfire::io {
|
|||||||
* @throws std::runtime_error If the file cannot be opened or if it
|
* @throws std::runtime_error If the file cannot be opened or if it
|
||||||
* contains formatting errors.
|
* contains formatting errors.
|
||||||
*/
|
*/
|
||||||
ParsedNetworkData parse(const std::string& filename) const override;
|
[[nodiscard]] ParsedNetworkData parse(const std::string& filename) const override;
|
||||||
private:
|
private:
|
||||||
using Config = fourdst::config::Config;
|
using Config = fourdst::config::Config;
|
||||||
using LogManager = fourdst::logging::LogManager;
|
using LogManager = fourdst::logging::LogManager;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace gridfire {
|
|||||||
*/
|
*/
|
||||||
virtual NetOut evaluate(const NetIn &netIn) = 0;
|
virtual NetOut evaluate(const NetIn &netIn) = 0;
|
||||||
|
|
||||||
virtual bool isStiff() const { return m_stiff; }
|
[[nodiscard]] virtual bool isStiff() const { return m_stiff; }
|
||||||
virtual void setStiff(const bool stiff) { m_stiff = stiff; }
|
virtual void setStiff(const bool stiff) { m_stiff = stiff; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -99,6 +99,6 @@ namespace gridfire::partition {
|
|||||||
* @return Unique pointer to a new PartitionFunction instance of the given type.
|
* @return Unique pointer to a new PartitionFunction instance of the given type.
|
||||||
* @throws std::runtime_error If the given type is not recognized.
|
* @throws std::runtime_error If the given type is not recognized.
|
||||||
+ */
|
+ */
|
||||||
std::unique_ptr<PartitionFunction> selectPartitionFunction(const BasePartitionType type) const;
|
[[nodiscard]] std::unique_ptr<PartitionFunction> selectPartitionFunction(const BasePartitionType type) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "cppad/cppad.hpp"
|
#include "cppad/cppad.hpp"
|
||||||
|
#include "fourdst/composition/composition.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file reaction.h
|
* @file reaction.h
|
||||||
@@ -78,8 +79,18 @@ namespace gridfire::reaction {
|
|||||||
public:
|
public:
|
||||||
virtual ~Reaction() = default;
|
virtual ~Reaction() = default;
|
||||||
|
|
||||||
[[nodiscard]] virtual double calculate_rate(double T9, double rho, const std::vector<double>& Y) const = 0;
|
[[nodiscard]] virtual double calculate_rate(
|
||||||
[[nodiscard]] virtual CppAD::AD<double> calculate_rate(CppAD::AD<double> T9, CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const = 0;
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue, const std::vector<double> &Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const = 0;
|
||||||
|
[[nodiscard]] virtual CppAD::AD<double> calculate_rate(
|
||||||
|
CppAD::AD<double> T9,
|
||||||
|
CppAD::AD<double> rho,
|
||||||
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue, const std::vector<CppAD::AD<double>>& Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual std::string_view id() const = 0;
|
[[nodiscard]] virtual std::string_view id() const = 0;
|
||||||
[[nodiscard]] virtual const std::vector<fourdst::atomic::Species>& reactants() const = 0;
|
[[nodiscard]] virtual const std::vector<fourdst::atomic::Species>& reactants() const = 0;
|
||||||
@@ -103,7 +114,26 @@ namespace gridfire::reaction {
|
|||||||
[[nodiscard]] virtual uint64_t hash(uint64_t seed) const = 0;
|
[[nodiscard]] virtual uint64_t hash(uint64_t seed) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual double qValue() const = 0;
|
[[nodiscard]] virtual double qValue() const = 0;
|
||||||
[[nodiscard]] virtual double calculate_forward_rate_log_derivative(double T9, double rho, const std::vector<double>& Y) const = 0;
|
|
||||||
|
[[nodiscard]] virtual double calculate_energy_generation_rate(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue, const std::vector<double>& Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
|
return calculate_rate(T9, rho, 0, 0, Y, index_to_species_map) * qValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual CppAD::AD<double> calculate_energy_generation_rate(
|
||||||
|
const CppAD::AD<double>& T9,
|
||||||
|
const CppAD::AD<double>& rho,
|
||||||
|
const CppAD::AD<double> &Ye,
|
||||||
|
const CppAD::AD<double> &mue, const std::vector<CppAD::AD<double>>& Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
|
return calculate_rate(T9, rho, {}, {}, Y, index_to_species_map) * qValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual double calculate_forward_rate_log_derivative(double T9, double rho, double Ye, double mue, const fourdst::composition::Composition& comp) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual ReactionType type() const = 0;
|
[[nodiscard]] virtual ReactionType type() const = 0;
|
||||||
|
|
||||||
@@ -145,21 +175,37 @@ namespace gridfire::reaction {
|
|||||||
* @brief Calculates the reaction rate for a given temperature.
|
* @brief Calculates the reaction rate for a given temperature.
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho Density [Not used in this implementation].
|
* @param rho Density [Not used in this implementation].
|
||||||
* @param Y Molar abundances of species [Not used in this implementation].
|
* @param Ye
|
||||||
|
* @param mue
|
||||||
|
* @param Y
|
||||||
|
* @param index_to_species_map
|
||||||
* @return The calculated reaction rate.
|
* @return The calculated reaction rate.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculate_rate(double T9, double rho, const std::vector<double>& Y) const override;
|
[[nodiscard]] double calculate_rate(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue, const std::vector<double> &Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculates the reaction rate for a given temperature using CppAD types.
|
* @brief Calculates the reaction rate for a given temperature using CppAD types.
|
||||||
* @param T9 The temperature in units of 10^9 K, as a CppAD::AD<double>.
|
* @param T9 The temperature in units of 10^9 K, as a CppAD::AD<double>.
|
||||||
* @param rho Density, as a CppAD::AD<double> [Not used in this implementation].
|
* @param rho Density, as a CppAD::AD<double> [Not used in this implementation].
|
||||||
|
* @param Ye
|
||||||
|
* @param mue
|
||||||
* @param Y Molar abundances of species, as a vector of CppAD::AD<double> [Not used in this implementation].
|
* @param Y Molar abundances of species, as a vector of CppAD::AD<double> [Not used in this implementation].
|
||||||
|
* @param index_to_species_map
|
||||||
* @return The calculated reaction rate, as a CppAD::AD<double>.
|
* @return The calculated reaction rate, as a CppAD::AD<double>.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] CppAD::AD<double> calculate_rate(CppAD::AD<double> T9, CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const override;
|
[[nodiscard]] CppAD::AD<double> calculate_rate(
|
||||||
|
CppAD::AD<double> T9,
|
||||||
|
CppAD::AD<double> rho,
|
||||||
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue, const std::vector<CppAD::AD<double>>& Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] double calculate_forward_rate_log_derivative(double T9, double rho, const std::vector<double>& Y) const override;
|
[[nodiscard]] double calculate_forward_rate_log_derivative(double T9, double rho, double Ye, double mue, const fourdst::composition::Composition& comp) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the reaction name in (projectile, ejectile) notation.
|
* @brief Gets the reaction name in (projectile, ejectile) notation.
|
||||||
@@ -389,12 +435,24 @@ namespace gridfire::reaction {
|
|||||||
* @brief Calculates the total reaction rate by summing all source rates.
|
* @brief Calculates the total reaction rate by summing all source rates.
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho
|
* @param rho
|
||||||
|
* @param Ye
|
||||||
|
* @param mue
|
||||||
* @param Y
|
* @param Y
|
||||||
|
* @param index_to_species_map
|
||||||
* @return The total calculated reaction rate.
|
* @return The total calculated reaction rate.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] double calculate_rate(double T9, double rho, const std::vector<double>& Y) const override;
|
[[nodiscard]] double calculate_rate(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue, const std::vector<double> &Y, const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] double calculate_forward_rate_log_derivative(double T9, double rho, const std::vector<double>& Y) const override;
|
[[nodiscard]] double calculate_forward_rate_log_derivative(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye, double mue, const fourdst::composition::Composition& comp
|
||||||
|
) const override;
|
||||||
|
|
||||||
[[nodiscard]] ReactionType type() const override { return ReactionType::LOGICAL_REACLIB; }
|
[[nodiscard]] ReactionType type() const override { return ReactionType::LOGICAL_REACLIB; }
|
||||||
|
|
||||||
@@ -404,10 +462,18 @@ namespace gridfire::reaction {
|
|||||||
* @brief Calculates the total reaction rate using CppAD types.
|
* @brief Calculates the total reaction rate using CppAD types.
|
||||||
* @param T9 The temperature in units of 10^9 K, as a CppAD::AD<double>.
|
* @param T9 The temperature in units of 10^9 K, as a CppAD::AD<double>.
|
||||||
* @param rho
|
* @param rho
|
||||||
|
* @param Ye
|
||||||
|
* @param mue
|
||||||
* @param Y
|
* @param Y
|
||||||
|
* @param index_to_species_map
|
||||||
* @return The total calculated reaction rate, as a CppAD::AD<double>.
|
* @return The total calculated reaction rate, as a CppAD::AD<double>.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] CppAD::AD<double> calculate_rate(CppAD::AD<double> T9, CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const override;
|
[[nodiscard]] CppAD::AD<double> calculate_rate(
|
||||||
|
CppAD::AD<double> T9,
|
||||||
|
CppAD::AD<double> rho,
|
||||||
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue, const std::vector<CppAD::AD<double>>& Y, const std::unordered_map<size_t,fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
|
||||||
/** @name Iterators
|
/** @name Iterators
|
||||||
* Provides iterators to loop over the rate coefficient sets.
|
* Provides iterators to loop over the rate coefficient sets.
|
||||||
|
|||||||
@@ -1,57 +1,254 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "fourdst/composition/atomicSpecies.h"
|
#define GRIDFIRE_WEAK_REACTION_LIB_SENTINEL -60.0
|
||||||
|
|
||||||
|
#include "gridfire/reaction/reaction.h"
|
||||||
|
#include "gridfire/reaction/weak/weak_types.h"
|
||||||
|
#include "gridfire/reaction/weak/weak_interpolator.h"
|
||||||
|
|
||||||
|
#include "gridfire/engine/engine_abstract.h"
|
||||||
|
|
||||||
|
#include "fourdst/composition/atomicSpecies.h"
|
||||||
|
#include "fourdst/constants/const.h"
|
||||||
|
|
||||||
|
#include "cppad/cppad.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <expected>
|
#include <expected>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace gridfire::rates::weak {
|
namespace gridfire::rates::weak {
|
||||||
enum class WeakReactionType {
|
|
||||||
BETA_PLUS_DECAY,
|
|
||||||
BETA_MINUS_DECAY,
|
|
||||||
ELECTRON_CAPTURE,
|
|
||||||
POSITRON_CAPTURE,
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::unordered_map<WeakReactionType, std::string> WeakReactionTypeNames = {
|
|
||||||
{WeakReactionType::BETA_PLUS_DECAY, "β+ Decay"},
|
|
||||||
{WeakReactionType::BETA_MINUS_DECAY, "β- Decay"},
|
|
||||||
{WeakReactionType::ELECTRON_CAPTURE, "e- Capture"},
|
|
||||||
{WeakReactionType::POSITRON_CAPTURE, "e+ Capture"},
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WeakReaction {
|
|
||||||
WeakReactionType type;
|
|
||||||
float T9;
|
|
||||||
float log_rhoYe;
|
|
||||||
float mu_e;
|
|
||||||
float log_rate;
|
|
||||||
float log_neutrino_loss;
|
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const WeakReaction& reaction) {
|
|
||||||
os << "WeakReaction(type=" << WeakReactionTypeNames[reaction.type]
|
|
||||||
<< ", T9=" << reaction.T9
|
|
||||||
<< ", log_rhoYe=" << reaction.log_rhoYe
|
|
||||||
<< ", mu_e=" << reaction.mu_e
|
|
||||||
<< ", log_rate=" << reaction.log_rate
|
|
||||||
<< ", log_neutrino_loss=" << reaction.log_neutrino_loss
|
|
||||||
<< ")";
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class WeakReactionMap {
|
class WeakReactionMap {
|
||||||
public:
|
public:
|
||||||
WeakReactionMap();
|
WeakReactionMap();
|
||||||
~WeakReactionMap() = default;
|
~WeakReactionMap() = default;
|
||||||
|
|
||||||
std::vector<WeakReaction> get_all_reactions() const;
|
[[nodiscard]] std::vector<WeakReactionEntry> get_all_reactions() const;
|
||||||
|
|
||||||
std::expected<std::vector<WeakReaction>, bool> get_species_reactions(const fourdst::atomic::Species &species) const;
|
[[nodiscard]] std::expected<std::vector<WeakReactionEntry>, WeakMapError> get_species_reactions(
|
||||||
std::expected<std::vector<WeakReaction>, bool> get_species_reactions(const std::string& species_name) const;
|
const fourdst::atomic::Species &species) const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::expected<std::vector<WeakReactionEntry>, WeakMapError> get_species_reactions(
|
||||||
|
const std::string &species_name) const;
|
||||||
private:
|
private:
|
||||||
std::unordered_map<fourdst::atomic::Species, std::vector<WeakReaction>> m_weak_network;
|
std::unordered_map<fourdst::atomic::Species, std::vector<WeakReactionEntry>> m_weak_network;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WeakReaction final : public reaction::Reaction {
|
||||||
|
public:
|
||||||
|
explicit WeakReaction(
|
||||||
|
const fourdst::atomic::Species &species,
|
||||||
|
WeakReactionType type,
|
||||||
|
const WeakRateInterpolator& interpolator
|
||||||
|
);
|
||||||
|
[[nodiscard]] double calculate_rate(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue,
|
||||||
|
const std::vector<double> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
[[nodiscard]] CppAD::AD<double> calculate_rate(
|
||||||
|
CppAD::AD<double> T9,
|
||||||
|
CppAD::AD<double> rho,
|
||||||
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue,
|
||||||
|
const std::vector<CppAD::AD<double>> &Y,
|
||||||
|
const std::unordered_map<size_t,fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
[[nodiscard]] std::string_view id() const override { return m_id; }
|
||||||
|
[[nodiscard]] const std::vector<fourdst::atomic::Species> &reactants() const override { return {m_reactant}; }
|
||||||
|
[[nodiscard]] const std::vector<fourdst::atomic::Species> &products() const override { return {m_product}; }
|
||||||
|
[[nodiscard]] bool contains(const fourdst::atomic::Species &species) const override;
|
||||||
|
[[nodiscard]] bool contains_reactant(const fourdst::atomic::Species &species) const override;
|
||||||
|
[[nodiscard]] bool contains_product(const fourdst::atomic::Species &species) const override;
|
||||||
|
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> all_species() const override;
|
||||||
|
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> reactant_species() const override;
|
||||||
|
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> product_species() const override;
|
||||||
|
[[nodiscard]] size_t num_species() const override { return 2; } // Always 2 for weak reactions
|
||||||
|
[[nodiscard]] std::unordered_map<fourdst::atomic::Species, int> stoichiometry() const override;
|
||||||
|
[[nodiscard]] int stoichiometry(const fourdst::atomic::Species &species) const override;
|
||||||
|
[[nodiscard]] uint64_t hash(uint64_t seed) const override;
|
||||||
|
[[nodiscard]] double qValue() const override;
|
||||||
|
[[nodiscard]] double calculate_energy_generation_rate(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue,
|
||||||
|
const std::vector<double>& Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const override;
|
||||||
|
[[nodiscard]] CppAD::AD<double> calculate_energy_generation_rate(
|
||||||
|
const CppAD::AD<double> &T9,
|
||||||
|
const CppAD::AD<double> &rho,
|
||||||
|
const CppAD::AD<double> &Ye,
|
||||||
|
const CppAD::AD<double> &mue,
|
||||||
|
const std::vector<CppAD::AD<double>> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species> &index_to_species_map
|
||||||
|
) const override;
|
||||||
|
[[nodiscard]] double calculate_forward_rate_log_derivative(
|
||||||
|
double T9,
|
||||||
|
double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue,
|
||||||
|
const fourdst::composition::Composition& composition
|
||||||
|
) const override;
|
||||||
|
[[nodiscard]] reaction::ReactionType type() const override { return reaction::ReactionType::WEAK; }
|
||||||
|
[[nodiscard]] std::unique_ptr<Reaction> clone() const override;
|
||||||
|
[[nodiscard]] bool is_reverse() const override { return false; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<IsArithmeticOrAD T>
|
||||||
|
T calculate_rate(
|
||||||
|
T T9,
|
||||||
|
T rho,
|
||||||
|
T Ye,
|
||||||
|
T mue,
|
||||||
|
const std::vector<T> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const;
|
||||||
|
|
||||||
|
double get_log_rate_from_payload(const WeakRatePayload& payload) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class AtomicWeakRate final : public CppAD::atomic_base<double> {
|
||||||
|
public:
|
||||||
|
AtomicWeakRate(
|
||||||
|
const WeakRateInterpolator& interpolator,
|
||||||
|
const size_t a,
|
||||||
|
const size_t z,
|
||||||
|
const WeakReactionType type
|
||||||
|
) :
|
||||||
|
CppAD::atomic_base<double>(std::format("atomic-{}-{}-weak-rate", a, z)),
|
||||||
|
m_interpolator(interpolator),
|
||||||
|
m_a(a),
|
||||||
|
m_z(z) ,
|
||||||
|
m_type(type) {}
|
||||||
|
|
||||||
|
bool forward(
|
||||||
|
size_t p,
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<bool>& vx,
|
||||||
|
CppAD::vector<bool>& vy,
|
||||||
|
const CppAD::vector<double>& tx,
|
||||||
|
CppAD::vector<double>& ty
|
||||||
|
) override;
|
||||||
|
bool reverse(
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<double>& tx,
|
||||||
|
const CppAD::vector<double>& ty,
|
||||||
|
CppAD::vector<double>& px,
|
||||||
|
const CppAD::vector<double>& py
|
||||||
|
) override;
|
||||||
|
bool for_sparse_jac(
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<std::set<size_t>>&r,
|
||||||
|
CppAD::vector<std::set<size_t>>& s
|
||||||
|
) override;
|
||||||
|
bool rev_sparse_jac(
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<std::set<size_t>>&rt,
|
||||||
|
CppAD::vector<std::set<size_t>>& st
|
||||||
|
) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const WeakRateInterpolator& m_interpolator;
|
||||||
|
const size_t m_a;
|
||||||
|
const size_t m_z;
|
||||||
|
const WeakReactionType m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct constants {
|
||||||
|
const fourdst::constant::Constants& c = fourdst::constant::Constants::getInstance();
|
||||||
|
fourdst::constant::Constant neutronMassG = c.get("mN");
|
||||||
|
fourdst::constant::Constant protonMassG = c.get("mP");
|
||||||
|
fourdst::constant::Constant electronMassG = c.get("mE");
|
||||||
|
fourdst::constant::Constant speedOfLight = c.get("c");
|
||||||
|
fourdst::constant::Constant eVgRelation = c.get("eV_kg"); // note that despite the symbol this is in g NOT kg
|
||||||
|
fourdst::constant::Constant MeV2Erg = c.get("MeV_to_erg");
|
||||||
|
fourdst::constant::Constant amu = c.get("u");
|
||||||
|
|
||||||
|
double MeVgRelation = eVgRelation.value * 1.0e6;
|
||||||
|
double MeVPerGraph = 1.0/MeVgRelation;
|
||||||
|
|
||||||
|
double neutronMassMeV = neutronMassG.value * MeVgRelation;
|
||||||
|
double protonMassMeV = protonMassG.value * MeVgRelation;
|
||||||
|
double electronMassMeV = electronMassG.value * MeVgRelation;
|
||||||
|
|
||||||
|
double u_to_MeV = (amu.value * speedOfLight.value * speedOfLight.value)/MeV2Erg.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
const constants m_constants;
|
||||||
|
fourdst::atomic::Species m_reactant;
|
||||||
|
fourdst::atomic::Species m_product;
|
||||||
|
|
||||||
|
size_t m_reactant_a;
|
||||||
|
size_t m_reactant_z;
|
||||||
|
size_t m_product_a;
|
||||||
|
size_t m_product_z;
|
||||||
|
|
||||||
|
std::string m_id;
|
||||||
|
WeakReactionType m_type;
|
||||||
|
|
||||||
|
const WeakRateInterpolator& m_interpolator;
|
||||||
|
|
||||||
|
AtomicWeakRate m_atomic;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<IsArithmeticOrAD T>
|
||||||
|
T WeakReaction::calculate_rate(
|
||||||
|
T T9,
|
||||||
|
T rho,
|
||||||
|
T Ye,
|
||||||
|
T mue,
|
||||||
|
const std::vector<T> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
|
T log_rhoYe = CppAD::log10(rho * Ye);
|
||||||
|
|
||||||
|
T rateConstant = static_cast<T>(0.0);
|
||||||
|
if constexpr (std::is_same_v<T, CppAD::AD<double>>) { // Case where T is an AD type
|
||||||
|
std::vector<T> ax = {T9, log_rhoYe, mue};
|
||||||
|
std::vector<T> ay(1);
|
||||||
|
m_atomic(ax, ay);
|
||||||
|
rateConstant = static_cast<T>(ay[0]);
|
||||||
|
} else { // The case where T is of type double
|
||||||
|
const std::expected<WeakRatePayload, InterpolationError> result = m_interpolator.get_rates(
|
||||||
|
static_cast<uint16_t>(m_reactant_a),
|
||||||
|
static_cast<uint8_t>(m_reactant_z),
|
||||||
|
T9,
|
||||||
|
log_rhoYe,
|
||||||
|
mue
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.has_value()) {
|
||||||
|
const InterpolationErrorType type = result.error().type;
|
||||||
|
const std::string msg = std::format(
|
||||||
|
"Failed to interpolate weak rate for (A={}, Z={}) at T9={}, log10(rho*Ye)={}, mu_e={} with error: {}",
|
||||||
|
m_reactant.name(), m_reactant_a, m_reactant_z, T9, log_rhoYe, mue, InterpolationErrorTypeMap.at(type)
|
||||||
|
);
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
const WeakRatePayload payload = result.value();
|
||||||
|
const double logRate = get_log_rate_from_payload(payload);
|
||||||
|
if (logRate <= GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||||
|
rateConstant = static_cast<T>(0.0);
|
||||||
|
} else {
|
||||||
|
rateConstant = CppAD::pow(10.0, logRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return rateConstant;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
44
src/include/gridfire/reaction/weak/weak_interpolator.h
Normal file
44
src/include/gridfire/reaction/weak/weak_interpolator.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "gridfire/reaction/weak/weak_types.h"
|
||||||
|
#include "fourdst/composition/atomicSpecies.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <expected>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace gridfire::rates::weak {
|
||||||
|
class WeakRateInterpolator {
|
||||||
|
public:
|
||||||
|
using RowDataTable = std::array<RateDataRow, 77400>; // Total number of entries in the weak rate table NOTE: THIS MUST EQUAL THE VALUE IN weak_rate_library.h
|
||||||
|
|
||||||
|
explicit WeakRateInterpolator(const RowDataTable& raw_data);
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<fourdst::atomic::Species> available_isotopes() const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::expected<WeakRatePayload, InterpolationError> get_rates(
|
||||||
|
uint16_t A,
|
||||||
|
uint8_t Z,
|
||||||
|
double t9,
|
||||||
|
double log_rhoYe,
|
||||||
|
double mu_e
|
||||||
|
) const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::expected<WeakRateDerivatives, InterpolationError> get_rate_derivatives(
|
||||||
|
uint16_t A,
|
||||||
|
uint8_t Z,
|
||||||
|
double t9,
|
||||||
|
double log_rhoYe,
|
||||||
|
double mu_e
|
||||||
|
) const;
|
||||||
|
private:
|
||||||
|
static uint32_t pack_isotope_id(uint16_t A, uint8_t Z);
|
||||||
|
|
||||||
|
std::unordered_map<uint32_t, IsotopeGrid> m_rate_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,25 +8,10 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include <cstdint>
|
#include "gridfire/reaction/weak/weak.h"
|
||||||
|
|
||||||
|
|
||||||
namespace gridfire::rates::weak {
|
namespace gridfire::rates::weak {
|
||||||
|
|
||||||
// Represents a single row from the unified weak rate table
|
|
||||||
struct RateDataRow {
|
|
||||||
uint16_t A;
|
|
||||||
uint8_t Z;
|
|
||||||
float t9;
|
|
||||||
float log_rhoye;
|
|
||||||
float mu_e;
|
|
||||||
float log_beta_plus;
|
|
||||||
float log_electron_capture;
|
|
||||||
float log_neutrino_loss_ec;
|
|
||||||
float log_beta_minus;
|
|
||||||
float log_positron_capture;
|
|
||||||
float log_antineutrino_loss_bd;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The complete, pre-processed weak rate table data
|
// The complete, pre-processed weak rate table data
|
||||||
static constexpr std::array<RateDataRow, 77400> UNIFIED_WEAK_DATA = {
|
static constexpr std::array<RateDataRow, 77400> UNIFIED_WEAK_DATA = {
|
||||||
RateDataRow(6, 3, 0.01, 5.0, 0.485, -60.0, -60.0, -60.0, -60.0, -60.0, -60.0),
|
RateDataRow(6, 3, 0.01, 5.0, 0.485, -60.0, -60.0, -60.0, -60.0, -60.0, -60.0),
|
||||||
|
|||||||
133
src/include/gridfire/reaction/weak/weak_types.h
Normal file
133
src/include/gridfire/reaction/weak/weak_types.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace gridfire::rates::weak {
|
||||||
|
struct RateDataRow {
|
||||||
|
uint16_t A;
|
||||||
|
uint8_t Z;
|
||||||
|
float t9;
|
||||||
|
float log_rhoye;
|
||||||
|
float mu_e;
|
||||||
|
float log_beta_plus;
|
||||||
|
float log_electron_capture;
|
||||||
|
float log_neutrino_loss_ec;
|
||||||
|
float log_beta_minus;
|
||||||
|
float log_positron_capture;
|
||||||
|
float log_antineutrino_loss_bd;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WeakReactionType {
|
||||||
|
BETA_PLUS_DECAY,
|
||||||
|
BETA_MINUS_DECAY,
|
||||||
|
ELECTRON_CAPTURE,
|
||||||
|
POSITRON_CAPTURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NeutrinoTypes {
|
||||||
|
ELECTRON_NEUTRINO,
|
||||||
|
ELECTRON_ANTINEUTRINO,
|
||||||
|
MUON_NEUTRINO,
|
||||||
|
MUON_ANTINEUTRINO,
|
||||||
|
TAU_NEUTRINO,
|
||||||
|
TAU_ANTINEUTRINO
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WeakMapError {
|
||||||
|
SPECIES_NOT_FOUND,
|
||||||
|
UNKNOWN_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WeakRatePayload {
|
||||||
|
double log_beta_plus;
|
||||||
|
double log_electron_capture;
|
||||||
|
double log_neutrino_loss_ec;
|
||||||
|
double log_beta_minus;
|
||||||
|
double log_positron_capture;
|
||||||
|
double log_antineutrino_loss_bd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WeakRateDerivatives {
|
||||||
|
// Each array holds [d/dT9, d/dlogRhoYe, d/dMuE]
|
||||||
|
std::array<double, 3> d_log_beta_plus;
|
||||||
|
std::array<double, 3> d_log_electron_capture;
|
||||||
|
std::array<double, 3> d_log_neutrino_loss_ec;
|
||||||
|
std::array<double, 3> d_log_beta_minus;
|
||||||
|
std::array<double, 3> d_log_positron_capture;
|
||||||
|
std::array<double, 3> d_log_antineutrino_loss_bd;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class InterpolationErrorType {
|
||||||
|
BOUNDS_ERROR,
|
||||||
|
UNKNOWN_SPECIES_ERROR,
|
||||||
|
UNKNOWN_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::unordered_map<InterpolationErrorType, std::string_view> InterpolationErrorTypeMap = {
|
||||||
|
{InterpolationErrorType::BOUNDS_ERROR, "Bounds Error"},
|
||||||
|
{InterpolationErrorType::UNKNOWN_SPECIES_ERROR, "Unknown Species Error"},
|
||||||
|
{InterpolationErrorType::UNKNOWN_ERROR, "Unknown Error"}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TableAxes {
|
||||||
|
T9,
|
||||||
|
LOG_RHOYE,
|
||||||
|
MUE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoundsErrorInfo {
|
||||||
|
TableAxes axis;
|
||||||
|
double axisMinValue;
|
||||||
|
double axisMaxValue;
|
||||||
|
double queryValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InterpolationError {
|
||||||
|
InterpolationErrorType type;
|
||||||
|
std::optional<std::unordered_map<TableAxes, BoundsErrorInfo>> boundsErrorInfo = std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IsotopeGrid {
|
||||||
|
std::vector<double> t9_axis;
|
||||||
|
std::vector<double> rhoYe_axis;
|
||||||
|
std::vector<double> mue_axis;
|
||||||
|
|
||||||
|
// index = (i_t9 * logRhoYe_axis.size() + j_rhoYe) + mue_axis.size() + k_mue
|
||||||
|
std::vector<WeakRatePayload> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view weak_reaction_type_name(const WeakReactionType t) noexcept {
|
||||||
|
switch (t) {
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY: return "bp";
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY: return "bm";
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE: return "ec";
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE: return "pc";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WeakReactionEntry {
|
||||||
|
WeakReactionType type;
|
||||||
|
float T9;
|
||||||
|
float log_rhoYe;
|
||||||
|
float mu_e;
|
||||||
|
float log_rate;
|
||||||
|
float log_neutrino_loss;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const WeakReactionEntry& reaction) {
|
||||||
|
os << "WeakReactionEntry(type=" << weak_reaction_type_name(reaction.type)
|
||||||
|
<< ", T9=" << reaction.T9
|
||||||
|
<< ", log_rhoYe=" << reaction.log_rhoYe
|
||||||
|
<< ", mu_e=" << reaction.mu_e
|
||||||
|
<< ", log_rate=" << reaction.log_rate
|
||||||
|
<< ", log_neutrino_loss=" << reaction.log_neutrino_loss
|
||||||
|
<< ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ namespace gridfire::screening {
|
|||||||
*
|
*
|
||||||
* @param reactions The set of logical reactions in the network.
|
* @param reactions The set of logical reactions in the network.
|
||||||
* @param species A vector of all atomic species involved in the network.
|
* @param species A vector of all atomic species involved in the network.
|
||||||
* @param Y A vector of the molar abundances (mol/g) for each species.
|
* @param Y The current composition, providing molar abundances (mol/g) for each species.
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho The plasma density in g/cm^3.
|
* @param rho The plasma density in g/cm^3.
|
||||||
* @return A vector of screening factors (dimensionless), one for each reaction
|
* @return A vector of screening factors (dimensionless), one for each reaction
|
||||||
@@ -73,10 +73,10 @@ namespace gridfire::screening {
|
|||||||
[[nodiscard]] virtual std::vector<double> calculateScreeningFactors(
|
[[nodiscard]] virtual std::vector<double> calculateScreeningFactors(
|
||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<double>& Y,
|
const std::vector<double> &Y,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculates screening factors using CppAD types for automatic differentiation.
|
* @brief Calculates screening factors using CppAD types for automatic differentiation.
|
||||||
@@ -88,7 +88,7 @@ namespace gridfire::screening {
|
|||||||
*
|
*
|
||||||
* @param reactions The set of logical reactions in the network.
|
* @param reactions The set of logical reactions in the network.
|
||||||
* @param species A vector of all atomic species involved in the network.
|
* @param species A vector of all atomic species involved in the network.
|
||||||
* @param Y A vector of the molar abundances (mol/g) for each species, as AD types.
|
* @param Y The current composition, providing molar abundances (mol/g) for each species.
|
||||||
* @param T9 The temperature in units of 10^9 K, as an AD type.
|
* @param T9 The temperature in units of 10^9 K, as an AD type.
|
||||||
* @param rho The plasma density in g/cm^3, as an AD type.
|
* @param rho The plasma density in g/cm^3, as an AD type.
|
||||||
* @return A vector of screening factors (dimensionless), as AD types.
|
* @return A vector of screening factors (dimensionless), as AD types.
|
||||||
@@ -100,9 +100,9 @@ namespace gridfire::screening {
|
|||||||
[[nodiscard]] virtual std::vector<ADDouble> calculateScreeningFactors(
|
[[nodiscard]] virtual std::vector<ADDouble> calculateScreeningFactors(
|
||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<ADDouble>& Y,
|
const std::vector<CppAD::AD<double>> &Y,
|
||||||
const ADDouble T9,
|
ADDouble T9,
|
||||||
const ADDouble rho
|
ADDouble rho
|
||||||
) const = 0;
|
) const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace gridfire::screening {
|
|||||||
*
|
*
|
||||||
* @param reactions The set of logical reactions in the network.
|
* @param reactions The set of logical reactions in the network.
|
||||||
* @param species A vector of all atomic species (unused).
|
* @param species A vector of all atomic species (unused).
|
||||||
* @param Y A vector of the molar abundances (unused).
|
* @param Y A vector of the molar abundances.
|
||||||
* @param T9 The temperature (unused).
|
* @param T9 The temperature (unused).
|
||||||
* @param rho The plasma density (unused).
|
* @param rho The plasma density (unused).
|
||||||
* @return A vector of doubles, with each element being 1.0, of the same
|
* @return A vector of doubles, with each element being 1.0, of the same
|
||||||
@@ -54,9 +54,9 @@ namespace gridfire::screening {
|
|||||||
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<double>& Y,
|
const std::vector<double> &Y,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +68,7 @@ namespace gridfire::screening {
|
|||||||
*
|
*
|
||||||
* @param reactions The set of logical reactions in the network.
|
* @param reactions The set of logical reactions in the network.
|
||||||
* @param species A vector of all atomic species (unused).
|
* @param species A vector of all atomic species (unused).
|
||||||
* @param Y A vector of the molar abundances as AD types (unused).
|
* @param Y The current composition, providing molar abundances (mol/g) for each species (unused).
|
||||||
* @param T9 The temperature as an AD type (unused).
|
* @param T9 The temperature as an AD type (unused).
|
||||||
* @param rho The plasma density as an AD type (unused).
|
* @param rho The plasma density as an AD type (unused).
|
||||||
* @return A vector of ADDouble, with each element being 1.0, of the same
|
* @return A vector of ADDouble, with each element being 1.0, of the same
|
||||||
@@ -77,9 +77,9 @@ namespace gridfire::screening {
|
|||||||
[[nodiscard]] std::vector<ADDouble> calculateScreeningFactors(
|
[[nodiscard]] std::vector<ADDouble> calculateScreeningFactors(
|
||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<ADDouble>& Y,
|
const std::vector<CppAD::AD<double>> &Y,
|
||||||
const ADDouble T9,
|
ADDouble T9,
|
||||||
const ADDouble rho
|
ADDouble rho
|
||||||
) const override;
|
) const override;
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +92,7 @@ namespace gridfire::screening {
|
|||||||
* @tparam T The numeric type, either `double` or `CppAD::AD<double>`.
|
* @tparam T The numeric type, either `double` or `CppAD::AD<double>`.
|
||||||
* @param reactions The set of reactions for which to calculate factors.
|
* @param reactions The set of reactions for which to calculate factors.
|
||||||
* @param species A vector of all atomic species (unused).
|
* @param species A vector of all atomic species (unused).
|
||||||
* @param Y A vector of molar abundances (unused).
|
* @param Y The current molar composition (unused).
|
||||||
* @param T9 The temperature (unused).
|
* @param T9 The temperature (unused).
|
||||||
* @param rho The density (unused).
|
* @param rho The density (unused).
|
||||||
* @return A vector of type `T` with all elements initialized to 1.0.
|
* @return A vector of type `T` with all elements initialized to 1.0.
|
||||||
@@ -102,8 +102,8 @@ namespace gridfire::screening {
|
|||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<T>& Y,
|
const std::vector<T>& Y,
|
||||||
const T T9,
|
const T& T9,
|
||||||
const T rho
|
const T& rho
|
||||||
) const;
|
) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ namespace gridfire::screening {
|
|||||||
* @tparam T The numeric type, either `double` or `CppAD::AD<double>`.
|
* @tparam T The numeric type, either `double` or `CppAD::AD<double>`.
|
||||||
* @param reactions The set of reactions, used to determine the size of the output vector.
|
* @param reactions The set of reactions, used to determine the size of the output vector.
|
||||||
* @param species Unused parameter.
|
* @param species Unused parameter.
|
||||||
* @param Y Unused parameter.
|
* @param Y Unused parameter.`
|
||||||
* @param T9 Unused parameter.
|
* @param T9 Unused parameter.
|
||||||
* @param rho Unused parameter.
|
* @param rho Unused parameter.
|
||||||
* @return A `std::vector<T>` of the same size as `reactions`, with all elements set to 1.0.
|
* @return A `std::vector<T>` of the same size as `reactions`, with all elements set to 1.0.
|
||||||
@@ -127,8 +127,8 @@ namespace gridfire::screening {
|
|||||||
const reaction::ReactionSet &reactions,
|
const reaction::ReactionSet &reactions,
|
||||||
const std::vector<fourdst::atomic::Species> &species,
|
const std::vector<fourdst::atomic::Species> &species,
|
||||||
const std::vector<T> &Y,
|
const std::vector<T> &Y,
|
||||||
const T T9,
|
const T& T9,
|
||||||
const T rho
|
const T& rho
|
||||||
) const {
|
) const {
|
||||||
return std::vector<T>(reactions.size(), T(1.0)); // Bare screening returns 1.0 for all reactions
|
return std::vector<T>(reactions.size(), T(1.0)); // Bare screening returns 1.0 for all reactions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace gridfire::screening {
|
|||||||
std::vector<T> IntermediateScreeningModel::calculateFactors_impl(
|
std::vector<T> IntermediateScreeningModel::calculateFactors_impl(
|
||||||
const reaction::ReactionSet &reactions,
|
const reaction::ReactionSet &reactions,
|
||||||
const std::vector<fourdst::atomic::Species> &species,
|
const std::vector<fourdst::atomic::Species> &species,
|
||||||
const std::vector<T> &Y,
|
const std::vector<T>& Y,
|
||||||
const T T9,
|
const T T9,
|
||||||
const T rho
|
const T rho
|
||||||
) const {
|
) const {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace gridfire::screening {
|
|||||||
*
|
*
|
||||||
* @param reactions The set of logical reactions in the network.
|
* @param reactions The set of logical reactions in the network.
|
||||||
* @param species A vector of all atomic species involved in the network.
|
* @param species A vector of all atomic species involved in the network.
|
||||||
* @param Y A vector of the molar abundances (mol/g) for each species.
|
* @param Y The composition object giving the current molar abundances.
|
||||||
* @param T9 The temperature in units of 10^9 K.
|
* @param T9 The temperature in units of 10^9 K.
|
||||||
* @param rho The plasma density in g/cm^3.
|
* @param rho The plasma density in g/cm^3.
|
||||||
* @return A vector of screening factors (dimensionless), one for each reaction.
|
* @return A vector of screening factors (dimensionless), one for each reaction.
|
||||||
@@ -50,9 +50,9 @@ namespace gridfire::screening {
|
|||||||
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<double>& Y,
|
const std::vector<double> &Y,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
) const override;
|
) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +64,7 @@ namespace gridfire::screening {
|
|||||||
*
|
*
|
||||||
* @param reactions The set of logical reactions in the network.
|
* @param reactions The set of logical reactions in the network.
|
||||||
* @param species A vector of all atomic species involved in the network.
|
* @param species A vector of all atomic species involved in the network.
|
||||||
* @param Y A vector of the molar abundances as AD types.
|
* @param Y The composition object giving the current molar abundances.
|
||||||
* @param T9 The temperature as an AD type.
|
* @param T9 The temperature as an AD type.
|
||||||
* @param rho The plasma density as an AD type.
|
* @param rho The plasma density as an AD type.
|
||||||
* @return A vector of screening factors as AD types.
|
* @return A vector of screening factors as AD types.
|
||||||
@@ -72,9 +72,9 @@ namespace gridfire::screening {
|
|||||||
[[nodiscard]] std::vector<CppAD::AD<double>> calculateScreeningFactors(
|
[[nodiscard]] std::vector<CppAD::AD<double>> calculateScreeningFactors(
|
||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<CppAD::AD<double>>& Y,
|
const std::vector<CppAD::AD<double>> &Y,
|
||||||
const CppAD::AD<double> T9,
|
CppAD::AD<double> T9,
|
||||||
const CppAD::AD<double> rho
|
CppAD::AD<double> rho
|
||||||
) const override;
|
) const override;
|
||||||
private:
|
private:
|
||||||
/// @brief Logger instance for recording trace and debug information.
|
/// @brief Logger instance for recording trace and debug information.
|
||||||
@@ -91,7 +91,7 @@ namespace gridfire::screening {
|
|||||||
* @tparam T The numeric type, either `double` or `CppAD::AD<double>`.
|
* @tparam T The numeric type, either `double` or `CppAD::AD<double>`.
|
||||||
* @param reactions The set of reactions.
|
* @param reactions The set of reactions.
|
||||||
* @param species A vector of all species in the network.
|
* @param species A vector of all species in the network.
|
||||||
* @param Y A vector of molar abundances.
|
* @param Y The composition object with current molar abundances.
|
||||||
* @param T9 The temperature in 10^9 K.
|
* @param T9 The temperature in 10^9 K.
|
||||||
* @param rho The density in g/cm^3.
|
* @param rho The density in g/cm^3.
|
||||||
* @return A vector of screening factors of type `T`.
|
* @return A vector of screening factors of type `T`.
|
||||||
@@ -101,8 +101,8 @@ namespace gridfire::screening {
|
|||||||
const reaction::ReactionSet& reactions,
|
const reaction::ReactionSet& reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<T>& Y,
|
const std::vector<T>& Y,
|
||||||
const T T9,
|
T T9,
|
||||||
const T rho
|
T rho
|
||||||
) const;
|
) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ namespace gridfire::screening {
|
|||||||
* @tparam T The numeric type (`double` or `CppAD::AD<double>`).
|
* @tparam T The numeric type (`double` or `CppAD::AD<double>`).
|
||||||
* @param reactions The set of reactions to be screened.
|
* @param reactions The set of reactions to be screened.
|
||||||
* @param species The list of all species in the network.
|
* @param species The list of all species in the network.
|
||||||
* @param Y The molar abundances of the species.
|
* @param Y The composition object providing current molar abundances.
|
||||||
* @param T9 The temperature in 10^9 K.
|
* @param T9 The temperature in 10^9 K.
|
||||||
* @param rho The density in g/cm^3.
|
* @param rho The density in g/cm^3.
|
||||||
* @return A vector of screening factors, one for each reaction.
|
* @return A vector of screening factors, one for each reaction.
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gridfire/engine/engine_graph.h"
|
|
||||||
#include "gridfire/engine/engine_abstract.h"
|
#include "gridfire/engine/engine_abstract.h"
|
||||||
#include "gridfire/network.h"
|
#include "gridfire/network.h"
|
||||||
|
|
||||||
#include "fourdst/logging/logging.h"
|
|
||||||
#include "fourdst/config/config.h"
|
|
||||||
|
|
||||||
#include "quill/Logger.h"
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -101,249 +95,4 @@ namespace gridfire::solver {
|
|||||||
* @brief Type alias for a network solver strategy that uses a DynamicEngine.
|
* @brief Type alias for a network solver strategy that uses a DynamicEngine.
|
||||||
*/
|
*/
|
||||||
using DynamicNetworkSolverStrategy = NetworkSolverStrategy<DynamicEngine>;
|
using DynamicNetworkSolverStrategy = NetworkSolverStrategy<DynamicEngine>;
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DirectNetworkSolver
|
|
||||||
* @brief A network solver that directly integrates the reaction network ODEs.
|
|
||||||
*
|
|
||||||
* This solver uses a Runge-Kutta method to directly integrate the reaction network
|
|
||||||
* ODEs. It is simpler than the QSENetworkSolver, but it can be less efficient for
|
|
||||||
* stiff networks with disparate timescales.
|
|
||||||
*
|
|
||||||
* @implements DynamicNetworkSolverStrategy
|
|
||||||
*/
|
|
||||||
class DirectNetworkSolver final : public DynamicNetworkSolverStrategy {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Constructor for the DirectNetworkSolver.
|
|
||||||
* @param engine The dynamic engine to use for evaluating the network.
|
|
||||||
*/
|
|
||||||
using DynamicNetworkSolverStrategy::DynamicNetworkSolverStrategy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct TimestepContext
|
|
||||||
* @brief Context for the timestep callback function for the DirectNetworkSolver.
|
|
||||||
*
|
|
||||||
* This struct contains the context that will be passed to the callback function at the end of each timestep.
|
|
||||||
* It includes the current time, state, timestep size, cached results, and other relevant information.
|
|
||||||
*
|
|
||||||
* This type should be used when defining a callback function
|
|
||||||
*
|
|
||||||
* **Example:**
|
|
||||||
* @code
|
|
||||||
* #include "gridfire/solver/solver.h"
|
|
||||||
*
|
|
||||||
* #include <ofstream>
|
|
||||||
* #include <ranges>
|
|
||||||
*
|
|
||||||
* static std::ofstream consumptionFile("consumption.txt");
|
|
||||||
* void callback(const gridfire::solver::DirectNetworkSolver::TimestepContext& context) {
|
|
||||||
* int H1Index = context.engine.getSpeciesIndex(fourdst::atomic::H_1);
|
|
||||||
* int He4Index = context.engine.getSpeciesIndex(fourdst::atomic::He_4);
|
|
||||||
*
|
|
||||||
* consumptionFile << context.t << "," << context.state(H1Index) << "," << context.state(He4Index) << "\n";
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* int main() {
|
|
||||||
* ... // Code to set up engine and solvers...
|
|
||||||
* solver.set_callback(callback);
|
|
||||||
* solver.evaluate(netIn);
|
|
||||||
* consumptionFile.close();
|
|
||||||
* }
|
|
||||||
* @endcode
|
|
||||||
*/
|
|
||||||
struct TimestepContext final : public SolverContextBase {
|
|
||||||
const double t; ///< Current time.
|
|
||||||
const boost::numeric::ublas::vector<double>& state; ///< Current state of the system.
|
|
||||||
const double dt; ///< Time step size.
|
|
||||||
const double cached_time; ///< Cached time for the last observed state.
|
|
||||||
const double last_observed_time; ///< Last time the state was observed.
|
|
||||||
const double last_step_time; ///< Last step time.
|
|
||||||
const double T9; ///< Temperature in units of 10^9 K.
|
|
||||||
const double rho; ///< Density in g/cm^3.
|
|
||||||
const std::optional<StepDerivatives<double>>& cached_result; ///< Cached result of the step derivatives.
|
|
||||||
const int num_steps; ///< Total number of steps taken.
|
|
||||||
const DynamicEngine& engine; ///< Reference to the dynamic engine.
|
|
||||||
const std::vector<fourdst::atomic::Species>& networkSpecies;
|
|
||||||
|
|
||||||
TimestepContext(
|
|
||||||
const double t,
|
|
||||||
const boost::numeric::ublas::vector<double> &state,
|
|
||||||
const double dt,
|
|
||||||
const double cached_time,
|
|
||||||
const double last_observed_time,
|
|
||||||
const double last_step_time,
|
|
||||||
const double t9,
|
|
||||||
const double rho,
|
|
||||||
const std::optional<StepDerivatives<double>> &cached_result,
|
|
||||||
const int num_steps,
|
|
||||||
const DynamicEngine &engine,
|
|
||||||
const std::vector<fourdst::atomic::Species>& networkSpecies
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Describe the context for callback functions.
|
|
||||||
* @return A vector of tuples, each containing a string for the parameter's name and a string for its type.
|
|
||||||
*
|
|
||||||
* This method provides a description of the context that will be passed to the callback function.
|
|
||||||
* The intent is that an end user can investigate the context and use this information to craft their own
|
|
||||||
* callback function.
|
|
||||||
*
|
|
||||||
* @implements SolverContextBase::describe
|
|
||||||
*/
|
|
||||||
[[nodiscard]] std::vector<std::tuple<std::string, std::string>> describe() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Type alias for a timestep callback function.
|
|
||||||
*
|
|
||||||
* @brief The type alias for the callback function that will be called at the end of each timestep.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
using TimestepCallback = std::function<void(const TimestepContext& context)>; ///< Type alias for a timestep callback function.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Evaluates the network for a given timestep using direct integration.
|
|
||||||
* @param netIn The input conditions for the network.
|
|
||||||
* @return The output conditions after the timestep.
|
|
||||||
*/
|
|
||||||
NetOut evaluate(const NetIn& netIn) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the callback function to be called at the end of each timestep.
|
|
||||||
* @param callback The callback function to be called at the end of each timestep.
|
|
||||||
*
|
|
||||||
* This function allows the user to set a callback function that will be called at the end of each timestep.
|
|
||||||
* The callback function will receive a gridfire::solver::DirectNetworkSolver::TimestepContext object.
|
|
||||||
*/
|
|
||||||
void set_callback(const std::any &callback) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Describe the context that will be passed to the callback function.
|
|
||||||
* @return A vector of tuples, each containing a string for the parameter's name and a string for its type.
|
|
||||||
*
|
|
||||||
* This method provides a description of the context that will be passed to the callback function.
|
|
||||||
* The intent is that an end user can investigate the context and use this information to craft their own
|
|
||||||
* callback function.
|
|
||||||
*
|
|
||||||
* @implements SolverContextBase::describe
|
|
||||||
*/
|
|
||||||
[[nodiscard]] std::vector<std::tuple<std::string, std::string>> describe_callback_context() const override;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* @struct RHSManager
|
|
||||||
* @brief Functor for calculating the right-hand side of the ODEs.
|
|
||||||
*
|
|
||||||
* This functor is used by the ODE solver to calculate the time derivatives of the
|
|
||||||
* species abundances. It takes the current abundances as input and returns the
|
|
||||||
* time derivatives.
|
|
||||||
*/
|
|
||||||
struct RHSManager {
|
|
||||||
DynamicEngine& m_engine; ///< The engine used to evaluate the network.
|
|
||||||
const double m_T9; ///< Temperature in units of 10^9 K.
|
|
||||||
const double m_rho; ///< Density in g/cm^3.
|
|
||||||
|
|
||||||
mutable double m_cached_time;
|
|
||||||
mutable std::optional<StepDerivatives<double>> m_cached_result;
|
|
||||||
|
|
||||||
mutable double m_last_observed_time = 0.0; ///< Last time the state was observed.
|
|
||||||
|
|
||||||
|
|
||||||
quill::Logger* m_logger = LogManager::getInstance().newFileLogger("integration.log", "GridFire"); ///< Logger instance.
|
|
||||||
mutable int m_num_steps = 0;
|
|
||||||
mutable double m_last_step_time = 1e-20;
|
|
||||||
|
|
||||||
TimestepCallback& m_callback;
|
|
||||||
const std::vector<fourdst::atomic::Species>& m_networkSpecies;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructor for the RHSFunctor.
|
|
||||||
* @param engine The engine used to evaluate the network.
|
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
|
||||||
* @param rho Density in g/cm^3.
|
|
||||||
* @param callback callback function to be called at the end of each timestep.
|
|
||||||
* @param networkSpecies vector of species in the network in the correct order.
|
|
||||||
*/
|
|
||||||
RHSManager(
|
|
||||||
DynamicEngine& engine,
|
|
||||||
const double T9,
|
|
||||||
const double rho,
|
|
||||||
TimestepCallback& callback,
|
|
||||||
const std::vector<fourdst::atomic::Species>& networkSpecies
|
|
||||||
) :
|
|
||||||
m_engine(engine),
|
|
||||||
m_T9(T9),
|
|
||||||
m_rho(rho),
|
|
||||||
m_cached_time(0),
|
|
||||||
m_callback(callback),
|
|
||||||
m_networkSpecies(networkSpecies){}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Calculates the time derivatives of the species abundances.
|
|
||||||
* @param Y Vector of current abundances.
|
|
||||||
* @param dYdt Vector to store the time derivatives.
|
|
||||||
* @param t Current time.
|
|
||||||
*/
|
|
||||||
void operator()(
|
|
||||||
const boost::numeric::ublas::vector<double>& Y,
|
|
||||||
boost::numeric::ublas::vector<double>& dYdt,
|
|
||||||
double t
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void observe(const boost::numeric::ublas::vector<double>& state, double t) const;
|
|
||||||
void compute_and_cache(const boost::numeric::ublas::vector<double>& state, double t) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct JacobianFunctor
|
|
||||||
* @brief Functor for calculating the Jacobian matrix.
|
|
||||||
*
|
|
||||||
* This functor is used by the ODE solver to calculate the Jacobian matrix of the
|
|
||||||
* ODEs. It takes the current abundances as input and returns the Jacobian matrix.
|
|
||||||
*/
|
|
||||||
struct JacobianFunctor {
|
|
||||||
DynamicEngine& m_engine; ///< The engine used to evaluate the network.
|
|
||||||
const double m_T9; ///< Temperature in units of 10^9 K.
|
|
||||||
const double m_rho; ///< Density in g/cm^3.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructor for the JacobianFunctor.
|
|
||||||
* @param engine The engine used to evaluate the network.
|
|
||||||
* @param T9 Temperature in units of 10^9 K.
|
|
||||||
* @param rho Density in g/cm^3.
|
|
||||||
*/
|
|
||||||
JacobianFunctor(
|
|
||||||
DynamicEngine& engine,
|
|
||||||
const double T9,
|
|
||||||
const double rho
|
|
||||||
) :
|
|
||||||
m_engine(engine),
|
|
||||||
m_T9(T9),
|
|
||||||
m_rho(rho) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Calculates the Jacobian matrix.
|
|
||||||
* @param Y Vector of current abundances.
|
|
||||||
* @param J Matrix to store the Jacobian matrix.
|
|
||||||
* @param t Current time.
|
|
||||||
* @param dfdt Vector to store the time derivatives (not used).
|
|
||||||
*/
|
|
||||||
void operator()(
|
|
||||||
const boost::numeric::ublas::vector<double>& Y,
|
|
||||||
boost::numeric::ublas::matrix<double>& J,
|
|
||||||
double t,
|
|
||||||
boost::numeric::ublas::vector<double>& dfdt
|
|
||||||
) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log"); ///< Logger instance.
|
|
||||||
Config& m_config = Config::getInstance(); ///< Configuration instance.
|
|
||||||
|
|
||||||
TimestepCallback m_callback;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ namespace gridfire::solver {
|
|||||||
|
|
||||||
void set_callback(const std::any &callback) override;
|
void set_callback(const std::any &callback) override;
|
||||||
|
|
||||||
bool get_stdout_logging_enabled() const;
|
[[nodiscard]] bool get_stdout_logging_enabled() const;
|
||||||
|
|
||||||
void set_stdout_logging_enabled(const bool value);
|
void set_stdout_logging_enabled(const bool value);
|
||||||
|
|
||||||
@@ -69,14 +69,14 @@ namespace gridfire::solver {
|
|||||||
const double last_step_time;
|
const double last_step_time;
|
||||||
const double T9;
|
const double T9;
|
||||||
const double rho;
|
const double rho;
|
||||||
const int num_steps;
|
const size_t num_steps;
|
||||||
const DynamicEngine& engine;
|
const DynamicEngine& engine;
|
||||||
const std::vector<fourdst::atomic::Species>& networkSpecies;
|
const std::vector<fourdst::atomic::Species>& networkSpecies;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
TimestepContext(
|
TimestepContext(
|
||||||
double t, const N_Vector& state, double dt, double last_step_time,
|
double t, const N_Vector& state, double dt, double last_step_time,
|
||||||
double t9, double rho, int num_steps, const DynamicEngine& engine,
|
double t9, double rho, size_t num_steps, const DynamicEngine& engine,
|
||||||
const std::vector<fourdst::atomic::Species>& networkSpecies
|
const std::vector<fourdst::atomic::Species>& networkSpecies
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -104,8 +104,8 @@ namespace gridfire::solver {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Config& m_config = Config::getInstance();
|
fourdst::config::Config& m_config = fourdst::config::Config::getInstance();
|
||||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||||
static int cvode_rhs_wrapper(sunrealtype t, N_Vector y, N_Vector ydot, void *user_data);
|
static int cvode_rhs_wrapper(sunrealtype t, N_Vector y, N_Vector ydot, void *user_data);
|
||||||
static int cvode_jac_wrapper(sunrealtype t, N_Vector y, N_Vector ydot, SUNMatrix J, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
|
static int cvode_jac_wrapper(sunrealtype t, N_Vector y, N_Vector ydot, SUNMatrix J, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
size_t numTriggers() const override;
|
size_t numTriggers() const override;
|
||||||
size_t numMisses() const override;
|
size_t numMisses() const override;
|
||||||
private:
|
private:
|
||||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||||
mutable size_t m_hits = 0;
|
mutable size_t m_hits = 0;
|
||||||
mutable size_t m_misses = 0;
|
mutable size_t m_misses = 0;
|
||||||
mutable size_t m_updates = 0;
|
mutable size_t m_updates = 0;
|
||||||
@@ -48,7 +48,7 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
size_t numTriggers() const override;
|
size_t numTriggers() const override;
|
||||||
size_t numMisses() const override;
|
size_t numMisses() const override;
|
||||||
private:
|
private:
|
||||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||||
mutable size_t m_hits = 0;
|
mutable size_t m_hits = 0;
|
||||||
mutable size_t m_misses = 0;
|
mutable size_t m_misses = 0;
|
||||||
mutable size_t m_updates = 0;
|
mutable size_t m_updates = 0;
|
||||||
@@ -71,7 +71,7 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
size_t numTriggers() const override;
|
size_t numTriggers() const override;
|
||||||
size_t numMisses() const override;
|
size_t numMisses() const override;
|
||||||
private:
|
private:
|
||||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||||
mutable size_t m_hits = 0;
|
mutable size_t m_hits = 0;
|
||||||
mutable size_t m_misses = 0;
|
mutable size_t m_misses = 0;
|
||||||
mutable size_t m_updates = 0;
|
mutable size_t m_updates = 0;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace gridfire::trigger {
|
namespace gridfire::trigger {
|
||||||
inline void printWhy(const TriggerResult& result, const int indent = 0) {
|
inline void printWhy(const TriggerResult& result, const int indent = 0) { // NOLINT(*-no-recursion)
|
||||||
const std::string prefix(indent * 2, ' ');
|
const std::string prefix(indent * 2, ' ');
|
||||||
std::cout << prefix << "• [" << (result.value ? "TRUE" : "FALSE")
|
std::cout << prefix << "• [" << (result.value ? "TRUE" : "FALSE")
|
||||||
<< "] " << result.name << ": " << result.description << std::endl;
|
<< "] " << result.name << ": " << result.description << std::endl;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include "gridfire/trigger/trigger_result.h"
|
#include "gridfire/trigger/trigger_result.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace gridfire::trigger {
|
namespace gridfire::trigger {
|
||||||
template <typename TriggerContextStruct>
|
template <typename TriggerContextStruct>
|
||||||
@@ -16,11 +15,11 @@ namespace gridfire::trigger {
|
|||||||
virtual void update(const TriggerContextStruct& ctx) = 0;
|
virtual void update(const TriggerContextStruct& ctx) = 0;
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
|
|
||||||
virtual std::string name() const = 0;
|
[[nodiscard]] virtual std::string name() const = 0;
|
||||||
virtual std::string describe() const = 0;
|
[[nodiscard]] virtual std::string describe() const = 0;
|
||||||
virtual TriggerResult why(const TriggerContextStruct& ctx) const = 0;
|
[[nodiscard]] virtual TriggerResult why(const TriggerContextStruct& ctx) const = 0;
|
||||||
|
|
||||||
virtual size_t numTriggers() const = 0;
|
[[nodiscard]] virtual size_t numTriggers() const = 0;
|
||||||
virtual size_t numMisses() const = 0;
|
[[nodiscard]] virtual size_t numMisses() const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,6 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <numeric>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
namespace gridfire::utils {
|
namespace gridfire::utils {
|
||||||
@@ -64,9 +59,9 @@ namespace gridfire::utils {
|
|||||||
*/
|
*/
|
||||||
std::string formatNuclearTimescaleLogString(
|
std::string formatNuclearTimescaleLogString(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition& composition,
|
||||||
const double T9,
|
double T9,
|
||||||
const double rho
|
double rho
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -15,20 +16,20 @@ namespace gridfire::utils {
|
|||||||
public:
|
public:
|
||||||
virtual ~ColumnBase() = default;
|
virtual ~ColumnBase() = default;
|
||||||
// Gets the string representation of the data at a given row
|
// Gets the string representation of the data at a given row
|
||||||
virtual std::string getCellData(size_t rowIndex) const = 0;
|
[[nodiscard]] virtual std::string getCellData(size_t rowIndex) const = 0;
|
||||||
// Gets the header text for the column
|
// Gets the header text for the column
|
||||||
virtual std::string getHeader() const = 0;
|
[[nodiscard]] virtual std::string getHeader() const = 0;
|
||||||
// Gets the number of data rows in the column
|
// Gets the number of data rows in the column
|
||||||
virtual size_t getRowCount() const = 0;
|
[[nodiscard]] virtual size_t getRowCount() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Column final : public ColumnBase {
|
class Column final : public ColumnBase {
|
||||||
public:
|
public:
|
||||||
Column(const std::string& header, const std::vector<T>& data)
|
Column(std::string header, const std::vector<T>& data)
|
||||||
: m_header(header), m_data(data) {}
|
: m_header(std::move(header)), m_data(data) {}
|
||||||
|
|
||||||
std::string getCellData(size_t rowIndex) const override {
|
[[nodiscard]] std::string getCellData(size_t rowIndex) const override {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
if (rowIndex < m_data.size()) {
|
if (rowIndex < m_data.size()) {
|
||||||
ss << m_data[rowIndex];
|
ss << m_data[rowIndex];
|
||||||
@@ -36,11 +37,11 @@ namespace gridfire::utils {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getHeader() const override {
|
[[nodiscard]] std::string getHeader() const override {
|
||||||
return m_header;
|
return m_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getRowCount() const override {
|
[[nodiscard]] size_t getRowCount() const override {
|
||||||
return m_data.size();
|
return m_data.size();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@@ -74,8 +75,8 @@ namespace gridfire::utils {
|
|||||||
std::stringstream table_ss;
|
std::stringstream table_ss;
|
||||||
|
|
||||||
// --- Table Title ---
|
// --- Table Title ---
|
||||||
size_t total_width = std::accumulate(col_widths.begin(), col_widths.end(), 0) + (num_cols * 3) + 1;
|
const size_t total_width = std::accumulate(col_widths.begin(), col_widths.end(), 0) + (num_cols * 3) + 1; // NOLINT(*-fold-init-type)
|
||||||
size_t title_padding = (total_width > tableName.length()) ? (total_width - tableName.length()) / 2 : 0;
|
const size_t title_padding = (total_width > tableName.length()) ? (total_width - tableName.length()) / 2 : 0;
|
||||||
table_ss << std::string(title_padding, ' ') << tableName << "\n";
|
table_ss << std::string(title_padding, ' ') << tableName << "\n";
|
||||||
|
|
||||||
// --- Helper to draw horizontal border ---
|
// --- Helper to draw horizontal border ---
|
||||||
@@ -94,7 +95,7 @@ namespace gridfire::utils {
|
|||||||
// --- Draw Header Row ---
|
// --- Draw Header Row ---
|
||||||
table_ss << "|";
|
table_ss << "|";
|
||||||
for (size_t j = 0; j < num_cols; ++j) {
|
for (size_t j = 0; j < num_cols; ++j) {
|
||||||
table_ss << " " << std::left << std::setw(col_widths[j]) << columns[j]->getHeader() << " |";
|
table_ss << " " << std::left << std::setw(col_widths[j]) << columns[j]->getHeader() << " |"; // NOLINT(*-narrowing-conversions)
|
||||||
}
|
}
|
||||||
table_ss << "\n";
|
table_ss << "\n";
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ namespace gridfire::utils {
|
|||||||
for (size_t i = 0; i < num_rows; ++i) {
|
for (size_t i = 0; i < num_rows; ++i) {
|
||||||
table_ss << "|";
|
table_ss << "|";
|
||||||
for (size_t j = 0; j < num_cols; ++j) {
|
for (size_t j = 0; j < num_cols; ++j) {
|
||||||
table_ss << " " << std::left << std::setw(col_widths[j]) << columns[j]->getCellData(i) << " |";
|
table_ss << " " << std::left << std::setw(col_widths[j]) << columns[j]->getCellData(i) << " |"; // NOLINT(*-narrowing-conversions)
|
||||||
}
|
}
|
||||||
table_ss << "\n";
|
table_ss << "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace gridfire::diagnostics {
|
namespace gridfire::diagnostics {
|
||||||
@@ -73,7 +72,7 @@ namespace gridfire::diagnostics {
|
|||||||
void inspect_species_balance(
|
void inspect_species_balance(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const std::string& species_name,
|
const std::string& species_name,
|
||||||
const std::vector<double>& Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) {
|
) {
|
||||||
@@ -89,15 +88,15 @@ namespace gridfire::diagnostics {
|
|||||||
const int stoichiometry = reaction->stoichiometry(species_obj);
|
const int stoichiometry = reaction->stoichiometry(species_obj);
|
||||||
if (stoichiometry == 0) continue;
|
if (stoichiometry == 0) continue;
|
||||||
|
|
||||||
const double flow = engine.calculateMolarReactionFlow(*reaction, Y_full, T9, rho);
|
const double flow = engine.calculateMolarReactionFlow(*reaction, comp, T9, rho);
|
||||||
|
|
||||||
if (stoichiometry > 0) {
|
if (stoichiometry > 0) {
|
||||||
creation_ids.push_back(std::string(reaction->id()));
|
creation_ids.emplace_back(reaction->id());
|
||||||
creation_stoichiometry.push_back(stoichiometry);
|
creation_stoichiometry.push_back(stoichiometry);
|
||||||
creation_flows.push_back(flow);
|
creation_flows.push_back(flow);
|
||||||
total_creation_flow += stoichiometry * flow;
|
total_creation_flow += stoichiometry * flow;
|
||||||
} else {
|
} else {
|
||||||
destruction_ids.push_back(std::string(reaction->id()));
|
destruction_ids.emplace_back(reaction->id());
|
||||||
destruction_stoichiometry.push_back(stoichiometry);
|
destruction_stoichiometry.push_back(stoichiometry);
|
||||||
destruction_flows.push_back(flow);
|
destruction_flows.push_back(flow);
|
||||||
total_destruction_flow += std::abs(stoichiometry) * flow;
|
total_destruction_flow += std::abs(stoichiometry) * flow;
|
||||||
@@ -129,38 +128,38 @@ namespace gridfire::diagnostics {
|
|||||||
|
|
||||||
void inspect_jacobian_stiffness(
|
void inspect_jacobian_stiffness(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const std::vector<double>& Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) {
|
) {
|
||||||
engine.generateJacobianMatrix(Y_full, T9, rho);
|
engine.generateJacobianMatrix(comp, T9, rho);
|
||||||
const auto& species_list = engine.getNetworkSpecies();
|
const auto& species_list = engine.getNetworkSpecies();
|
||||||
|
|
||||||
double max_diag = 0.0;
|
double max_diag = 0.0;
|
||||||
double max_off_diag = 0.0;
|
double max_off_diag = 0.0;
|
||||||
int max_diag_idx = -1;
|
std::optional<fourdst::atomic::Species> max_diag_species = std::nullopt;
|
||||||
int max_off_diag_i = -1, max_off_diag_j = -1;
|
std::optional<std::pair<fourdst::atomic::Species, fourdst::atomic::Species>> max_off_diag_species = std::nullopt;
|
||||||
|
|
||||||
for (size_t i = 0; i < species_list.size(); ++i) {
|
for (const auto& rowSpecies : species_list) {
|
||||||
for (size_t j = 0; j < species_list.size(); ++j) {
|
for (const auto& colSpecies : species_list) {
|
||||||
const double val = std::abs(engine.getJacobianMatrixEntry(i, j));
|
const double val = std::abs(engine.getJacobianMatrixEntry(rowSpecies, colSpecies));
|
||||||
if (i == j) {
|
if (rowSpecies == colSpecies) {
|
||||||
if (val > max_diag) { max_diag = val; max_diag_idx = i; }
|
if (val > max_diag) { max_diag = val; max_diag_species = colSpecies; }
|
||||||
} else {
|
} else {
|
||||||
if (val > max_off_diag) { max_off_diag = val; max_off_diag_i = i; max_off_diag_j = j; }
|
if (val > max_off_diag) { max_off_diag = val; max_off_diag_species = {rowSpecies, colSpecies};}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "\n--- Jacobian Stiffness Report ---" << std::endl;
|
std::cout << "\n--- Jacobian Stiffness Report ---" << std::endl;
|
||||||
if (max_diag_idx != -1) {
|
if (max_diag_species.has_value()) {
|
||||||
std::cout << " Largest Diagonal Element (d(dYi/dt)/dYi): " << std::scientific << max_diag
|
std::cout << " Largest Diagonal Element (d(dYi/dt)/dYi): " << std::scientific << max_diag
|
||||||
<< " for species " << species_list[max_diag_idx].name() << std::endl;
|
<< " for species " << max_diag_species->name() << std::endl;
|
||||||
}
|
}
|
||||||
if (max_off_diag_i != -1) {
|
if (max_off_diag_species.has_value()) {
|
||||||
std::cout << " Largest Off-Diagonal Element (d(dYi/dt)/dYj): " << std::scientific << max_off_diag
|
std::cout << " Largest Off-Diagonal Element (d(dYi/dt)/dYj): " << std::scientific << max_off_diag
|
||||||
<< " for d(" << species_list[max_off_diag_i].name()
|
<< " for d(" << max_off_diag_species->first.name()
|
||||||
<< ")/d(" << species_list[max_off_diag_j].name() << ")" << std::endl;
|
<< ")/d(" << max_off_diag_species->second.name() << ")" << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << "---------------------------------" << std::endl;
|
std::cout << "---------------------------------" << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "quill/LogMacros.h"
|
#include "quill/LogMacros.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -40,7 +39,8 @@ namespace gridfire {
|
|||||||
const fourdst::composition::Composition &composition,
|
const fourdst::composition::Composition &composition,
|
||||||
const partition::PartitionFunction& partitionFunction,
|
const partition::PartitionFunction& partitionFunction,
|
||||||
const BuildDepthType buildDepth) :
|
const BuildDepthType buildDepth) :
|
||||||
m_reactions(build_reaclib_nuclear_network(composition, buildDepth, false)),
|
m_weakRateInterpolator(rates::weak::UNIFIED_WEAK_DATA),
|
||||||
|
m_reactions(build_reaclib_nuclear_network(composition, m_weakRateInterpolator, buildDepth, false)),
|
||||||
m_depth(buildDepth),
|
m_depth(buildDepth),
|
||||||
m_partitionFunction(partitionFunction.clone())
|
m_partitionFunction(partitionFunction.clone())
|
||||||
{
|
{
|
||||||
@@ -50,15 +50,19 @@ namespace gridfire {
|
|||||||
GraphEngine::GraphEngine(
|
GraphEngine::GraphEngine(
|
||||||
const reaction::ReactionSet &reactions
|
const reaction::ReactionSet &reactions
|
||||||
) :
|
) :
|
||||||
m_reactions(reactions) {
|
m_weakRateInterpolator(rates::weak::UNIFIED_WEAK_DATA),
|
||||||
|
m_reactions(reactions)
|
||||||
|
{
|
||||||
syncInternalMaps();
|
syncInternalMaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::expected<StepDerivatives<double>, expectations::StaleEngineError> GraphEngine::calculateRHSAndEnergy(
|
std::expected<StepDerivatives<double>, expectations::StaleEngineError> GraphEngine::calculateRHSAndEnergy(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
|
const double Ye = comp.getElectronAbundance();
|
||||||
|
const double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
if (m_usePrecomputation) {
|
if (m_usePrecomputation) {
|
||||||
std::vector<double> bare_rates;
|
std::vector<double> bare_rates;
|
||||||
std::vector<double> bare_reverse_rates;
|
std::vector<double> bare_reverse_rates;
|
||||||
@@ -66,33 +70,35 @@ namespace gridfire {
|
|||||||
bare_reverse_rates.reserve(m_reactions.size());
|
bare_reverse_rates.reserve(m_reactions.size());
|
||||||
|
|
||||||
// TODO: Add cache to this
|
// TODO: Add cache to this
|
||||||
|
|
||||||
for (const auto& reaction: m_reactions) {
|
for (const auto& reaction: m_reactions) {
|
||||||
bare_rates.push_back(reaction->calculate_rate(T9, rho, Y));
|
bare_rates.push_back(reaction->calculate_rate(T9, rho, Ye, mue, comp.getMolarAbundanceVector(), m_indexToSpeciesMap));
|
||||||
bare_reverse_rates.push_back(calculateReverseRate(*reaction, T9, rho, Y));
|
bare_reverse_rates.push_back(calculateReverseRate(*reaction, T9, rho, comp));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- The public facing interface can always use the precomputed version since taping is done internally ---
|
// --- The public facing interface can always use the precomputed version since taping is done internally ---
|
||||||
return calculateAllDerivativesUsingPrecomputation(Y, bare_rates, bare_reverse_rates, T9, rho);
|
return calculateAllDerivativesUsingPrecomputation(comp, bare_rates, bare_reverse_rates, T9, rho);
|
||||||
} else {
|
} else {
|
||||||
return calculateAllDerivatives<double>(Y, T9, rho);
|
return calculateAllDerivatives<double>(comp.getMolarAbundanceVector(), T9, rho, Ye, mue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnergyDerivatives GraphEngine::calculateEpsDerivatives(
|
EnergyDerivatives GraphEngine::calculateEpsDerivatives(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
const size_t numSpecies = m_networkSpecies.size();
|
const size_t numSpecies = m_networkSpecies.size();
|
||||||
const size_t numADInputs = numSpecies + 2; // +2 for T9 and rho
|
const size_t numADInputs = numSpecies + 2; // +2 for T9 and rho
|
||||||
|
|
||||||
if (Y.size() != numSpecies) {
|
if (comp.getRegisteredSpecies().size() != numSpecies) {
|
||||||
LOG_ERROR(m_logger, "Input abundance vector size ({}) does not match number of species in the network ({}).",
|
LOG_ERROR(m_logger, "Input abundance vector size ({}) does not match number of species in the network ({}).",
|
||||||
Y.size(), numSpecies);
|
comp.getRegisteredSpecies().size(), numSpecies);
|
||||||
throw std::invalid_argument("Input abundance vector size does not match number of species in the network.");
|
throw std::invalid_argument("Input abundance vector size does not match number of species in the network.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<double> x(numADInputs);
|
std::vector<double> x(numADInputs);
|
||||||
|
const std::vector<double> Y = comp.getMolarAbundanceVector();
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
for (size_t i = 0; i < numSpecies; ++i) {
|
||||||
x[i] = Y[i];
|
x[i] = Y[i];
|
||||||
}
|
}
|
||||||
@@ -148,6 +154,7 @@ namespace gridfire {
|
|||||||
|
|
||||||
// --- Network Graph Construction Methods ---
|
// --- Network Graph Construction Methods ---
|
||||||
void GraphEngine::collectNetworkSpecies() {
|
void GraphEngine::collectNetworkSpecies() {
|
||||||
|
//TODO: Ensure consistent ordering in the m_networkSpecies vector so that it is ordered by species mass.
|
||||||
m_networkSpecies.clear();
|
m_networkSpecies.clear();
|
||||||
m_networkSpeciesMap.clear();
|
m_networkSpeciesMap.clear();
|
||||||
|
|
||||||
@@ -190,6 +197,10 @@ namespace gridfire {
|
|||||||
for (size_t i = 0; i < m_networkSpecies.size(); ++i) {
|
for (size_t i = 0; i < m_networkSpecies.size(); ++i) {
|
||||||
m_speciesToIndexMap.insert({m_networkSpecies[i], i});
|
m_speciesToIndexMap.insert({m_networkSpecies[i], i});
|
||||||
}
|
}
|
||||||
|
m_indexToSpeciesMap.clear();
|
||||||
|
for (size_t i = 0; i < m_networkSpecies.size(); ++i) {
|
||||||
|
m_indexToSpeciesMap.insert({i, m_networkSpecies[i]});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEngine::reserveJacobianMatrix() const {
|
void GraphEngine::reserveJacobianMatrix() const {
|
||||||
@@ -287,13 +298,18 @@ namespace gridfire {
|
|||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho,
|
const double rho,
|
||||||
const std::vector<double> &Y
|
const fourdst::composition::Composition &comp
|
||||||
) const {
|
) const {
|
||||||
if (!m_useReverseReactions) {
|
if (!m_useReverseReactions) {
|
||||||
LOG_TRACE_L3_LIMIT_EVERY_N(std::numeric_limits<int>::max(), m_logger, "Reverse reactions are disabled. Returning 0.0 for reverse rate of reaction '{}'.", reaction.id());
|
LOG_TRACE_L3_LIMIT_EVERY_N(std::numeric_limits<int>::max(), m_logger, "Reverse reactions are disabled. Returning 0.0 for reverse rate of reaction '{}'.", reaction.id());
|
||||||
return 0.0; // If reverse reactions are not used, return 0.0
|
return 0.0; // If reverse reactions are not used, return 0.0
|
||||||
}
|
}
|
||||||
const double temp = T9 * 1e9; // Convert T9 to Kelvin
|
const double temp = T9 * 1e9; // Convert T9 to Kelvin
|
||||||
|
const double Ye = comp.getElectronAbundance();
|
||||||
|
|
||||||
|
// TODO: This is a dummy value for the electron chemical potential. We eventually need to replace this with an EOS call.
|
||||||
|
const double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
|
|
||||||
|
|
||||||
// In debug builds we check the units on kB to ensure it is in erg/K. This is removed in release builds to avoid overhead. (Note assert is a no-op in release builds)
|
// In debug builds we check the units on kB to ensure it is in erg/K. This is removed in release builds to avoid overhead. (Note assert is a no-op in release builds)
|
||||||
assert(Constants::getInstance().get("kB").unit == "erg / K");
|
assert(Constants::getInstance().get("kB").unit == "erg / K");
|
||||||
@@ -301,7 +317,7 @@ namespace gridfire {
|
|||||||
const double kBMeV = m_constants.kB * 624151; // Convert kB to MeV/K NOTE: This relies on the fact that m_constants.kB is in erg/K!
|
const double kBMeV = m_constants.kB * 624151; // Convert kB to MeV/K NOTE: This relies on the fact that m_constants.kB is in erg/K!
|
||||||
const double expFactor = std::exp(-reaction.qValue() / (kBMeV * temp));
|
const double expFactor = std::exp(-reaction.qValue() / (kBMeV * temp));
|
||||||
double reverseRate = 0.0;
|
double reverseRate = 0.0;
|
||||||
const double forwardRate = reaction.calculate_rate(T9, rho, Y);
|
const double forwardRate = reaction.calculate_rate(T9, rho, Ye, mue, comp.getMolarAbundanceVector(), m_indexToSpeciesMap);
|
||||||
|
|
||||||
if (reaction.reactants().size() == 2 && reaction.products().size() == 2) {
|
if (reaction.reactants().size() == 2 && reaction.products().size() == 2) {
|
||||||
reverseRate = calculateReverseRateTwoBody(reaction, T9, forwardRate, expFactor);
|
reverseRate = calculateReverseRateTwoBody(reaction, T9, forwardRate, expFactor);
|
||||||
@@ -393,14 +409,17 @@ namespace gridfire {
|
|||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho,
|
const double rho,
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition& comp,
|
||||||
const double reverseRate
|
const double reverseRate
|
||||||
) const {
|
) const {
|
||||||
if (!m_useReverseReactions) {
|
if (!m_useReverseReactions) {
|
||||||
LOG_TRACE_L3_LIMIT_EVERY_N(std::numeric_limits<int>::max(), m_logger, "Reverse reactions are disabled. Returning 0.0 for reverse rate of reaction '{}'.", reaction.id());
|
LOG_TRACE_L3_LIMIT_EVERY_N(std::numeric_limits<int>::max(), m_logger, "Reverse reactions are disabled. Returning 0.0 for reverse rate of reaction '{}'.", reaction.id());
|
||||||
return 0.0; // If reverse reactions are not used, return 0.0
|
return 0.0; // If reverse reactions are not used, return 0.0
|
||||||
}
|
}
|
||||||
const double d_log_kFwd = reaction.calculate_forward_rate_log_derivative(T9, rho, Y);
|
double Ye = comp.getElectronAbundance();
|
||||||
|
// TODO: This is a dummy value for the electron chemical potential. We eventually need to replace this with an EOS call.
|
||||||
|
double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
|
const double d_log_kFwd = reaction.calculate_forward_rate_log_derivative(T9, rho, Ye, mue, comp);
|
||||||
|
|
||||||
auto log_deriv_pf_op = [&](double acc, const auto& species) {
|
auto log_deriv_pf_op = [&](double acc, const auto& species) {
|
||||||
const double g = m_partitionFunction->evaluate(species.z(), species.a(), T9);
|
const double g = m_partitionFunction->evaluate(species.z(), species.a(), T9);
|
||||||
@@ -486,7 +505,7 @@ namespace gridfire {
|
|||||||
void GraphEngine::rebuild(const fourdst::composition::Composition& comp, const BuildDepthType depth) {
|
void GraphEngine::rebuild(const fourdst::composition::Composition& comp, const BuildDepthType depth) {
|
||||||
if (depth != m_depth) {
|
if (depth != m_depth) {
|
||||||
m_depth = depth;
|
m_depth = depth;
|
||||||
m_reactions = build_reaclib_nuclear_network(comp, m_depth, false);
|
m_reactions = build_reaclib_nuclear_network(comp, m_weakRateInterpolator, m_depth, false);
|
||||||
syncInternalMaps(); // Resync internal maps after changing the depth
|
syncInternalMaps(); // Resync internal maps after changing the depth
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(m_logger, "Rebuild requested with the same depth. No changes made to the network.");
|
LOG_DEBUG(m_logger, "Rebuild requested with the same depth. No changes made to the network.");
|
||||||
@@ -494,7 +513,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StepDerivatives<double> GraphEngine::calculateAllDerivativesUsingPrecomputation(
|
StepDerivatives<double> GraphEngine::calculateAllDerivativesUsingPrecomputation(
|
||||||
const std::vector<double> &Y_in,
|
const fourdst::composition::Composition& comp,
|
||||||
const std::vector<double> &bare_rates,
|
const std::vector<double> &bare_rates,
|
||||||
const std::vector<double> &bare_reverse_rates,
|
const std::vector<double> &bare_reverse_rates,
|
||||||
const double T9,
|
const double T9,
|
||||||
@@ -504,33 +523,27 @@ namespace gridfire {
|
|||||||
const std::vector<double> screeningFactors = m_screeningModel->calculateScreeningFactors(
|
const std::vector<double> screeningFactors = m_screeningModel->calculateScreeningFactors(
|
||||||
m_reactions,
|
m_reactions,
|
||||||
m_networkSpecies,
|
m_networkSpecies,
|
||||||
Y_in,
|
comp.getMolarAbundanceVector(),
|
||||||
T9,
|
T9,
|
||||||
rho
|
rho
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Fix up the precomputation to use the new comp in interface as opposed to a raw vector of molar abundances
|
||||||
|
// This will require carefully checking the way the precomputation is stashed.
|
||||||
|
|
||||||
// --- Optimized loop ---
|
// --- Optimized loop ---
|
||||||
std::vector<double> molarReactionFlows;
|
std::vector<double> molarReactionFlows;
|
||||||
molarReactionFlows.reserve(m_precomputedReactions.size());
|
molarReactionFlows.reserve(m_precomputedReactions.size());
|
||||||
|
|
||||||
for (const auto& precomp : m_precomputedReactions) {
|
for (const auto& precomp : m_precomputedReactions) {
|
||||||
double forwardAbundanceProduct = 1.0;
|
double forwardAbundanceProduct = 1.0;
|
||||||
// bool below_threshold = false;
|
|
||||||
for (size_t i = 0; i < precomp.unique_reactant_indices.size(); ++i) {
|
for (size_t i = 0; i < precomp.unique_reactant_indices.size(); ++i) {
|
||||||
const size_t reactantIndex = precomp.unique_reactant_indices[i];
|
const size_t reactantIndex = precomp.unique_reactant_indices[i];
|
||||||
|
const fourdst::atomic::Species& reactant = m_networkSpecies[reactantIndex];
|
||||||
const int power = precomp.reactant_powers[i];
|
const int power = precomp.reactant_powers[i];
|
||||||
// const double abundance = Y_in[reactantIndex];
|
|
||||||
// if (abundance < MIN_ABUNDANCE_THRESHOLD) {
|
|
||||||
// below_threshold = true;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
forwardAbundanceProduct *= std::pow(Y_in[reactantIndex], power);
|
forwardAbundanceProduct *= std::pow(comp.getMolarAbundance(reactant), power);
|
||||||
}
|
}
|
||||||
// if (below_threshold) {
|
|
||||||
// molarReactionFlows.push_back(0.0);
|
|
||||||
// continue; // Skip this reaction if any reactant is below the abundance threshold
|
|
||||||
// }
|
|
||||||
|
|
||||||
const double bare_rate = bare_rates[precomp.reaction_index];
|
const double bare_rate = bare_rates[precomp.reaction_index];
|
||||||
const double screeningFactor = screeningFactors[precomp.reaction_index];
|
const double screeningFactor = screeningFactors[precomp.reaction_index];
|
||||||
@@ -549,7 +562,9 @@ namespace gridfire {
|
|||||||
const double bare_reverse_rate = bare_reverse_rates[precomp.reaction_index];
|
const double bare_reverse_rate = bare_reverse_rates[precomp.reaction_index];
|
||||||
double reverseAbundanceProduct = 1.0;
|
double reverseAbundanceProduct = 1.0;
|
||||||
for (size_t i = 0; i < precomp.unique_product_indices.size(); ++i) {
|
for (size_t i = 0; i < precomp.unique_product_indices.size(); ++i) {
|
||||||
reverseAbundanceProduct *= std::pow(Y_in[precomp.unique_product_indices[i]], precomp.product_powers[i]);
|
const size_t productIndex = precomp.unique_product_indices[i];
|
||||||
|
const fourdst::atomic::Species& product = m_networkSpecies[productIndex];
|
||||||
|
reverseAbundanceProduct *= std::pow(comp.getMolarAbundance(product), precomp.product_powers[i]);
|
||||||
}
|
}
|
||||||
reverseMolarReactionFlow = screeningFactor *
|
reverseMolarReactionFlow = screeningFactor *
|
||||||
bare_reverse_rate *
|
bare_reverse_rate *
|
||||||
@@ -564,25 +579,28 @@ namespace gridfire {
|
|||||||
|
|
||||||
// --- Assemble molar abundance derivatives ---
|
// --- Assemble molar abundance derivatives ---
|
||||||
StepDerivatives<double> result;
|
StepDerivatives<double> result;
|
||||||
result.dydt.assign(m_networkSpecies.size(), 0.0); // Initialize derivatives to zero
|
for (const auto& species: m_networkSpecies) {
|
||||||
|
result.dydt[species] = 0.0; // Initialize the change in abundance for each network species to 0
|
||||||
|
}
|
||||||
for (size_t j = 0; j < m_precomputedReactions.size(); ++j) {
|
for (size_t j = 0; j < m_precomputedReactions.size(); ++j) {
|
||||||
const auto& precomp = m_precomputedReactions[j];
|
const auto& precomp = m_precomputedReactions[j];
|
||||||
const double R_j = molarReactionFlows[j];
|
const double R_j = molarReactionFlows[j];
|
||||||
|
|
||||||
for (size_t i = 0; i < precomp.affected_species_indices.size(); ++i) {
|
for (size_t i = 0; i < precomp.affected_species_indices.size(); ++i) {
|
||||||
const size_t speciesIndex = precomp.affected_species_indices[i];
|
const size_t speciesIndex = precomp.affected_species_indices[i];
|
||||||
|
const fourdst::atomic::Species& species = m_networkSpecies[speciesIndex];
|
||||||
|
|
||||||
const int stoichiometricCoefficient = precomp.stoichiometric_coefficients[i];
|
const int stoichiometricCoefficient = precomp.stoichiometric_coefficients[i];
|
||||||
|
|
||||||
// Update the derivative for this species
|
// Update the derivative for this species
|
||||||
result.dydt[speciesIndex] += static_cast<double>(stoichiometricCoefficient) * R_j;
|
result.dydt.at(species) += static_cast<double>(stoichiometricCoefficient) * R_j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Calculate the nuclear energy generation rate ---
|
// --- Calculate the nuclear energy generation rate ---
|
||||||
double massProductionRate = 0.0; // [mol][s^-1]
|
double massProductionRate = 0.0; // [mol][s^-1]
|
||||||
for (size_t i = 0; i < m_networkSpecies.size(); ++i) {
|
for (const auto & species : m_networkSpecies) {
|
||||||
const auto& species = m_networkSpecies[i];
|
massProductionRate += result.dydt[species] * species.mass() * m_constants.u;
|
||||||
massProductionRate += result.dydt[i] * species.mass() * m_constants.u;
|
|
||||||
}
|
}
|
||||||
result.nuclearEnergyGenerationRate = -massProductionRate * m_constants.Na * m_constants.c * m_constants.c; // [erg][s^-1][g^-1]
|
result.nuclearEnergyGenerationRate = -massProductionRate * m_constants.Na * m_constants.c * m_constants.c; // [erg][s^-1][g^-1]
|
||||||
return result;
|
return result;
|
||||||
@@ -631,21 +649,22 @@ namespace gridfire {
|
|||||||
m_stoichiometryMatrix.nnz()); // Assuming nnz() exists for compressed_matrix
|
m_stoichiometryMatrix.nnz()); // Assuming nnz() exists for compressed_matrix
|
||||||
}
|
}
|
||||||
|
|
||||||
StepDerivatives<double> GraphEngine::calculateAllDerivatives(
|
// StepDerivatives<double> GraphEngine::calculateAllDerivatives(
|
||||||
const std::vector<double> &Y_in,
|
// const std::vector<double> &Y,
|
||||||
const double T9,
|
// const double T9,
|
||||||
const double rho
|
// const double rho
|
||||||
) const {
|
// ) const {
|
||||||
return calculateAllDerivatives<double>(Y_in, T9, rho);
|
// return calculateAllDerivatives<double>(Y, T9, rho);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
StepDerivatives<ADDouble> GraphEngine::calculateAllDerivatives(
|
// StepDerivatives<ADDouble> GraphEngine::calculateAllDerivatives(
|
||||||
const std::vector<ADDouble> &Y_in,
|
// const std::vector<ADDouble> &Y,
|
||||||
const ADDouble &T9,
|
// ADDouble T9,
|
||||||
const ADDouble &rho
|
// ADDouble rho
|
||||||
) const {
|
// ) const {
|
||||||
return calculateAllDerivatives<ADDouble>(Y_in, T9, rho);
|
// //TODO: Sort out why this template is not being found
|
||||||
}
|
// return calculateAllDerivatives<ADDouble>(Y, T9, rho);
|
||||||
|
// }
|
||||||
|
|
||||||
void GraphEngine::setScreeningModel(const screening::ScreeningType model) {
|
void GraphEngine::setScreeningModel(const screening::ScreeningType model) {
|
||||||
m_screeningModel = screening::selectScreeningModel(model);
|
m_screeningModel = screening::selectScreeningModel(model);
|
||||||
@@ -670,15 +689,21 @@ namespace gridfire {
|
|||||||
|
|
||||||
double GraphEngine::calculateMolarReactionFlow(
|
double GraphEngine::calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
return calculateMolarReactionFlow<double>(reaction, Y, T9, rho);
|
|
||||||
|
const double Ye = comp.getElectronAbundance();
|
||||||
|
|
||||||
|
// TODO: This is a dummy placeholder which must be replaced with an EOS call
|
||||||
|
const double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
|
|
||||||
|
return calculateMolarReactionFlow<double>(reaction, comp.getMolarAbundanceVector(), T9, rho, Ye, mue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEngine::generateJacobianMatrix(
|
void GraphEngine::generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
@@ -688,6 +713,7 @@ namespace gridfire {
|
|||||||
|
|
||||||
// 1. Pack the input variables into a vector for CppAD
|
// 1. Pack the input variables into a vector for CppAD
|
||||||
std::vector<double> adInput(numSpecies + 2, 0.0); // +2 for T9 and rho
|
std::vector<double> adInput(numSpecies + 2, 0.0); // +2 for T9 and rho
|
||||||
|
const std::vector<double>& Y_dynamic = comp.getMolarAbundanceVector();
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
for (size_t i = 0; i < numSpecies; ++i) {
|
||||||
adInput[i] = std::max(Y_dynamic[i], 1e-99); // regularize the jacobian...
|
adInput[i] = std::max(Y_dynamic[i], 1e-99); // regularize the jacobian...
|
||||||
}
|
}
|
||||||
@@ -711,7 +737,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GraphEngine::generateJacobianMatrix(
|
void GraphEngine::generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho,
|
const double rho,
|
||||||
const SparsityPattern &sparsityPattern
|
const SparsityPattern &sparsityPattern
|
||||||
@@ -719,6 +745,7 @@ namespace gridfire {
|
|||||||
// --- Pack the input variables into a vector for CppAD ---
|
// --- Pack the input variables into a vector for CppAD ---
|
||||||
const size_t numSpecies = m_networkSpecies.size();
|
const size_t numSpecies = m_networkSpecies.size();
|
||||||
std::vector<double> x(numSpecies + 2, 0.0);
|
std::vector<double> x(numSpecies + 2, 0.0);
|
||||||
|
const std::vector<double>& Y_dynamic = comp.getMolarAbundanceVector();
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
for (size_t i = 0; i < numSpecies; ++i) {
|
||||||
x[i] = Y_dynamic[i];
|
x[i] = Y_dynamic[i];
|
||||||
}
|
}
|
||||||
@@ -767,8 +794,13 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double GraphEngine::getJacobianMatrixEntry(const int i, const int j) const {
|
double GraphEngine::getJacobianMatrixEntry(
|
||||||
// LOG_TRACE_L3(m_logger, "Getting jacobian matrix entry for {},{} = {}", i, j, m_jacobianMatrix(i, j));
|
const fourdst::atomic::Species& rowSpecies,
|
||||||
|
const fourdst::atomic::Species& colSpecies
|
||||||
|
) const {
|
||||||
|
//PERF: There may be some way to make this more efficient
|
||||||
|
const size_t i = getSpeciesIndex(rowSpecies);
|
||||||
|
const size_t j = getSpeciesIndex(colSpecies);
|
||||||
return m_jacobianMatrix(i, j);
|
return m_jacobianMatrix(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,10 +811,10 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int GraphEngine::getStoichiometryMatrixEntry(
|
int GraphEngine::getStoichiometryMatrixEntry(
|
||||||
const int speciesIndex,
|
const fourdst::atomic::Species& species,
|
||||||
const int reactionIndex
|
const reaction::Reaction &reaction
|
||||||
) const {
|
) const {
|
||||||
return m_stoichiometryMatrix(speciesIndex, reactionIndex);
|
return reaction.stoichiometry(species);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphEngine::exportToDot(const std::string &filename) const {
|
void GraphEngine::exportToDot(const std::string &filename) const {
|
||||||
@@ -871,18 +903,21 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesTimescales(
|
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesTimescales(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
auto [dydt, _] = calculateAllDerivatives<double>(Y, T9, rho);
|
const double Ye = comp.getElectronAbundance();
|
||||||
|
// TODO: This is a dummy placeholder which must be replaced with an EOS call
|
||||||
|
const double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
|
|
||||||
|
auto [dydt, _] = calculateAllDerivatives<double>(comp.getMolarAbundanceVector(), T9, rho, Ye, mue);
|
||||||
std::unordered_map<fourdst::atomic::Species, double> speciesTimescales;
|
std::unordered_map<fourdst::atomic::Species, double> speciesTimescales;
|
||||||
speciesTimescales.reserve(m_networkSpecies.size());
|
speciesTimescales.reserve(m_networkSpecies.size());
|
||||||
for (size_t i = 0; i < m_networkSpecies.size(); ++i) {
|
for (const auto& species : m_networkSpecies) {
|
||||||
double timescale = std::numeric_limits<double>::infinity();
|
double timescale = std::numeric_limits<double>::infinity();
|
||||||
const auto species = m_networkSpecies[i];
|
if (std::abs(dydt.at(species)) > 0.0) {
|
||||||
if (std::abs(dydt[i]) > 0.0) {
|
timescale = std::abs(comp.getMolarAbundance(species) / dydt.at(species));
|
||||||
timescale = std::abs(Y[i] / dydt[i]);
|
|
||||||
}
|
}
|
||||||
speciesTimescales.emplace(species, timescale);
|
speciesTimescales.emplace(species, timescale);
|
||||||
}
|
}
|
||||||
@@ -890,24 +925,28 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesDestructionTimescales(
|
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesDestructionTimescales(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
auto [dydt, _] = calculateAllDerivatives<double>(Y, T9, rho);
|
const double Ye = comp.getElectronAbundance();
|
||||||
|
// TODO: This is a dummy placeholder which must be replaced with an EOS call
|
||||||
|
const double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
|
|
||||||
|
auto [dydt, _] = calculateAllDerivatives<double>(comp.getMolarAbundanceVector(), T9, rho, Ye, mue);
|
||||||
std::unordered_map<fourdst::atomic::Species, double> speciesDestructionTimescales;
|
std::unordered_map<fourdst::atomic::Species, double> speciesDestructionTimescales;
|
||||||
speciesDestructionTimescales.reserve(m_networkSpecies.size());
|
speciesDestructionTimescales.reserve(m_networkSpecies.size());
|
||||||
for (const auto& species : m_networkSpecies) {
|
for (const auto& species : m_networkSpecies) {
|
||||||
double netDestructionFlow = 0.0;
|
double netDestructionFlow = 0.0;
|
||||||
for (const auto& reaction : m_reactions) {
|
for (const auto& reaction : m_reactions) {
|
||||||
if (reaction->stoichiometry(species) < 0) {
|
if (reaction->stoichiometry(species) < 0) {
|
||||||
const auto flow = calculateMolarReactionFlow<double>(*reaction, Y, T9, rho);
|
const auto flow = calculateMolarReactionFlow<double>(*reaction, comp.getMolarAbundanceVector(), T9, rho, Ye, mue);
|
||||||
netDestructionFlow += flow;
|
netDestructionFlow += flow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double timescale = std::numeric_limits<double>::infinity();
|
double timescale = std::numeric_limits<double>::infinity();
|
||||||
if (netDestructionFlow != 0.0) {
|
if (netDestructionFlow != 0.0) {
|
||||||
timescale = Y[getSpeciesIndex(species)] / netDestructionFlow;
|
timescale = comp.getMolarAbundance(species) / netDestructionFlow;
|
||||||
}
|
}
|
||||||
speciesDestructionTimescales.emplace(species, timescale);
|
speciesDestructionTimescales.emplace(species, timescale);
|
||||||
}
|
}
|
||||||
@@ -964,12 +1003,21 @@ namespace gridfire {
|
|||||||
const CppAD::AD<double> adT9 = adInput[numSpecies];
|
const CppAD::AD<double> adT9 = adInput[numSpecies];
|
||||||
const CppAD::AD<double> adRho = adInput[numSpecies + 1];
|
const CppAD::AD<double> adRho = adInput[numSpecies + 1];
|
||||||
|
|
||||||
|
// Dummy values for Ye and mue to let taping happen
|
||||||
|
const CppAD::AD<double> adYe = 1.0;
|
||||||
|
const CppAD::AD<double> adMue = 1.0;
|
||||||
|
|
||||||
|
|
||||||
// 5. Call the actual templated function
|
// 5. Call the actual templated function
|
||||||
// We let T9 and rho be constant, so we pass them as fixed values.
|
// We let T9 and rho be constant, so we pass them as fixed values.
|
||||||
auto [dydt, nuclearEnergyGenerationRate] = calculateAllDerivatives<CppAD::AD<double>>(adY, adT9, adRho);
|
auto [dydt, nuclearEnergyGenerationRate] = calculateAllDerivatives<CppAD::AD<double>>(adY, adT9, adRho, adYe, adMue);
|
||||||
|
|
||||||
m_rhsADFun.Dependent(adInput, dydt);
|
// Extract the raw vector from the associative map
|
||||||
|
std::vector<CppAD::AD<double>> dydt_vec;
|
||||||
|
dydt_vec.reserve(dydt.size());
|
||||||
|
std::ranges::transform(dydt, std::back_inserter(dydt_vec),[](const auto& kv) { return kv.second; });
|
||||||
|
|
||||||
|
m_rhsADFun.Dependent(adInput, dydt_vec);
|
||||||
|
|
||||||
LOG_TRACE_L1(m_logger, "AD tape recorded successfully for the RHS calculation. Number of independent variables: {}.",
|
LOG_TRACE_L1(m_logger, "AD tape recorded successfully for the RHS calculation. Number of independent variables: {}.",
|
||||||
adInput.size());
|
adInput.size());
|
||||||
@@ -996,16 +1044,19 @@ namespace gridfire {
|
|||||||
|
|
||||||
CppAD::Independent(adInput);
|
CppAD::Independent(adInput);
|
||||||
|
|
||||||
const std::vector<CppAD::AD<double>> adY(adInput.begin(), adInput.begin() + numSpecies);
|
const std::vector<CppAD::AD<double>> adY(adInput.begin(), adInput.begin() + static_cast<long>(numSpecies));
|
||||||
const CppAD::AD<double> adT9 = adInput[numSpecies];
|
const CppAD::AD<double> adT9 = adInput[numSpecies];
|
||||||
const CppAD::AD<double> adRho = adInput[numSpecies + 1];
|
const CppAD::AD<double> adRho = adInput[numSpecies + 1];
|
||||||
|
|
||||||
StepDerivatives<CppAD::AD<double>> derivatives = calculateAllDerivatives<CppAD::AD<double>>(adY, adT9, adRho);
|
// Dummy values for Ye and mue to let taping happen
|
||||||
|
const CppAD::AD<double> adYe = 1.0;
|
||||||
|
const CppAD::AD<double> adMue = 1.0;
|
||||||
|
|
||||||
|
auto [dydt, nuclearEnergyGenerationRate] = calculateAllDerivatives<CppAD::AD<double>>(adY, adT9, adRho, adYe, adMue);
|
||||||
|
|
||||||
std::vector<CppAD::AD<double>> adOutput(1);
|
std::vector<CppAD::AD<double>> adOutput(1);
|
||||||
adOutput[0] = derivatives.nuclearEnergyGenerationRate;
|
adOutput[0] = nuclearEnergyGenerationRate;
|
||||||
m_epsADFun.Dependent(adInput, adOutput);
|
m_epsADFun.Dependent(adInput, adOutput);
|
||||||
// m_epsADFun.optimize();
|
|
||||||
|
|
||||||
LOG_TRACE_L1(m_logger, "AD tape recorded successfully for the EPS calculation. Number of independent variables: {}.", adInput.size());
|
LOG_TRACE_L1(m_logger, "AD tape recorded successfully for the EPS calculation. Number of independent variables: {}.", adInput.size());
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#include "gridfire/engine/procedures/construction.h"
|
#include "gridfire/engine/procedures/construction.h"
|
||||||
|
#include "gridfire/reaction/weak/weak_interpolator.h"
|
||||||
|
#include "gridfire/reaction/weak/weak.h"
|
||||||
|
#include "gridfire/reaction/weak/weak_types.h"
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "gridfire/reaction/reaction.h"
|
#include "gridfire/reaction/reaction.h"
|
||||||
#include "gridfire/reaction/reaclib.h"
|
#include "gridfire/reaction/reaclib.h"
|
||||||
@@ -20,11 +24,11 @@ namespace gridfire {
|
|||||||
using fourdst::atomic::Species;
|
using fourdst::atomic::Species;
|
||||||
|
|
||||||
|
|
||||||
ReactionSet build_reaclib_nuclear_network(
|
ReactionSet build_nuclear_network(
|
||||||
const Composition &composition,
|
const Composition& composition,
|
||||||
BuildDepthType maxLayers,
|
const rates::weak::WeakRateInterpolator& weak_interpolator,
|
||||||
bool reverse
|
BuildDepthType maxLayers,
|
||||||
) {
|
bool reverse_reaclib) {
|
||||||
int depth;
|
int depth;
|
||||||
if (std::holds_alternative<NetworkBuildDepth>(maxLayers)) {
|
if (std::holds_alternative<NetworkBuildDepth>(maxLayers)) {
|
||||||
depth = static_cast<int>(std::get<NetworkBuildDepth>(maxLayers));
|
depth = static_cast<int>(std::get<NetworkBuildDepth>(maxLayers));
|
||||||
@@ -37,31 +41,71 @@ namespace gridfire {
|
|||||||
throw std::logic_error("Network build depth is set to 0. No reactions will be collected.");
|
throw std::logic_error("Network build depth is set to 0. No reactions will be collected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& allReactions = reaclib::get_all_reaclib_reactions();
|
// --- Step 1: Create a single master pool that owns all possible reactions ---
|
||||||
std::vector<Reaction*> remainingReactions;
|
ReactionSet master_reaction_pool;
|
||||||
for (const auto& reaction : allReactions) {
|
|
||||||
if (reaction->is_reverse() == reverse) {
|
// Clone all relevant REACLIB reactions into the master pool
|
||||||
remainingReactions.push_back(reaction.get());
|
const auto& allReaclibReactions = reaclib::get_all_reaclib_reactions();
|
||||||
|
for (const auto& reaction : allReaclibReactions) {
|
||||||
|
if (reaction->is_reverse() == reverse_reaclib) {
|
||||||
|
master_reaction_pool.add_reaction(reaction->clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth == static_cast<int>(NetworkBuildDepth::Full)) {
|
for (const auto& parent_species: weak_interpolator.available_isotopes()) {
|
||||||
LOG_INFO(logger, "Building full nuclear network with a total of {} reactions.", allReactions.size());
|
master_reaction_pool.add_reaction(
|
||||||
const ReactionSet reactionSet(remainingReactions);
|
std::make_unique<rates::weak::WeakReaction>(
|
||||||
return reactionSet;
|
parent_species,
|
||||||
|
rates::weak::WeakReactionType::BETA_PLUS_DECAY,
|
||||||
|
weak_interpolator
|
||||||
|
)
|
||||||
|
);
|
||||||
|
master_reaction_pool.add_reaction(
|
||||||
|
std::make_unique<rates::weak::WeakReaction>(
|
||||||
|
parent_species,
|
||||||
|
rates::weak::WeakReactionType::BETA_MINUS_DECAY,
|
||||||
|
weak_interpolator
|
||||||
|
)
|
||||||
|
);
|
||||||
|
master_reaction_pool.add_reaction(
|
||||||
|
std::make_unique<rates::weak::WeakReaction>(
|
||||||
|
parent_species,
|
||||||
|
rates::weak::WeakReactionType::ELECTRON_CAPTURE,
|
||||||
|
weak_interpolator
|
||||||
|
)
|
||||||
|
);
|
||||||
|
master_reaction_pool.add_reaction(
|
||||||
|
std::make_unique<rates::weak::WeakReaction>(
|
||||||
|
parent_species,
|
||||||
|
rates::weak::WeakReactionType::POSITRON_CAPTURE,
|
||||||
|
weak_interpolator
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Step 2: Use non-owning raw pointers for the fast build algorithm ---
|
||||||
|
std::vector<Reaction*> remainingReactions;
|
||||||
|
remainingReactions.reserve(master_reaction_pool.size());
|
||||||
|
for(const auto& reaction : master_reaction_pool) {
|
||||||
|
remainingReactions.push_back(reaction.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth == static_cast<int>(NetworkBuildDepth::Full)) {
|
||||||
|
LOG_INFO(logger, "Building full nuclear network with a total of {} reactions.", remainingReactions.size());
|
||||||
|
return master_reaction_pool; // No need to build layer by layer if we want the full network
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 3: Execute the layered network build using observing pointers ---
|
||||||
std::unordered_set<Species> availableSpecies;
|
std::unordered_set<Species> availableSpecies;
|
||||||
for (const auto &entry: composition | std::views::values) {
|
for (const auto& entry : composition | std::views::values) {
|
||||||
if (entry.mass_fraction() > 0.0) {
|
if (entry.mass_fraction() > 0.0) {
|
||||||
availableSpecies.insert(entry.isotope());
|
availableSpecies.insert(entry.isotope());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Reaction*> collectedReactionPtrs;
|
||||||
std::vector<Reaction*> collectedReactions;
|
|
||||||
|
|
||||||
LOG_INFO(logger, "Starting network construction with {} available species.", availableSpecies.size());
|
LOG_INFO(logger, "Starting network construction with {} available species.", availableSpecies.size());
|
||||||
|
|
||||||
for (int layer = 0; layer < depth && !remainingReactions.empty(); ++layer) {
|
for (int layer = 0; layer < depth && !remainingReactions.empty(); ++layer) {
|
||||||
LOG_TRACE_L1(logger, "Collecting reactions for layer {} with {} remaining reactions. Currently there are {} available species", layer, remainingReactions.size(), availableSpecies.size());
|
LOG_TRACE_L1(logger, "Collecting reactions for layer {} with {} remaining reactions. Currently there are {} available species", layer, remainingReactions.size(), availableSpecies.size());
|
||||||
std::vector<Reaction*> reactionsForNextPass;
|
std::vector<Reaction*> reactionsForNextPass;
|
||||||
@@ -70,7 +114,7 @@ namespace gridfire {
|
|||||||
|
|
||||||
reactionsForNextPass.reserve(remainingReactions.size());
|
reactionsForNextPass.reserve(remainingReactions.size());
|
||||||
|
|
||||||
for (const auto &reaction : remainingReactions) {
|
for (Reaction* reaction : remainingReactions) {
|
||||||
bool allReactantsAvailable = true;
|
bool allReactantsAvailable = true;
|
||||||
for (const auto& reactant : reaction->reactants()) {
|
for (const auto& reactant : reaction->reactants()) {
|
||||||
if (!availableSpecies.contains(reactant)) {
|
if (!availableSpecies.contains(reactant)) {
|
||||||
@@ -80,7 +124,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (allReactantsAvailable) {
|
if (allReactantsAvailable) {
|
||||||
collectedReactions.push_back(reaction);
|
collectedReactionPtrs.push_back(reaction);
|
||||||
newReactionsAdded = true;
|
newReactionsAdded = true;
|
||||||
|
|
||||||
for (const auto& product : reaction->products()) {
|
for (const auto& product : reaction->products()) {
|
||||||
@@ -92,19 +136,29 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!newReactionsAdded) {
|
if (!newReactionsAdded) {
|
||||||
LOG_INFO(logger, "No new reactions added in layer {}. Stopping network construction with {} reactions collected.", layer, collectedReactions.size());
|
LOG_INFO(logger, "No new reactions added in layer {}. Stopping network construction.", layer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_TRACE_L1(logger, "Layer {}: Collected {} reactions. New products this layer: {}", layer, collectedReactions.size(), newProductsThisLayer.size());
|
LOG_TRACE_L1(logger, "Layer {}: Collected {} new reactions. New products this layer: {}", collectedReactionPtrs.size() - collectedReactionPtrs.size(), newProductsThisLayer.size());
|
||||||
availableSpecies.insert(newProductsThisLayer.begin(), newProductsThisLayer.end());
|
availableSpecies.insert(newProductsThisLayer.begin(), newProductsThisLayer.end());
|
||||||
|
|
||||||
remainingReactions = std::move(reactionsForNextPass);
|
remainingReactions = std::move(reactionsForNextPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(logger, "Network construction completed with {} reactions collected.", collectedReactions.size());
|
// --- Step 4: Construct the final ReactionSet by moving ownership ---
|
||||||
const ReactionSet reactionSet(collectedReactions);
|
LOG_INFO(logger, "Network construction completed. Assembling final set of {} reactions.", collectedReactionPtrs.size());
|
||||||
return reactionSet;
|
ReactionSet finalReactionSet;
|
||||||
|
|
||||||
|
std::unordered_set<Reaction*> collectedPtrSet(collectedReactionPtrs.begin(), collectedReactionPtrs.end());
|
||||||
|
|
||||||
|
for (auto& reaction_ptr : master_reaction_pool) {
|
||||||
|
if (reaction_ptr && collectedPtrSet.contains(reaction_ptr.get())) {
|
||||||
|
finalReactionSet.add_reaction(std::move(reaction_ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalReactionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace gridfire {
|
|||||||
const reaction::Reaction* findDominantCreationChannel (
|
const reaction::Reaction* findDominantCreationChannel (
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const Species& species,
|
const Species& species,
|
||||||
const std::vector<double>& Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) {
|
) {
|
||||||
@@ -25,7 +25,7 @@ namespace gridfire {
|
|||||||
double maxFlow = -1.0;
|
double maxFlow = -1.0;
|
||||||
for (const auto& reaction : engine.getNetworkReactions()) {
|
for (const auto& reaction : engine.getNetworkReactions()) {
|
||||||
if (reaction->contains(species) && reaction->stoichiometry(species) > 0) {
|
if (reaction->contains(species) && reaction->stoichiometry(species) > 0) {
|
||||||
const double flow = engine.calculateMolarReactionFlow(*reaction, Y, T9, rho);
|
const double flow = engine.calculateMolarReactionFlow(*reaction, comp, T9, rho);
|
||||||
if (flow > maxFlow) {
|
if (flow > maxFlow) {
|
||||||
maxFlow = flow;
|
maxFlow = flow;
|
||||||
dominateReaction = reaction.get();
|
dominateReaction = reaction.get();
|
||||||
@@ -67,7 +67,7 @@ namespace gridfire {
|
|||||||
* robustly primed composition.
|
* robustly primed composition.
|
||||||
*/
|
*/
|
||||||
PrimingReport primeNetwork(const NetIn& netIn, DynamicEngine& engine) {
|
PrimingReport primeNetwork(const NetIn& netIn, DynamicEngine& engine) {
|
||||||
auto logger = LogManager::getInstance().getLogger("log");
|
auto logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||||
|
|
||||||
// --- Initial Setup ---
|
// --- Initial Setup ---
|
||||||
// Identify all species with zero initial mass fraction that need to be primed.
|
// Identify all species with zero initial mass fraction that need to be primed.
|
||||||
@@ -127,9 +127,6 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
tempComp.finalize(true);
|
tempComp.finalize(true);
|
||||||
|
|
||||||
NetIn tempNetIn = netIn;
|
|
||||||
tempNetIn.composition = tempComp;
|
|
||||||
|
|
||||||
NetworkPrimingEngineView primer(primingSpecies, engine);
|
NetworkPrimingEngineView primer(primingSpecies, engine);
|
||||||
if (primer.getNetworkReactions().size() == 0) {
|
if (primer.getNetworkReactions().size() == 0) {
|
||||||
LOG_ERROR(logger, "No priming reactions found for species {}.", primingSpecies.name());
|
LOG_ERROR(logger, "No priming reactions found for species {}.", primingSpecies.name());
|
||||||
@@ -138,15 +135,14 @@ namespace gridfire {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto Y = primer.mapNetInToMolarAbundanceVector(tempNetIn);
|
const double destructionRateConstant = calculateDestructionRateConstant(primer, primingSpecies, tempComp, T9, rho);
|
||||||
const double destructionRateConstant = calculateDestructionRateConstant(primer, primingSpecies, Y, T9, rho);
|
|
||||||
|
|
||||||
if (destructionRateConstant > 1e-99) {
|
if (destructionRateConstant > 1e-99) {
|
||||||
const double creationRate = calculateCreationRate(primer, primingSpecies, Y, T9, rho);
|
const double creationRate = calculateCreationRate(primer, primingSpecies, tempComp, T9, rho);
|
||||||
double equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
|
double equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
|
||||||
if (std::isnan(equilibriumMassFraction)) equilibriumMassFraction = 0.0;
|
if (std::isnan(equilibriumMassFraction)) equilibriumMassFraction = 0.0;
|
||||||
|
|
||||||
if (const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho)) {
|
if (const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, tempComp, T9, rho)) {
|
||||||
// Store the request instead of applying it immediately.
|
// Store the request instead of applying it immediately.
|
||||||
requests.push_back({primingSpecies, equilibriumMassFraction, dominantChannel->reactants()});
|
requests.push_back({primingSpecies, equilibriumMassFraction, dominantChannel->reactants()});
|
||||||
} else {
|
} else {
|
||||||
@@ -403,19 +399,17 @@ namespace gridfire {
|
|||||||
|
|
||||||
double calculateDestructionRateConstant(
|
double calculateDestructionRateConstant(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const fourdst::atomic::Species& species,
|
const Species& species,
|
||||||
const std::vector<double>& Y,
|
const Composition& comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) {
|
) {
|
||||||
const size_t speciesIndex = engine.getSpeciesIndex(species);
|
//TODO: previously (when using raw vectors) I set y[speciesIndex] = 1.0 to let there be enough so that just the destruction rate could be found (without bottlenecks from abundance) we will need to do a similar thing here.
|
||||||
std::vector<double> Y_scaled(Y.begin(), Y.end());
|
|
||||||
Y_scaled[speciesIndex] = 1.0; // Set the abundance of the species to 1.0 for rate constant calculation
|
|
||||||
double destructionRateConstant = 0.0;
|
double destructionRateConstant = 0.0;
|
||||||
for (const auto& reaction: engine.getNetworkReactions()) {
|
for (const auto& reaction: engine.getNetworkReactions()) {
|
||||||
if (reaction->contains_reactant(species)) {
|
if (reaction->contains_reactant(species)) {
|
||||||
const int stoichiometry = reaction->stoichiometry(species);
|
const int stoichiometry = reaction->stoichiometry(species);
|
||||||
destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(*reaction, Y_scaled, T9, rho);
|
destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(*reaction, comp, T9, rho);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return destructionRateConstant;
|
return destructionRateConstant;
|
||||||
@@ -424,7 +418,7 @@ namespace gridfire {
|
|||||||
double calculateCreationRate(
|
double calculateCreationRate(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
const Species& species,
|
const Species& species,
|
||||||
const std::vector<double>& Y,
|
const Composition& comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) {
|
) {
|
||||||
@@ -432,9 +426,9 @@ namespace gridfire {
|
|||||||
for (const auto& reaction: engine.getNetworkReactions()) {
|
for (const auto& reaction: engine.getNetworkReactions()) {
|
||||||
const int stoichiometry = reaction->stoichiometry(species);
|
const int stoichiometry = reaction->stoichiometry(species);
|
||||||
if (stoichiometry > 0) {
|
if (stoichiometry > 0) {
|
||||||
if (engine.calculateMolarReactionFlow(*reaction, Y, T9, rho) > 0.0) {
|
if (engine.calculateMolarReactionFlow(*reaction, comp, T9, rho) > 0.0) {
|
||||||
}
|
}
|
||||||
creationRate += stoichiometry * engine.calculateMolarReactionFlow(*reaction, Y, T9, rho);
|
creationRate += stoichiometry * engine.calculateMolarReactionFlow(*reaction, comp, T9, rho);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return creationRate;
|
return creationRate;
|
||||||
|
|||||||
@@ -95,8 +95,7 @@ namespace gridfire {
|
|||||||
|
|
||||||
LOG_TRACE_L1(m_logger, "Updating AdaptiveEngineView with new network input...");
|
LOG_TRACE_L1(m_logger, "Updating AdaptiveEngineView with new network input...");
|
||||||
|
|
||||||
std::vector<double> Y_Full;
|
auto [allFlows, composition] = calculateAllReactionFlows(updatedNetIn);
|
||||||
std::vector<ReactionFlow> allFlows = calculateAllReactionFlows(updatedNetIn, Y_Full);
|
|
||||||
|
|
||||||
double maxFlow = 0.0;
|
double maxFlow = 0.0;
|
||||||
|
|
||||||
@@ -110,11 +109,11 @@ namespace gridfire {
|
|||||||
const std::unordered_set<Species> reachableSpecies = findReachableSpecies(updatedNetIn);
|
const std::unordered_set<Species> reachableSpecies = findReachableSpecies(updatedNetIn);
|
||||||
LOG_DEBUG(m_logger, "Found {} reachable species in adaptive engine view.", reachableSpecies.size());
|
LOG_DEBUG(m_logger, "Found {} reachable species in adaptive engine view.", reachableSpecies.size());
|
||||||
|
|
||||||
const std::vector<const reaction::Reaction*> finalReactions = cullReactionsByFlow(allFlows, reachableSpecies, Y_Full, maxFlow);
|
const std::vector<const reaction::Reaction*> finalReactions = cullReactionsByFlow(allFlows, reachableSpecies, composition, maxFlow);
|
||||||
|
|
||||||
finalizeActiveSet(finalReactions);
|
finalizeActiveSet(finalReactions);
|
||||||
|
|
||||||
auto [rescuedReactions, rescuedSpecies] = rescueEdgeSpeciesDestructionChannel(Y_Full, netIn.temperature/1e9, netIn.density, m_activeSpecies, m_activeReactions);
|
auto [rescuedReactions, rescuedSpecies] = rescueEdgeSpeciesDestructionChannel(composition, netIn.temperature/1e9, netIn.density, m_activeSpecies, m_activeReactions);
|
||||||
|
|
||||||
for (const auto& reactionPtr : rescuedReactions) {
|
for (const auto& reactionPtr : rescuedReactions) {
|
||||||
m_activeReactions.add_reaction(*reactionPtr);
|
m_activeReactions.add_reaction(*reactionPtr);
|
||||||
@@ -145,59 +144,46 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::expected<StepDerivatives<double>, expectations::StaleEngineError> AdaptiveEngineView::calculateRHSAndEnergy(
|
std::expected<StepDerivatives<double>, expectations::StaleEngineError> AdaptiveEngineView::calculateRHSAndEnergy(
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
|
// TODO: Think about if I need to reach in and adjust the composition to zero out inactive species.
|
||||||
const auto Y_full = mapCulledToFull(Y_culled);
|
auto result = m_baseEngine.calculateRHSAndEnergy(comp, T9, rho);
|
||||||
|
|
||||||
auto result = m_baseEngine.calculateRHSAndEnergy(Y_full, T9, rho);
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::unexpected{result.error()};
|
return std::unexpected{result.error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto [dydt, nuclearEnergyGenerationRate] = result.value();
|
return result.value();
|
||||||
StepDerivatives<double> culledResults;
|
|
||||||
culledResults.nuclearEnergyGenerationRate = nuclearEnergyGenerationRate;
|
|
||||||
culledResults.dydt = mapFullToCulled(dydt);
|
|
||||||
|
|
||||||
return culledResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EnergyDerivatives AdaptiveEngineView::calculateEpsDerivatives(
|
EnergyDerivatives AdaptiveEngineView::calculateEpsDerivatives(
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
const auto Y_full = mapCulledToFull(Y_culled);
|
return m_baseEngine.calculateEpsDerivatives(comp, T9, rho);
|
||||||
|
|
||||||
return m_baseEngine.calculateEpsDerivatives(Y_full, T9, rho);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdaptiveEngineView::generateJacobianMatrix(
|
void AdaptiveEngineView::generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
const auto Y_full = mapCulledToFull(Y_dynamic);
|
m_baseEngine.generateJacobianMatrix(comp, T9, rho);
|
||||||
|
|
||||||
m_baseEngine.generateJacobianMatrix(Y_full, T9, rho);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double AdaptiveEngineView::getJacobianMatrixEntry(
|
double AdaptiveEngineView::getJacobianMatrixEntry(
|
||||||
const int i_culled,
|
const Species &rowSpecies,
|
||||||
const int j_culled
|
const Species &colSpecies
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
const size_t i_full = mapCulledToFullSpeciesIndex(i_culled);
|
|
||||||
const size_t j_full = mapCulledToFullSpeciesIndex(j_culled);
|
|
||||||
|
|
||||||
return m_baseEngine.getJacobianMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
|
return m_baseEngine.getJacobianMatrixEntry(rowSpecies, colSpecies);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdaptiveEngineView::generateStoichiometryMatrix() {
|
void AdaptiveEngineView::generateStoichiometryMatrix() {
|
||||||
@@ -206,18 +192,16 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AdaptiveEngineView::getStoichiometryMatrixEntry(
|
int AdaptiveEngineView::getStoichiometryMatrixEntry(
|
||||||
const int speciesIndex_culled,
|
const Species &species,
|
||||||
const int reactionIndex_culled
|
const reaction::Reaction& reaction
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
const size_t speciesIndex_full = mapCulledToFullSpeciesIndex(speciesIndex_culled);
|
return m_baseEngine.getStoichiometryMatrixEntry(species, reaction);
|
||||||
const size_t reactionIndex_full = mapCulledToFullReactionIndex(reactionIndex_culled);
|
|
||||||
return m_baseEngine.getStoichiometryMatrixEntry(static_cast<int>(speciesIndex_full), static_cast<int>(reactionIndex_full));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double AdaptiveEngineView::calculateMolarReactionFlow(
|
double AdaptiveEngineView::calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
@@ -227,9 +211,8 @@ namespace gridfire {
|
|||||||
m_logger -> flush_log();
|
m_logger -> flush_log();
|
||||||
throw std::runtime_error("Reaction not found in active reactions: " + std::string(reaction.id()));
|
throw std::runtime_error("Reaction not found in active reactions: " + std::string(reaction.id()));
|
||||||
}
|
}
|
||||||
const auto Y = mapCulledToFull(Y_culled);
|
|
||||||
|
|
||||||
return m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho);
|
return m_baseEngine.calculateMolarReactionFlow(reaction, comp, T9, rho);
|
||||||
}
|
}
|
||||||
|
|
||||||
const reaction::ReactionSet & AdaptiveEngineView::getNetworkReactions() const {
|
const reaction::ReactionSet & AdaptiveEngineView::getNetworkReactions() const {
|
||||||
@@ -242,13 +225,12 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> AdaptiveEngineView::getSpeciesTimescales(
|
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> AdaptiveEngineView::getSpeciesTimescales(
|
||||||
const std::vector<double> &Y_culled,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
const auto Y_full = mapCulledToFull(Y_culled);
|
const auto result = m_baseEngine.getSpeciesTimescales(comp, T9, rho);
|
||||||
const auto result = m_baseEngine.getSpeciesTimescales(Y_full, T9, rho);
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::unexpected{result.error()};
|
return std::unexpected{result.error()};
|
||||||
@@ -270,15 +252,13 @@ namespace gridfire {
|
|||||||
|
|
||||||
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError>
|
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError>
|
||||||
AdaptiveEngineView::getSpeciesDestructionTimescales(
|
AdaptiveEngineView::getSpeciesDestructionTimescales(
|
||||||
const std::vector<double> &Y,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateState();
|
validateState();
|
||||||
|
|
||||||
const std::vector<double> Y_full = mapCulledToFull(Y);
|
const auto result = m_baseEngine.getSpeciesDestructionTimescales(comp, T9, rho);
|
||||||
|
|
||||||
const auto result = m_baseEngine.getSpeciesDestructionTimescales(Y_full, T9, rho);
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::unexpected{result.error()};
|
return std::unexpected{result.error()};
|
||||||
}
|
}
|
||||||
@@ -344,7 +324,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t AdaptiveEngineView::mapCulledToFullSpeciesIndex(size_t culledSpeciesIndex) const {
|
size_t AdaptiveEngineView::mapCulledToFullSpeciesIndex(size_t culledSpeciesIndex) const {
|
||||||
if (culledSpeciesIndex < 0 || culledSpeciesIndex >= m_speciesIndexMap.size()) {
|
if (culledSpeciesIndex >= m_speciesIndexMap.size()) {
|
||||||
LOG_ERROR(m_logger, "Culled index {} is out of bounds for species index map of size {}.", culledSpeciesIndex, m_speciesIndexMap.size());
|
LOG_ERROR(m_logger, "Culled index {} is out of bounds for species index map of size {}.", culledSpeciesIndex, m_speciesIndexMap.size());
|
||||||
m_logger->flush_log();
|
m_logger->flush_log();
|
||||||
throw std::out_of_range("Culled index " + std::to_string(culledSpeciesIndex) + " is out of bounds for species index map of size " + std::to_string(m_speciesIndexMap.size()) + ".");
|
throw std::out_of_range("Culled index " + std::to_string(culledSpeciesIndex) + " is out of bounds for species index map of size " + std::to_string(m_speciesIndexMap.size()) + ".");
|
||||||
@@ -353,7 +333,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t AdaptiveEngineView::mapCulledToFullReactionIndex(size_t culledReactionIndex) const {
|
size_t AdaptiveEngineView::mapCulledToFullReactionIndex(size_t culledReactionIndex) const {
|
||||||
if (culledReactionIndex < 0 || culledReactionIndex >= m_reactionIndexMap.size()) {
|
if (culledReactionIndex >= m_reactionIndexMap.size()) {
|
||||||
LOG_ERROR(m_logger, "Culled index {} is out of bounds for reaction index map of size {}.", culledReactionIndex, m_reactionIndexMap.size());
|
LOG_ERROR(m_logger, "Culled index {} is out of bounds for reaction index map of size {}.", culledReactionIndex, m_reactionIndexMap.size());
|
||||||
m_logger->flush_log();
|
m_logger->flush_log();
|
||||||
throw std::out_of_range("Culled index " + std::to_string(culledReactionIndex) + " is out of bounds for reaction index map of size " + std::to_string(m_reactionIndexMap.size()) + ".");
|
throw std::out_of_range("Culled index " + std::to_string(culledReactionIndex) + " is out of bounds for reaction index map of size " + std::to_string(m_reactionIndexMap.size()) + ".");
|
||||||
@@ -369,21 +349,17 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Change this to use a return value instead of an output parameter.
|
std::pair<std::vector<AdaptiveEngineView::ReactionFlow>, fourdst::composition::Composition> AdaptiveEngineView::calculateAllReactionFlows(
|
||||||
std::vector<AdaptiveEngineView::ReactionFlow> AdaptiveEngineView::calculateAllReactionFlows(
|
const NetIn &netIn
|
||||||
const NetIn &netIn,
|
|
||||||
std::vector<double> &out_Y_Full
|
|
||||||
) const {
|
) const {
|
||||||
const auto& fullSpeciesList = m_baseEngine.getNetworkSpecies();
|
const auto& fullSpeciesList = m_baseEngine.getNetworkSpecies();
|
||||||
out_Y_Full.clear();
|
fourdst::composition::Composition composition = netIn.composition;
|
||||||
out_Y_Full.reserve(fullSpeciesList.size());
|
|
||||||
|
|
||||||
for (const auto& species: fullSpeciesList) {
|
for (const auto& species: fullSpeciesList) {
|
||||||
if (netIn.composition.contains(species)) {
|
if (!netIn.composition.contains(species)) {
|
||||||
out_Y_Full.push_back(netIn.composition.getMolarAbundance(std::string(species.name())));
|
|
||||||
} else {
|
|
||||||
LOG_TRACE_L2(m_logger, "Species '{}' not found in composition. Setting abundance to 0.0.", species.name());
|
LOG_TRACE_L2(m_logger, "Species '{}' not found in composition. Setting abundance to 0.0.", species.name());
|
||||||
out_Y_Full.push_back(0.0);
|
composition.registerSpecies(species);
|
||||||
|
composition.setMassFraction(species, 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,11 +370,11 @@ namespace gridfire {
|
|||||||
const auto& fullReactionSet = m_baseEngine.getNetworkReactions();
|
const auto& fullReactionSet = m_baseEngine.getNetworkReactions();
|
||||||
reactionFlows.reserve(fullReactionSet.size());
|
reactionFlows.reserve(fullReactionSet.size());
|
||||||
for (const auto& reaction : fullReactionSet) {
|
for (const auto& reaction : fullReactionSet) {
|
||||||
const double flow = m_baseEngine.calculateMolarReactionFlow(*reaction, out_Y_Full, T9, rho);
|
const double flow = m_baseEngine.calculateMolarReactionFlow(*reaction, composition, T9, rho);
|
||||||
reactionFlows.push_back({reaction.get(), flow});
|
reactionFlows.push_back({reaction.get(), flow});
|
||||||
LOG_TRACE_L1(m_logger, "Reaction '{}' has flow rate: {:0.3E} [mol/s/g]", reaction->id(), flow);
|
LOG_TRACE_L1(m_logger, "Reaction '{}' has flow rate: {:0.3E} [mol/s/g]", reaction->id(), flow);
|
||||||
}
|
}
|
||||||
return reactionFlows;
|
return {reactionFlows, composition};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<Species> AdaptiveEngineView::findReachableSpecies(
|
std::unordered_set<Species> AdaptiveEngineView::findReachableSpecies(
|
||||||
@@ -447,7 +423,7 @@ namespace gridfire {
|
|||||||
std::vector<const reaction::Reaction *> AdaptiveEngineView::cullReactionsByFlow(
|
std::vector<const reaction::Reaction *> AdaptiveEngineView::cullReactionsByFlow(
|
||||||
const std::vector<ReactionFlow> &allFlows,
|
const std::vector<ReactionFlow> &allFlows,
|
||||||
const std::unordered_set<fourdst::atomic::Species> &reachableSpecies,
|
const std::unordered_set<fourdst::atomic::Species> &reachableSpecies,
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
const double maxFlow
|
const double maxFlow
|
||||||
) const {
|
) const {
|
||||||
LOG_TRACE_L1(m_logger, "Culling reactions based on flow rates...");
|
LOG_TRACE_L1(m_logger, "Culling reactions based on flow rates...");
|
||||||
@@ -464,9 +440,7 @@ namespace gridfire {
|
|||||||
bool zero_flow_due_to_reachable_reactants = false;
|
bool zero_flow_due_to_reachable_reactants = false;
|
||||||
if (flowRate < 1e-99 && flowRate > 0.0) {
|
if (flowRate < 1e-99 && flowRate > 0.0) {
|
||||||
for (const auto& reactant: reactionPtr->reactants()) {
|
for (const auto& reactant: reactionPtr->reactants()) {
|
||||||
const auto it = std::ranges::find(m_baseEngine.getNetworkSpecies(), reactant);
|
if (comp.getMolarAbundance(reactant) < 1e-99 && reachableSpecies.contains(reactant)) {
|
||||||
const size_t index = std::distance(m_baseEngine.getNetworkSpecies().begin(), it);
|
|
||||||
if (Y_full[index] < 1e-99 && reachableSpecies.contains(reactant)) {
|
|
||||||
LOG_TRACE_L1(m_logger, "Maintaining reaction '{}' with low flow ({:0.3E} [mol/s/g]) due to reachable reactant '{}'.", reactionPtr->id(), flowRate, reactant.name());
|
LOG_TRACE_L1(m_logger, "Maintaining reaction '{}' with low flow ({:0.3E} [mol/s/g]) due to reachable reactant '{}'.", reactionPtr->id(), flowRate, reactant.name());
|
||||||
zero_flow_due_to_reachable_reactants = true;
|
zero_flow_due_to_reachable_reactants = true;
|
||||||
break;
|
break;
|
||||||
@@ -488,13 +462,13 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdaptiveEngineView::RescueSet AdaptiveEngineView::rescueEdgeSpeciesDestructionChannel(
|
AdaptiveEngineView::RescueSet AdaptiveEngineView::rescueEdgeSpeciesDestructionChannel(
|
||||||
const std::vector<double> &Y_full,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho,
|
const double rho,
|
||||||
const std::vector<Species> &activeSpecies,
|
const std::vector<Species> &activeSpecies,
|
||||||
const reaction::ReactionSet &activeReactions
|
const reaction::ReactionSet &activeReactions
|
||||||
) const {
|
) const {
|
||||||
const auto result = m_baseEngine.getSpeciesTimescales(Y_full, T9, rho);
|
const auto result = m_baseEngine.getSpeciesTimescales(comp, T9, rho);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG_ERROR(m_logger, "Failed to get species timescales due to stale engine state.");
|
LOG_ERROR(m_logger, "Failed to get species timescales due to stale engine state.");
|
||||||
throw exceptions::StaleEngineError("Failed to get species timescales");
|
throw exceptions::StaleEngineError("Failed to get species timescales");
|
||||||
@@ -565,8 +539,23 @@ namespace gridfire {
|
|||||||
allOtherReactantsAreAvailable = false;
|
allOtherReactantsAreAvailable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allOtherReactantsAreAvailable && speciesToCheckIsConsumed) {
|
if (allOtherReactantsAreAvailable) {
|
||||||
double rate = reaction->calculate_rate(T9, rho, Y_full);
|
std::vector<double> Y = comp.getMolarAbundanceVector();
|
||||||
|
|
||||||
|
const double Ye = comp.getElectronAbundance();
|
||||||
|
// TODO: This is a dummy placeholder which must be replaced with an EOS call
|
||||||
|
const double mue = 5.0e-3 * std::pow(rho * Ye, 1.0 / 3.0) + 0.5 * T9;
|
||||||
|
|
||||||
|
std::unordered_map<Species, double> speciesMassMap;
|
||||||
|
for (const auto &entry: comp | std::views::values) {
|
||||||
|
speciesMassMap[entry.isotope()] = entry.isotope().mass();
|
||||||
|
}
|
||||||
|
std::unordered_map<size_t, Species> speciesIndexMap;
|
||||||
|
for (const auto& entry: comp | std::views::values) {
|
||||||
|
size_t distance = std::distance(speciesMassMap.begin(), speciesMassMap.find(entry.isotope()));
|
||||||
|
speciesIndexMap.emplace(distance, entry.isotope());
|
||||||
|
}
|
||||||
|
double rate = reaction->calculate_rate(T9, rho, Ye, mue, Y, speciesIndexMap);
|
||||||
if (rate > maxSpeciesConsumptionRate) {
|
if (rate > maxSpeciesConsumptionRate) {
|
||||||
maxSpeciesConsumptionRate = rate;
|
maxSpeciesConsumptionRate = rate;
|
||||||
reactionsToRescue[species] = reaction.get();
|
reactionsToRescue[species] = reaction.get();
|
||||||
|
|||||||
@@ -28,58 +28,48 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::expected<StepDerivatives<double>, expectations::StaleEngineError> DefinedEngineView::calculateRHSAndEnergy(
|
std::expected<StepDerivatives<double>, expectations::StaleEngineError> DefinedEngineView::calculateRHSAndEnergy(
|
||||||
const std::vector<double> &Y_defined,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const auto Y_full = mapViewToFull(Y_defined);
|
const auto result = m_baseEngine.calculateRHSAndEnergy(comp, T9, rho);
|
||||||
const auto result = m_baseEngine.calculateRHSAndEnergy(Y_full, T9, rho);
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::unexpected{result.error()};
|
return std::unexpected{result.error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto [dydt, nuclearEnergyGenerationRate] = result.value();
|
return result.value();
|
||||||
StepDerivatives<double> definedResults;
|
|
||||||
definedResults.nuclearEnergyGenerationRate = nuclearEnergyGenerationRate;
|
|
||||||
definedResults.dydt = mapFullToView(dydt);
|
|
||||||
return definedResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EnergyDerivatives DefinedEngineView::calculateEpsDerivatives(
|
EnergyDerivatives DefinedEngineView::calculateEpsDerivatives(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const auto Y_full = mapViewToFull(Y_dynamic);
|
return m_baseEngine.calculateEpsDerivatives(comp, T9, rho);
|
||||||
return m_baseEngine.calculateEpsDerivatives(Y_full, T9, rho);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinedEngineView::generateJacobianMatrix(
|
void DefinedEngineView::generateJacobianMatrix(
|
||||||
const std::vector<double> &Y_dynamic,
|
const fourdst::composition::Composition& comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const auto Y_full = mapViewToFull(Y_dynamic);
|
m_baseEngine.generateJacobianMatrix(comp, T9, rho);
|
||||||
m_baseEngine.generateJacobianMatrix(Y_full, T9, rho);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double DefinedEngineView::getJacobianMatrixEntry(
|
double DefinedEngineView::getJacobianMatrixEntry(
|
||||||
const int i_defined,
|
const Species& rowSpecies,
|
||||||
const int j_defined
|
const Species& colSpecies
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const size_t i_full = mapViewToFullSpeciesIndex(i_defined);
|
return m_baseEngine.getJacobianMatrixEntry(rowSpecies, colSpecies);
|
||||||
const size_t j_full = mapViewToFullSpeciesIndex(j_defined);
|
|
||||||
|
|
||||||
return m_baseEngine.getJacobianMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinedEngineView::generateStoichiometryMatrix() {
|
void DefinedEngineView::generateStoichiometryMatrix() {
|
||||||
@@ -89,19 +79,17 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int DefinedEngineView::getStoichiometryMatrixEntry(
|
int DefinedEngineView::getStoichiometryMatrixEntry(
|
||||||
const int speciesIndex_defined,
|
const Species& species,
|
||||||
const int reactionIndex_defined
|
const reaction::Reaction& reaction
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const size_t i_full = mapViewToFullSpeciesIndex(speciesIndex_defined);
|
return m_baseEngine.getStoichiometryMatrixEntry(species, reaction);
|
||||||
const size_t j_full = mapViewToFullReactionIndex(reactionIndex_defined);
|
|
||||||
return m_baseEngine.getStoichiometryMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double DefinedEngineView::calculateMolarReactionFlow(
|
double DefinedEngineView::calculateMolarReactionFlow(
|
||||||
const reaction::Reaction &reaction,
|
const reaction::Reaction &reaction,
|
||||||
const std::vector<double> &Y_defined,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
@@ -112,8 +100,7 @@ namespace gridfire {
|
|||||||
m_logger -> flush_log();
|
m_logger -> flush_log();
|
||||||
throw std::runtime_error("Reaction not found in active reactions: " + std::string(reaction.id()));
|
throw std::runtime_error("Reaction not found in active reactions: " + std::string(reaction.id()));
|
||||||
}
|
}
|
||||||
const auto Y_full = mapViewToFull(Y_defined);
|
return m_baseEngine.calculateMolarReactionFlow(reaction, comp, T9, rho);
|
||||||
return m_baseEngine.calculateMolarReactionFlow(reaction, Y_full, T9, rho);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const reaction::ReactionSet & DefinedEngineView::getNetworkReactions() const {
|
const reaction::ReactionSet & DefinedEngineView::getNetworkReactions() const {
|
||||||
@@ -131,14 +118,13 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> DefinedEngineView::getSpeciesTimescales(
|
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> DefinedEngineView::getSpeciesTimescales(
|
||||||
const std::vector<double> &Y_defined,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const auto Y_full = mapViewToFull(Y_defined);
|
const auto result = m_baseEngine.getSpeciesTimescales(comp, T9, rho);
|
||||||
const auto result = m_baseEngine.getSpeciesTimescales(Y_full, T9, rho);
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::unexpected{result.error()};
|
return std::unexpected{result.error()};
|
||||||
}
|
}
|
||||||
@@ -155,14 +141,13 @@ namespace gridfire {
|
|||||||
|
|
||||||
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError>
|
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError>
|
||||||
DefinedEngineView::getSpeciesDestructionTimescales(
|
DefinedEngineView::getSpeciesDestructionTimescales(
|
||||||
const std::vector<double> &Y_defined,
|
const fourdst::composition::Composition &comp,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) const {
|
) const {
|
||||||
validateNetworkState();
|
validateNetworkState();
|
||||||
|
|
||||||
const auto Y_full = mapViewToFull(Y_defined);
|
const auto result = m_baseEngine.getSpeciesDestructionTimescales(comp, T9, rho);
|
||||||
const auto result = m_baseEngine.getSpeciesDestructionTimescales(Y_full, T9, rho);
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::unexpected{result.error()};
|
return std::unexpected{result.error()};
|
||||||
@@ -304,7 +289,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t DefinedEngineView::mapViewToFullSpeciesIndex(size_t culledSpeciesIndex) const {
|
size_t DefinedEngineView::mapViewToFullSpeciesIndex(size_t culledSpeciesIndex) const {
|
||||||
if (culledSpeciesIndex < 0 || culledSpeciesIndex >= m_speciesIndexMap.size()) {
|
if (culledSpeciesIndex >= m_speciesIndexMap.size()) {
|
||||||
LOG_ERROR(m_logger, "Defined index {} is out of bounds for species index map of size {}.", culledSpeciesIndex, m_speciesIndexMap.size());
|
LOG_ERROR(m_logger, "Defined index {} is out of bounds for species index map of size {}.", culledSpeciesIndex, m_speciesIndexMap.size());
|
||||||
m_logger->flush_log();
|
m_logger->flush_log();
|
||||||
throw std::out_of_range("Defined index " + std::to_string(culledSpeciesIndex) + " is out of bounds for species index map of size " + std::to_string(m_speciesIndexMap.size()) + ".");
|
throw std::out_of_range("Defined index " + std::to_string(culledSpeciesIndex) + " is out of bounds for species index map of size " + std::to_string(m_speciesIndexMap.size()) + ".");
|
||||||
@@ -313,7 +298,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t DefinedEngineView::mapViewToFullReactionIndex(size_t culledReactionIndex) const {
|
size_t DefinedEngineView::mapViewToFullReactionIndex(size_t culledReactionIndex) const {
|
||||||
if (culledReactionIndex < 0 || culledReactionIndex >= m_reactionIndexMap.size()) {
|
if (culledReactionIndex >= m_reactionIndexMap.size()) {
|
||||||
LOG_ERROR(m_logger, "Defined index {} is out of bounds for reaction index map of size {}.", culledReactionIndex, m_reactionIndexMap.size());
|
LOG_ERROR(m_logger, "Defined index {} is out of bounds for reaction index map of size {}.", culledReactionIndex, m_reactionIndexMap.size());
|
||||||
m_logger->flush_log();
|
m_logger->flush_log();
|
||||||
throw std::out_of_range("Defined index " + std::to_string(culledReactionIndex) + " is out of bounds for reaction index map of size " + std::to_string(m_reactionIndexMap.size()) + ".");
|
throw std::out_of_range("Defined index " + std::to_string(culledReactionIndex) + " is out of bounds for reaction index map of size " + std::to_string(m_reactionIndexMap.size()) + ".");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,7 @@ namespace gridfire::io {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
SimpleReactionListFileParser::SimpleReactionListFileParser() {}
|
SimpleReactionListFileParser::SimpleReactionListFileParser() = default;
|
||||||
|
|
||||||
ParsedNetworkData SimpleReactionListFileParser::parse(const std::string& filename) const {
|
ParsedNetworkData SimpleReactionListFileParser::parse(const std::string& filename) const {
|
||||||
LOG_TRACE_L1(m_logger, "Parsing simple reaction list file: {}", filename);
|
LOG_TRACE_L1(m_logger, "Parsing simple reaction list file: {}", filename);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
//
|
//
|
||||||
// *********************************************************************** */
|
// *********************************************************************** */
|
||||||
#include "gridfire/network.h"
|
#include "gridfire/network.h"
|
||||||
#include "gridfire/reaction/reaclib.h"
|
|
||||||
#include "gridfire/reaction/reaction.h"
|
#include "gridfire/reaction/reaction.h"
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
@@ -74,7 +73,7 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
const auto ritr = std::find_if(str.rbegin(), std::string::const_reverse_iterator(startIt),
|
const auto ritr = std::find_if(str.rbegin(), std::string::const_reverse_iterator(startIt),
|
||||||
[](const unsigned char ch){ return !std::isspace(ch); });
|
[](const unsigned char ch){ return !std::isspace(ch); });
|
||||||
return std::string(startIt, ritr.base());
|
return {startIt, ritr.base()};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|||||||
@@ -45,15 +45,35 @@ namespace gridfire::reaction {
|
|||||||
m_rateCoefficients(sets),
|
m_rateCoefficients(sets),
|
||||||
m_reverse(reverse) {}
|
m_reverse(reverse) {}
|
||||||
|
|
||||||
double ReaclibReaction::calculate_rate(const double T9, const double rho, const std::vector<double>& Y) const {
|
double ReaclibReaction::calculate_rate(
|
||||||
|
const double T9,
|
||||||
|
const double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue,
|
||||||
|
const std::vector<double> &Y,
|
||||||
|
const std::unordered_map<size_t, Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
return calculate_rate<double>(T9);
|
return calculate_rate<double>(T9);
|
||||||
}
|
}
|
||||||
|
|
||||||
CppAD::AD<double> ReaclibReaction::calculate_rate(const CppAD::AD<double> T9, const CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const {
|
CppAD::AD<double> ReaclibReaction::calculate_rate(
|
||||||
|
const CppAD::AD<double> T9,
|
||||||
|
const CppAD::AD<double> rho,
|
||||||
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue,
|
||||||
|
const std::vector<CppAD::AD<double>>& Y,
|
||||||
|
const std::unordered_map<size_t, Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
return calculate_rate<CppAD::AD<double>>(T9);
|
return calculate_rate<CppAD::AD<double>>(T9);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ReaclibReaction::calculate_forward_rate_log_derivative(const double T9, const double rho, const std::vector<double>& Y) const {
|
double ReaclibReaction::calculate_forward_rate_log_derivative(
|
||||||
|
const double T9,
|
||||||
|
const double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue,
|
||||||
|
const fourdst::composition::Composition& comp
|
||||||
|
) const {
|
||||||
constexpr double r_p13 = 1.0 / 3.0;
|
constexpr double r_p13 = 1.0 / 3.0;
|
||||||
constexpr double r_p53 = 5.0 / 3.0;
|
constexpr double r_p53 = 5.0 / 3.0;
|
||||||
constexpr double r_p23 = 2.0 / 3.0;
|
constexpr double r_p23 = 2.0 / 3.0;
|
||||||
@@ -80,21 +100,11 @@ namespace gridfire::reaction {
|
|||||||
|
|
||||||
|
|
||||||
bool ReaclibReaction::contains_reactant(const Species& species) const {
|
bool ReaclibReaction::contains_reactant(const Species& species) const {
|
||||||
for (const auto& reactant : m_reactants) {
|
return std::ranges::any_of(m_reactants, [&](const Species& r) { return r == species; });
|
||||||
if (reactant == species) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReaclibReaction::contains_product(const Species& species) const {
|
bool ReaclibReaction::contains_product(const Species& species) const {
|
||||||
for (const auto& product : m_products) {
|
return std::ranges::any_of(m_products, [&](const Species& p) { return p == species; });
|
||||||
if (product == species) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<Species> ReaclibReaction::all_species() const {
|
std::unordered_set<Species> ReaclibReaction::all_species() const {
|
||||||
@@ -224,11 +234,20 @@ namespace gridfire::reaction {
|
|||||||
m_rates.push_back(reaction.rateCoefficients());
|
m_rates.push_back(reaction.rateCoefficients());
|
||||||
}
|
}
|
||||||
|
|
||||||
double LogicalReaclibReaction::calculate_rate(const double T9, const double rho, const std::vector<double>& Y) const {
|
double LogicalReaclibReaction::calculate_rate(
|
||||||
|
const double T9,
|
||||||
|
const double rho,
|
||||||
|
double Ye,
|
||||||
|
double mue, const std::vector<double> &Y, const std::unordered_map<size_t, Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
return calculate_rate<double>(T9);
|
return calculate_rate<double>(T9);
|
||||||
}
|
}
|
||||||
|
|
||||||
double LogicalReaclibReaction::calculate_forward_rate_log_derivative(const double T9, const double rho, const std::vector<double>& Y) const {
|
double LogicalReaclibReaction::calculate_forward_rate_log_derivative(
|
||||||
|
const double T9,
|
||||||
|
const double rho,
|
||||||
|
double Ye, double mue, const fourdst::composition::Composition& comp
|
||||||
|
) const {
|
||||||
constexpr double r_p13 = 1.0 / 3.0;
|
constexpr double r_p13 = 1.0 / 3.0;
|
||||||
constexpr double r_p53 = 5.0 / 3.0;
|
constexpr double r_p53 = 5.0 / 3.0;
|
||||||
constexpr double r_p23 = 2.0 / 3.0;
|
constexpr double r_p23 = 2.0 / 3.0;
|
||||||
@@ -286,7 +305,8 @@ namespace gridfire::reaction {
|
|||||||
CppAD::AD<double> LogicalReaclibReaction::calculate_rate(
|
CppAD::AD<double> LogicalReaclibReaction::calculate_rate(
|
||||||
const CppAD::AD<double> T9,
|
const CppAD::AD<double> T9,
|
||||||
const CppAD::AD<double> rho,
|
const CppAD::AD<double> rho,
|
||||||
const std::vector<CppAD::AD<double>>& Y
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue, const std::vector<CppAD::AD<double>>& Y, const std::unordered_map<size_t, Species>& index_to_species_map
|
||||||
) const {
|
) const {
|
||||||
return calculate_rate<CppAD::AD<double>>(T9);
|
return calculate_rate<CppAD::AD<double>>(T9);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,20 +7,81 @@
|
|||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <expected>
|
#include <expected>
|
||||||
|
#include <vector>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
#define GRIDFIRE_WEAK_REACTION_LIB_SENTINEL -60.0
|
#include "gridfire/reaction/weak/weak_interpolator.h"
|
||||||
|
|
||||||
|
#include "xxhash64.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
fourdst::atomic::Species resolve_weak_product(
|
||||||
|
const gridfire::rates::weak::WeakReactionType type,
|
||||||
|
const fourdst::atomic::Species& reactant
|
||||||
|
) {
|
||||||
|
using namespace fourdst::atomic;
|
||||||
|
using namespace gridfire::rates::weak;
|
||||||
|
|
||||||
|
std::optional<Species> product; // Use optional so that we can start in a valid "null" state
|
||||||
|
switch (type) {
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY:
|
||||||
|
product = az_to_species(reactant.a(), reactant.z() + 1);
|
||||||
|
return product.value();
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY:
|
||||||
|
product = az_to_species(reactant.a(), reactant.z() - 1);
|
||||||
|
return product.value();
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE:
|
||||||
|
product = az_to_species(reactant.a(), reactant.z() - 1);
|
||||||
|
return product.value();
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE:
|
||||||
|
product = az_to_species(reactant.a(), reactant.z() + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!product.has_value()) {
|
||||||
|
throw std::runtime_error("Failed to resolve weak reaction product for reactant: " + std::string(reactant.name()));
|
||||||
|
}
|
||||||
|
return product.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string resolve_weak_id(
|
||||||
|
const gridfire::rates::weak::WeakReactionType type,
|
||||||
|
const fourdst::atomic::Species& reactant,
|
||||||
|
const fourdst::atomic::Species& product
|
||||||
|
) {
|
||||||
|
using namespace gridfire::rates::weak;
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
switch (type) {
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY:
|
||||||
|
id = std::format("{}(,ν|)e-,{}", reactant.name(), product.name());
|
||||||
|
break;
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY:
|
||||||
|
id = std::format("{}(,ν)e+,{}", reactant.name(), product.name());
|
||||||
|
break;
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE:
|
||||||
|
id = std::format("{}(e-,ν){}", reactant.name(), product.name());
|
||||||
|
break;
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE:
|
||||||
|
id = std::format("{}(e+,ν|){}", reactant.name(), product.name());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace gridfire::rates::weak {
|
namespace gridfire::rates::weak {
|
||||||
WeakReactionMap::WeakReactionMap() {
|
WeakReactionMap::WeakReactionMap() {
|
||||||
using namespace fourdst::atomic;
|
using namespace fourdst::atomic;
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable once CppUseStructuredBinding
|
||||||
for (const auto& weak_reaction_record : UNIFIED_WEAK_DATA) {
|
for (const auto& weak_reaction_record : UNIFIED_WEAK_DATA) {
|
||||||
Species species = az_to_species(weak_reaction_record.A, weak_reaction_record.Z);
|
Species species = az_to_species(weak_reaction_record.A, weak_reaction_record.Z);
|
||||||
|
|
||||||
if (weak_reaction_record.log_beta_minus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
if (weak_reaction_record.log_beta_minus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||||
m_weak_network[species].push_back(
|
m_weak_network[species].push_back(
|
||||||
WeakReaction{
|
WeakReactionEntry{
|
||||||
WeakReactionType::BETA_MINUS_DECAY,
|
WeakReactionType::BETA_MINUS_DECAY,
|
||||||
weak_reaction_record.t9,
|
weak_reaction_record.t9,
|
||||||
weak_reaction_record.log_rhoye,
|
weak_reaction_record.log_rhoye,
|
||||||
@@ -32,7 +93,7 @@ namespace gridfire::rates::weak {
|
|||||||
}
|
}
|
||||||
if (weak_reaction_record.log_beta_plus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
if (weak_reaction_record.log_beta_plus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||||
m_weak_network[species].push_back(
|
m_weak_network[species].push_back(
|
||||||
WeakReaction{
|
WeakReactionEntry{
|
||||||
WeakReactionType::BETA_PLUS_DECAY,
|
WeakReactionType::BETA_PLUS_DECAY,
|
||||||
weak_reaction_record.t9,
|
weak_reaction_record.t9,
|
||||||
weak_reaction_record.log_rhoye,
|
weak_reaction_record.log_rhoye,
|
||||||
@@ -44,7 +105,7 @@ namespace gridfire::rates::weak {
|
|||||||
}
|
}
|
||||||
if (weak_reaction_record.log_electron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
if (weak_reaction_record.log_electron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||||
m_weak_network[species].push_back(
|
m_weak_network[species].push_back(
|
||||||
WeakReaction{
|
WeakReactionEntry{
|
||||||
WeakReactionType::ELECTRON_CAPTURE,
|
WeakReactionType::ELECTRON_CAPTURE,
|
||||||
weak_reaction_record.t9,
|
weak_reaction_record.t9,
|
||||||
weak_reaction_record.log_rhoye,
|
weak_reaction_record.log_rhoye,
|
||||||
@@ -56,7 +117,7 @@ namespace gridfire::rates::weak {
|
|||||||
}
|
}
|
||||||
if (weak_reaction_record.log_positron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
if (weak_reaction_record.log_positron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||||
m_weak_network[species].push_back(
|
m_weak_network[species].push_back(
|
||||||
WeakReaction{
|
WeakReactionEntry{
|
||||||
WeakReactionType::POSITRON_CAPTURE,
|
WeakReactionType::POSITRON_CAPTURE,
|
||||||
weak_reaction_record.t9,
|
weak_reaction_record.t9,
|
||||||
weak_reaction_record.log_rhoye,
|
weak_reaction_record.log_rhoye,
|
||||||
@@ -69,26 +130,391 @@ namespace gridfire::rates::weak {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WeakReaction> WeakReactionMap::get_all_reactions() const {
|
std::vector<WeakReactionEntry> WeakReactionMap::get_all_reactions() const {
|
||||||
std::vector<WeakReaction> reactions;
|
std::vector<WeakReactionEntry> reactions;
|
||||||
for (const auto &species_reactions: m_weak_network | std::views::values) {
|
for (const auto &species_reactions: m_weak_network | std::views::values) {
|
||||||
reactions.insert(reactions.end(), species_reactions.begin(), species_reactions.end());
|
reactions.insert(reactions.end(), species_reactions.begin(), species_reactions.end());
|
||||||
}
|
}
|
||||||
return reactions;
|
return reactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::expected<std::vector<WeakReaction>, bool> WeakReactionMap::get_species_reactions(const fourdst::atomic::Species &species) const {
|
std::expected<std::vector<WeakReactionEntry>, WeakMapError> WeakReactionMap::get_species_reactions(
|
||||||
|
const fourdst::atomic::Species &species) const {
|
||||||
if (m_weak_network.contains(species)) {
|
if (m_weak_network.contains(species)) {
|
||||||
return m_weak_network.at(species);
|
return m_weak_network.at(species);
|
||||||
}
|
}
|
||||||
return std::unexpected(false);
|
return std::unexpected(WeakMapError::SPECIES_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::expected<std::vector<WeakReaction>, bool> WeakReactionMap::get_species_reactions(const std::string &species_name) const {
|
std::expected<std::vector<WeakReactionEntry>, WeakMapError> WeakReactionMap::get_species_reactions(
|
||||||
fourdst::atomic::Species species = fourdst::atomic::species.at(species_name);
|
const std::string &species_name) const {
|
||||||
|
const fourdst::atomic::Species species = fourdst::atomic::species.at(species_name);
|
||||||
if (m_weak_network.contains(species)) {
|
if (m_weak_network.contains(species)) {
|
||||||
return m_weak_network.at(species);
|
return m_weak_network.at(species);
|
||||||
}
|
}
|
||||||
return std::unexpected(false);
|
return std::unexpected(WeakMapError::SPECIES_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WeakReaction::WeakReaction(
|
||||||
|
const fourdst::atomic::Species &species,
|
||||||
|
const WeakReactionType type,
|
||||||
|
const WeakRateInterpolator &interpolator
|
||||||
|
) :
|
||||||
|
m_reactant(species),
|
||||||
|
m_product(resolve_weak_product(type, species)),
|
||||||
|
m_reactant_a(species.a()),
|
||||||
|
m_reactant_z(species.z()),
|
||||||
|
m_product_a(m_product.a()),
|
||||||
|
m_product_z(m_product.z()),
|
||||||
|
m_id(resolve_weak_id(type, species, m_product)),
|
||||||
|
m_type(type),
|
||||||
|
m_interpolator(interpolator),
|
||||||
|
m_atomic(m_interpolator, m_reactant_a, m_reactant_z, m_type) {}
|
||||||
|
|
||||||
|
double WeakReaction::calculate_rate(
|
||||||
|
const double T9,
|
||||||
|
const double rho,
|
||||||
|
const double Ye,
|
||||||
|
const double mue,
|
||||||
|
const std::vector<double> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
|
return calculate_rate<double>(T9, rho, Ye, mue, Y, index_to_species_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
CppAD::AD<double> WeakReaction::calculate_rate(
|
||||||
|
CppAD::AD<double> T9,
|
||||||
|
CppAD::AD<double> rho,
|
||||||
|
CppAD::AD<double> Ye,
|
||||||
|
CppAD::AD<double> mue, const std::vector<CppAD::AD<double>> &Y, const std::unordered_map<size_t,fourdst::atomic::Species>& index_to_species_map
|
||||||
|
) const {
|
||||||
|
return static_cast<CppAD::AD<double>>(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::contains(const fourdst::atomic::Species &species) const {
|
||||||
|
return contains_reactant(species) || contains_product(species);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::contains_reactant(const fourdst::atomic::Species& species) const {
|
||||||
|
if (m_reactant == species) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::contains_product(const fourdst::atomic::Species &species) const {
|
||||||
|
if (m_product == species) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<fourdst::atomic::Species> WeakReaction::all_species() const {
|
||||||
|
return {m_reactant, m_product};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<fourdst::atomic::Species> WeakReaction::reactant_species() const {
|
||||||
|
return {m_reactant};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<fourdst::atomic::Species> WeakReaction::product_species() const {
|
||||||
|
return {m_product};
|
||||||
|
}
|
||||||
|
|
||||||
|
int WeakReaction::stoichiometry(const fourdst::atomic::Species &species) const {
|
||||||
|
if (species == m_reactant) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (species == m_product) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<fourdst::atomic::Species, int> WeakReaction::stoichiometry() const {
|
||||||
|
return {
|
||||||
|
{m_reactant, -1},
|
||||||
|
{m_product, 1}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t WeakReaction::hash(const uint64_t seed) const {
|
||||||
|
const std::string reaction_string = std::format(
|
||||||
|
"{}:{}({})",
|
||||||
|
m_reactant.name(),
|
||||||
|
m_product.name(),
|
||||||
|
static_cast<int>(m_type)
|
||||||
|
);
|
||||||
|
return XXHash64::hash(reaction_string.data(), reaction_string.size(), seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
double WeakReaction::qValue() const {
|
||||||
|
// We ignore neutrino mass as it is negligible compared to other masses here.
|
||||||
|
double Q_MeV = 0.0;
|
||||||
|
|
||||||
|
const double parentMass_u = m_reactant.mass();
|
||||||
|
const double daughterMass_u = m_product.mass();
|
||||||
|
const double electronMass_MeV = m_constants.electronMassMeV;
|
||||||
|
|
||||||
|
const double nuclearMassDiff_MeV = (parentMass_u - daughterMass_u) * m_constants.u_to_MeV;
|
||||||
|
switch (m_type) {
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY:
|
||||||
|
Q_MeV = nuclearMassDiff_MeV - 2.0 * electronMass_MeV;
|
||||||
|
break;
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE:
|
||||||
|
Q_MeV = nuclearMassDiff_MeV + 2.0 * electronMass_MeV;
|
||||||
|
break;
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY:
|
||||||
|
Q_MeV = nuclearMassDiff_MeV;
|
||||||
|
break;
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE:
|
||||||
|
Q_MeV = nuclearMassDiff_MeV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Q_MeV;
|
||||||
|
}
|
||||||
|
|
||||||
|
double WeakReaction::calculate_energy_generation_rate(
|
||||||
|
const double T9,
|
||||||
|
const double rho,
|
||||||
|
const double Ye,
|
||||||
|
const double mue,
|
||||||
|
const std::vector<double> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species> &index_to_species_map
|
||||||
|
) const {
|
||||||
|
std::expected<WeakRatePayload, InterpolationError> rates = m_interpolator.get_rates(
|
||||||
|
static_cast<uint16_t>(m_reactant_a),
|
||||||
|
static_cast<uint8_t>(m_reactant_z),
|
||||||
|
T9,
|
||||||
|
std::log10(rho * Ye),
|
||||||
|
mue
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!rates.has_value()) {
|
||||||
|
const InterpolationErrorType type = rates.error().type;
|
||||||
|
const std::string msg = std::format(
|
||||||
|
"Failed to interpolate weak rate for (A={}, Z={}) at T9={}, log10(rho*Ye)={}, mu_e={} with error: {}",
|
||||||
|
m_reactant.name(), m_reactant_a, m_reactant_z, T9, std::log10(rho * Ye), mue, InterpolationErrorTypeMap.at(type)
|
||||||
|
);
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
double logNeutrinoLossRate = 0.0;
|
||||||
|
if (m_type == WeakReactionType::BETA_PLUS_DECAY || m_type == WeakReactionType::ELECTRON_CAPTURE) {
|
||||||
|
logNeutrinoLossRate = rates->log_antineutrino_loss_bd;
|
||||||
|
} else if (m_type == WeakReactionType::BETA_MINUS_DECAY || m_type == WeakReactionType::POSITRON_CAPTURE) {
|
||||||
|
logNeutrinoLossRate = rates->log_neutrino_loss_ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double neutrinoLossRate = std::pow(10, logNeutrinoLossRate);
|
||||||
|
|
||||||
|
const double EDeposited_MeV = qValue() - neutrinoLossRate;
|
||||||
|
|
||||||
|
// We reimplement this logic here instead of calling calculate_rate() to avoid
|
||||||
|
// doing the interpolation twice (since the payload has already been interpolated).
|
||||||
|
const double logRate = get_log_rate_from_payload(rates.value());
|
||||||
|
double lambda = 0.0;
|
||||||
|
if (logRate > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||||
|
lambda = std::pow(10, logRate);
|
||||||
|
}
|
||||||
|
return lambda * EDeposited_MeV; // returns in MeV / s
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CppAD::AD<double> WeakReaction::calculate_energy_generation_rate(
|
||||||
|
const CppAD::AD<double> &T9,
|
||||||
|
const CppAD::AD<double> &rho,
|
||||||
|
const CppAD::AD<double> &Ye,
|
||||||
|
const CppAD::AD<double> &mue,
|
||||||
|
const std::vector<CppAD::AD<double>> &Y,
|
||||||
|
const std::unordered_map<size_t, fourdst::atomic::Species> &index_to_species_map
|
||||||
|
) const {
|
||||||
|
const CppAD::AD<double> log_rhoYe = CppAD::log10(rho * Ye);
|
||||||
|
std::vector<CppAD::AD<double>> ax = {T9, log_rhoYe, mue};
|
||||||
|
std::vector<CppAD::AD<double>> ay(1);
|
||||||
|
m_atomic(ax, ay); // TODO: Sort out why this isn't working and checkline 222 in weak.h where a similar line is
|
||||||
|
//TODO: think about how to get out neutrino loss in a autodiff safe way. This may mean I need to add an extra output to the atomic base
|
||||||
|
// so that I can get out both the rate and the neutrino loss rate. This will also mean that the sparsity pattern will need to
|
||||||
|
// be updated to account for the extra output.
|
||||||
|
CppAD::AD<double> rateConstant = ay[0];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<reaction::Reaction> WeakReaction::clone() const {
|
||||||
|
std::unique_ptr<reaction::Reaction> reaction_ptr = std::make_unique<WeakReaction>(
|
||||||
|
m_reactant,
|
||||||
|
m_type,
|
||||||
|
m_interpolator
|
||||||
|
);
|
||||||
|
return reaction_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
double WeakReaction::get_log_rate_from_payload(const WeakRatePayload &payload) const {
|
||||||
|
double logRate = 0.0;
|
||||||
|
switch (m_type) {
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY:
|
||||||
|
logRate = payload.log_beta_minus;
|
||||||
|
break;
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY:
|
||||||
|
logRate = payload.log_beta_plus;
|
||||||
|
break;
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE:
|
||||||
|
logRate = payload.log_electron_capture;
|
||||||
|
break;
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE:
|
||||||
|
logRate = payload.log_positron_capture;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return logRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::AtomicWeakRate::forward (
|
||||||
|
const size_t p,
|
||||||
|
const size_t q,
|
||||||
|
const CppAD::vector<bool> &vx,
|
||||||
|
CppAD::vector<bool> &vy,
|
||||||
|
const CppAD::vector<double> &tx,
|
||||||
|
CppAD::vector<double> &ty
|
||||||
|
) {
|
||||||
|
// Doing this explicitly (only allowing p == 0) makes forward mode AD impossible for now.
|
||||||
|
if (p != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const double T9 = tx[0];
|
||||||
|
const double log10_rhoye = tx[1];
|
||||||
|
const double mu_e = tx[2];
|
||||||
|
|
||||||
|
const std::expected<WeakRatePayload, InterpolationError> result = m_interpolator.get_rates(
|
||||||
|
static_cast<uint16_t>(m_a),
|
||||||
|
static_cast<uint8_t>(m_z),
|
||||||
|
T9,
|
||||||
|
log10_rhoye,
|
||||||
|
mu_e
|
||||||
|
);
|
||||||
|
if (!result.has_value()) {
|
||||||
|
const InterpolationErrorType type = result.error().type;
|
||||||
|
std::string msg = std::format(
|
||||||
|
"Failed to interpolate weak rate for (A={}, Z={}) at T9={}, log10(rho*Ye)={}, mu_e={} with error: {}",
|
||||||
|
m_a, m_z, T9, log10_rhoye, mu_e, InterpolationErrorTypeMap.at(type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
switch (m_type) {
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY:
|
||||||
|
ty[0] = std::pow(10, result.value().log_beta_minus);
|
||||||
|
break;
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY:
|
||||||
|
ty[0] = std::pow(10, result.value().log_beta_plus);
|
||||||
|
break;
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE:
|
||||||
|
ty[0] = std::pow(10, result.value().log_electron_capture);
|
||||||
|
break;
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE:
|
||||||
|
ty[0] = std::pow(10, result.value().log_positron_capture);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vx.size() > 0) {
|
||||||
|
vy[0] = vx[0] || vx[1] || vx[2]; // Sets the output sparsity pattern
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::AtomicWeakRate::reverse(
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<double> &tx,
|
||||||
|
const CppAD::vector<double> &ty,
|
||||||
|
CppAD::vector<double> &px,
|
||||||
|
const CppAD::vector<double> &py
|
||||||
|
) {
|
||||||
|
const double T9 = tx[0];
|
||||||
|
const double log10_rhoye = tx[1];
|
||||||
|
const double mu_e = tx[2];
|
||||||
|
|
||||||
|
const std::expected<WeakRateDerivatives, InterpolationError> result = m_interpolator.get_rate_derivatives(
|
||||||
|
static_cast<uint16_t>(m_a),
|
||||||
|
static_cast<uint8_t>(m_z),
|
||||||
|
T9,
|
||||||
|
log10_rhoye,
|
||||||
|
mu_e
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.has_value()) {
|
||||||
|
const InterpolationErrorType type = result.error().type;
|
||||||
|
const std::string msg = std::format(
|
||||||
|
"Failed to interpolate weak rate derivatives for (A={}, Z={}) at T9={}, log10(rho*Ye)={}, mu_e={} with error: {}",
|
||||||
|
m_a, m_z, T9, log10_rhoye, mu_e, InterpolationErrorTypeMap.at(type)
|
||||||
|
);
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
WeakRateDerivatives derivatives = result.value();
|
||||||
|
|
||||||
|
double dT9 = 0.0;
|
||||||
|
double dRho = 0.0;
|
||||||
|
double dMuE = 0.0;
|
||||||
|
switch (m_type) {
|
||||||
|
case WeakReactionType::BETA_MINUS_DECAY:
|
||||||
|
dT9 = py[0] * derivatives.d_log_beta_minus[0];
|
||||||
|
dRho = py[0] * derivatives.d_log_beta_minus[1];
|
||||||
|
dMuE = py[0] * derivatives.d_log_beta_minus[2];
|
||||||
|
break;
|
||||||
|
case WeakReactionType::BETA_PLUS_DECAY:
|
||||||
|
dT9 = py[0] * derivatives.d_log_beta_plus[0];
|
||||||
|
dRho = py[0] * derivatives.d_log_beta_plus[1];
|
||||||
|
dMuE = py[0] * derivatives.d_log_beta_plus[2];
|
||||||
|
break;
|
||||||
|
case WeakReactionType::ELECTRON_CAPTURE:
|
||||||
|
dT9 = py[0] * derivatives.d_log_electron_capture[0];
|
||||||
|
dRho = py[0] * derivatives.d_log_electron_capture[1];
|
||||||
|
dMuE = py[0] * derivatives.d_log_electron_capture[2];
|
||||||
|
break;
|
||||||
|
case WeakReactionType::POSITRON_CAPTURE:
|
||||||
|
dT9 = py[0] * derivatives.d_log_positron_capture[0];
|
||||||
|
dRho = py[0] * derivatives.d_log_positron_capture[1];
|
||||||
|
dMuE = py[0] * derivatives.d_log_positron_capture[2];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
px[0] = py[0] * dT9; // d(rate)/dT9
|
||||||
|
px[1] = py[0] * dRho; // d(rate)/dlogRhoYe
|
||||||
|
px[2] = py[0] * dMuE; // d(rate)/dMuE
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::AtomicWeakRate::for_sparse_jac(
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<std::set<size_t> > &r,
|
||||||
|
CppAD::vector<std::set<size_t> > &s
|
||||||
|
) {
|
||||||
|
s[0] = r[0];
|
||||||
|
s[0].insert(r[1].begin(), r[1].end());
|
||||||
|
s[0].insert(r[2].begin(), r[2].end());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeakReaction::AtomicWeakRate::rev_sparse_jac(
|
||||||
|
size_t q,
|
||||||
|
const CppAD::vector<std::set<size_t> > &rt,
|
||||||
|
CppAD::vector<std::set<size_t> > &st
|
||||||
|
) {
|
||||||
|
// What this is saying is that each of the three input variables (T9, rho, Ye)
|
||||||
|
// all only affect the output variable (the rate) since there is only
|
||||||
|
// one output variable.
|
||||||
|
st[0] = rt[0];
|
||||||
|
st[1] = rt[0];
|
||||||
|
st[2] = rt[0];
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
308
src/lib/reaction/weak/weak_interpolator.cpp
Normal file
308
src/lib/reaction/weak/weak_interpolator.cpp
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
#include "gridfire/reaction/weak/weak_interpolator.h"
|
||||||
|
#include "gridfire/reaction/reaction.h"
|
||||||
|
#include "gridfire/reaction/weak/weak.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <expected>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#include "fourdst/composition/species.h"
|
||||||
|
|
||||||
|
namespace gridfire::rates::weak {
|
||||||
|
|
||||||
|
WeakRateInterpolator::WeakRateInterpolator(const RowDataTable &raw_data) {
|
||||||
|
std::map<uint32_t, std::vector<const RateDataRow*>> grouped_rows;
|
||||||
|
for (const auto& row : raw_data) {
|
||||||
|
grouped_rows[pack_isotope_id(row.A, row.Z)].push_back(&row);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& [isotope_id, rows] : grouped_rows) {
|
||||||
|
IsotopeGrid grid;
|
||||||
|
|
||||||
|
std::set<float> unique_t9, unique_rhoYe, unique_mue;
|
||||||
|
for (const auto* row : rows) {
|
||||||
|
unique_t9.emplace(row->t9);
|
||||||
|
unique_rhoYe.emplace(row->log_rhoye);
|
||||||
|
unique_mue.emplace(row->mu_e);
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.t9_axis.reserve(unique_t9.size());
|
||||||
|
grid.rhoYe_axis.reserve(unique_rhoYe.size());
|
||||||
|
grid.mue_axis.reserve(unique_mue.size());
|
||||||
|
|
||||||
|
grid.t9_axis.insert(grid.t9_axis.begin(), unique_t9.begin(), unique_t9.end());
|
||||||
|
grid.rhoYe_axis.insert(grid.rhoYe_axis.begin(), unique_rhoYe.begin(), unique_rhoYe.end());
|
||||||
|
grid.mue_axis.insert(grid.mue_axis.begin(), unique_mue.begin(), unique_mue.end());
|
||||||
|
|
||||||
|
std::ranges::sort(grid.t9_axis);
|
||||||
|
std::ranges::sort(grid.rhoYe_axis);
|
||||||
|
std::ranges::sort(grid.mue_axis);
|
||||||
|
|
||||||
|
const size_t nt9 = grid.t9_axis.size();
|
||||||
|
const size_t nrhoYe = grid.rhoYe_axis.size();
|
||||||
|
const size_t nmue = grid.mue_axis.size();
|
||||||
|
|
||||||
|
grid.data.resize(nt9 * nrhoYe * nmue);
|
||||||
|
|
||||||
|
// Reverse map for quick index lookup
|
||||||
|
std::unordered_map<float, size_t> t9_map, rhoYe_map, mue_map;
|
||||||
|
for (size_t i = 0; i < nt9; i++) { t9_map[grid.t9_axis[i]] = i; }
|
||||||
|
for (size_t j = 0; j < nrhoYe; j++) { rhoYe_map[grid.rhoYe_axis[j]] = j; }
|
||||||
|
for (size_t k = 0; k < nmue; k++) { mue_map[grid.mue_axis[k]] = k; }
|
||||||
|
|
||||||
|
for (const auto* row: rows) {
|
||||||
|
size_t i_t9 = t9_map.at(row->t9);
|
||||||
|
size_t j_rhoYe = rhoYe_map.at(row->log_rhoye);
|
||||||
|
size_t k_mue = mue_map.at(row->mu_e);
|
||||||
|
|
||||||
|
size_t index = (i_t9 * nrhoYe + j_rhoYe) * nmue + k_mue;
|
||||||
|
grid.data[index] = WeakRatePayload{
|
||||||
|
row->log_beta_plus,
|
||||||
|
row->log_electron_capture,
|
||||||
|
row->log_neutrino_loss_ec,
|
||||||
|
row->log_beta_minus,
|
||||||
|
row->log_positron_capture,
|
||||||
|
row->log_antineutrino_loss_bd
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m_rate_table[isotope_id] = std::move(grid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<fourdst::atomic::Species> WeakRateInterpolator::available_isotopes() const {
|
||||||
|
std::vector<fourdst::atomic::Species> isotopes;
|
||||||
|
for (const auto &packed_id: m_rate_table | std::views::keys) {
|
||||||
|
const uint16_t A = static_cast<uint16_t>(packed_id >> 8);
|
||||||
|
const uint8_t Z = static_cast<uint8_t>(packed_id & 0xFF);
|
||||||
|
try {
|
||||||
|
fourdst::atomic::Species species = fourdst::atomic::az_to_species(A, Z);
|
||||||
|
isotopes.push_back(species);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throw std::runtime_error("Error converting A=" + std::to_string(A) + ", Z=" + std::to_string(Z) + " to Species: " + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isotopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::expected<WeakRatePayload, InterpolationError> WeakRateInterpolator::get_rates(
|
||||||
|
const uint16_t A,
|
||||||
|
const uint8_t Z,
|
||||||
|
const double t9,
|
||||||
|
const double log_rhoYe,
|
||||||
|
const double mu_e
|
||||||
|
) const {
|
||||||
|
const auto it = m_rate_table.find(pack_isotope_id(A, Z));
|
||||||
|
if (it == m_rate_table.end()) {
|
||||||
|
return std::unexpected(InterpolationError{InterpolationErrorType::UNKNOWN_SPECIES_ERROR});
|
||||||
|
}
|
||||||
|
const auto&[t9_axis, rhoYe_axis, mue_axis, data] = it->second;
|
||||||
|
|
||||||
|
// Now find the bracketing indices for t9, log_rhoYe, and mu_e
|
||||||
|
auto find_lower_index = [](const std::vector<double>& axis, const double value) -> std::optional<size_t> {
|
||||||
|
const auto upperBoundIterator = std::ranges::upper_bound(axis, value);
|
||||||
|
if (upperBoundIterator == axis.begin() || upperBoundIterator == axis.end()) {
|
||||||
|
return std::nullopt; // Out of bounds
|
||||||
|
}
|
||||||
|
return std::distance(axis.begin(), upperBoundIterator) - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto i_t9_opt = find_lower_index(t9_axis, t9);
|
||||||
|
const auto j_rhoYe_opt = find_lower_index(rhoYe_axis, log_rhoYe);
|
||||||
|
const auto k_mue_opt = find_lower_index(mue_axis, mu_e);
|
||||||
|
|
||||||
|
if (!i_t9_opt || !j_rhoYe_opt || !k_mue_opt) {
|
||||||
|
std::unordered_map<TableAxes, BoundsErrorInfo> boundsInfo;
|
||||||
|
if (!i_t9_opt) {
|
||||||
|
boundsInfo[TableAxes::T9] = BoundsErrorInfo{
|
||||||
|
TableAxes::T9,
|
||||||
|
t9_axis.front(),
|
||||||
|
t9_axis.back(),
|
||||||
|
t9
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!j_rhoYe_opt) {
|
||||||
|
boundsInfo[TableAxes::LOG_RHOYE] = BoundsErrorInfo{
|
||||||
|
TableAxes::LOG_RHOYE,
|
||||||
|
rhoYe_axis.front(),
|
||||||
|
rhoYe_axis.back(),
|
||||||
|
log_rhoYe
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!k_mue_opt) {
|
||||||
|
boundsInfo[TableAxes::MUE] = BoundsErrorInfo{
|
||||||
|
TableAxes::MUE,
|
||||||
|
mue_axis.front(),
|
||||||
|
mue_axis.back(),
|
||||||
|
mu_e
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return std::unexpected(
|
||||||
|
InterpolationError{
|
||||||
|
InterpolationErrorType::BOUNDS_ERROR,
|
||||||
|
boundsInfo
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t i = i_t9_opt.value();
|
||||||
|
const size_t j = j_rhoYe_opt.value();
|
||||||
|
const size_t k = k_mue_opt.value();
|
||||||
|
|
||||||
|
// Coordinates of the bounding cube
|
||||||
|
const double t1 = t9_axis[i];
|
||||||
|
const double t2 = t9_axis[i + 1];
|
||||||
|
const double r1 = rhoYe_axis[j];
|
||||||
|
const double r2 = rhoYe_axis[j + 1];
|
||||||
|
const double m1 = mue_axis[k];
|
||||||
|
const double m2 = mue_axis[k + 1];
|
||||||
|
|
||||||
|
const double td = (t9 - t1) / (t2 - t1);
|
||||||
|
const double rd = (log_rhoYe - r1) / (r2 - r1);
|
||||||
|
const double md = (mu_e - m1) / (m2 - m1);
|
||||||
|
|
||||||
|
auto lerp = [](const double v0, const double v1, const double t) {
|
||||||
|
return v0 * (1 - t) + v1 * t;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto interpolationField = [&](auto field_accessor) {
|
||||||
|
const size_t nrhoYe = rhoYe_axis.size();
|
||||||
|
const size_t nmue = mue_axis.size();
|
||||||
|
|
||||||
|
auto get_val = [&](const size_t i_t, const size_t j_r, const size_t k_m) {
|
||||||
|
return field_accessor(data[(i_t * nrhoYe + j_r) * nmue + k_m]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const double c000 = get_val(i, j, k);
|
||||||
|
const double c001 = get_val(i, j, k + 1);
|
||||||
|
const double c010 = get_val(i, j + 1, k);
|
||||||
|
const double c011 = get_val(i, j + 1, k + 1);
|
||||||
|
const double c100 = get_val(i + 1, j, k);
|
||||||
|
const double c101 = get_val(i + 1, j, k + 1);
|
||||||
|
const double c110 = get_val(i + 1, j + 1, k);
|
||||||
|
const double c111 = get_val(i + 1, j + 1, k + 1);
|
||||||
|
|
||||||
|
const double c00 = lerp(c000, c001, md);
|
||||||
|
const double c01 = lerp(c010, c011, md);
|
||||||
|
const double c10 = lerp(c100, c101, md);
|
||||||
|
const double c11 = lerp(c110, c111, md);
|
||||||
|
|
||||||
|
const double c0 = lerp(c00, c01, rd);
|
||||||
|
const double c1 = lerp(c10, c11, rd);
|
||||||
|
|
||||||
|
return lerp(c0, c1, td);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
WeakRatePayload result;
|
||||||
|
|
||||||
|
result.log_beta_plus = interpolationField([](const WeakRatePayload& p) { return p.log_beta_plus; });
|
||||||
|
result.log_electron_capture = interpolationField([](const WeakRatePayload& p) { return p.log_electron_capture; });
|
||||||
|
result.log_neutrino_loss_ec = interpolationField([](const WeakRatePayload& p) { return p.log_neutrino_loss_ec; });
|
||||||
|
result.log_beta_minus = interpolationField([](const WeakRatePayload& p) { return p.log_beta_minus; });
|
||||||
|
result.log_positron_capture = interpolationField([](const WeakRatePayload& p) { return p.log_positron_capture; });
|
||||||
|
result.log_antineutrino_loss_bd = interpolationField([](const WeakRatePayload& p) { return p.log_antineutrino_loss_bd; });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::expected<WeakRateDerivatives, InterpolationError> WeakRateInterpolator::get_rate_derivatives(
|
||||||
|
uint16_t A,
|
||||||
|
uint8_t Z,
|
||||||
|
double t9,
|
||||||
|
double log_rhoYe,
|
||||||
|
double mu_e
|
||||||
|
) const {
|
||||||
|
WeakRateDerivatives result;
|
||||||
|
constexpr double eps = 1e-6; // Small perturbation for finite difference
|
||||||
|
|
||||||
|
// Perturbations for finite difference
|
||||||
|
const double h_t9 = (t9 > 1e-9) ? t9 * eps : eps;
|
||||||
|
const auto payload_plus_t9 = get_rates(A, Z, t9 + h_t9, log_rhoYe, mu_e);
|
||||||
|
const auto payload_minus_t9 = get_rates(A, Z, t9 - h_t9, log_rhoYe, mu_e);
|
||||||
|
|
||||||
|
const double h_rhoYe = (std::abs(log_rhoYe) > 1e-9) ? std::abs(log_rhoYe) * eps : eps;
|
||||||
|
const auto payload_plus_rhoYe = get_rates(A, Z, t9, log_rhoYe + h_rhoYe, mu_e);
|
||||||
|
const auto payload_minus_rhoYe = get_rates(A, Z, t9, log_rhoYe - h_rhoYe, mu_e);
|
||||||
|
|
||||||
|
const double h_mue = (std::abs(mu_e) > 1e-9) ? std::abs(mu_e) * eps : eps;
|
||||||
|
const auto payload_plus_mue = get_rates(A, Z, t9, log_rhoYe, mu_e + h_mue);
|
||||||
|
const auto payload_minus_mue = get_rates(A, Z, t9, log_rhoYe, mu_e - h_mue);
|
||||||
|
|
||||||
|
if (!payload_plus_t9 || !payload_minus_t9 || !payload_plus_rhoYe || !payload_minus_rhoYe || !payload_plus_mue || !payload_minus_mue) {
|
||||||
|
const auto it = m_rate_table.find(pack_isotope_id(A, Z));
|
||||||
|
if (it == m_rate_table.end()) {
|
||||||
|
return std::unexpected(InterpolationError{InterpolationErrorType::UNKNOWN_SPECIES_ERROR});
|
||||||
|
}
|
||||||
|
|
||||||
|
const IsotopeGrid& grid = it->second;
|
||||||
|
InterpolationError error;
|
||||||
|
std::unordered_map<TableAxes, BoundsErrorInfo> boundsInfo;
|
||||||
|
if (!payload_minus_t9 || !payload_plus_t9) {
|
||||||
|
boundsInfo[TableAxes::T9] = BoundsErrorInfo{
|
||||||
|
TableAxes::T9,
|
||||||
|
grid.t9_axis.front(),
|
||||||
|
grid.t9_axis.back(),
|
||||||
|
t9
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!payload_minus_rhoYe || !payload_plus_rhoYe) {
|
||||||
|
boundsInfo[TableAxes::LOG_RHOYE] = BoundsErrorInfo{
|
||||||
|
TableAxes::LOG_RHOYE,
|
||||||
|
grid.rhoYe_axis.front(),
|
||||||
|
grid.rhoYe_axis.back(),
|
||||||
|
log_rhoYe
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!payload_minus_mue || !payload_plus_mue) {
|
||||||
|
boundsInfo[TableAxes::MUE] = BoundsErrorInfo{
|
||||||
|
TableAxes::MUE,
|
||||||
|
grid.mue_axis.front(),
|
||||||
|
grid.mue_axis.back(),
|
||||||
|
mu_e
|
||||||
|
};
|
||||||
|
}
|
||||||
|
error.type = InterpolationErrorType::BOUNDS_ERROR;
|
||||||
|
error.boundsErrorInfo = boundsInfo;
|
||||||
|
return std::unexpected(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derivatives wrt. T9
|
||||||
|
const double t9_denominator = 2 * h_t9;
|
||||||
|
result.d_log_beta_plus[0] = (payload_plus_t9->log_beta_plus - payload_minus_t9->log_beta_plus) / t9_denominator;
|
||||||
|
result.d_log_beta_minus[0] = (payload_plus_t9->log_beta_minus - payload_minus_t9->log_beta_minus) / t9_denominator;
|
||||||
|
result.d_log_electron_capture[0] = (payload_plus_t9->log_electron_capture - payload_minus_t9->log_electron_capture) / t9_denominator;
|
||||||
|
result.d_log_neutrino_loss_ec[0] = (payload_plus_t9->log_neutrino_loss_ec - payload_minus_t9->log_neutrino_loss_ec) / t9_denominator;
|
||||||
|
result.d_log_positron_capture[0] = (payload_plus_t9->log_positron_capture - payload_minus_t9->log_positron_capture) / t9_denominator;
|
||||||
|
result.d_log_antineutrino_loss_bd[0] = (payload_plus_t9->log_antineutrino_loss_bd - payload_minus_t9->log_antineutrino_loss_bd) / t9_denominator;
|
||||||
|
|
||||||
|
// Derivatives wrt. logRhoYe
|
||||||
|
const double rhoYe_denominator = 2 * h_rhoYe;
|
||||||
|
result.d_log_beta_plus[1] = (payload_plus_rhoYe->log_beta_plus - payload_minus_rhoYe->log_beta_plus) / rhoYe_denominator;
|
||||||
|
result.d_log_beta_minus[1] = (payload_plus_rhoYe->log_beta_minus - payload_minus_rhoYe->log_beta_minus) / rhoYe_denominator;
|
||||||
|
result.d_log_electron_capture[1] = (payload_plus_rhoYe->log_electron_capture - payload_minus_rhoYe->log_electron_capture) / rhoYe_denominator;
|
||||||
|
result.d_log_neutrino_loss_ec[1] = (payload_plus_rhoYe->log_neutrino_loss_ec - payload_minus_rhoYe->log_neutrino_loss_ec) / rhoYe_denominator;
|
||||||
|
result.d_log_positron_capture[1] = (payload_plus_rhoYe->log_positron_capture - payload_minus_rhoYe->log_positron_capture) / rhoYe_denominator;
|
||||||
|
result.d_log_antineutrino_loss_bd[1] = (payload_plus_rhoYe->log_antineutrino_loss_bd - payload_minus_rhoYe->log_antineutrino_loss_bd) / rhoYe_denominator;
|
||||||
|
|
||||||
|
// Derivatives wrt. MuE
|
||||||
|
const double mue_denominator = 2 * h_mue;
|
||||||
|
result.d_log_beta_plus[2] = (payload_plus_mue->log_beta_plus - payload_minus_mue->log_beta_plus) / mue_denominator;
|
||||||
|
result.d_log_beta_minus[2] = (payload_plus_mue->log_beta_minus - payload_minus_mue->log_beta_minus) / mue_denominator;
|
||||||
|
result.d_log_electron_capture[2] = (payload_plus_mue->log_electron_capture - payload_minus_mue->log_electron_capture) / mue_denominator;
|
||||||
|
result.d_log_neutrino_loss_ec[2] = (payload_plus_mue->log_neutrino_loss_ec - payload_minus_mue->log_neutrino_loss_ec) / mue_denominator;
|
||||||
|
result.d_log_positron_capture[2] = (payload_plus_mue->log_positron_capture - payload_minus_mue->log_positron_capture) / mue_denominator;
|
||||||
|
result.d_log_antineutrino_loss_bd[2] = (payload_plus_mue->log_antineutrino_loss_bd - payload_minus_mue->log_antineutrino_loss_bd) / mue_denominator;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t WeakRateInterpolator::pack_isotope_id(const uint16_t A, const uint8_t Z) {
|
||||||
|
return (static_cast<uint32_t>(A) << 8) | static_cast<uint32_t>(Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ namespace gridfire::screening {
|
|||||||
std::vector<ADDouble> BareScreeningModel::calculateScreeningFactors(
|
std::vector<ADDouble> BareScreeningModel::calculateScreeningFactors(
|
||||||
const reaction::ReactionSet &reactions,
|
const reaction::ReactionSet &reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<ADDouble> &Y,
|
const std::vector<screening::ADDouble> &Y,
|
||||||
const ADDouble T9,
|
const ADDouble T9,
|
||||||
const ADDouble rho
|
const ADDouble rho
|
||||||
) const {
|
) const {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace gridfire::screening {
|
|||||||
std::vector<ADDouble> WeakScreeningModel::calculateScreeningFactors(
|
std::vector<ADDouble> WeakScreeningModel::calculateScreeningFactors(
|
||||||
const reaction::ReactionSet &reactions,
|
const reaction::ReactionSet &reactions,
|
||||||
const std::vector<fourdst::atomic::Species>& species,
|
const std::vector<fourdst::atomic::Species>& species,
|
||||||
const std::vector<ADDouble> &Y,
|
const std::vector<screening::ADDouble> &Y,
|
||||||
const ADDouble T9,
|
const ADDouble T9,
|
||||||
const ADDouble rho
|
const ADDouble rho
|
||||||
) const {
|
) const {
|
||||||
|
|||||||
@@ -1,356 +0,0 @@
|
|||||||
#include "gridfire/solver/solver.h"
|
|
||||||
#include "gridfire/engine/engine_graph.h"
|
|
||||||
#include "gridfire/network.h"
|
|
||||||
#include "gridfire/exceptions/error_engine.h"
|
|
||||||
|
|
||||||
#include "fourdst/composition/atomicSpecies.h"
|
|
||||||
#include "fourdst/composition/composition.h"
|
|
||||||
#include "fourdst/config/config.h"
|
|
||||||
|
|
||||||
#include "fourdst/plugin/plugin.h"
|
|
||||||
|
|
||||||
#include "gridfire/interfaces/solver/solver_interfaces.h"
|
|
||||||
|
|
||||||
#include "unsupported/Eigen/NonLinearOptimization"
|
|
||||||
|
|
||||||
#include <boost/numeric/odeint.hpp>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include "quill/LogMacros.h"
|
|
||||||
|
|
||||||
namespace gridfire::solver {
|
|
||||||
NetOut DirectNetworkSolver::evaluate(const NetIn &netIn) {
|
|
||||||
namespace ublas = boost::numeric::ublas;
|
|
||||||
namespace odeint = boost::numeric::odeint;
|
|
||||||
using fourdst::composition::Composition;
|
|
||||||
|
|
||||||
|
|
||||||
const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
|
|
||||||
|
|
||||||
const auto absTol = m_config.get<double>("gridfire:solver:DirectNetworkSolver:absTol", 1.0e-8);
|
|
||||||
const auto relTol = m_config.get<double>("gridfire:solver:DirectNetworkSolver:relTol", 1.0e-8);
|
|
||||||
|
|
||||||
Composition equilibratedComposition = m_engine.update(netIn);
|
|
||||||
size_t numSpecies = m_engine.getNetworkSpecies().size();
|
|
||||||
ublas::vector<double> Y(numSpecies + 1);
|
|
||||||
|
|
||||||
RHSManager manager(m_engine, T9, netIn.density, m_callback, m_engine.getNetworkSpecies());
|
|
||||||
JacobianFunctor jacobianFunctor(m_engine, T9, netIn.density);
|
|
||||||
|
|
||||||
auto populateY = [&](const Composition& comp) {
|
|
||||||
const size_t numSpeciesInternal = m_engine.getNetworkSpecies().size();
|
|
||||||
Y.resize(numSpeciesInternal + 1);
|
|
||||||
for (size_t i = 0; i < numSpeciesInternal; i++) {
|
|
||||||
const auto& species = m_engine.getNetworkSpecies()[i];
|
|
||||||
if (!comp.contains(species)) {
|
|
||||||
double lim = std::numeric_limits<double>::min();
|
|
||||||
LOG_DEBUG(m_logger, "Species '{}' not found in composition. Setting abundance to {:0.3E}.", species.name(), lim);
|
|
||||||
Y(i) = lim; // Species not in the composition, set to zero
|
|
||||||
} else {
|
|
||||||
Y(i) = comp.getMolarAbundance(species);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: a good starting point to make the temperature, density, and energy self consistent would be to turn this into an accumulator
|
|
||||||
Y(numSpeciesInternal) = 0.0; // Specific energy rate, initialized to zero
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is a quick debug that can be turned on. For solar code input parameters (T~1.5e7K, ρ~1.5e3 g/cm^3) this should be near 8e-17
|
|
||||||
// std::cout << "D/H: " << equilibratedComposition.getMolarAbundance("H-2") / equilibratedComposition.getMolarAbundance("H-1") << std::endl;
|
|
||||||
|
|
||||||
populateY(equilibratedComposition);
|
|
||||||
const auto stepper = odeint::make_controlled<odeint::rosenbrock4<double>>(absTol, relTol);
|
|
||||||
|
|
||||||
double current_time = 0.0;
|
|
||||||
double current_initial_timestep = netIn.dt0;
|
|
||||||
double accumulated_energy = 0.0;
|
|
||||||
// size_t total_update_stages_triggered = 0;
|
|
||||||
|
|
||||||
while (current_time < netIn.tMax) {
|
|
||||||
try {
|
|
||||||
odeint::integrate_adaptive(
|
|
||||||
stepper,
|
|
||||||
std::make_pair(manager, jacobianFunctor),
|
|
||||||
Y,
|
|
||||||
current_time,
|
|
||||||
netIn.tMax,
|
|
||||||
current_initial_timestep,
|
|
||||||
[&](const auto& state, double t) {
|
|
||||||
current_time = t;
|
|
||||||
manager.observe(state, t);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
current_time = netIn.tMax;
|
|
||||||
} catch (const exceptions::StaleEngineTrigger &e) {
|
|
||||||
LOG_INFO(m_logger, "Catching StaleEngineTrigger at t = {:0.3E} with T9 = {:0.3E}, rho = {:0.3E}. Triggering update stage (last stage took {} steps).", current_time, T9, netIn.density, e.totalSteps());
|
|
||||||
exceptions::StaleEngineTrigger::state staleState = e.getState();
|
|
||||||
accumulated_energy += e.energy(); // Add the specific energy rate to the accumulated energy
|
|
||||||
// total_update_stages_triggered++;
|
|
||||||
|
|
||||||
Composition temp_comp;
|
|
||||||
std::vector<double> mass_fractions;
|
|
||||||
size_t num_species_at_stop = e.numSpecies();
|
|
||||||
|
|
||||||
if (num_species_at_stop != m_engine.getNetworkSpecies().size()) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"StaleEngineError state has a different number of species than the engine. This should not happen."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
mass_fractions.reserve(num_species_at_stop);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num_species_at_stop; ++i) {
|
|
||||||
const auto& species = m_engine.getNetworkSpecies()[i];
|
|
||||||
temp_comp.registerSpecies(species);
|
|
||||||
mass_fractions.push_back(e.getMolarAbundance(i) * species.mass()); // Convert from molar abundance to mass fraction
|
|
||||||
}
|
|
||||||
temp_comp.setMassFraction(m_engine.getNetworkSpecies(), mass_fractions);
|
|
||||||
temp_comp.finalize(true);
|
|
||||||
|
|
||||||
NetIn netInTemp = netIn;
|
|
||||||
netInTemp.temperature = e.temperature();
|
|
||||||
netInTemp.density = e.density();
|
|
||||||
netInTemp.composition = temp_comp;
|
|
||||||
|
|
||||||
Composition currentComposition = m_engine.update(netInTemp);
|
|
||||||
populateY(currentComposition);
|
|
||||||
Y(Y.size() - 1) = e.energy(); // Set the specific energy rate from the stale state
|
|
||||||
numSpecies = m_engine.getNetworkSpecies().size();
|
|
||||||
|
|
||||||
// current_initial_timestep = 0.001 * manager.m_last_step_time; // set the new timestep to the last successful timestep before repartitioning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accumulated_energy += Y(Y.size() - 1); // Add the specific energy rate to the accumulated energy
|
|
||||||
|
|
||||||
std::vector<double> finalMassFractions(numSpecies);
|
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
|
||||||
const double molarMass = m_engine.getNetworkSpecies()[i].mass();
|
|
||||||
finalMassFractions[i] = Y(i) * molarMass; // Convert from molar abundance to mass fraction
|
|
||||||
if (finalMassFractions[i] < MIN_ABUNDANCE_THRESHOLD) {
|
|
||||||
finalMassFractions[i] = 0.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> speciesNames;
|
|
||||||
speciesNames.reserve(numSpecies);
|
|
||||||
for (const auto& species : m_engine.getNetworkSpecies()) {
|
|
||||||
speciesNames.emplace_back(species.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
Composition outputComposition(speciesNames);
|
|
||||||
outputComposition.setMassFraction(speciesNames, finalMassFractions);
|
|
||||||
outputComposition.finalize(true);
|
|
||||||
|
|
||||||
NetOut netOut;
|
|
||||||
netOut.composition = outputComposition;
|
|
||||||
netOut.energy = accumulated_energy; // Specific energy rate
|
|
||||||
netOut.num_steps = manager.m_num_steps;
|
|
||||||
|
|
||||||
auto [dEps_dT, dEps_dRho] = m_engine.calculateEpsDerivatives(
|
|
||||||
std::vector<double>(Y.begin(), Y.begin() + numSpecies), // TODO: This narrowing should probably be solved. Its possible unforeseen bugs will arise from this
|
|
||||||
T9,
|
|
||||||
netIn.density
|
|
||||||
);
|
|
||||||
|
|
||||||
netOut.dEps_dT = dEps_dT;
|
|
||||||
netOut.dEps_dRho = dEps_dRho;
|
|
||||||
|
|
||||||
return netOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectNetworkSolver::set_callback(const std::any& callback) {
|
|
||||||
if (!callback.has_value()) {
|
|
||||||
m_callback = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using FunctionPtrType = void (*)(const TimestepContext&);
|
|
||||||
|
|
||||||
if (callback.type() == typeid(TimestepCallback)) {
|
|
||||||
m_callback = std::any_cast<TimestepCallback>(callback);
|
|
||||||
}
|
|
||||||
else if (callback.type() == typeid(FunctionPtrType)) {
|
|
||||||
auto func_ptr = std::any_cast<FunctionPtrType>(callback);
|
|
||||||
m_callback = func_ptr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw std::invalid_argument("Unsupported type passed to set_callback. "
|
|
||||||
"Provide a std::function or a matching function pointer.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<std::tuple<std::string, std::string>> DirectNetworkSolver::describe_callback_context() const {
|
|
||||||
const TimestepContext context(
|
|
||||||
0.0, // time
|
|
||||||
boost::numeric::ublas::vector<double>(), // state
|
|
||||||
0.0, // dt
|
|
||||||
0.0, // cached_time
|
|
||||||
0.0, // last_observed_time
|
|
||||||
0.0, // last_step_time
|
|
||||||
0.0, // T9
|
|
||||||
0.0, // rho
|
|
||||||
std::nullopt, // cached_result
|
|
||||||
0, // num_steps
|
|
||||||
m_engine, // engine,
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
return context.describe();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectNetworkSolver::RHSManager::operator()(
|
|
||||||
const boost::numeric::ublas::vector<double> &Y,
|
|
||||||
boost::numeric::ublas::vector<double> &dYdt,
|
|
||||||
const double t
|
|
||||||
) const {
|
|
||||||
const size_t numSpecies = m_engine.getNetworkSpecies().size();
|
|
||||||
if (t != m_cached_time || !m_cached_result.has_value() || m_cached_result.value().dydt.size() != numSpecies + 1) {
|
|
||||||
compute_and_cache(Y, t);
|
|
||||||
}
|
|
||||||
const auto&[dydt, nuclearEnergyGenerationRate] = m_cached_result.value();
|
|
||||||
dYdt.resize(numSpecies + 1);
|
|
||||||
std::ranges::copy(dydt, dYdt.begin());
|
|
||||||
dYdt(numSpecies) = nuclearEnergyGenerationRate; // Set the last element to the specific energy rate
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectNetworkSolver::RHSManager::observe(
|
|
||||||
const boost::numeric::ublas::vector<double> &state,
|
|
||||||
const double t
|
|
||||||
) const {
|
|
||||||
double dt = t - m_last_observed_time;
|
|
||||||
compute_and_cache(state, t);
|
|
||||||
LOG_INFO(
|
|
||||||
m_logger,
|
|
||||||
"(Step {}) Observed state at t = {:0.3E} (dt = {:0.3E})",
|
|
||||||
m_num_steps,
|
|
||||||
t,
|
|
||||||
dt
|
|
||||||
);
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << std::scientific << std::setprecision(3);
|
|
||||||
oss << "(Step: " << std::setw(10) << m_num_steps << ") t = " << t << " (dt = " << dt << ", eps_nuc: " << state(state.size() - 1) << " [erg])\n";
|
|
||||||
std::cout << oss.str();
|
|
||||||
|
|
||||||
fourdst::plugin::manager::PluginManager &pluginManager = fourdst::plugin::manager::PluginManager::getInstance();
|
|
||||||
|
|
||||||
if (pluginManager.has("gridfire/solver")) {
|
|
||||||
auto* plugin = pluginManager.get<SolverPluginInterface>("gridfire/solver");
|
|
||||||
plugin -> log_time(t, dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback logic
|
|
||||||
if (m_callback) {
|
|
||||||
LOG_TRACE_L1(m_logger, "Calling user callback function at t = {:0.3E} with dt = {:0.3E}", t, dt);
|
|
||||||
const TimestepContext context(
|
|
||||||
t,
|
|
||||||
state,
|
|
||||||
dt,
|
|
||||||
m_cached_time,
|
|
||||||
m_last_observed_time,
|
|
||||||
m_last_step_time,
|
|
||||||
m_T9,
|
|
||||||
m_rho,
|
|
||||||
m_cached_result,
|
|
||||||
m_num_steps,
|
|
||||||
m_engine,
|
|
||||||
m_networkSpecies
|
|
||||||
);
|
|
||||||
|
|
||||||
m_callback(context);
|
|
||||||
LOG_TRACE_L1(m_logger, "User callback function completed at t = {:0.3E} with dt = {:0.3E}", t, dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_last_observed_time = t;
|
|
||||||
m_last_step_time = dt;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectNetworkSolver::RHSManager::compute_and_cache(
|
|
||||||
const boost::numeric::ublas::vector<double> &state,
|
|
||||||
double t
|
|
||||||
) const {
|
|
||||||
std::vector<double> y_vec(state.begin(), state.end() - 1);
|
|
||||||
std::ranges::replace_if(
|
|
||||||
y_vec,
|
|
||||||
[](const double yi){
|
|
||||||
return yi < 0.0;
|
|
||||||
},
|
|
||||||
0.0 // Avoid negative abundances
|
|
||||||
);
|
|
||||||
|
|
||||||
const auto result = m_engine.calculateRHSAndEnergy(y_vec, m_T9, m_rho);
|
|
||||||
if (!result) {
|
|
||||||
LOG_INFO(m_logger,
|
|
||||||
"Triggering update stage due to stale engine detected at t = {:0.3E} with T9 = {:0.3E}, rho = {:0.3E}, y_vec (size: {})",
|
|
||||||
t, m_T9, m_rho, y_vec.size());
|
|
||||||
throw exceptions::StaleEngineTrigger({m_T9, m_rho, y_vec, t, m_num_steps, state(state.size() - 1)});
|
|
||||||
}
|
|
||||||
m_cached_result = result.value();
|
|
||||||
m_cached_time = t;
|
|
||||||
|
|
||||||
m_num_steps++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectNetworkSolver::JacobianFunctor::operator()(
|
|
||||||
const boost::numeric::ublas::vector<double> &Y,
|
|
||||||
boost::numeric::ublas::matrix<double> &J,
|
|
||||||
double t,
|
|
||||||
boost::numeric::ublas::vector<double> &dfdt
|
|
||||||
) const {
|
|
||||||
size_t numSpecies = m_engine.getNetworkSpecies().size();
|
|
||||||
J.resize(numSpecies+1, numSpecies+1);
|
|
||||||
J.clear();
|
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
|
||||||
for (size_t j = 0; j < numSpecies; ++j) {
|
|
||||||
J(i, j) = m_engine.getJacobianMatrixEntry(i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectNetworkSolver::TimestepContext::TimestepContext(
|
|
||||||
const double t,
|
|
||||||
const boost::numeric::ublas::vector<double> &state,
|
|
||||||
const double dt,
|
|
||||||
const double cached_time,
|
|
||||||
const double last_observed_time,
|
|
||||||
const double last_step_time,
|
|
||||||
const double t9,
|
|
||||||
const double rho,
|
|
||||||
const std::optional<StepDerivatives<double>> &cached_result,
|
|
||||||
const int num_steps,
|
|
||||||
const DynamicEngine &engine,
|
|
||||||
const std::vector<fourdst::atomic::Species> &networkSpecies
|
|
||||||
)
|
|
||||||
: t(t),
|
|
||||||
state(state),
|
|
||||||
dt(dt),
|
|
||||||
cached_time(cached_time),
|
|
||||||
last_observed_time(last_observed_time),
|
|
||||||
last_step_time(last_step_time),
|
|
||||||
T9(t9),
|
|
||||||
rho(rho),
|
|
||||||
cached_result(cached_result),
|
|
||||||
num_steps(num_steps),
|
|
||||||
engine(engine),
|
|
||||||
networkSpecies(networkSpecies) {}
|
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, std::string>> DirectNetworkSolver::TimestepContext::describe() const {
|
|
||||||
return {
|
|
||||||
{"time", "double"},
|
|
||||||
{"state", "boost::numeric::ublas::vector<double>&"},
|
|
||||||
{"dt", "double"},
|
|
||||||
{"cached_time", "double"},
|
|
||||||
{"last_observed_time", "double"},
|
|
||||||
{"last_step_time", "double"},
|
|
||||||
{"T9", "double"},
|
|
||||||
{"rho", "double"},
|
|
||||||
{"cached_result", "std::optional<StepDerivatives<double>>&"},
|
|
||||||
{"num_steps", "int"},
|
|
||||||
{"engine", "DynamicEngine&"},
|
|
||||||
{"networkSpecies", "std::vector<fourdst::atomic::Species>&"}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "fourdst/composition/exceptions/exceptions_composition.h"
|
#include "fourdst/composition/exceptions/exceptions_composition.h"
|
||||||
|
#include "gridfire/engine/engine_graph.h"
|
||||||
#include "gridfire/solver/strategies/triggers/engine_partitioning_trigger.h"
|
#include "gridfire/solver/strategies/triggers/engine_partitioning_trigger.h"
|
||||||
#include "gridfire/trigger/procedures/trigger_pprint.h"
|
#include "gridfire/trigger/procedures/trigger_pprint.h"
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ namespace {
|
|||||||
#elif SUNDIALS_HAVE_PTHREADS
|
#elif SUNDIALS_HAVE_PTHREADS
|
||||||
N_Vector vec = N_VNew_Pthreads(size, sun_ctx);
|
N_Vector vec = N_VNew_Pthreads(size, sun_ctx);
|
||||||
#else
|
#else
|
||||||
N_Vector vec = N_VNew_Serial(size, sun_ctx);
|
N_Vector vec = N_VNew_Serial(static_cast<long long>(size), sun_ctx);
|
||||||
#endif
|
#endif
|
||||||
check_cvode_flag(vec == nullptr ? -1 : 0, "N_VNew");
|
check_cvode_flag(vec == nullptr ? -1 : 0, "N_VNew");
|
||||||
return vec;
|
return vec;
|
||||||
@@ -87,7 +88,7 @@ namespace gridfire::solver {
|
|||||||
const double last_step_time,
|
const double last_step_time,
|
||||||
const double t9,
|
const double t9,
|
||||||
const double rho,
|
const double rho,
|
||||||
const int num_steps,
|
const size_t num_steps,
|
||||||
const DynamicEngine &engine,
|
const DynamicEngine &engine,
|
||||||
const std::vector<fourdst::atomic::Species> &networkSpecies
|
const std::vector<fourdst::atomic::Species> &networkSpecies
|
||||||
) :
|
) :
|
||||||
@@ -157,6 +158,7 @@ namespace gridfire::solver {
|
|||||||
user_data.engine = &m_engine;
|
user_data.engine = &m_engine;
|
||||||
|
|
||||||
double current_time = 0;
|
double current_time = 0;
|
||||||
|
// ReSharper disable once CppTooWideScope
|
||||||
[[maybe_unused]] double last_callback_time = 0;
|
[[maybe_unused]] double last_callback_time = 0;
|
||||||
m_num_steps = 0;
|
m_num_steps = 0;
|
||||||
double accumulated_energy = 0.0;
|
double accumulated_energy = 0.0;
|
||||||
@@ -169,7 +171,7 @@ namespace gridfire::solver {
|
|||||||
|
|
||||||
check_cvode_flag(CVodeSetUserData(m_cvode_mem, &user_data), "CVodeSetUserData");
|
check_cvode_flag(CVodeSetUserData(m_cvode_mem, &user_data), "CVodeSetUserData");
|
||||||
|
|
||||||
int flag = -1;
|
int flag{};
|
||||||
if (m_stdout_logging_enabled) {
|
if (m_stdout_logging_enabled) {
|
||||||
flag = CVode(m_cvode_mem, netIn.tMax, m_Y, ¤t_time, CV_ONE_STEP);
|
flag = CVode(m_cvode_mem, netIn.tMax, m_Y, ¤t_time, CV_ONE_STEP);
|
||||||
} else {
|
} else {
|
||||||
@@ -304,10 +306,8 @@ namespace gridfire::solver {
|
|||||||
netOut.energy = accumulated_energy;
|
netOut.energy = accumulated_energy;
|
||||||
check_cvode_flag(CVodeGetNumSteps(m_cvode_mem, reinterpret_cast<long int *>(&netOut.num_steps)), "CVodeGetNumSteps");
|
check_cvode_flag(CVodeGetNumSteps(m_cvode_mem, reinterpret_cast<long int *>(&netOut.num_steps)), "CVodeGetNumSteps");
|
||||||
|
|
||||||
outputComposition.setCompositionMode(false); // set to number fraction mode
|
|
||||||
std::vector<double> Y = outputComposition.getNumberFractionVector(); // TODO need to ensure that the canonical vector representation is used throughout the code to make sure tracking does not get messed up
|
|
||||||
auto [dEps_dT, dEps_dRho] = m_engine.calculateEpsDerivatives(
|
auto [dEps_dT, dEps_dRho] = m_engine.calculateEpsDerivatives(
|
||||||
std::vector<double>(Y.begin(), Y.begin() + numSpecies), // TODO: This narrowing should probably be solved. Its possible unforeseen bugs will arise from this
|
outputComposition,
|
||||||
T9,
|
T9,
|
||||||
netIn.density
|
netIn.density
|
||||||
);
|
);
|
||||||
@@ -374,9 +374,11 @@ namespace gridfire::solver {
|
|||||||
|
|
||||||
for (size_t j = 0; j < numSpecies; ++j) {
|
for (size_t j = 0; j < numSpecies; ++j) {
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
for (size_t i = 0; i < numSpecies; ++i) {
|
||||||
|
const fourdst::atomic::Species& species_j = engine->getNetworkSpecies()[j];
|
||||||
|
const fourdst::atomic::Species& species_i = engine->getNetworkSpecies()[i];
|
||||||
// J(i,j) = d(f_i)/d(y_j)
|
// J(i,j) = d(f_i)/d(y_j)
|
||||||
// Column-major order format for SUNDenseMatrix: J_data[j*N + i]
|
// Column-major order format for SUNDenseMatrix: J_data[j*N + i]
|
||||||
J_data[j * N + i] = engine->getJacobianMatrixEntry(i, j);
|
J_data[j * N + i] = engine->getJacobianMatrixEntry(species_i, species_j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,11 +400,30 @@ namespace gridfire::solver {
|
|||||||
const size_t numSpecies = m_engine.getNetworkSpecies().size();
|
const size_t numSpecies = m_engine.getNetworkSpecies().size();
|
||||||
sunrealtype* y_data = N_VGetArrayPointer(y);
|
sunrealtype* y_data = N_VGetArrayPointer(y);
|
||||||
|
|
||||||
|
// PERF: The trade off of ensured index consistency is some performance here. If this becomes a bottleneck we can revisit.
|
||||||
|
// The specific trade off is that we have decided to enforce that all interfaces accept composition objects rather
|
||||||
|
// than raw vectors of molar abundances. This then lets any method lookup the species by name rather than relying on
|
||||||
|
// the index in the vector being consistent. The trade off is that sometimes we need to construct a composition object
|
||||||
|
// which, at the moment, requires a somewhat expensive set of operations. Perhaps in the future we could enforce
|
||||||
|
// some consistent memory layout for the composition object to make this cheeper. That optimization would need to be
|
||||||
|
// done in the libcomposition library though...
|
||||||
std::vector<double> y_vec(y_data, y_data + numSpecies);
|
std::vector<double> y_vec(y_data, y_data + numSpecies);
|
||||||
|
std::vector<std::string> symbols;
|
||||||
|
symbols.reserve(numSpecies);
|
||||||
|
for (const auto& species : m_engine.getNetworkSpecies()) {
|
||||||
|
symbols.emplace_back(species.name());
|
||||||
|
}
|
||||||
|
std::vector<double> X;
|
||||||
|
X.reserve(numSpecies);
|
||||||
|
for (size_t i = 0; i < numSpecies; ++i) {
|
||||||
|
const double molarMass = m_engine.getNetworkSpecies()[i].mass();
|
||||||
|
X.push_back(y_vec[i] * molarMass); // Convert from molar abundance to mass fraction
|
||||||
|
}
|
||||||
|
fourdst::composition::Composition composition(symbols, X);
|
||||||
|
|
||||||
std::ranges::replace_if(y_vec, [](const double val) { return val < 0.0; }, 0.0);
|
std::ranges::replace_if(y_vec, [](const double val) { return val < 0.0; }, 0.0);
|
||||||
|
|
||||||
const auto result = m_engine.calculateRHSAndEnergy(y_vec, data->T9, data->rho);
|
const auto result = m_engine.calculateRHSAndEnergy(composition, data->T9, data->rho);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw exceptions::StaleEngineTrigger({data->T9, data->rho, y_vec, t, m_num_steps, y_data[numSpecies]});
|
throw exceptions::StaleEngineTrigger({data->T9, data->rho, y_vec, t, m_num_steps, y_data[numSpecies]});
|
||||||
}
|
}
|
||||||
@@ -411,7 +432,7 @@ namespace gridfire::solver {
|
|||||||
const auto& [dydt, nuclearEnergyGenerationRate] = result.value();
|
const auto& [dydt, nuclearEnergyGenerationRate] = result.value();
|
||||||
|
|
||||||
for (size_t i = 0; i < numSpecies; ++i) {
|
for (size_t i = 0; i < numSpecies; ++i) {
|
||||||
ydot_data[i] = dydt[i];
|
ydot_data[i] = dydt.at(m_engine.getNetworkSpecies()[i]);
|
||||||
}
|
}
|
||||||
ydot_data[numSpecies] = nuclearEnergyGenerationRate; // Set the last element to the specific energy rate
|
ydot_data[numSpecies] = nuclearEnergyGenerationRate; // Set the last element to the specific energy rate
|
||||||
}
|
}
|
||||||
@@ -513,6 +534,7 @@ namespace gridfire::solver {
|
|||||||
|
|
||||||
std::vector<double> Y_full(y_data, y_data + num_components - 1);
|
std::vector<double> Y_full(y_data, y_data + num_components - 1);
|
||||||
|
|
||||||
|
|
||||||
std::ranges::replace_if(
|
std::ranges::replace_if(
|
||||||
Y_full,
|
Y_full,
|
||||||
[](const double val) {
|
[](const double val) {
|
||||||
@@ -528,8 +550,9 @@ namespace gridfire::solver {
|
|||||||
const double err_ratio = std::abs(y_err_data[i]) / weight;
|
const double err_ratio = std::abs(y_err_data[i]) / weight;
|
||||||
|
|
||||||
err_ratios[i] = err_ratio;
|
err_ratios[i] = err_ratio;
|
||||||
speciesNames.push_back(std::string(user_data.networkSpecies->at(i).name()));
|
speciesNames.emplace_back(user_data.networkSpecies->at(i).name());
|
||||||
}
|
}
|
||||||
|
fourdst::composition::Composition composition(speciesNames, Y_full);
|
||||||
|
|
||||||
if (err_ratios.empty()) {
|
if (err_ratios.empty()) {
|
||||||
return;
|
return;
|
||||||
@@ -565,9 +588,9 @@ namespace gridfire::solver {
|
|||||||
columns.push_back(std::make_unique<utils::Column<double>>("Error Ratio", sorted_err_ratios));
|
columns.push_back(std::make_unique<utils::Column<double>>("Error Ratio", sorted_err_ratios));
|
||||||
|
|
||||||
std::cout << utils::format_table("Species Error Ratios", columns) << std::endl;
|
std::cout << utils::format_table("Species Error Ratios", columns) << std::endl;
|
||||||
diagnostics::inspect_jacobian_stiffness(*user_data.engine, Y_full, user_data.T9, user_data.rho);
|
diagnostics::inspect_jacobian_stiffness(*user_data.engine, composition, user_data.T9, user_data.rho);
|
||||||
diagnostics::inspect_species_balance(*user_data.engine, "N-14", Y_full, user_data.T9, user_data.rho);
|
diagnostics::inspect_species_balance(*user_data.engine, "N-14", composition, user_data.T9, user_data.rho);
|
||||||
diagnostics::inspect_species_balance(*user_data.engine, "n-1", Y_full, user_data.T9, user_data.rho);
|
diagnostics::inspect_species_balance(*user_data.engine, "n-1", composition, user_data.T9, user_data.rho);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,13 +94,12 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OffDiagonalTrigger::check(const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx) const {
|
bool OffDiagonalTrigger::check(const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx) const {
|
||||||
const size_t numSpecies = ctx.engine.getNetworkSpecies().size();
|
for (const auto& rowSpecies : ctx.engine.getNetworkSpecies()) {
|
||||||
for (int row = 0; row < numSpecies; ++row) {
|
for (const auto& colSpecies : ctx.engine.getNetworkSpecies()) {
|
||||||
for (int col = 0; col < numSpecies; ++col) {
|
double DRowDCol = std::abs(ctx.engine.getJacobianMatrixEntry(rowSpecies, colSpecies));
|
||||||
double DRowDCol = std::abs(ctx.engine.getJacobianMatrixEntry(row, col));
|
if (rowSpecies != colSpecies && DRowDCol > m_threshold) {
|
||||||
if (row != col && DRowDCol > m_threshold) {
|
|
||||||
m_hits++;
|
m_hits++;
|
||||||
LOG_TRACE_L2(m_logger, "OffDiagonalTrigger triggered at t = {} due to entry ({}, {}) = {}", ctx.t, row, col, DRowDCol);
|
LOG_TRACE_L2(m_logger, "OffDiagonalTrigger triggered at t = {} due to entry ({}, {}) = {}", ctx.t, rowSpecies.name(), colSpecies.name(), DRowDCol);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +172,7 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TimestepCollapseTrigger::check(const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx) const {
|
bool TimestepCollapseTrigger::check(const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx) const {
|
||||||
if (m_timestep_window.size() < 1) {
|
if (m_timestep_window.empty()) {
|
||||||
m_misses++;
|
m_misses++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -181,7 +180,7 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
for (const auto& dt : m_timestep_window) {
|
for (const auto& dt : m_timestep_window) {
|
||||||
averageTimestep += dt;
|
averageTimestep += dt;
|
||||||
}
|
}
|
||||||
averageTimestep /= m_timestep_window.size();
|
averageTimestep /= static_cast<double>(m_timestep_window.size());
|
||||||
if (m_relative && (std::abs(ctx.dt - averageTimestep) / averageTimestep) >= m_threshold) {
|
if (m_relative && (std::abs(ctx.dt - averageTimestep) / averageTimestep) >= m_threshold) {
|
||||||
m_hits++;
|
m_hits++;
|
||||||
LOG_TRACE_L2(m_logger, "TimestepCollapseTrigger triggered at t = {} due to relative growth: dt = {}, average dt = {}, threshold = {}", ctx.t, ctx.dt, averageTimestep, m_threshold);
|
LOG_TRACE_L2(m_logger, "TimestepCollapseTrigger triggered at t = {} due to relative growth: dt = {}, average dt = {}, threshold = {}", ctx.t, ctx.dt, averageTimestep, m_threshold);
|
||||||
@@ -250,6 +249,12 @@ namespace gridfire::trigger::solver::CVODE {
|
|||||||
using ctx_t = gridfire::solver::CVODESolverStrategy::TimestepContext;
|
using ctx_t = gridfire::solver::CVODESolverStrategy::TimestepContext;
|
||||||
|
|
||||||
// Create the individual conditions that can trigger a repartitioning
|
// Create the individual conditions that can trigger a repartitioning
|
||||||
|
// The current trigger logic is as follows
|
||||||
|
// 1. Trigger every 1000th time that the simulation time exceeds the simulationTimeInterval
|
||||||
|
// 2. OR if any off-diagonal Jacobian entry exceeds the offDiagonalThreshold
|
||||||
|
// 3. OR every 10th time that the timestep growth exceeds the timestepGrowthThreshold (relative or absolute)
|
||||||
|
|
||||||
|
// TODO: This logic likely needs to be revisited; however, for now it is easy enough to change and test and it works reasonably well
|
||||||
auto simulationTimeTrigger = std::make_unique<EveryNthTrigger<ctx_t>>(std::make_unique<SimulationTimeTrigger>(simulationTimeInterval), 1000);
|
auto simulationTimeTrigger = std::make_unique<EveryNthTrigger<ctx_t>>(std::make_unique<SimulationTimeTrigger>(simulationTimeInterval), 1000);
|
||||||
auto offDiagTrigger = std::make_unique<OffDiagonalTrigger>(offDiagonalThreshold);
|
auto offDiagTrigger = std::make_unique<OffDiagonalTrigger>(offDiagonalThreshold);
|
||||||
auto timestepGrowthTrigger = std::make_unique<EveryNthTrigger<ctx_t>>(std::make_unique<TimestepCollapseTrigger>(timestepGrowthThreshold, timestepGrowthRelative, timestepGrowthWindowSize), 10);
|
auto timestepGrowthTrigger = std::make_unique<EveryNthTrigger<ctx_t>>(std::make_unique<TimestepCollapseTrigger>(timestepGrowthThreshold, timestepGrowthRelative, timestepGrowthWindowSize), 10);
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
|
|
||||||
std::string gridfire::utils::formatNuclearTimescaleLogString(
|
std::string gridfire::utils::formatNuclearTimescaleLogString(
|
||||||
const DynamicEngine& engine,
|
const DynamicEngine& engine,
|
||||||
std::vector<double> const& Y,
|
const fourdst::composition::Composition& composition,
|
||||||
const double T9,
|
const double T9,
|
||||||
const double rho
|
const double rho
|
||||||
) {
|
) {
|
||||||
auto const& result = engine.getSpeciesTimescales(Y, T9, rho);
|
auto const& result = engine.getSpeciesTimescales(composition, T9, rho);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "Failed to get species timescales: " << result.error();
|
ss << "Failed to get species timescales: " << result.error();
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ gridfire_sources = files(
|
|||||||
'lib/engine/diagnostics/dynamic_engine_diagnostics.cpp',
|
'lib/engine/diagnostics/dynamic_engine_diagnostics.cpp',
|
||||||
'lib/reaction/reaction.cpp',
|
'lib/reaction/reaction.cpp',
|
||||||
'lib/reaction/reaclib.cpp',
|
'lib/reaction/reaclib.cpp',
|
||||||
|
'lib/reaction/weak/weak.cpp',
|
||||||
|
'lib/reaction/weak/weak_interpolator.cpp',
|
||||||
'lib/io/network_file.cpp',
|
'lib/io/network_file.cpp',
|
||||||
'lib/solver/solver.cpp',
|
|
||||||
'lib/solver/strategies/CVODE_solver_strategy.cpp',
|
'lib/solver/strategies/CVODE_solver_strategy.cpp',
|
||||||
'lib/solver/strategies/triggers/engine_partitioning_trigger.cpp',
|
'lib/solver/strategies/triggers/engine_partitioning_trigger.cpp',
|
||||||
'lib/screening/screening_types.cpp',
|
'lib/screening/screening_types.cpp',
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ void register_reaction_bindings(py::module &m) {
|
|||||||
.def(
|
.def(
|
||||||
"calculate_rate",
|
"calculate_rate",
|
||||||
[](const gridfire::reaction::ReaclibReaction& self, const double T9, const double rho, const std::vector<double>& Y) -> double {
|
[](const gridfire::reaction::ReaclibReaction& self, const double T9, const double rho, const std::vector<double>& Y) -> double {
|
||||||
return self.calculate_rate(T9, rho, Y);
|
return self.calculate_rate(T9, rho, 0, TODO, Y, TODO);
|
||||||
},
|
},
|
||||||
py::arg("T9"),
|
py::arg("T9"),
|
||||||
py::arg("rho"),
|
py::arg("rho"),
|
||||||
@@ -211,7 +211,7 @@ void register_reaction_bindings(py::module &m) {
|
|||||||
.def(
|
.def(
|
||||||
"calculate_rate",
|
"calculate_rate",
|
||||||
[](const gridfire::reaction::LogicalReaclibReaction& self, const double T9, const double rho, const std::vector<double>& Y) -> double {
|
[](const gridfire::reaction::LogicalReaclibReaction& self, const double T9, const double rho, const std::vector<double>& Y) -> double {
|
||||||
return self.calculate_rate(T9, rho, Y);
|
return self.calculate_rate(T9, rho, 0, TODO, Y, TODO);
|
||||||
},
|
},
|
||||||
py::arg("T9"),
|
py::arg("T9"),
|
||||||
"Calculate the reaction rate at a given temperature T9 (in units of 10^9 K)."
|
"Calculate the reaction rate at a given temperature T9 (in units of 10^9 K)."
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[wrap-git]
|
[wrap-git]
|
||||||
url = https://github.com/4D-STAR/fourdst
|
url = https://github.com/4D-STAR/fourdst
|
||||||
revision = v0.8.0
|
revision = v0.8.1
|
||||||
depth = 1
|
depth = 1
|
||||||
|
|||||||
@@ -5,12 +5,7 @@
|
|||||||
#include "gridfire/engine/engine_approx8.h"
|
#include "gridfire/engine/engine_approx8.h"
|
||||||
#include "gridfire/engine/views/engine_adaptive.h"
|
#include "gridfire/engine/views/engine_adaptive.h"
|
||||||
#include "gridfire/partition/partition_types.h"
|
#include "gridfire/partition/partition_types.h"
|
||||||
#include "gridfire/engine/views/engine_defined.h"
|
|
||||||
#include "gridfire/engine/views/engine_multiscale.h"
|
#include "gridfire/engine/views/engine_multiscale.h"
|
||||||
#include "gridfire/engine/procedures/priming.h"
|
|
||||||
#include "gridfire/io/network_file.h"
|
|
||||||
|
|
||||||
#include "gridfire/solver/solver.h"
|
|
||||||
#include "gridfire/solver/strategies/CVODE_solver_strategy.h"
|
#include "gridfire/solver/strategies/CVODE_solver_strategy.h"
|
||||||
|
|
||||||
#include "gridfire/network.h"
|
#include "gridfire/network.h"
|
||||||
@@ -32,19 +27,6 @@
|
|||||||
|
|
||||||
static std::terminate_handler g_previousHandler = nullptr;
|
static std::terminate_handler g_previousHandler = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void callback(const gridfire::solver::DirectNetworkSolver::TimestepContext& ctx) {
|
|
||||||
const auto H1IndexPtr = std::ranges::find(ctx.engine.getNetworkSpecies(), fourdst::atomic::H_1);
|
|
||||||
const auto He4IndexPtr = std::ranges::find(ctx.engine.getNetworkSpecies(), fourdst::atomic::He_4);
|
|
||||||
|
|
||||||
const size_t H1Index = H1IndexPtr != ctx.engine.getNetworkSpecies().end() ? std::distance(ctx.engine.getNetworkSpecies().begin(), H1IndexPtr) : -1;
|
|
||||||
const size_t He4Index = He4IndexPtr != ctx.engine.getNetworkSpecies().end() ? std::distance(ctx.engine.getNetworkSpecies().begin(), He4IndexPtr) : -1;
|
|
||||||
|
|
||||||
std::cout << "Time: " << ctx.t << ", H-1: " << ctx.state(H1Index) << ", He-4: " << ctx.state(He4Index) << "\n";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void measure_execution_time(const std::function<void()>& callback, const std::string& name)
|
void measure_execution_time(const std::function<void()>& callback, const std::string& name)
|
||||||
{
|
{
|
||||||
const auto startTime = std::chrono::steady_clock::now();
|
const auto startTime = std::chrono::steady_clock::now();
|
||||||
|
|||||||
Reference in New Issue
Block a user