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.");
247 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());
250 const double temp = T9 * 1e9;
253 assert(Constants::getInstance().get(
"kB").unit ==
"erg / K");
256 const double expFactor = std::exp(-
reaction.qValue() / (kBMeV * temp));
257 double reverseRate = 0.0;
258 const double forwardRate =
reaction.calculate_rate(T9);
263 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());
265 LOG_TRACE_L2_LIMIT_EVERY_N(1000,
m_logger,
"Calculated reverse rate for reaction '{}': {:.3E} at T9={:.3E}.",
reaction.id(), reverseRate, T9);
272 const double forwardRate,
273 const double expFactor
275 std::vector<double> reactantPartitionFunctions;
276 std::vector<double> productPartitionFunctions;
278 reactantPartitionFunctions.reserve(
reaction.reactants().size());
279 productPartitionFunctions.reserve(
reaction.products().size());
281 std::unordered_map<fourdst::atomic::Species, int> reactantMultiplicity;
282 std::unordered_map<fourdst::atomic::Species, int> productMultiplicity;
284 reactantMultiplicity.reserve(
reaction.reactants().size());
285 productMultiplicity.reserve(
reaction.products().size());
287 for (
const auto& reactant :
reaction.reactants()) {
288 reactantMultiplicity[reactant] += 1;
290 for (
const auto& product :
reaction.products()) {
291 productMultiplicity[product] += 1;
293 double reactantSymmetryFactor = 1.0;
294 double productSymmetryFactor = 1.0;
295 for (
const auto& count : reactantMultiplicity | std::views::values) {
296 reactantSymmetryFactor *= std::tgamma(count + 1);
298 for (
const auto& count : productMultiplicity | std::views::values) {
299 productSymmetryFactor *= std::tgamma(count + 1);
301 const double symmetryFactor = reactantSymmetryFactor / productSymmetryFactor;
304 auto mass_op = [](
double acc,
const auto& species) {
return acc * species.a(); };
305 const double massNumerator = std::accumulate(
311 const double massDenominator = std::accumulate(
319 auto pf_op = [&](
double acc,
const auto& species) {
322 const double partitionFunctionNumerator = std::accumulate(
328 const double partitionFunctionDenominator = std::accumulate(
335 const double CT = std::pow(massNumerator/massDenominator, 1.5) *
336 (partitionFunctionNumerator/partitionFunctionDenominator);
338 const double reverseRate = forwardRate * symmetryFactor * CT * expFactor;
339 if (!std::isfinite(reverseRate)) {
349 const double reverseRate
352 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());
355 const double d_log_kFwd =
reaction.calculate_forward_rate_log_derivative(T9);
357 auto log_deriv_pf_op = [&](
double acc,
const auto& species) {
359 const double dg_dT =
m_partitionFunction->evaluateDerivative(species.z(), species.a(), T9);
360 return (g == 0.0) ? acc : acc + (dg_dT / g);
363 const double reactant_log_derivative_sum = std::accumulate(
370 const double product_log_derivative_sum = std::accumulate(
377 const double d_log_C = reactant_log_derivative_sum - product_log_derivative_sum;
381 const double log_total_derivative = d_log_kFwd + d_log_C + d_log_exp;
383 return reverseRate * log_total_derivative;
401 for (
const auto& [symbol, entry] : netIn.
composition) {
409 fourdst::composition::Composition composition;
411 std::vector<std::string> symbols;
414 symbols.emplace_back(symbol.name());
416 composition.registerSymbol(symbols);
417 for (
const auto& [symbol, entry] : netIn.
composition) {
419 composition.setMassFraction(symbol, entry.mass_fraction());
421 composition.setMassFraction(symbol, 0.0);
424 composition.finalize(
true);
431 return primingReport;
444 LOG_DEBUG(
m_logger,
"Rebuild requested with the same depth. No changes made to the network.");
449 const std::vector<double> &Y_in,
450 const std::vector<double> &bare_rates,
451 const std::vector<double> &bare_reverse_rates,
456 const std::vector<double> screeningFactors =
m_screeningModel->calculateScreeningFactors(
465 std::vector<double> molarReactionFlows;
469 double forwardAbundanceProduct = 1.0;
471 for (
size_t i = 0; i < precomp.unique_reactant_indices.size(); ++i) {
472 const size_t reactantIndex = precomp.unique_reactant_indices[i];
473 const int power = precomp.reactant_powers[i];
480 forwardAbundanceProduct *= std::pow(Y_in[reactantIndex], power);
487 const double bare_rate = bare_rates[precomp.reaction_index];
488 const double screeningFactor = screeningFactors[precomp.reaction_index];
489 const size_t numReactants =
m_reactions[precomp.reaction_index].reactants().size();
490 const size_t numProducts =
m_reactions[precomp.reaction_index].products().size();
492 const double forwardMolarReactionFlow =
495 precomp.symmetry_factor *
496 forwardAbundanceProduct *
497 std::pow(rho, numReactants > 1 ? numReactants - 1 : 0.0);
499 double reverseMolarReactionFlow = 0.0;
501 const double bare_reverse_rate = bare_reverse_rates[precomp.reaction_index];
502 double reverseAbundanceProduct = 1.0;
503 for (
size_t i = 0; i < precomp.unique_product_indices.size(); ++i) {
504 reverseAbundanceProduct *= std::pow(Y_in[precomp.unique_product_indices[i]], precomp.product_powers[i]);
506 reverseMolarReactionFlow = screeningFactor *
508 precomp.reverse_symmetry_factor *
509 reverseAbundanceProduct *
510 std::pow(rho, numProducts > 1 ? numProducts - 1 : 0.0);
513 molarReactionFlows.push_back(forwardMolarReactionFlow - reverseMolarReactionFlow);
522 const double R_j = molarReactionFlows[j];
524 for (
size_t i = 0; i < precomp.affected_species_indices.size(); ++i) {
525 const size_t speciesIndex = precomp.affected_species_indices[i];
526 const int stoichiometricCoefficient = precomp.stoichiometric_coefficients[i];
529 result.
dydt[speciesIndex] +=
static_cast<double>(stoichiometricCoefficient) * R_j;
534 double massProductionRate = 0.0;
546 LOG_TRACE_L1(
m_logger,
"Generating stoichiometry matrix...");
553 LOG_TRACE_L1(
m_logger,
"Stoichiometry matrix initialized with dimensions: {} rows (species) x {} columns (reactions).",
554 numSpecies, numReactions);
558 size_t reactionColumnIndex = 0;
561 std::unordered_map<fourdst::atomic::Species, int> netStoichiometry =
reaction.stoichiometry();
564 for (
const auto& [species, coefficient] : netStoichiometry) {
568 const size_t speciesRowIndex = it->second;
573 LOG_ERROR(
m_logger,
"CRITICAL ERROR: Species '{}' from reaction '{}' stoichiometry not found in species to index map.",
576 throw std::runtime_error(
"Species not found in species to index map: " + std::string(species.name()));
579 reactionColumnIndex++;
582 LOG_TRACE_L1(
m_logger,
"Stoichiometry matrix population complete. Number of non-zero elements: {}.",
587 const std::vector<double> &Y_in,
595 const std::vector<ADDouble> &Y_in,
625 const std::vector<double> &Y,
633 const std::vector<double> &Y_dynamic,
638 LOG_TRACE_L1_LIMIT_EVERY_N(1000,
m_logger,
"Generating jacobian matrix for T9={}, rho={}..", T9, rho);
642 std::vector<double> adInput(numSpecies + 2, 0.0);
643 for (
size_t i = 0; i < numSpecies; ++i) {
644 adInput[i] = std::max(Y_dynamic[i], 1e-99);
646 adInput[numSpecies] = T9;
647 adInput[numSpecies + 1] = rho;
650 const std::vector<double> dotY =
m_rhsADFun.Jacobian(adInput);
654 for (
size_t i = 0; i < numSpecies; ++i) {
655 for (
size_t j = 0; j < numSpecies; ++j) {
656 const double value = dotY[i * (numSpecies + 2) + j];
666 const std::vector<double> &Y_dynamic,
673 std::vector<double> x(numSpecies + 2, 0.0);
674 for (
size_t i = 0; i < numSpecies; ++i) {
678 x[numSpecies + 1] = rho;
681 const size_t nnz = sparsityPattern.size();
682 std::vector<size_t> row_indices(nnz);
683 std::vector<size_t> col_indices(nnz);
685 for (
size_t k = 0; k < nnz; ++k) {
686 row_indices[k] = sparsityPattern[k].first;
687 col_indices[k] = sparsityPattern[k].second;
690 std::vector<double> values(nnz);
691 const size_t num_rows_jac = numSpecies;
692 const size_t num_cols_jac = numSpecies + 2;
694 CppAD::sparse_rc<std::vector<size_t>> CppAD_sparsity_pattern(num_rows_jac, num_cols_jac, nnz);
695 for (
size_t k = 0; k < nnz; ++k) {
696 CppAD_sparsity_pattern.set(k, sparsityPattern[k].first, sparsityPattern[k].second);
699 CppAD::sparse_rcv<std::vector<size_t>, std::vector<double>> jac_subset(CppAD_sparsity_pattern);
711 for (
size_t k = 0; k < nnz; ++k) {
712 const size_t row = jac_subset.row()[k];
713 const size_t col = jac_subset.col()[k];
714 const double value = jac_subset.val()[k];
734 const int speciesIndex,
735 const int reactionIndex
741 LOG_TRACE_L1(
m_logger,
"Exporting network graph to DOT file: {}", filename);
743 std::ofstream dotFile(filename);
744 if (!dotFile.is_open()) {
745 LOG_ERROR(
m_logger,
"Failed to open file for writing: {}", filename);
747 throw std::runtime_error(
"Failed to open file for writing: " + filename);
750 dotFile <<
"digraph NuclearReactionNetwork {\n";
751 dotFile <<
" graph [rankdir=LR, splines=true, overlap=false, bgcolor=\"#f0f0f0\"];\n";
752 dotFile <<
" node [shape=circle, style=filled, fillcolor=\"#a7c7e7\", fontname=\"Helvetica\"];\n";
753 dotFile <<
" edge [fontname=\"Helvetica\", fontsize=10];\n\n";
756 dotFile <<
" // --- Species Nodes ---\n";
758 dotFile <<
" \"" << species.name() <<
"\" [label=\"" << species.name() <<
"\"];\n";
763 dotFile <<
" // --- Reaction Edges ---\n";
766 std::string reactionNodeId =
"reaction_" + std::string(
reaction.id());
769 dotFile <<
" \"" << reactionNodeId <<
"\" [shape=point, fillcolor=black, width=0.1, height=0.1, label=\"\"];\n";
772 for (
const auto& reactant :
reaction.reactants()) {
773 dotFile <<
" \"" << reactant.name() <<
"\" -> \"" << reactionNodeId <<
"\";\n";
777 for (
const auto& product :
reaction.products()) {
778 dotFile <<
" \"" << reactionNodeId <<
"\" -> \"" << product.name() <<
"\" [label=\"" <<
reaction.qValue() <<
" MeV\"];\n";
785 LOG_TRACE_L1(
m_logger,
"Successfully exported network to {}", filename);
789 LOG_TRACE_L1(
m_logger,
"Exporting network graph to CSV file: {}", filename);
791 std::ofstream csvFile(filename, std::ios::out | std::ios::trunc);
792 if (!csvFile.is_open()) {
793 LOG_ERROR(
m_logger,
"Failed to open file for writing: {}", filename);
795 throw std::runtime_error(
"Failed to open file for writing: " + filename);
797 csvFile <<
"Reaction;Reactants;Products;Q-value;sources;rates\n";
803 for (
const auto& reactant :
reaction.reactants()) {
804 csvFile << reactant.name();
805 if (++count <
reaction.reactants().size()) {
811 for (
const auto& product :
reaction.products()) {
812 csvFile << product.name();
813 if (++count <
reaction.products().size()) {
817 csvFile <<
";" <<
reaction.qValue() <<
";";
821 for (
const auto& source : sources) {
823 if (++count < sources.size()) {
830 for (
const auto& rates :
reaction) {
839 LOG_TRACE_L1(
m_logger,
"Successfully exported network graph to {}", filename);
843 const std::vector<double> &Y,
848 std::unordered_map<fourdst::atomic::Species, double> speciesTimescales;
851 double timescale = std::numeric_limits<double>::infinity();
853 if (std::abs(dydt[i]) > 0.0) {
854 timescale = std::abs(Y[i] / dydt[i]);
856 speciesTimescales.emplace(species, timescale);
858 return speciesTimescales;
862 const std::vector<double> &Y,
867 std::unordered_map<fourdst::atomic::Species, double> speciesDestructionTimescales;
870 double netDestructionFlow = 0.0;
872 if (
reaction.stoichiometry(species) < 0) {
874 netDestructionFlow += flow;
877 double timescale = std::numeric_limits<double>::infinity();
878 if (netDestructionFlow != 0.0) {
881 speciesDestructionTimescales.emplace(species, timescale);
883 return speciesDestructionTimescales;
887 fourdst::composition::Composition baseUpdatedComposition = netIn.
composition;
890 baseUpdatedComposition.registerSpecies(species);
891 baseUpdatedComposition.setMassFraction(species, 0.0);
894 baseUpdatedComposition.finalize(
false);
895 return baseUpdatedComposition;
903 LOG_TRACE_L1(
m_logger,
"Recording AD tape for the RHS calculation...");
907 if (numSpecies == 0) {
908 LOG_ERROR(
m_logger,
"Cannot record AD tape: No species in the network.");
910 throw std::runtime_error(
"Cannot record AD tape: No species in the network.");
912 const size_t numADInputs = numSpecies + 2;
920 const auto uniformMassFraction =
static_cast<CppAD::AD<double>
>(1.0 /
static_cast<double>(numSpecies));
921 std::vector<CppAD::AD<double>> adInput(numADInputs, uniformMassFraction);
922 adInput[numSpecies] = 1.0;
923 adInput[numSpecies + 1] = 1.0;
927 CppAD::Independent(adInput);
929 std::vector<CppAD::AD<double>> adY(numSpecies);
930 for(
size_t i = 0; i < numSpecies; ++i) {
933 const CppAD::AD<double> adT9 = adInput[numSpecies];
934 const CppAD::AD<double> adRho = adInput[numSpecies + 1];
943 LOG_TRACE_L1(
m_logger,
"AD tape recorded successfully for the RHS calculation. Number of independent variables: {}.",
961 LOG_TRACE_L1(
m_logger,
"Pre-computing constant components of GraphNetwork state...");
964 std::unordered_map<fourdst::atomic::Species, size_t> speciesIndexMap;
979 std::unordered_map<size_t, int> reactantCounts;
980 for (
const auto& reactant:
reaction.reactants()) {
981 size_t reactantIndex = speciesIndexMap.at(reactant);
982 reactantCounts[reactantIndex]++;
985 double symmetryDenominator = 1.0;
986 for (
const auto& [index, count] : reactantCounts) {
990 symmetryDenominator *= std::tgamma(count + 1);
997 std::unordered_map<size_t, int> productCounts;
998 for (
const auto& product :
reaction.products()) {
999 productCounts[speciesIndexMap.at(product)]++;
1001 double reverseSymmetryDenominator = 1.0;
1002 for (
const auto& [index, count] : productCounts) {
1005 reverseSymmetryDenominator *= std::tgamma(count + 1);
1016 const auto stoichiometryMap =
reaction.stoichiometry();
1020 for (
const auto& [species, coeff] : stoichiometryMap) {
1032 const CppAD::vector<bool> &vx,
1033 CppAD::vector<bool> &vy,
1034 const CppAD::vector<double> &tx,
1035 CppAD::vector<double> &ty
1038 if ( p != 0) {
return false; }
1039 const double T9 = tx[0];
1043 ty[0] = reverseRate;
1045 if (vx.size() > 0) {
1053 const CppAD::vector<double> &tx,
1054 const CppAD::vector<double> &ty,
1055 CppAD::vector<double> &px,
1056 const CppAD::vector<double> &py
1058 const double T9 = tx[0];
1059 const double reverseRate = ty[0];
1061 const double derivative =
m_engine.calculateReverseRateTwoBodyDerivative(
m_reaction, T9, reverseRate);
1064 px[0] = py[0] * derivative;
1071 const CppAD::vector<std::set<size_t>> &r,
1072 CppAD::vector<std::set<size_t>> &s
1080 const CppAD::vector<std::set<size_t>> &rt,
1081 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.
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).