3#include "atomicSpecies.h"
9#include <unordered_map>
12#include <boost/numeric/ublas/matrix_sparse.hpp>
14#include "cppad/cppad.hpp"
16#include "quill/LogMacros.h"
45 concept IsArithmeticOrAD = std::is_same_v<T, double> || std::is_same_v<T, CppAD::AD<double>>;
94 const double cullingThreshold,
const double T9);
126 [[nodiscard]]
const std::vector<serif::atomic::Species>&
getNetworkSpecies()
const;
153 const reaclib::REACLIBReaction &reaction)
const;
165 [[nodiscard]]
bool involvesSpecies(
const serif::atomic::Species& species)
const;
174 [[deprecated(
"not implimented")]] std::vector<std::vector<std::string>>
detectCycles()
const;
223 void operator()(
const boost::numeric::ublas::vector<double>&Y, boost::numeric::ublas::vector<double>& dYdt,
double )
const {
224 const std::vector<double> y(Y.begin(), Y.begin() +
m_numSpecies);
229 std::ranges::copy(derivatives.
dydt, dYdt.begin());
257 void operator()(
const boost::numeric::ublas::vector<double>& Y, boost::numeric::ublas::matrix<double>& J,
double , boost::numeric::ublas::vector<double>& )
const {
258 const std::vector<double> y_species(Y.begin(), Y.begin() +
m_numSpecies);
266 for (
auto it1 =
m_network.m_jacobianMatrix.begin1(); it1 !=
m_network.m_jacobianMatrix.end1(); ++it1) {
267 for (
auto it2 = it1.begin(); it2 != it1.end(); ++it2) {
268 J(it2.index1(), it2.index2()) = *it2;
278 template <IsArithmeticOrAD T>
366 template <IsArithmeticOrAD T>
398 template <IsArithmeticOrAD GeneralScalarType>
399 std::vector<GeneralScalarType>
calculateRHS(
const std::vector<GeneralScalarType> &Y,
const GeneralScalarType T9,
400 const GeneralScalarType rho)
const;
416 template <IsArithmeticOrAD GeneralScalarType>
418 const std::vector<GeneralScalarType> &Y,
const GeneralScalarType T9,
419 const GeneralScalarType rho)
const;
440 void detectStiff(
const NetIn &netIn,
double T9,
double numSpecies,
const boost::numeric::ublas::vector<double>& Y);
444 template<IsArithmeticOrAD T>
446 const std::vector<T> &Y, T T9, T rho)
const {
454 const T u =
static_cast<T
>(
m_constants.get(
"u").value);
455 const T MeV_to_erg =
static_cast<T
>(
m_constants.get(
"MeV_to_erg").value);
457 T volumetricEnergyRate =
static_cast<T
>(0.0);
460 for (
size_t reactionIndex = 0; reactionIndex <
m_reactions.size(); ++reactionIndex) {
467 for (
size_t speciesIndex = 0; speciesIndex <
m_networkSpecies.size(); ++speciesIndex) {
470 const T speciesAtomicMassAMU =
static_cast<T
>(
m_networkSpecies[speciesIndex].mass());
471 const T speciesAtomicMassGrams = speciesAtomicMassAMU * u;
472 result.
dydt[speciesIndex] += (nu_ij * reactionRate * speciesAtomicMassGrams) / rho;
477 const T q_value_ergs =
static_cast<T
>(reaction.qValue()) * MeV_to_erg;
478 volumetricEnergyRate += reactionRate * q_value_ergs;
487 template <IsArithmeticOrAD GeneralScalarType>
489 const GeneralScalarType T9,
const GeneralScalarType rho)
const {
492 const auto u = constants.get(
"u");
493 const GeneralScalarType uValue =
static_cast<GeneralScalarType
>(u.value);
494 const GeneralScalarType k_reaction = reaction.calculate_rate(T9);
496 GeneralScalarType reactant_product_or_particle_densities =
static_cast<GeneralScalarType
>(1.0);
498 std::unordered_map<std::string, int> reactant_counts;
499 reactant_counts.reserve(reaction.reactants().size());
500 for (
const auto& reactant : reaction.reactants()) {
501 reactant_counts[std::string(reactant.name())]++;
507 if (rho < minDensityThreshold) {
510 return static_cast<GeneralScalarType
>(0.0);
513 for (
const auto& [species_name, count] : reactant_counts) {
516 LOG_ERROR(
m_logger,
"Reactant species '{}' not found in species to index map for reaction '{}'.",
517 species_name, reaction.id());
518 throw std::runtime_error(
"Reactant species not found in species to index map: " + species_name);
520 const size_t species_index = species_it->second;
521 const GeneralScalarType Yi = Y[species_index];
523 if (Yi < minAbundanceThreshold) {
524 return static_cast<GeneralScalarType
>(0.0);
527 GeneralScalarType atomicMassAMU =
static_cast<GeneralScalarType
>(
m_networkSpecies[species_index].mass());
530 GeneralScalarType ni;
531 const GeneralScalarType denominator = atomicMassAMU * uValue;
532 if (denominator > minDensityThreshold) {
533 ni = (Yi * rho) / (denominator);
535 ni =
static_cast<GeneralScalarType
>(0.0);
538 reactant_product_or_particle_densities *= ni;
542 reactant_product_or_particle_densities /=
static_cast<GeneralScalarType
>(std::tgamma(
static_cast<double>(count + 1)));
545 const GeneralScalarType Na =
static_cast<GeneralScalarType
>(constants.get(
"N_a").value);
546 const int numReactants =
static_cast<int>(reaction.reactants().size());
547 GeneralScalarType molarCorrectionFactor =
static_cast<GeneralScalarType
>(1.0);
548 if (numReactants > 1) {
549 molarCorrectionFactor = CppAD::pow(Na,
static_cast<GeneralScalarType
>(reaction.reactants().size() - 1));
551 return (reactant_product_or_particle_densities * k_reaction) / molarCorrectionFactor;
554 template <IsArithmeticOrAD GeneralScalarType>
556 const std::vector<GeneralScalarType>& Y,
557 const GeneralScalarType T9,
558 const GeneralScalarType rho)
const {
561 return derivatives.dydt;
Manages the composition of elements.
static Constants & getInstance()
get instance of constants singleton
std::vector< GeneralScalarType > calculateRHS(const std::vector< GeneralScalarType > &Y, const GeneralScalarType T9, const GeneralScalarType rho) const
Calculate the right-hand side (dY/dt) for the ODE system.
std::vector< std::string > topologicalSortReactions() const
Perform a topological sort of the reactions (not implemented).
boost::numeric::ublas::compressed_matrix< double > m_jacobianMatrix
Jacobian matrix (species x species).
const std::vector< serif::atomic::Species > & getNetworkSpecies() const
Get the vector of unique species in the network.
std::unordered_map< std::string_view, serif::atomic::Species > m_networkSpeciesMap
Map from species name to Species object.
std::unordered_map< std::string_view, const reaclib::REACLIBReaction > m_reactionIDMap
Map from reaction ID to REACLIBReaction. //PERF: This makes copies of REACLIBReaction and could be a ...
GeneralScalarType calculateReactionRate(const reaclib::REACLIBReaction &reaction, const std::vector< GeneralScalarType > &Y, const GeneralScalarType T9, const GeneralScalarType rho) const
Calculate the reaction rate for a given reaction in dimensions of particles per cm^3 per second.
CppAD::ADFun< double > m_rhsADFun
CppAD function for the right-hand side of the ODE.
reaclib::REACLIBReactionSet m_reactions
Set of REACLIB reactions in the network.
std::unordered_map< serif::atomic::Species, int > getNetReactionStoichiometry(const reaclib::REACLIBReaction &reaction) const
Get the net stoichiometric coefficients for all species in a reaction.
void populateReactionIDMap()
Populate the reaction ID map from the reaction set.
void detectStiff(const NetIn &netIn, double T9, double numSpecies, const boost::numeric::ublas::vector< double > &Y)
Detect if the network is stiff and select the appropriate ODE solver.
GraphNetwork(const serif::composition::Composition &composition)
Construct a GraphNetwork from a composition.
bool validateConservation() const
Validate mass and charge conservation for all reactions.
void populateSpeciesToIndexMap()
Populate the species-to-index map for matrix construction.
void reserveJacobianMatrix()
Reserve and resize the Jacobian matrix.
void validateComposition(const serif::composition::Composition &composition, double culling, double T9)
Validate and update the network composition if needed.
void collectNetworkSpecies()
Collect all unique species from the reaction set.
std::unordered_map< serif::atomic::Species, size_t > m_speciesToIndexMap
Map from species to their index in the stoichiometry matrix.
void generateStoichiometryMatrix()
Generate the stoichiometry matrix for the network.
void syncInternalMaps()
Synchronize all internal maps and matrices after network changes.
bool involvesSpecies(const serif::atomic::Species &species) const
Check if a species is present in the network.
void generateJacobianMatrix(const std::vector< double > &Y, const double T9, const double rho)
Generate the Jacobian matrix for the network.
const reaclib::REACLIBReactionSet & getNetworkReactions() const
Get the set of REACLIB reactions in the network.
boost::numeric::ublas::compressed_matrix< int > m_stoichiometryMatrix
Stoichiometry matrix (species x reactions).
std::vector< std::vector< std::string > > detectCycles() const
Detect cycles in the reaction network (not implemented).
NetOut evaluate(const NetIn &netIn) override
Evolve the network for the given input conditions.
std::vector< serif::atomic::Species > m_networkSpecies
Vector of unique species in the network.
void recordADTape()
Record the CppAD tape for automatic differentiation.
StepDerivatives< T > calculateAllDerivatives(const std::vector< T > &Y, T T9, T rho) const
Calculate all derivatives (dY/dt and energy rate) for the current state.
Network(const NetworkFormat format=NetworkFormat::APPROX8)
serif::constant::Constants & m_constants
quill::Logger * m_logger
Logger instance.
Concept to check if a type is either double or CppAD::AD<double>.
static constexpr double MIN_JACOBIAN_THRESHOLD
Minimum Jacobian entry threshold for sparsity.
static constexpr double MIN_DENSITY_THRESHOLD
Minimum density threshold (g/cm^3) below which reactions are ignored.
static constexpr double MIN_ABUNDANCE_THRESHOLD
Minimum abundance threshold below which reactions are ignored.
GraphNetwork & m_network
Reference to the network.
const double m_T9
Temperature in 10^9 K.
const size_t m_numSpecies
Number of species.
JacobianTerm(GraphNetwork &network, const double T9, const double rho)
Construct a JacobianTerm functor.
void operator()(const boost::numeric::ublas::vector< double > &Y, boost::numeric::ublas::matrix< double > &J, double, boost::numeric::ublas::vector< double > &) const
Compute the Jacobian matrix for the ODE solver.
const double m_rho
Density in g/cm^3.
const double m_T9
Temperature in 10^9 K.
void operator()(const boost::numeric::ublas::vector< double > &Y, boost::numeric::ublas::vector< double > &dYdt, double) const
Compute dY/dt and energy rate for the ODE solver.
ODETerm(GraphNetwork &network, const double T9, double rho)
Construct an ODETerm functor.
GraphNetwork & m_network
Reference to the network.
const size_t m_numSpecies
Number of species.
const double m_rho
Density in g/cm^3.
Struct holding derivatives for a single ODE step.
T specificEnergyRate
Specific energy generation rate.
std::vector< T > dydt
Derivatives of abundances.
Input structure for the network evaluation.
Output structure for the network evaluation.