9#include "fourdst/composition/species.h"
10#include "fourdst/composition/atomicSpecies.h"
12#include "quill/LogMacros.h"
20#include <unordered_map>
26#include <boost/numeric/odeint.hpp>
28#include "cppad/cppad.hpp"
29#include "cppad/utility/sparse_rc.hpp"
30#include "cppad/utility/sparse_rcv.hpp"
35 const fourdst::composition::Composition &composition,
40 const fourdst::composition::Composition &composition,
58 const std::vector<double> &Y,
63 std::vector<double> bare_rates;
64 std::vector<double> bare_reverse_rates;
70 bare_rates.push_back(
reaction.calculate_rate(T9));
82 LOG_INFO(
m_logger,
"Synchronizing internal maps for REACLIB graph network (serif::network::GraphNetwork)...");
94 const std::vector<bool> select_domain(n,
true);
95 const std::vector<bool> select_range(m,
true);
101 LOG_INFO(
m_logger,
"Internal maps synchronized. Network contains {} species and {} reactions.",
110 std::set<std::string_view> uniqueSpeciesNames;
113 for (
const auto& reactant:
reaction.reactants()) {
114 uniqueSpeciesNames.insert(reactant.name());
116 for (
const auto& product:
reaction.products()) {
117 uniqueSpeciesNames.insert(product.name());
121 for (
const auto& name: uniqueSpeciesNames) {
122 auto it = fourdst::atomic::species.find(std::string(name));
123 if (it != fourdst::atomic::species.end()) {
127 LOG_ERROR(
m_logger,
"Species '{}' not found in global atomic species database.", name);
129 throw std::runtime_error(
"Species not found in global atomic species database: " + std::string(name));
136 LOG_TRACE_L1(
m_logger,
"Populating reaction ID map for REACLIB graph network (serif::network::GraphNetwork)...");
157 LOG_TRACE_L2(
m_logger,
"Jacobian matrix resized to {} rows and {} columns.",
170 LOG_TRACE_L3(
m_logger,
"Providing access to network reactions set. Size: {}.",
m_reactions.size());
182 LOG_DEBUG(
m_logger,
"Checking if species '{}' is involved in the network: {}.", species.name(), found ?
"Yes" :
"No");
188 LOG_TRACE_L1(
m_logger,
"Validating mass (A) and charge (Z) conservation across all reactions in the network.");
191 uint64_t totalReactantA = 0;
192 uint64_t totalReactantZ = 0;
193 uint64_t totalProductA = 0;
194 uint64_t totalProductZ = 0;
197 for (
const auto& reactant :
reaction.reactants()) {
200 totalReactantA += it->second.a();
201 totalReactantZ += it->second.z();
205 LOG_ERROR(
m_logger,
"CRITICAL ERROR: Reactant species '{}' in reaction '{}' not found in network species map during conservation validation.",
212 for (
const auto& product :
reaction.products()) {
215 totalProductA += it->second.a();
216 totalProductZ += it->second.z();
219 LOG_ERROR(
m_logger,
"CRITICAL ERROR: Product species '{}' in reaction '{}' not found in network species map during conservation validation.",
226 if (totalReactantA != totalProductA) {
227 LOG_ERROR(
m_logger,
"Mass number (A) not conserved for reaction '{}': Reactants A={} vs Products A={}.",
228 reaction.id(), totalReactantA, totalProductA);
231 if (totalReactantZ != totalProductZ) {
232 LOG_ERROR(
m_logger,
"Atomic number (Z) not conserved for reaction '{}': Reactants Z={} vs Products Z={}.",
233 reaction.id(), totalReactantZ, totalProductZ);
238 LOG_TRACE_L1(
m_logger,
"Mass (A) and charge (Z) conservation validated successfully for all reactions.");
256 LOG_DEBUG(
m_logger,
"Reaction set not cached. Rebuilding the reaction set for T9={} and culling={}.", T9, culling);
267 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());
272 std::cout <<
"\texpFactor = exp(-qValue/(kB * T9))\n";
273 std::cout <<
"\texpFactor: " << expFactor <<
" for reaction: " <<
reaction.peName() << std::endl;
274 std::cout <<
"\tQ-value: " <<
reaction.qValue() <<
" at T9: " << T9 << std::endl;
275 std::cout <<
"\tT9: " << T9 << std::endl;
276 std::cout <<
"\tkB * T9: " <<
m_constants.kB * T9 << std::endl;
277 std::cout <<
"\tqValue/(kB * T9): " <<
reaction.qValue() / (
m_constants.kB * T9) << std::endl;
279 double reverseRate = 0.0;
280 const double forwardRate =
reaction.calculate_rate(T9);
285 LOG_WARNING_LIMIT_EVERY_N(1000000,
m_logger,
"Reverse rate calculation for reactions with more than two reactants or products is not implemented (reaction id {}).",
reaction.peName());
287 LOG_TRACE_L2_LIMIT_EVERY_N(1000,
m_logger,
"Calculated reverse rate for reaction '{}': {:.3E} at T9={:.3E}.",
reaction.id(), reverseRate, T9);
294 const double forwardRate,
295 const double expFactor
297 std::vector<double> reactantPartitionFunctions;
298 std::vector<double> productPartitionFunctions;
300 reactantPartitionFunctions.reserve(
reaction.reactants().size());
301 productPartitionFunctions.reserve(
reaction.products().size());
303 std::unordered_map<fourdst::atomic::Species, int> reactantMultiplicity;
304 std::unordered_map<fourdst::atomic::Species, int> productMultiplicity;
306 reactantMultiplicity.reserve(
reaction.reactants().size());
307 productMultiplicity.reserve(
reaction.products().size());
309 for (
const auto& reactant :
reaction.reactants()) {
310 reactantMultiplicity[reactant] += 1;
312 for (
const auto& product :
reaction.products()) {
313 productMultiplicity[product] += 1;
315 double reactantSymmetryFactor = 1.0;
316 double productSymmetryFactor = 1.0;
317 for (
const auto& count : reactantMultiplicity | std::views::values) {
318 reactantSymmetryFactor *= std::tgamma(count + 1);
320 for (
const auto& count : productMultiplicity | std::views::values) {
321 productSymmetryFactor *= std::tgamma(count + 1);
323 const double symmetryFactor = reactantSymmetryFactor / productSymmetryFactor;
326 auto mass_op = [](
double acc,
const auto& species) {
return acc * species.a(); };
327 const double massNumerator = std::accumulate(
333 const double massDenominator = std::accumulate(
341 auto pf_op = [&](
double acc,
const auto& species) {
344 const double partitionFunctionNumerator = std::accumulate(
350 const double partitionFunctionDenominator = std::accumulate(
357 const double CT = std::pow(massNumerator/massDenominator, 1.5) *
358 (partitionFunctionNumerator/partitionFunctionDenominator);
360 const double reverseRate = forwardRate * symmetryFactor * CT * expFactor;
361 if (!std::isfinite(reverseRate)) {
371 const double reverseRate
374 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());
377 const double d_log_kFwd =
reaction.calculate_forward_rate_log_derivative(T9);
379 auto log_deriv_pf_op = [&](
double acc,
const auto& species) {
381 const double dg_dT =
m_partitionFunction->evaluateDerivative(species.z(), species.a(), T9);
382 return (g == 0.0) ? acc : acc + (dg_dT / g);
385 const double reactant_log_derivative_sum = std::accumulate(
392 const double product_log_derivative_sum = std::accumulate(
399 const double d_log_C = reactant_log_derivative_sum - product_log_derivative_sum;
403 const double log_total_derivative = d_log_kFwd + d_log_C + d_log_exp;
405 return reverseRate * log_total_derivative;
423 for (
const auto& [symbol, entry] : netIn.
composition) {
431 fourdst::composition::Composition composition;
433 std::vector<std::string> symbols;
436 symbols.emplace_back(symbol.name());
438 composition.registerSymbol(symbols);
439 for (
const auto& [symbol, entry] : netIn.
composition) {
441 composition.setMassFraction(symbol, entry.mass_fraction());
443 composition.setMassFraction(symbol, 0.0);
446 composition.finalize(
true);
453 return primingReport;
466 LOG_DEBUG(
m_logger,
"Rebuild requested with the same depth. No changes made to the network.");
471 const std::vector<double> &Y_in,
472 const std::vector<double> &bare_rates,
473 const std::vector<double> &bare_reverse_rates,
478 const std::vector<double> screeningFactors =
m_screeningModel->calculateScreeningFactors(
487 std::vector<double> molarReactionFlows;
491 double forwardAbundanceProduct = 1.0;
493 for (
size_t i = 0; i < precomp.unique_reactant_indices.size(); ++i) {
494 const size_t reactantIndex = precomp.unique_reactant_indices[i];
495 const int power = precomp.reactant_powers[i];
502 forwardAbundanceProduct *= std::pow(Y_in[reactantIndex], power);
509 const double bare_rate = bare_rates[precomp.reaction_index];
510 const double screeningFactor = screeningFactors[precomp.reaction_index];
511 const size_t numReactants =
m_reactions[precomp.reaction_index].reactants().size();
512 const size_t numProducts =
m_reactions[precomp.reaction_index].products().size();
514 const double forwardMolarReactionFlow =
517 precomp.symmetry_factor *
518 forwardAbundanceProduct *
519 std::pow(rho, numReactants > 1 ? numReactants - 1 : 0.0);
521 double reverseMolarReactionFlow = 0.0;
523 const double bare_reverse_rate = bare_reverse_rates[precomp.reaction_index];
524 double reverseAbundanceProduct = 1.0;
525 for (
size_t i = 0; i < precomp.unique_product_indices.size(); ++i) {
526 reverseAbundanceProduct *= std::pow(Y_in[precomp.unique_product_indices[i]], precomp.product_powers[i]);
528 reverseMolarReactionFlow = screeningFactor *
530 precomp.reverse_symmetry_factor *
531 reverseAbundanceProduct *
532 std::pow(rho, numProducts > 1 ? numProducts - 1 : 0.0);
535 molarReactionFlows.push_back(forwardMolarReactionFlow - reverseMolarReactionFlow);
544 const double R_j = molarReactionFlows[j];
546 for (
size_t i = 0; i < precomp.affected_species_indices.size(); ++i) {
547 const size_t speciesIndex = precomp.affected_species_indices[i];
548 const int stoichiometricCoefficient = precomp.stoichiometric_coefficients[i];
551 result.
dydt[speciesIndex] +=
static_cast<double>(stoichiometricCoefficient) * R_j;
556 double massProductionRate = 0.0;
568 LOG_TRACE_L1(
m_logger,
"Generating stoichiometry matrix...");
575 LOG_TRACE_L1(
m_logger,
"Stoichiometry matrix initialized with dimensions: {} rows (species) x {} columns (reactions).",
576 numSpecies, numReactions);
580 size_t reactionColumnIndex = 0;
583 std::unordered_map<fourdst::atomic::Species, int> netStoichiometry =
reaction.stoichiometry();
586 for (
const auto& [species, coefficient] : netStoichiometry) {
590 const size_t speciesRowIndex = it->second;
595 LOG_ERROR(
m_logger,
"CRITICAL ERROR: Species '{}' from reaction '{}' stoichiometry not found in species to index map.",
598 throw std::runtime_error(
"Species not found in species to index map: " + std::string(species.name()));
601 reactionColumnIndex++;
604 LOG_TRACE_L1(
m_logger,
"Stoichiometry matrix population complete. Number of non-zero elements: {}.",
609 const std::vector<double> &Y_in,
617 const std::vector<ADDouble> &Y_in,
647 const std::vector<double> &Y,
655 const std::vector<double> &Y_dynamic,
660 LOG_TRACE_L1_LIMIT_EVERY_N(1000,
m_logger,
"Generating jacobian matrix for T9={}, rho={}..", T9, rho);
664 std::vector<double> adInput(numSpecies + 2, 0.0);
665 for (
size_t i = 0; i < numSpecies; ++i) {
666 adInput[i] = std::max(Y_dynamic[i], 1e-99);
668 adInput[numSpecies] = T9;
669 adInput[numSpecies + 1] = rho;
672 const std::vector<double> dotY =
m_rhsADFun.Jacobian(adInput);
676 for (
size_t i = 0; i < numSpecies; ++i) {
677 for (
size_t j = 0; j < numSpecies; ++j) {
678 const double value = dotY[i * (numSpecies + 2) + j];
688 const std::vector<double> &Y_dynamic,
695 std::vector<double> x(numSpecies + 2, 0.0);
696 for (
size_t i = 0; i < numSpecies; ++i) {
700 x[numSpecies + 1] = rho;
703 const size_t nnz = sparsityPattern.size();
704 std::vector<size_t> row_indices(nnz);
705 std::vector<size_t> col_indices(nnz);
707 for (
size_t k = 0; k < nnz; ++k) {
708 row_indices[k] = sparsityPattern[k].first;
709 col_indices[k] = sparsityPattern[k].second;
712 std::vector<double> values(nnz);
713 const size_t num_rows_jac = numSpecies;
714 const size_t num_cols_jac = numSpecies + 2;
716 CppAD::sparse_rc<std::vector<size_t>> CppAD_sparsity_pattern(num_rows_jac, num_cols_jac, nnz);
717 for (
size_t k = 0; k < nnz; ++k) {
718 CppAD_sparsity_pattern.set(k, sparsityPattern[k].first, sparsityPattern[k].second);
721 CppAD::sparse_rcv<std::vector<size_t>, std::vector<double>> jac_subset(CppAD_sparsity_pattern);
733 for (
size_t k = 0; k < nnz; ++k) {
734 const size_t row = jac_subset.row()[k];
735 const size_t col = jac_subset.col()[k];
736 const double value = jac_subset.val()[k];
756 const int speciesIndex,
757 const int reactionIndex
763 LOG_TRACE_L1(
m_logger,
"Exporting network graph to DOT file: {}", filename);
765 std::ofstream dotFile(filename);
766 if (!dotFile.is_open()) {
767 LOG_ERROR(
m_logger,
"Failed to open file for writing: {}", filename);
769 throw std::runtime_error(
"Failed to open file for writing: " + filename);
772 dotFile <<
"digraph NuclearReactionNetwork {\n";
773 dotFile <<
" graph [rankdir=LR, splines=true, overlap=false, bgcolor=\"#f0f0f0\"];\n";
774 dotFile <<
" node [shape=circle, style=filled, fillcolor=\"#a7c7e7\", fontname=\"Helvetica\"];\n";
775 dotFile <<
" edge [fontname=\"Helvetica\", fontsize=10];\n\n";
778 dotFile <<
" // --- Species Nodes ---\n";
780 dotFile <<
" \"" << species.name() <<
"\" [label=\"" << species.name() <<
"\"];\n";
785 dotFile <<
" // --- Reaction Edges ---\n";
788 std::string reactionNodeId =
"reaction_" + std::string(
reaction.id());
791 dotFile <<
" \"" << reactionNodeId <<
"\" [shape=point, fillcolor=black, width=0.1, height=0.1, label=\"\"];\n";
794 for (
const auto& reactant :
reaction.reactants()) {
795 dotFile <<
" \"" << reactant.name() <<
"\" -> \"" << reactionNodeId <<
"\";\n";
799 for (
const auto& product :
reaction.products()) {
800 dotFile <<
" \"" << reactionNodeId <<
"\" -> \"" << product.name() <<
"\" [label=\"" <<
reaction.qValue() <<
" MeV\"];\n";
807 LOG_TRACE_L1(
m_logger,
"Successfully exported network to {}", filename);
811 LOG_TRACE_L1(
m_logger,
"Exporting network graph to CSV file: {}", filename);
813 std::ofstream csvFile(filename, std::ios::out | std::ios::trunc);
814 if (!csvFile.is_open()) {
815 LOG_ERROR(
m_logger,
"Failed to open file for writing: {}", filename);
817 throw std::runtime_error(
"Failed to open file for writing: " + filename);
819 csvFile <<
"Reaction;Reactants;Products;Q-value;sources;rates\n";
825 for (
const auto& reactant :
reaction.reactants()) {
826 csvFile << reactant.name();
827 if (++count <
reaction.reactants().size()) {
833 for (
const auto& product :
reaction.products()) {
834 csvFile << product.name();
835 if (++count <
reaction.products().size()) {
839 csvFile <<
";" <<
reaction.qValue() <<
";";
843 for (
const auto& source : sources) {
845 if (++count < sources.size()) {
852 for (
const auto& rates :
reaction) {
861 LOG_TRACE_L1(
m_logger,
"Successfully exported network graph to {}", filename);
865 const std::vector<double> &Y,
870 std::unordered_map<fourdst::atomic::Species, double> speciesTimescales;
873 double timescale = std::numeric_limits<double>::infinity();
875 if (std::abs(dydt[i]) > 0.0) {
876 timescale = std::abs(Y[i] / dydt[i]);
878 speciesTimescales.emplace(species, timescale);
880 return speciesTimescales;
884 const std::vector<double> &Y,
889 std::unordered_map<fourdst::atomic::Species, double> speciesDestructionTimescales;
892 double netDestructionFlow = 0.0;
894 if (
reaction.stoichiometry(species) < 0) {
896 netDestructionFlow += flow;
899 double timescale = std::numeric_limits<double>::infinity();
900 if (netDestructionFlow != 0.0) {
903 speciesDestructionTimescales.emplace(species, timescale);
905 return speciesDestructionTimescales;
909 fourdst::composition::Composition baseUpdatedComposition = netIn.
composition;
912 baseUpdatedComposition.registerSpecies(species);
913 baseUpdatedComposition.setMassFraction(species, 0.0);
916 baseUpdatedComposition.finalize(
false);
917 return baseUpdatedComposition;
925 LOG_TRACE_L1(
m_logger,
"Recording AD tape for the RHS calculation...");
929 if (numSpecies == 0) {
930 LOG_ERROR(
m_logger,
"Cannot record AD tape: No species in the network.");
932 throw std::runtime_error(
"Cannot record AD tape: No species in the network.");
934 const size_t numADInputs = numSpecies + 2;
942 const auto uniformMassFraction =
static_cast<CppAD::AD<double>
>(1.0 /
static_cast<double>(numSpecies));
943 std::vector<CppAD::AD<double>> adInput(numADInputs, uniformMassFraction);
944 adInput[numSpecies] = 1.0;
945 adInput[numSpecies + 1] = 1.0;
949 CppAD::Independent(adInput);
951 std::vector<CppAD::AD<double>> adY(numSpecies);
952 for(
size_t i = 0; i < numSpecies; ++i) {
955 const CppAD::AD<double> adT9 = adInput[numSpecies];
956 const CppAD::AD<double> adRho = adInput[numSpecies + 1];
965 LOG_TRACE_L1(
m_logger,
"AD tape recorded successfully for the RHS calculation. Number of independent variables: {}.",
983 LOG_TRACE_L1(
m_logger,
"Pre-computing constant components of GraphNetwork state...");
986 std::unordered_map<fourdst::atomic::Species, size_t> speciesIndexMap;
1001 std::unordered_map<size_t, int> reactantCounts;
1002 for (
const auto& reactant:
reaction.reactants()) {
1003 size_t reactantIndex = speciesIndexMap.at(reactant);
1004 reactantCounts[reactantIndex]++;
1007 double symmetryDenominator = 1.0;
1008 for (
const auto& [index, count] : reactantCounts) {
1012 symmetryDenominator *= std::tgamma(count + 1);
1019 std::unordered_map<size_t, int> productCounts;
1020 for (
const auto& product :
reaction.products()) {
1021 productCounts[speciesIndexMap.at(product)]++;
1023 double reverseSymmetryDenominator = 1.0;
1024 for (
const auto& [index, count] : productCounts) {
1027 reverseSymmetryDenominator *= std::tgamma(count + 1);
1038 const auto stoichiometryMap =
reaction.stoichiometry();
1042 for (
const auto& [species, coeff] : stoichiometryMap) {
1054 const CppAD::vector<bool> &vx,
1055 CppAD::vector<bool> &vy,
1056 const CppAD::vector<double> &tx,
1057 CppAD::vector<double> &ty
1060 if ( p != 0) {
return false; }
1061 const double T9 = tx[0];
1065 ty[0] = reverseRate;
1067 if (vx.size() > 0) {
1075 const CppAD::vector<double> &tx,
1076 const CppAD::vector<double> &ty,
1077 CppAD::vector<double> &px,
1078 const CppAD::vector<double> &py
1080 const double T9 = tx[0];
1081 const double reverseRate = ty[0];
1083 const double derivative =
m_engine.calculateReverseRateTwoBodyDerivative(
m_reaction, T9, reverseRate);
1086 px[0] = py[0] * derivative;
1093 const CppAD::vector<std::set<size_t>> &r,
1094 CppAD::vector<std::set<size_t>> &s
1102 const CppAD::vector<std::set<size_t>> &rt,
1103 CppAD::vector<std::set<size_t>> &st
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
const GraphEngine & m_engine
bool rev_sparse_jac(size_t q, const CppAD::vector< std::set< size_t > > &rt, CppAD::vector< std::set< size_t > > &st) override
const reaction::Reaction & m_reaction
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 for_sparse_jac(size_t q, const CppAD::vector< std::set< size_t > > &r, CppAD::vector< std::set< size_t > > &s) override
bool isPrecomputationEnabled() const
double calculateReverseRateTwoBody(const reaction::Reaction &reaction, const double T9, const double forwardRate, const double expFactor) const
double calculateReverseRate(const reaction::Reaction &reaction, double T9) const
const std::vector< fourdst::atomic::Species > & getNetworkSpecies() const override
Gets the list of species in the network.
BuildDepthType getDepth() const override
bool m_usePrecomputation
Flag to enable or disable using precomputed reactions for efficiency. Mathematically,...
CppAD::sparse_rc< std::vector< size_t > > m_full_jacobian_sparsity_pattern
Full sparsity pattern for the Jacobian matrix.
CppAD::sparse_jac_work m_jac_work
Work object for sparse Jacobian calculations.
void populateReactionIDMap()
Populates the reaction ID map.
std::vector< double > mapNetInToMolarAbundanceVector(const NetIn &netIn) const override
void collectAtomicReverseRateAtomicBases()
CppAD::ADFun< double > m_rhsADFun
CppAD function for the right-hand side of the ODE.
boost::numeric::ublas::compressed_matrix< double > m_jacobianMatrix
Jacobian matrix (species x species).
double getJacobianMatrixEntry(const int i, const int j) const override
Gets an entry from the previously generated Jacobian matrix.
std::unordered_map< std::string_view, fourdst::atomic::Species > m_networkSpeciesMap
Map from species name to Species object.
bool m_useReverseReactions
Flag to enable or disable reverse reactions. If false, only forward reactions are considered.
std::unique_ptr< partition::PartitionFunction > m_partitionFunction
Partition function for the network.
void setNetworkReactions(const reaction::LogicalReactionSet &reactions) override
void setUseReverseReactions(bool useReverse)
void populateSpeciesToIndexMap()
Populates the species-to-index map.
screening::ScreeningType m_screeningType
Screening type for the reaction network. Default to no screening.
fourdst::composition::Composition update(const NetIn &netIn) override
Update the internal state of the engine.
std::vector< PrecomputedReaction > m_precomputedReactions
Precomputed reactions for efficiency.
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 ...
std::expected< std::unordered_map< fourdst::atomic::Species, double >, expectations::StaleEngineError > getSpeciesTimescales(const std::vector< double > &Y, double T9, double rho) const override
Computes timescales for all species in the network.
screening::ScreeningType getScreeningModel() const override
Get the current electron screening model.
int getStoichiometryMatrixEntry(const int speciesIndex, const int reactionIndex) const override
Gets an entry from the stoichiometry matrix.
void setPrecomputation(bool precompute)
void setScreeningModel(screening::ScreeningType) override
Set the electron screening model.
std::vector< std::unique_ptr< AtomicReverseRate > > m_atomicReverseRates
void exportToCSV(const std::string &filename) const
Exports the network to a CSV file for analysis.
static std::unordered_map< fourdst::atomic::Species, int > getNetReactionStoichiometry(const reaction::Reaction &reaction)
Gets the net stoichiometry for a given reaction.
void reserveJacobianMatrix() const
Reserves space for the Jacobian matrix.
int getSpeciesIndex(const fourdst::atomic::Species &species) const override
double calculateMolarReactionFlow(const reaction::Reaction &reaction, const std::vector< double > &Y, const double T9, const double rho) const override
Calculates the molar reaction flow for a given reaction.
std::vector< fourdst::atomic::Species > m_networkSpecies
Vector of unique species in the network.
void recordADTape()
Records the AD tape for the right-hand side of the ODE.
StepDerivatives< double > calculateAllDerivativesUsingPrecomputation(const std::vector< double > &Y_in, const std::vector< double > &bare_rates, const std::vector< double > &bare_reverse_rates, double T9, double rho) const
bool involvesSpecies(const fourdst::atomic::Species &species) const
Checks if a given species is involved in the network.
std::expected< StepDerivatives< double >, expectations::StaleEngineError > calculateRHSAndEnergy(const std::vector< double > &Y, const double T9, const double rho) const override
Calculates the right-hand side (dY/dt) and energy generation rate.
reaction::LogicalReactionSet m_reactions
Set of REACLIB reactions in the network.
void syncInternalMaps()
Synchronizes the internal maps.
bool validateConservation() const
Validates mass and charge conservation across all reactions.
void generateJacobianMatrix(const std::vector< double > &Y_dynamic, const double T9, const double rho) const override
Generates the Jacobian matrix for the current state.
boost::numeric::ublas::compressed_matrix< int > m_stoichiometryMatrix
Stoichiometry matrix (species x reactions).
const reaction::LogicalReactionSet & getNetworkReactions() const override
Gets the set of logical reactions in the network.
std::unordered_map< fourdst::atomic::Species, size_t > m_speciesToIndexMap
Map from species to their index in the stoichiometry matrix.
void rebuild(const fourdst::composition::Composition &comp, const BuildDepthType depth) override
void exportToDot(const std::string &filename) const
Exports the network to a DOT file for visualization.
const partition::PartitionFunction & getPartitionFunction() const
bool isUsingReverseReactions() const
PrimingReport primeEngine(const NetIn &netIn) override
void generateStoichiometryMatrix() override
Generates the stoichiometry matrix for the network.
void collectNetworkSpecies()
Collects the unique species in the network.
void validateComposition(const fourdst::composition::Composition &composition, double culling, double T9)
Validates the composition against the current reaction set.
std::expected< std::unordered_map< fourdst::atomic::Species, double >, expectations::StaleEngineError > getSpeciesDestructionTimescales(const std::vector< double > &Y, double T9, double rho) const override
bool isStale(const NetIn &netIn) override
std::unique_ptr< screening::ScreeningModel > m_screeningModel
double calculateReverseRateTwoBodyDerivative(const reaction::Reaction &reaction, const double T9, const double reverseRate) const
StepDerivatives< T > calculateAllDerivatives(const std::vector< T > &Y_in, T T9, T rho) const
Calculates all derivatives (dY/dt) and the energy generation rate.
GraphEngine(const fourdst::composition::Composition &composition, const BuildDepthType=NetworkBuildDepth::Full)
Constructs a GraphEngine from a composition.
Abstract interface for evaluating nuclear partition functions.
Represents a single nuclear reaction from a specific data source.
TemplatedReactionSet< LogicalReaction > LogicalReactionSet
A set of logical reactions.
std::unique_ptr< ScreeningModel > selectScreeningModel(ScreeningType type)
A factory function to select and create a screening model.
ScreeningType
Enumerates the available plasma screening models.
CppAD::AD< double > ADDouble
Alias for CppAD AD type for double precision.
std::variant< NetworkBuildDepth, int > BuildDepthType
Variant specifying either a predefined NetworkBuildDepth or a custom integer depth.
std::vector< std::pair< size_t, size_t > > SparsityPattern
PrimingReport primeNetwork(const NetIn &, DynamicEngine &engine)
Primes absent species in the network to their equilibrium abundances.
static constexpr double MIN_JACOBIAN_THRESHOLD
Minimum value for Jacobian matrix entries.
reaction::LogicalReactionSet build_reaclib_nuclear_network(const fourdst::composition::Composition &composition, BuildDepthType maxLayers=NetworkBuildDepth::Full, bool reverse=false)
Builds a nuclear reaction network from the Reaclib library based on an initial composition.
Defines classes for representing and managing nuclear reactions.
std::vector< int > reactant_powers
std::vector< int > product_powers
Powers of each unique product in the reverse reaction.
std::vector< size_t > affected_species_indices
std::vector< size_t > unique_reactant_indices
double reverse_symmetry_factor
Symmetry factor for reverse reactions.
std::vector< int > stoichiometric_coefficients
std::vector< size_t > unique_product_indices
Unique product indices for reverse reactions.
double density
Density in g/cm^3.
fourdst::composition::Composition composition
Composition of the network.
double temperature
Temperature in Kelvin.
Captures the result of a network priming operation.
Structure holding derivatives and energy generation for a network step.
T nuclearEnergyGenerationRate
Specific energy generation rate (e.g., erg/g/s).
std::vector< T > dydt
Derivatives of abundances (dY/dt for each species).