refactor(reaction): refactored to an abstract reaction class in prep for weak reactions

This commit is contained in:
2025-08-14 13:33:46 -04:00
parent d920a55ba6
commit 0b77f2e269
81 changed files with 1050041 additions and 913 deletions

View File

@@ -447,10 +447,10 @@ namespace gridfire::approx8{
m_tMax = netIn.tMax;
m_dt0 = netIn.dt0;
const double stiff_abs_tol = m_config.get<double>("Network:Approx8:Stiff:AbsTol", 1.0e-6);
const double stiff_rel_tol = m_config.get<double>("Network:Approx8:Stiff:RelTol", 1.0e-6);
const double nonstiff_abs_tol = m_config.get<double>("Network:Approx8:NonStiff:AbsTol", 1.0e-6);
const double nonstiff_rel_tol = m_config.get<double>("Network:Approx8:NonStiff:RelTol", 1.0e-6);
const auto stiff_abs_tol = m_config.get<double>("Network:Approx8:Stiff:AbsTol", 1.0e-6);
const auto stiff_rel_tol = m_config.get<double>("Network:Approx8:Stiff:RelTol", 1.0e-6);
const auto nonstiff_abs_tol = m_config.get<double>("Network:Approx8:NonStiff:AbsTol", 1.0e-6);
const auto nonstiff_rel_tol = m_config.get<double>("Network:Approx8:NonStiff:RelTol", 1.0e-6);
int num_steps = -1;

View File

@@ -48,7 +48,7 @@ namespace gridfire {
}
GraphEngine::GraphEngine(
const reaction::LogicalReactionSet &reactions
const reaction::ReactionSet &reactions
) :
m_reactions(reactions) {
syncInternalMaps();
@@ -67,8 +67,8 @@ namespace gridfire {
// TODO: Add cache to this
for (const auto& reaction: m_reactions) {
bare_rates.push_back(reaction.calculate_rate(T9));
bare_reverse_rates.push_back(calculateReverseRate(reaction, T9));
bare_rates.push_back(reaction->calculate_rate(T9, rho, Y));
bare_reverse_rates.push_back(calculateReverseRate(*reaction, T9, rho, Y));
}
// --- The public facing interface can always use the precomputed version since taping is done internally ---
@@ -110,10 +110,10 @@ namespace gridfire {
std::set<std::string_view> uniqueSpeciesNames;
for (const auto& reaction: m_reactions) {
for (const auto& reactant: reaction.reactants()) {
for (const auto& reactant: reaction->reactants()) {
uniqueSpeciesNames.insert(reactant.name());
}
for (const auto& product: reaction.products()) {
for (const auto& product: reaction->products()) {
uniqueSpeciesNames.insert(product.name());
}
}
@@ -136,7 +136,7 @@ namespace gridfire {
LOG_TRACE_L1(m_logger, "Populating reaction ID map for REACLIB graph network (serif::network::GraphNetwork)...");
m_reactionIDMap.clear();
for (auto& reaction: m_reactions) {
m_reactionIDMap.emplace(reaction.id(), &reaction);
m_reactionIDMap.emplace(reaction->id(), reaction.get());
}
LOG_TRACE_L1(m_logger, "Populated {} reactions in the reaction ID map.", m_reactionIDMap.size());
}
@@ -165,13 +165,13 @@ namespace gridfire {
return m_networkSpecies;
}
const reaction::LogicalReactionSet& GraphEngine::getNetworkReactions() const {
const reaction::ReactionSet& GraphEngine::getNetworkReactions() const {
// Returns a constant reference to the set of reactions in the network.
LOG_TRACE_L3(m_logger, "Providing access to network reactions set. Size: {}.", m_reactions.size());
return m_reactions;
}
void GraphEngine::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
void GraphEngine::setNetworkReactions(const reaction::ReactionSet &reactions) {
m_reactions = reactions;
syncInternalMaps();
}
@@ -194,7 +194,7 @@ namespace gridfire {
uint64_t totalProductZ = 0;
// Calculate total A and Z for reactants
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
auto it = m_networkSpeciesMap.find(reactant.name());
if (it != m_networkSpeciesMap.end()) {
totalReactantA += it->second.a();
@@ -203,13 +203,13 @@ namespace gridfire {
// This scenario indicates a severe data integrity issue:
// a reactant is part of a reaction but not in the network's species map.
LOG_ERROR(m_logger, "CRITICAL ERROR: Reactant species '{}' in reaction '{}' not found in network species map during conservation validation.",
reactant.name(), reaction.id());
reactant.name(), reaction->id());
return false;
}
}
// Calculate total A and Z for products
for (const auto& product : reaction.products()) {
for (const auto& product : reaction->products()) {
auto it = m_networkSpeciesMap.find(product.name());
if (it != m_networkSpeciesMap.end()) {
totalProductA += it->second.a();
@@ -217,7 +217,7 @@ namespace gridfire {
} else {
// Similar critical error for product species
LOG_ERROR(m_logger, "CRITICAL ERROR: Product species '{}' in reaction '{}' not found in network species map during conservation validation.",
product.name(), reaction.id());
product.name(), reaction->id());
return false;
}
}
@@ -225,12 +225,12 @@ namespace gridfire {
// Compare totals for conservation
if (totalReactantA != totalProductA) {
LOG_ERROR(m_logger, "Mass number (A) not conserved for reaction '{}': Reactants A={} vs Products A={}.",
reaction.id(), totalReactantA, totalProductA);
reaction->id(), totalReactantA, totalProductA);
return false;
}
if (totalReactantZ != totalProductZ) {
LOG_ERROR(m_logger, "Atomic number (Z) not conserved for reaction '{}': Reactants Z={} vs Products Z={}.",
reaction.id(), totalReactantZ, totalProductZ);
reaction->id(), totalReactantZ, totalProductZ);
return false;
}
}
@@ -241,7 +241,9 @@ namespace gridfire {
double GraphEngine::calculateReverseRate(
const reaction::Reaction &reaction,
const double T9
const double T9,
const double rho,
const std::vector<double> &Y
) const {
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());
@@ -255,12 +257,12 @@ 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 expFactor = std::exp(-reaction.qValue() / (kBMeV * temp));
double reverseRate = 0.0;
const double forwardRate = reaction.calculate_rate(T9);
const double forwardRate = reaction.calculate_rate(T9, rho, Y);
if (reaction.reactants().size() == 2 && reaction.products().size() == 2) {
reverseRate = calculateReverseRateTwoBody(reaction, T9, forwardRate, expFactor);
} else {
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());
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.id());
}
LOG_TRACE_L2_LIMIT_EVERY_N(1000, m_logger, "Calculated reverse rate for reaction '{}': {:.3E} at T9={:.3E}.", reaction.id(), reverseRate, T9);
return reverseRate;
@@ -346,13 +348,15 @@ namespace gridfire {
double GraphEngine::calculateReverseRateTwoBodyDerivative(
const reaction::Reaction &reaction,
const double T9,
const double rho,
const std::vector<double> &Y,
const double reverseRate
) const {
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());
return 0.0; // If reverse reactions are not used, return 0.0
}
const double d_log_kFwd = reaction.calculate_forward_rate_log_derivative(T9);
const double d_log_kFwd = reaction.calculate_forward_rate_log_derivative(T9, rho, Y);
auto log_deriv_pf_op = [&](double acc, const auto& species) {
const double g = m_partitionFunction->evaluate(species.z(), species.a(), T9);
@@ -392,7 +396,7 @@ namespace gridfire {
m_useReverseReactions = useReverse;
}
int GraphEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const {
size_t GraphEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const {
return m_speciesToIndexMap.at(species); // Returns the index of the species in the stoichiometry matrix
}
@@ -494,7 +498,7 @@ namespace gridfire {
bare_rate *
precomp.symmetry_factor *
forwardAbundanceProduct *
std::pow(rho, numReactants > 1 ? numReactants - 1 : 0.0);
std::pow(rho, numReactants > 1 ? static_cast<double>(numReactants) - 1 : 0.0);
double reverseMolarReactionFlow = 0.0;
if (precomp.reverse_symmetry_factor != 0.0 and m_useReverseReactions) {
@@ -507,7 +511,7 @@ namespace gridfire {
bare_reverse_rate *
precomp.reverse_symmetry_factor *
reverseAbundanceProduct *
std::pow(rho, numProducts > 1 ? numProducts - 1 : 0.0);
std::pow(rho, numProducts > 1 ? static_cast<double>(numProducts) - 1 : 0.0);
}
molarReactionFlows.push_back(forwardMolarReactionFlow - reverseMolarReactionFlow);
@@ -558,7 +562,7 @@ namespace gridfire {
size_t reactionColumnIndex = 0;
for (const auto& reaction : m_reactions) {
// Get the net stoichiometry for the current reaction
std::unordered_map<fourdst::atomic::Species, int> netStoichiometry = reaction.stoichiometry();
std::unordered_map<fourdst::atomic::Species, int> netStoichiometry = reaction->stoichiometry();
// Iterate through the species and their coefficients in the stoichiometry map
for (const auto& [species, coefficient] : netStoichiometry) {
@@ -571,7 +575,7 @@ namespace gridfire {
} else {
// This scenario should ideally not happen if m_networkSpeciesMap and m_speciesToIndexMap are correctly synced
LOG_ERROR(m_logger, "CRITICAL ERROR: Species '{}' from reaction '{}' stoichiometry not found in species to index map.",
species.name(), reaction.id());
species.name(), reaction->id());
m_logger -> flush_log();
throw std::runtime_error("Species not found in species to index map: " + std::string(species.name()));
}
@@ -763,19 +767,19 @@ namespace gridfire {
dotFile << " // --- Reaction Edges ---\n";
for (const auto& reaction : m_reactions) {
// Create a unique ID for the reaction node
std::string reactionNodeId = "reaction_" + std::string(reaction.id());
std::string reactionNodeId = "reaction_" + std::string(reaction->id());
// Define the reaction node (small, black dot)
dotFile << " \"" << reactionNodeId << "\" [shape=point, fillcolor=black, width=0.1, height=0.1, label=\"\"];\n";
// Draw edges from reactants to the reaction node
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
dotFile << " \"" << reactant.name() << "\" -> \"" << reactionNodeId << "\";\n";
}
// Draw edges from the reaction node to products
for (const auto& product : reaction.products()) {
dotFile << " \"" << reactionNodeId << "\" -> \"" << product.name() << "\" [label=\"" << reaction.qValue() << " MeV\"];\n";
for (const auto& product : reaction->products()) {
dotFile << " \"" << reactionNodeId << "\" -> \"" << product.name() << "\" [label=\"" << reaction->qValue() << " MeV\"];\n";
}
dotFile << "\n";
}
@@ -797,42 +801,25 @@ namespace gridfire {
csvFile << "Reaction;Reactants;Products;Q-value;sources;rates\n";
for (const auto& reaction : m_reactions) {
// Dynamic cast to REACLIBReaction to access specific properties
csvFile << reaction.id() << ";";
csvFile << reaction->id() << ";";
// Reactants
size_t count = 0;
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
csvFile << reactant.name();
if (++count < reaction.reactants().size()) {
if (++count < reaction->reactants().size()) {
csvFile << ",";
}
}
csvFile << ";";
count = 0;
for (const auto& product : reaction.products()) {
for (const auto& product : reaction->products()) {
csvFile << product.name();
if (++count < reaction.products().size()) {
if (++count < reaction->products().size()) {
csvFile << ",";
}
}
csvFile << ";" << reaction.qValue() << ";";
csvFile << ";" << reaction->qValue() << ";";
// Reaction coefficients
auto sources = reaction.sources();
count = 0;
for (const auto& source : sources) {
csvFile << source;
if (++count < sources.size()) {
csvFile << ",";
}
}
csvFile << ";";
// Reaction coefficients
count = 0;
for (const auto& rates : reaction) {
csvFile << rates;
if (++count < reaction.size()) {
csvFile << ",";
}
}
csvFile << "\n";
}
csvFile.close();
@@ -869,8 +856,8 @@ namespace gridfire {
for (const auto& species : m_networkSpecies) {
double netDestructionFlow = 0.0;
for (const auto& reaction : m_reactions) {
if (reaction.stoichiometry(species) < 0) {
const double flow = calculateMolarReactionFlow<double>(reaction, Y, T9, rho);
if (reaction->stoichiometry(species) < 0) {
const auto flow = calculateMolarReactionFlow<double>(*reaction, Y, T9, rho);
netDestructionFlow += flow;
}
}
@@ -899,7 +886,7 @@ namespace gridfire {
return false;
}
void GraphEngine::recordADTape() {
void GraphEngine::recordADTape() const {
LOG_TRACE_L1(m_logger, "Recording AD tape for the RHS calculation...");
// Task 1: Set dimensions and initialize the matrix
@@ -949,8 +936,8 @@ namespace gridfire {
m_atomicReverseRates.reserve(m_reactions.size());
for (const auto& reaction: m_reactions) {
if (reaction.qValue() != 0.0) {
m_atomicReverseRates.push_back(std::make_unique<AtomicReverseRate>(reaction, *this));
if (reaction->qValue() != 0.0) {
m_atomicReverseRates.push_back(std::make_unique<AtomicReverseRate>(*reaction, *this));
} else {
m_atomicReverseRates.push_back(nullptr);
}
@@ -1038,7 +1025,8 @@ namespace gridfire {
if ( p != 0) { return false; }
const double T9 = tx[0];
const double reverseRate = m_engine.calculateReverseRate(m_reaction, T9);
// TODO: Handle rho and Y
const double reverseRate = m_engine.calculateReverseRate(m_reaction, T9, 0, {});
// std::cout << m_reaction.peName() << " reverseRate: " << reverseRate << " at T9: " << T9 << "\n";
ty[0] = reverseRate; // Store the reverse rate in the output vector
@@ -1058,8 +1046,8 @@ namespace gridfire {
const double T9 = tx[0];
const double reverseRate = ty[0];
const double derivative = m_engine.calculateReverseRateTwoBodyDerivative(m_reaction, T9, reverseRate);
// std::cout << m_reaction.peName() << " reverseRate Derivative: " << derivative << "\n";
// TODO: Handle rho and Y
const double derivative = m_engine.calculateReverseRateTwoBodyDerivative(m_reaction, T9, 0, {}, reverseRate);
px[0] = py[0] * derivative; // Return the derivative of the reverse rate with respect to T9

View File

@@ -14,14 +14,13 @@
#include "quill/LogMacros.h"
namespace gridfire {
using reaction::LogicalReactionSet;
using reaction::ReactionSet;
using reaction::Reaction;
using fourdst::composition::Composition;
using fourdst::atomic::Species;
LogicalReactionSet build_reaclib_nuclear_network(
ReactionSet build_reaclib_nuclear_network(
const Composition &composition,
BuildDepthType maxLayers,
bool reverse
@@ -38,18 +37,18 @@ namespace gridfire {
throw std::logic_error("Network build depth is set to 0. No reactions will be collected.");
}
const auto allReactions = reaclib::get_all_reactions();
std::vector<Reaction> remainingReactions;
const auto& allReactions = reaclib::get_all_reaclib_reactions();
std::vector<Reaction*> remainingReactions;
for (const auto& reaction : allReactions) {
if (reaction.is_reverse() == reverse) {
remainingReactions.push_back(reaction);
if (reaction->is_reverse() == reverse) {
remainingReactions.push_back(reaction.get());
}
}
if (depth == static_cast<int>(NetworkBuildDepth::Full)) {
LOG_INFO(logger, "Building full nuclear network with a total of {} reactions.", allReactions.size());
const ReactionSet reactionSet(remainingReactions);
return reaction::packReactionSetToLogicalReactionSet(reactionSet);
return reaction::packReactionSet(reactionSet);
}
std::unordered_set<Species> availableSpecies;
@@ -60,12 +59,12 @@ namespace gridfire {
}
std::vector<Reaction> collectedReactions;
std::vector<Reaction*> collectedReactions;
LOG_INFO(logger, "Starting network construction with {} available species.", availableSpecies.size());
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());
std::vector<Reaction> reactionsForNextPass;
std::vector<Reaction*> reactionsForNextPass;
std::unordered_set<Species> newProductsThisLayer;
bool newReactionsAdded = false;
@@ -73,7 +72,7 @@ namespace gridfire {
for (const auto &reaction : remainingReactions) {
bool allReactantsAvailable = true;
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
if (!availableSpecies.contains(reactant)) {
allReactantsAvailable = false;
break;
@@ -84,7 +83,7 @@ namespace gridfire {
collectedReactions.push_back(reaction);
newReactionsAdded = true;
for (const auto& product : reaction.products()) {
for (const auto& product : reaction->products()) {
newProductsThisLayer.insert(product);
}
} else {
@@ -105,9 +104,7 @@ namespace gridfire {
LOG_INFO(logger, "Network construction completed with {} reactions collected.", collectedReactions.size());
const ReactionSet reactionSet(collectedReactions);
return reaction::packReactionSetToLogicalReactionSet(reactionSet);
return reaction::packReactionSet(reactionSet);
}
}

View File

@@ -24,11 +24,11 @@ namespace gridfire {
const reaction::Reaction* dominateReaction = nullptr;
double maxFlow = -1.0;
for (const auto& reaction : engine.getNetworkReactions()) {
if (reaction.contains(species) && reaction.stoichiometry(species) > 0) {
const double flow = engine.calculateMolarReactionFlow(reaction, Y, T9, rho);
if (reaction->contains(species) && reaction->stoichiometry(species) > 0) {
const double flow = engine.calculateMolarReactionFlow(*reaction, Y, T9, rho);
if (flow > maxFlow) {
maxFlow = flow;
dominateReaction = &reaction;
dominateReaction = reaction.get();
}
}
}
@@ -105,9 +105,8 @@ namespace gridfire {
const auto Y = primer.mapNetInToMolarAbundanceVector(tempNetIn);
const double destructionRateConstant = calculateDestructionRateConstant(primer, primingSpecies, Y, T9, rho);
double equilibriumMassFraction = 0.0;
if (destructionRateConstant > 1e-99) {
double equilibriumMassFraction = 0.0;
const double creationRate = calculateCreationRate(primer, primingSpecies, Y, T9, rho);
equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
if (std::isnan(equilibriumMassFraction)) {
@@ -116,9 +115,7 @@ namespace gridfire {
}
LOG_TRACE_L3(logger, "Found equilibrium for {}: X_eq = {:.4e}", primingSpecies.name(), equilibriumMassFraction);
const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho);
if (dominantChannel) {
if (const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho)) {
LOG_TRACE_L3(logger, "Dominant creation channel for {}: {}", primingSpecies.name(), dominantChannel->peName());
double totalReactantMass = 0.0;
@@ -170,7 +167,7 @@ namespace gridfire {
std::vector<std::string> final_symbols;
std::vector<double> final_mass_fractions;
for(const auto& [species, mass_fraction] : currentMassFractions) {
final_symbols.push_back(std::string(species.name()));
final_symbols.emplace_back(species.name());
if (mass_fraction < 0.0 && std::abs(mass_fraction) < 1e-16) {
final_mass_fractions.push_back(0.0); // Avoid negative mass fractions
} else {
@@ -197,14 +194,14 @@ namespace gridfire {
const double T9,
const double rho
) {
const int speciesIndex = engine.getSpeciesIndex(species);
const size_t speciesIndex = engine.getSpeciesIndex(species);
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;
for (const auto& reaction: engine.getNetworkReactions()) {
if (reaction.contains_reactant(species)) {
const int stoichiometry = reaction.stoichiometry(species);
destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(reaction, Y_scaled, T9, rho);
if (reaction->contains_reactant(species)) {
const int stoichiometry = reaction->stoichiometry(species);
destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(*reaction, Y_scaled, T9, rho);
}
}
return destructionRateConstant;
@@ -219,9 +216,9 @@ namespace gridfire {
) {
double creationRate = 0.0;
for (const auto& reaction: engine.getNetworkReactions()) {
const int stoichiometry = reaction.stoichiometry(species);
const int stoichiometry = reaction->stoichiometry(species);
if (stoichiometry > 0) {
creationRate += stoichiometry * engine.calculateMolarReactionFlow(reaction, Y, T9, rho);
creationRate += stoichiometry * engine.calculateMolarReactionFlow(*reaction, Y, T9, rho);
}
}
return creationRate;

View File

@@ -70,12 +70,12 @@ namespace gridfire {
reactionIndexMap.reserve(m_activeReactions.size());
for (const auto& active_reaction_ptr : m_activeReactions) {
auto it = fullReactionReverseMap.find(active_reaction_ptr.id());
auto it = fullReactionReverseMap.find(active_reaction_ptr->id());
if (it != fullReactionReverseMap.end()) {
reactionIndexMap.push_back(it->second);
} else {
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr.id());
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr->id());
m_logger->flush_log();
throw std::runtime_error("Mismatch between active reactions and base engine.");
}
@@ -89,11 +89,6 @@ namespace gridfire {
fourdst::composition::Composition baseUpdatedComposition = m_baseEngine.update(netIn);
NetIn updatedNetIn = netIn;
// for (const auto &entry: netIn.composition | std::views::values) {
// if (baseUpdatedComposition.contains(entry.isotope())) {
// updatedNetIn.composition.setMassFraction(entry.isotope(), baseUpdatedComposition.getMassFraction(entry.isotope()));
// }
// }
updatedNetIn.composition = baseUpdatedComposition;
updatedNetIn.composition.finalize(false);
@@ -115,7 +110,7 @@ namespace gridfire {
const std::unordered_set<Species> reachableSpecies = findReachableSpecies(updatedNetIn);
LOG_DEBUG(m_logger, "Found {} reachable species in adaptive engine view.", reachableSpecies.size());
const std::vector<const reaction::LogicalReaction*> finalReactions = cullReactionsByFlow(allFlows, reachableSpecies, Y_Full, maxFlow);
const std::vector<const reaction::Reaction*> finalReactions = cullReactionsByFlow(allFlows, reachableSpecies, Y_Full, maxFlow);
finalizeActiveSet(finalReactions);
@@ -191,7 +186,7 @@ namespace gridfire {
const size_t i_full = mapCulledToFullSpeciesIndex(i_culled);
const size_t j_full = mapCulledToFullSpeciesIndex(j_culled);
return m_baseEngine.getJacobianMatrixEntry(i_full, j_full);
return m_baseEngine.getJacobianMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
}
void AdaptiveEngineView::generateStoichiometryMatrix() {
@@ -206,7 +201,7 @@ namespace gridfire {
validateState();
const size_t speciesIndex_full = mapCulledToFullSpeciesIndex(speciesIndex_culled);
const size_t reactionIndex_full = mapCulledToFullReactionIndex(reactionIndex_culled);
return m_baseEngine.getStoichiometryMatrixEntry(speciesIndex_full, reactionIndex_full);
return m_baseEngine.getStoichiometryMatrixEntry(static_cast<int>(speciesIndex_full), static_cast<int>(reactionIndex_full));
}
double AdaptiveEngineView::calculateMolarReactionFlow(
@@ -226,11 +221,11 @@ namespace gridfire {
return m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho);
}
const reaction::LogicalReactionSet & AdaptiveEngineView::getNetworkReactions() const {
const reaction::ReactionSet & AdaptiveEngineView::getNetworkReactions() const {
return m_activeReactions;
}
void AdaptiveEngineView::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
void AdaptiveEngineView::setNetworkReactions(const reaction::ReactionSet &reactions) {
LOG_CRITICAL(m_logger, "AdaptiveEngineView does not support setting network reactions directly. Use update() with NetIn instead. Perhaps you meant to call this on the base engine?");
throw exceptions::UnableToSetNetworkReactionsError("AdaptiveEngineView does not support setting network reactions directly. Use update() with NetIn instead. Perhaps you meant to call this on the base engine?");
}
@@ -248,7 +243,7 @@ namespace gridfire {
return std::unexpected{result.error()};
}
const std::unordered_map<Species, double> fullTimescales = result.value();
const std::unordered_map<Species, double>& fullTimescales = result.value();
std::unordered_map<Species, double> culledTimescales;
@@ -262,22 +257,21 @@ namespace gridfire {
}
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError>
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError>
AdaptiveEngineView::getSpeciesDestructionTimescales(
const std::vector<double> &Y,
double T9,
double rho
const double T9,
const double rho
) const {
validateState();
const auto Y_full = mapCulledToFull(Y);
const auto result = m_baseEngine.getSpeciesDestructionTimescales(Y_full, T9, rho);
const std::vector<double> Y_full = mapCulledToFull(Y);
const auto result = m_baseEngine.getSpeciesDestructionTimescales(Y_full, T9, rho);
if (!result) {
return std::unexpected{result.error()};
}
const std::unordered_map<Species, double> destructionTimescales = result.value();
const std::unordered_map<Species, double>& destructionTimescales = result.value();
std::unordered_map<Species, double> culledTimescales;
culledTimescales.reserve(m_activeSpecies.size());
@@ -309,7 +303,7 @@ namespace gridfire {
return m_baseEngine.primeEngine(netIn);
}
int AdaptiveEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
size_t AdaptiveEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
const auto it = std::ranges::find(m_activeSpecies, species);
if (it != m_activeSpecies.end()) {
return static_cast<int>(std::distance(m_activeSpecies.begin(), it));
@@ -389,8 +383,8 @@ namespace gridfire {
const auto& fullReactionSet = m_baseEngine.getNetworkReactions();
reactionFlows.reserve(fullReactionSet.size());
for (const auto& reaction : fullReactionSet) {
const double flow = m_baseEngine.calculateMolarReactionFlow(reaction, out_Y_Full, T9, rho);
reactionFlows.push_back({&reaction, flow});
const double flow = m_baseEngine.calculateMolarReactionFlow(*reaction, out_Y_Full, T9, rho);
reactionFlows.push_back({reaction.get(), flow});
LOG_TRACE_L1(m_logger, "Reaction '{}' has flow rate: {:0.3E} [mol/s/g]", reaction.id(), flow);
}
return reactionFlows;
@@ -418,14 +412,14 @@ namespace gridfire {
new_species_found_in_pass = false;
for (const auto& reaction: m_baseEngine.getNetworkReactions()) {
bool all_reactants_reachable = true;
for (const auto& reactant: reaction.reactants()) {
for (const auto& reactant: reaction->reactants()) {
if (!reachable.contains(reactant)) {
all_reactants_reachable = false;
break;
}
}
if (all_reactants_reachable) {
for (const auto& product: reaction.products()) {
for (const auto& product: reaction->products()) {
if (!reachable.contains(product)) {
reachable.insert(product);
new_species_found_in_pass = true;
@@ -439,7 +433,7 @@ namespace gridfire {
return reachable;
}
std::vector<const reaction::LogicalReaction *> AdaptiveEngineView::cullReactionsByFlow(
std::vector<const reaction::Reaction *> AdaptiveEngineView::cullReactionsByFlow(
const std::vector<ReactionFlow> &allFlows,
const std::unordered_set<fourdst::atomic::Species> &reachableSpecies,
const std::vector<double> &Y_full,
@@ -449,7 +443,7 @@ namespace gridfire {
const auto relative_culling_threshold = m_config.get<double>("gridfire:AdaptiveEngineView:RelativeCullingThreshold", 1e-75);
double absoluteCullingThreshold = relative_culling_threshold * maxFlow;
LOG_DEBUG(m_logger, "Relative culling threshold: {:0.3E} ({})", relative_culling_threshold, absoluteCullingThreshold);
std::vector<const reaction::LogicalReaction*> culledReactions;
std::vector<const reaction::Reaction*> culledReactions;
for (const auto& [reactionPtr, flowRate]: allFlows) {
bool keepReaction = false;
if (flowRate > absoluteCullingThreshold) {
@@ -487,7 +481,7 @@ namespace gridfire {
const double T9,
const double rho,
const std::vector<Species> &activeSpecies,
const reaction::LogicalReactionSet &activeReactions
const reaction::ReactionSet &activeReactions
) const {
const auto result = m_baseEngine.getSpeciesTimescales(Y_full, T9, rho);
if (!result) {
@@ -497,7 +491,7 @@ namespace gridfire {
std::unordered_map<Species, double> timescales = result.value();
std::set<Species> onlyProducedSpecies;
for (const auto& reaction : activeReactions) {
const std::vector<Species> products = reaction.products();
const std::vector<Species>& products = reaction->products();
onlyProducedSpecies.insert(products.begin(), products.end());
}
@@ -506,7 +500,7 @@ namespace gridfire {
onlyProducedSpecies,
[&](const Species &species) {
for (const auto& reaction : activeReactions) {
if (reaction.contains_reactant(species)) {
if (reaction->contains_reactant(species)) {
return true; // If any active reaction consumes the species then erase it from the set.
}
}
@@ -545,26 +539,26 @@ namespace gridfire {
}()
);
std::unordered_map<Species, const reaction::LogicalReaction*> reactionsToRescue;
std::unordered_map<Species, const reaction::Reaction*> reactionsToRescue;
for (const auto& species : onlyProducedSpecies) {
double maxSpeciesConsumptionRate = 0.0;
for (const auto& reaction : m_baseEngine.getNetworkReactions()) {
const bool speciesToCheckIsConsumed = reaction.contains_reactant(species);
const bool speciesToCheckIsConsumed = reaction->contains_reactant(species);
if (!speciesToCheckIsConsumed) {
continue; // If the species is not consumed by this reaction, skip it.
}
bool allOtherReactantsAreAvailable = true;
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
const bool reactantIsAvailable = std::ranges::contains(activeSpecies, reactant);
if (!reactantIsAvailable && reactant != species) {
allOtherReactantsAreAvailable = false;
}
}
if (allOtherReactantsAreAvailable && speciesToCheckIsConsumed) {
double rate = reaction.calculate_rate(T9);
double rate = reaction->calculate_rate(T9, rho, Y_full);
if (rate > maxSpeciesConsumptionRate) {
maxSpeciesConsumptionRate = rate;
reactionsToRescue[species] = &reaction;
reactionsToRescue[species] = reaction.get();
}
}
}
@@ -626,7 +620,7 @@ namespace gridfire {
);
RescueSet rescueSet;
std::unordered_set<const reaction::LogicalReaction*> newReactions;
std::unordered_set<const reaction::Reaction*> newReactions;
std::unordered_set<Species> newSpecies;
for (const auto &reactionPtr: reactionsToRescue | std::views::values) {
@@ -639,7 +633,7 @@ namespace gridfire {
}
void AdaptiveEngineView::finalizeActiveSet(
const std::vector<const reaction::LogicalReaction *> &finalReactions
const std::vector<const reaction::Reaction *> &finalReactions
) {
std::unordered_set<Species>finalSpeciesSet;
m_activeReactions.clear();

View File

@@ -68,7 +68,7 @@ namespace gridfire {
const size_t i_full = mapViewToFullSpeciesIndex(i_defined);
const size_t j_full = mapViewToFullSpeciesIndex(j_defined);
return m_baseEngine.getJacobianMatrixEntry(i_full, j_full);
return m_baseEngine.getJacobianMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
}
void DefinedEngineView::generateStoichiometryMatrix() {
@@ -85,7 +85,7 @@ namespace gridfire {
const size_t i_full = mapViewToFullSpeciesIndex(speciesIndex_defined);
const size_t j_full = mapViewToFullReactionIndex(reactionIndex_defined);
return m_baseEngine.getStoichiometryMatrixEntry(i_full, j_full);
return m_baseEngine.getStoichiometryMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
}
double DefinedEngineView::calculateMolarReactionFlow(
@@ -105,16 +105,16 @@ namespace gridfire {
return m_baseEngine.calculateMolarReactionFlow(reaction, Y_full, T9, rho);
}
const reaction::LogicalReactionSet & DefinedEngineView::getNetworkReactions() const {
const reaction::ReactionSet & DefinedEngineView::getNetworkReactions() const {
validateNetworkState();
return m_activeReactions;
}
void DefinedEngineView::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
void DefinedEngineView::setNetworkReactions(const reaction::ReactionSet &reactions) {
std::vector<std::string> peNames;
for (const auto& reaction : reactions) {
peNames.push_back(std::string(reaction.id()));
peNames.emplace_back(reaction->id());
}
collect(peNames);
}
@@ -185,7 +185,7 @@ namespace gridfire {
return m_baseEngine.getScreeningModel();
}
int DefinedEngineView::getSpeciesIndex(const Species &species) const {
size_t DefinedEngineView::getSpeciesIndex(const Species &species) const {
validateNetworkState();
const auto it = std::ranges::find(m_activeSpecies, species);
@@ -259,12 +259,12 @@ namespace gridfire {
reactionIndexMap.reserve(m_activeReactions.size());
for (const auto& active_reaction_ptr : m_activeReactions) {
auto it = fullReactionReverseMap.find(active_reaction_ptr.id());
auto it = fullReactionReverseMap.find(active_reaction_ptr->id());
if (it != fullReactionReverseMap.end()) {
reactionIndexMap.push_back(it->second);
} else {
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr.id());
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr->id());
m_logger->flush_log();
throw std::runtime_error("Mismatch between active reactions and base engine.");
}
@@ -328,20 +328,20 @@ namespace gridfire {
m_logger->flush_log();
throw std::runtime_error("Reaction with name '" + std::string(peName) + "' not found in the base engine's network reactions.");
}
auto reaction = fullNetworkReactionSet[peName];
for (const auto& reactant : reaction.reactants()) {
const reaction::Reaction* reaction = &fullNetworkReactionSet[peName];
for (const auto& reactant : reaction->reactants()) {
if (!seenSpecies.contains(reactant)) {
seenSpecies.insert(reactant);
m_activeSpecies.push_back(reactant);
}
}
for (const auto& product : reaction.products()) {
for (const auto& product : reaction->products()) {
if (!seenSpecies.contains(product)) {
seenSpecies.insert(product);
m_activeSpecies.push_back(product);
}
}
m_activeReactions.add_reaction(reaction);
m_activeReactions.add_reaction(*reaction);
}
LOG_TRACE_L3(m_logger, "DefinedEngineView built with {} active species and {} active reactions.", m_activeSpecies.size(), m_activeReactions.size());
LOG_TRACE_L3(m_logger, "Active species: {}", [this]() -> std::string {

View File

@@ -44,7 +44,7 @@ namespace {
std::unordered_set<size_t> visited;
for (const size_t& start_node : nodes) {
if (visited.find(start_node) == visited.end()) {
if (!visited.contains(start_node)) {
std::vector<size_t> current_component;
std::queue<size_t> q;
@@ -56,9 +56,9 @@ namespace {
q.pop();
current_component.push_back(u);
if (graph.count(u)) {
if (graph.contains(u)) {
for (const auto& v : graph.at(u)) {
if (visited.find(v) == visited.end()) {
if (!visited.contains(v)) {
visited.insert(v);
q.push(v);
}
@@ -194,8 +194,7 @@ namespace gridfire {
}
auto deriv = result.value();
for (size_t i = 0; i < m_algebraic_species_indices.size(); ++i) {
const size_t species_index = m_algebraic_species_indices[i];
for (const size_t species_index : m_algebraic_species_indices) {
deriv.dydt[species_index] = 0.0; // Fix the algebraic species to the equilibrium abundances we calculate.
}
return deriv;
@@ -283,11 +282,11 @@ namespace gridfire {
return m_baseEngine.calculateMolarReactionFlow(reaction, Y_mutable, T9, rho);
}
const reaction::LogicalReactionSet & MultiscalePartitioningEngineView::getNetworkReactions() const {
const reaction::ReactionSet & MultiscalePartitioningEngineView::getNetworkReactions() const {
return m_baseEngine.getNetworkReactions();
}
void MultiscalePartitioningEngineView::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
void MultiscalePartitioningEngineView::setNetworkReactions(const reaction::ReactionSet &reactions) {
LOG_CRITICAL(m_logger, "setNetworkReactions is not supported in MultiscalePartitioningEngineView. Did you mean to call this on the base engine?");
throw exceptions::UnableToSetNetworkReactionsError("setNetworkReactions is not supported in MultiscalePartitioningEngineView. Did you mean to call this on the base engine?");
}
@@ -508,7 +507,7 @@ namespace gridfire {
}()
);
m_qse_groups = std::move(validated_groups);
m_qse_groups = validated_groups;
LOG_TRACE_L1(m_logger, "Identified {} QSE groups.", m_qse_groups.size());
for (const auto& group : m_qse_groups) {
@@ -589,7 +588,7 @@ namespace gridfire {
double max_log_flow = std::numeric_limits<double>::lowest();
for (const auto& reaction : all_reactions) {
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho));
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, Y, T9, rho));
reaction_flows.push_back(flow);
if (flow > 1e-99) { // Avoid log(0)
double log_flow = std::log10(flow);
@@ -627,7 +626,7 @@ namespace gridfire {
// Group species by mass number for ranked layout.
// If species.a() returns incorrect values (e.g., 0 for many species), they will be grouped together here.
species_by_mass[species.a()].push_back(std::string(species.name()));
species_by_mass[species.a()].emplace_back(species.name());
}
dotFile << "\n";
@@ -843,7 +842,7 @@ namespace gridfire {
return equilibrateNetwork(Y, T9, rho);
}
int MultiscalePartitioningEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
size_t MultiscalePartitioningEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
return m_baseEngine.getSpeciesIndex(species);
}
@@ -859,14 +858,14 @@ namespace gridfire {
m_logger->flush_log();
throw exceptions::StaleEngineError("Failed to get species timescales due to stale engine state");
}
std::unordered_map<Species, double> all_timescales = result.value();
const std::unordered_map<Species, double>& all_timescales = result.value();
const auto& all_species = m_baseEngine.getNetworkSpecies();
std::vector<std::pair<double, size_t>> sorted_timescales;
for (size_t i = 0; i < all_species.size(); ++i) {
double timescale = all_timescales.at(all_species[i]);
if (std::isfinite(timescale) && timescale > 0) {
sorted_timescales.push_back({timescale, i});
sorted_timescales.emplace_back(timescale, i);
}
}
@@ -972,32 +971,6 @@ namespace gridfire {
}
// std::unordered_map<size_t, std::vector<size_t>> MultiscalePartitioningEngineView::buildConnectivityGraph(
// const std::unordered_set<size_t> &fast_reaction_indices
// ) const {
// const auto& all_reactions = m_baseEngine.getNetworkReactions();
// std::unordered_map<size_t, std::vector<size_t>> connectivity;
// for (const size_t reaction_idx : fast_reaction_indices) {
// const auto& reaction = all_reactions[reaction_idx];
// const auto& reactants = reaction.reactants();
// const auto& products = reaction.products();
//
// // For each fast reaction, create edges between all reactants and all products.
// // This represents that nucleons can flow quickly between these species.
// for (const auto& reactant : reactants) {
// const size_t reactant_idx = m_baseEngine.getSpeciesIndex(reactant);
// for (const auto& product : products) {
// const size_t product_idx = m_baseEngine.getSpeciesIndex(product);
//
// // Add a two-way edge to the adjacency list.
// connectivity[reactant_idx].push_back(product_idx);
// connectivity[product_idx].push_back(reactant_idx);
// }
// }
// }
// return connectivity;
// }
std::vector<MultiscalePartitioningEngineView::QSEGroup>
MultiscalePartitioningEngineView::validateGroupsWithFluxAnalysis(
const std::vector<QSEGroup> &candidate_groups,
@@ -1016,14 +989,14 @@ namespace gridfire {
);
for (const auto& reaction: m_baseEngine.getNetworkReactions()) {
const double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho));
const double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, Y, T9, rho));
if (flow == 0.0) {
continue; // Skip reactions with zero flow
}
bool has_internal_reactant = false;
bool has_external_reactant = false;
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
if (group_members.contains(m_baseEngine.getSpeciesIndex(reactant))) {
has_internal_reactant = true;
} else {
@@ -1034,7 +1007,7 @@ namespace gridfire {
bool has_internal_product = false;
bool has_external_product = false;
for (const auto& product : reaction.products()) {
for (const auto& product : reaction->products()) {
if (group_members.contains(m_baseEngine.getSpeciesIndex(product))) {
has_internal_product = true;
} else {
@@ -1231,7 +1204,7 @@ namespace gridfire {
Eigen::VectorXd Y_scale(qse_solve_indices.size());
Eigen::VectorXd v_initial(qse_solve_indices.size());
for (size_t i = 0; i < qse_solve_indices.size(); ++i) {
for (long i = 0; i < qse_solve_indices.size(); ++i) {
constexpr double abundance_floor = 1.0e-15;
const double initial_abundance = Y_full[qse_solve_indices[i]];
Y_scale(i) = std::max(initial_abundance, abundance_floor);
@@ -1273,7 +1246,7 @@ namespace gridfire {
}
LOG_TRACE_L1(m_logger, "Minimization succeeded!");
Eigen::VectorXd Y_final_qse = Y_scale.array() * v_initial.array().sinh(); // Convert back to physical abundances using asinh scaling
for (size_t i = 0; i < qse_solve_indices.size(); ++i) {
for (long i = 0; i < qse_solve_indices.size(); ++i) {
LOG_TRACE_L1(
m_logger,
"Species {} (index {}) started with abundance {} and ended with {}.",
@@ -1314,7 +1287,7 @@ namespace gridfire {
const double timescale = all_timescales.at(all_species[species_idx]);
mean_timescale += timescale;
}
mean_timescale = mean_timescale / pool.size();
mean_timescale = mean_timescale / static_cast<double>(pool.size());
if (std::isinf(mean_timescale)) {
LOG_CRITICAL(m_logger, "Encountered infinite mean timescale for pool {} with species: {}",
count, [&]() -> std::string {
@@ -1355,8 +1328,8 @@ namespace gridfire {
return result;
}();
std::map<size_t, std::vector<reaction::LogicalReaction*>> speciesReactionMap;
std::vector<const reaction::LogicalReaction*> candidate_reactions;
std::map<size_t, std::vector<reaction::LogicalReaclibReaction*>> speciesReactionMap;
std::vector<const reaction::LogicalReaclibReaction*> candidate_reactions;
auto getSpeciesIdx = [&](const std::vector<Species> &species) -> std::vector<size_t> {
std::vector<size_t> result;
@@ -1369,8 +1342,8 @@ namespace gridfire {
};
for (const auto& reaction : m_baseEngine.getNetworkReactions()) {
const std::vector<Species> &reactants = reaction.reactants();
const std::vector<Species> &products = reaction.products();
const std::vector<Species> &reactants = reaction->reactants();
const std::vector<Species> &products = reaction->products();
std::unordered_set<Species> reactant_set(reactants.begin(), reactants.end());
std::unordered_set<Species> product_set(products.begin(), products.end());
@@ -1422,15 +1395,15 @@ namespace gridfire {
if (pool.empty()) continue; // Skip empty pools
// For each pool first identify all topological bridge connections
std::vector<std::pair<reaction::LogicalReaction, double>> bridge_reactions;
std::vector<std::pair<const reaction::Reaction*, double>> bridge_reactions;
for (const auto& species_idx : pool) {
Species ash = all_species[species_idx];
for (const auto& reaction : all_reactions) {
if (reaction.contains(ash)) {
if (reaction->contains(ash)) {
// Check to make sure there is at least one reactant that is not in the pool
// This lets seed nuclei bring mass into the QSE group.
bool has_external_reactant = false;
for (const auto& reactant : reaction.reactants()) {
for (const auto& reactant : reaction->reactants()) {
if (std::ranges::find(pool, m_baseEngine.getSpeciesIndex(reactant)) == pool.end()) {
has_external_reactant = true;
LOG_TRACE_L3(m_logger, "Found external reactant {} in reaction {} for species {}.", reactant.name(), reaction.id(), ash.name());
@@ -1438,9 +1411,9 @@ namespace gridfire {
}
}
if (has_external_reactant) {
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho));
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, Y, T9, rho));
LOG_TRACE_L3(m_logger, "Found bridge reaction {} with flow {} for species {}.", reaction.id(), flow, ash.name());
bridge_reactions.push_back({reaction, flow});
bridge_reactions.emplace_back(reaction.get(), flow);
}
}
}
@@ -1467,8 +1440,8 @@ namespace gridfire {
}
std::vector<size_t> seed_indices;
for (size_t i = 0; i < bridge_reactions.size(); ++i) {
for (const auto& fuel : bridge_reactions[i].first.reactants()) {
for (auto &reaction: bridge_reactions | std::views::keys) {
for (const auto& fuel : reaction->reactants()) {
size_t fuel_idx = m_baseEngine.getSpeciesIndex(fuel);
// Only add the fuel if it is not already in the pool
if (std::ranges::find(pool, fuel_idx) == pool.end()) {
@@ -1492,7 +1465,7 @@ namespace gridfire {
mean_timescale += species.halfLife();
}
}
mean_timescale /= poolSet.size();
mean_timescale /= static_cast<double>(poolSet.size());
QSEGroup qse_group(all_indices, false, poolSet, seedSet, mean_timescale);
candidate_groups.push_back(qse_group);
}
@@ -1505,7 +1478,7 @@ namespace gridfire {
std::vector<double> y_trial = m_Y_full_initial;
Eigen::VectorXd y_qse = m_Y_scale.array() * v_qse.array().sinh(); // Convert to physical abundances using asinh scaling
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
y_trial[m_qse_solve_indices[i]] = y_qse(i);
}
@@ -1514,8 +1487,8 @@ namespace gridfire {
throw exceptions::StaleEngineError("Failed to calculate RHS and energy due to stale engine state");
}
const auto&[dydt, nuclearEnergyGenerationRate] = result.value();
f_qse.resize(m_qse_solve_indices.size());
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
f_qse.resize(static_cast<long>(m_qse_solve_indices.size()));
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
f_qse(i) = dydt[m_qse_solve_indices[i]];
}
@@ -1526,20 +1499,18 @@ namespace gridfire {
std::vector<double> y_trial = m_Y_full_initial;
Eigen::VectorXd y_qse = m_Y_scale.array() * v_qse.array().sinh(); // Convert to physical abundances using asinh scaling
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
y_trial[m_qse_solve_indices[i]] = y_qse(i);
}
// TODO: Think about if the jacobian matrix should be mutable so that generateJacobianMatrix can be const
m_view->getBaseEngine().generateJacobianMatrix(y_trial, m_T9, m_rho);
// TODO: Think very carefully about the indices here.
J_qse.resize(m_qse_solve_indices.size(), m_qse_solve_indices.size());
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
for (size_t j = 0; j < m_qse_solve_indices.size(); ++j) {
J_qse.resize(static_cast<long>(m_qse_solve_indices.size()), static_cast<long>(m_qse_solve_indices.size()));
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
for (long j = 0; j < m_qse_solve_indices.size(); ++j) {
J_qse(i, j) = m_view->getBaseEngine().getJacobianMatrixEntry(
m_qse_solve_indices[i],
m_qse_solve_indices[j]
static_cast<int>(m_qse_solve_indices[i]),
static_cast<int>(m_qse_solve_indices[j])
);
}
}

View File

@@ -2,7 +2,6 @@
#include "gridfire/solver/solver.h"
#include "fourdst/composition/species.h"
#include "fourdst/logging/logging.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
@@ -12,9 +11,6 @@
#include <unordered_set>
#include <stdexcept>
#include <unordered_map>
#include <utility>
#include <ranges>
#include <cmath>
namespace gridfire {
@@ -54,8 +50,8 @@ namespace gridfire {
) const {
std::unordered_set<std::string> primeReactions;
for (const auto &reaction : baseEngine.getNetworkReactions()) {
if (reaction.contains(primingSpecies)) {
primeReactions.insert(std::string(reaction.peName()));
if (reaction->contains(primingSpecies)) {
primeReactions.insert(std::string(reaction->id()));
}
}
if (primeReactions.empty()) {

View File

@@ -2,7 +2,6 @@
#include <ranges>
#include "fourdst/logging/logging.h"
#include "fourdst/composition/atomicSpecies.h"
#include "fourdst/composition/species.h"

View File

@@ -23,10 +23,10 @@ namespace gridfire::partition {
const auto* records = reinterpret_cast<const record::RauscherThielemannPartitionDataRecord*>(rauscher_thielemann_partition_data);
for (size_t i = 0; i < numRecords; ++i) {
const auto&[z, a, ground_state_spin, normalized_g_values] = records[i];
IsotopeData data;
IsotopeData data{};
data.ground_state_spin = ground_state_spin;
std::ranges::copy(normalized_g_values, data.normalized_g_values.begin());
const int key = make_key(z, a);
const int key = make_key(static_cast<int>(z), static_cast<int>(a));
LOG_TRACE_L3_LIMIT_EVERY_N(
100,
m_logger,
@@ -36,7 +36,7 @@ namespace gridfire::partition {
key
);
m_partitionData[key] = std::move(data);
m_partitionData[key] = data;
}
}

View File

@@ -26,7 +26,7 @@ std::string trim_whitespace(const std::string& str) {
}
namespace gridfire::reaclib {
static reaction::LogicalReactionSet* s_all_reaclib_reactions_ptr = nullptr;
static reaction::ReactionSet* s_all_reaclib_reactions_ptr = nullptr;
#pragma pack(push, 1)
struct ReactionRecord {
@@ -85,7 +85,7 @@ namespace gridfire::reaclib {
const auto* records = reinterpret_cast<const ReactionRecord*>(raw_reactions_data);
constexpr size_t num_reactions = raw_reactions_data_len / sizeof(ReactionRecord);
std::vector<reaction::Reaction> reaction_list;
std::vector<std::unique_ptr<reaction::Reaction>> reaction_list;
reaction_list.reserve(num_reactions);
for (size_t i = 0; i < num_reactions; ++i) {
@@ -108,7 +108,7 @@ namespace gridfire::reaclib {
};
// Construct the Reaction object. We use rpName for both the unique ID and the human-readable name.
reaction_list.emplace_back(
reaction_list.emplace_back(std::make_unique<reaction::ReaclibReaction>(
rpName_sv,
rpName_sv,
chapter,
@@ -118,15 +118,15 @@ namespace gridfire::reaclib {
label_sv,
rate_coeffs,
reverse
);
));
}
// The ReactionSet takes the vector of all individual reactions.
const reaction::ReactionSet reaction_set(std::move(reaction_list));
// The LogicalReactionSet groups reactions by their peName, which is what we want.
s_all_reaclib_reactions_ptr = new reaction::LogicalReactionSet(
reaction::packReactionSetToLogicalReactionSet(reaction_set)
s_all_reaclib_reactions_ptr = new reaction::ReactionSet(
reaction::packReactionSet(reaction_set)
);
s_initialized = true;
@@ -135,7 +135,7 @@ namespace gridfire::reaclib {
// --- Public Interface Implementation ---
const reaction::LogicalReactionSet& get_all_reactions() {
const reaction::ReactionSet &get_all_reaclib_reactions() {
// This ensures that the initialization happens only on the first call.
if (!s_initialized) {
initializeAllReaclibReactions();

View File

@@ -13,10 +13,19 @@
#include "xxhash64.h"
namespace {
std::string_view safe_check_reactant_id(const std::vector<gridfire::reaction::ReaclibReaction>& reactions) {
if (reactions.empty()) {
throw std::runtime_error("No reactions found in the REACLIB reaction set.");
}
return reactions.front().peName();
}
}
namespace gridfire::reaction {
using namespace fourdst::atomic;
Reaction::Reaction(
ReaclibReaction::ReaclibReaction(
const std::string_view id,
const std::string_view peName,
const int chapter,
@@ -36,15 +45,15 @@ namespace gridfire::reaction {
m_rateCoefficients(sets),
m_reverse(reverse) {}
double Reaction::calculate_rate(const double T9) const {
double ReaclibReaction::calculate_rate(const double T9, const double rho, const std::vector<double>& Y) const {
return calculate_rate<double>(T9);
}
CppAD::AD<double> Reaction::calculate_rate(const CppAD::AD<double> T9) const {
CppAD::AD<double> ReaclibReaction::calculate_rate(const CppAD::AD<double> T9, const CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const {
return calculate_rate<CppAD::AD<double>>(T9);
}
double Reaction::calculate_forward_rate_log_derivative(const double T9) const {
double ReaclibReaction::calculate_forward_rate_log_derivative(const double T9, const double rho, const std::vector<double>& Y) const {
constexpr double r_p13 = 1.0 / 3.0;
constexpr double r_p53 = 5.0 / 3.0;
constexpr double r_p23 = 2.0 / 3.0;
@@ -65,12 +74,12 @@ namespace gridfire::reaction {
return d_log_k_fwd_dT9; // Return the derivative of the log rate with respect to T9
}
bool Reaction::contains(const Species &species) const {
bool ReaclibReaction::contains(const Species &species) const {
return contains_reactant(species) || contains_product(species);
}
bool Reaction::contains_reactant(const Species& species) const {
bool ReaclibReaction::contains_reactant(const Species& species) const {
for (const auto& reactant : m_reactants) {
if (reactant == species) {
return true;
@@ -79,7 +88,7 @@ namespace gridfire::reaction {
return false;
}
bool Reaction::contains_product(const Species& species) const {
bool ReaclibReaction::contains_product(const Species& species) const {
for (const auto& product : m_products) {
if (product == species) {
return true;
@@ -88,14 +97,14 @@ namespace gridfire::reaction {
return false;
}
std::unordered_set<Species> Reaction::all_species() const {
std::unordered_set<Species> ReaclibReaction::all_species() const {
auto rs = reactant_species();
auto ps = product_species();
rs.insert(ps.begin(), ps.end());
return rs;
}
std::unordered_set<Species> Reaction::reactant_species() const {
std::unordered_set<Species> ReaclibReaction::reactant_species() const {
std::unordered_set<Species> reactantsSet;
for (const auto& reactant : m_reactants) {
reactantsSet.insert(reactant);
@@ -103,7 +112,7 @@ namespace gridfire::reaction {
return reactantsSet;
}
std::unordered_set<Species> Reaction::product_species() const {
std::unordered_set<Species> ReaclibReaction::product_species() const {
std::unordered_set<Species> productsSet;
for (const auto& product : m_products) {
productsSet.insert(product);
@@ -111,7 +120,7 @@ namespace gridfire::reaction {
return productsSet;
}
int Reaction::stoichiometry(const Species& species) const {
int ReaclibReaction::stoichiometry(const Species& species) const {
int s = 0;
for (const auto& reactant : m_reactants) {
if (reactant == species) {
@@ -126,11 +135,11 @@ namespace gridfire::reaction {
return s;
}
size_t Reaction::num_species() const {
size_t ReaclibReaction::num_species() const {
return all_species().size();
}
std::unordered_map<Species, int> Reaction::stoichiometry() const {
std::unordered_map<Species, int> ReaclibReaction::stoichiometry() const {
std::unordered_map<Species, int> stoichiometryMap;
for (const auto& reactant : m_reactants) {
stoichiometryMap[reactant]--;
@@ -141,7 +150,7 @@ namespace gridfire::reaction {
return stoichiometryMap;
}
double Reaction::excess_energy() const {
double ReaclibReaction::excess_energy() const {
double reactantMass = 0.0;
double productMass = 0.0;
constexpr double AMU2MeV = 931.494893; // Conversion factor from atomic mass unit to MeV
@@ -154,14 +163,18 @@ namespace gridfire::reaction {
return (reactantMass - productMass) * AMU2MeV;
}
uint64_t Reaction::hash(const uint64_t seed) const {
uint64_t ReaclibReaction::hash(const uint64_t seed) const {
return XXHash64::hash(m_id.data(), m_id.size(), seed);
}
std::unique_ptr<Reaction> ReaclibReaction::clone() const {
return std::make_unique<ReaclibReaction>(*this);
}
LogicalReaction::LogicalReaction(const std::vector<Reaction>& reactants) :
Reaction(reactants.front().peName(),
LogicalReaclibReaction::LogicalReaclibReaction(const std::vector<ReaclibReaction>& reactants) :
ReaclibReaction(
safe_check_reactant_id(reactants), // Use this first to check if the reactants array is empty and safely exit if so
reactants.front().peName(),
reactants.front().chapter(),
reactants.front().reactants(),
@@ -177,45 +190,45 @@ namespace gridfire::reaction {
if (std::abs(std::abs(reaction.qValue()) - std::abs(m_qValue)) > 1e-6) {
LOG_ERROR(
m_logger,
"LogicalReaction constructed with reactions having different Q-values. Expected {} got {}.",
"LogicalReaclibReaction constructed with reactions having different Q-values. Expected {} got {}.",
m_qValue,
reaction.qValue()
);
m_logger -> flush_log();
throw std::runtime_error("LogicalReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + " (difference : " + std::to_string(std::abs(reaction.qValue() - m_qValue)) + ").");
throw std::runtime_error("LogicalReaclibReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + " (difference : " + std::to_string(std::abs(reaction.qValue() - m_qValue)) + ").");
}
m_sources.push_back(std::string(reaction.sourceLabel()));
m_sources.emplace_back(reaction.sourceLabel());
m_rates.push_back(reaction.rateCoefficients());
}
}
void LogicalReaction::add_reaction(const Reaction& reaction) {
void LogicalReaclibReaction::add_reaction(const ReaclibReaction& reaction) {
if (reaction.peName() != m_id) {
LOG_ERROR(m_logger, "Cannot add reaction with different peName to LogicalReaction. Expected {} got {}.", m_id, reaction.peName());
LOG_ERROR(m_logger, "Cannot add reaction with different peName to LogicalReaclibReaction. Expected {} got {}.", m_id, reaction.peName());
m_logger -> flush_log();
throw std::runtime_error("Cannot add reaction with different peName to LogicalReaction. Expected " + std::string(m_id) + " got " + std::string(reaction.peName()) + ".");
throw std::runtime_error("Cannot add reaction with different peName to LogicalReaclibReaction. Expected " + std::string(m_id) + " got " + std::string(reaction.peName()) + ".");
}
for (const auto& source : m_sources) {
if (source == reaction.sourceLabel()) {
LOG_ERROR(m_logger, "Cannot add reaction with duplicate source label {} to LogicalReaction.", reaction.sourceLabel());
LOG_ERROR(m_logger, "Cannot add reaction with duplicate source label {} to LogicalReaclibReaction.", reaction.sourceLabel());
m_logger -> flush_log();
throw std::runtime_error("Cannot add reaction with duplicate source label " + std::string(reaction.sourceLabel()) + " to LogicalReaction.");
throw std::runtime_error("Cannot add reaction with duplicate source label " + std::string(reaction.sourceLabel()) + " to LogicalReaclibReaction.");
}
}
if (std::abs(reaction.qValue() - m_qValue) > 1e-6) {
LOG_ERROR(m_logger, "LogicalReaction constructed with reactions having different Q-values. Expected {} got {}.", m_qValue, reaction.qValue());
LOG_ERROR(m_logger, "LogicalReaclibReaction constructed with reactions having different Q-values. Expected {} got {}.", m_qValue, reaction.qValue());
m_logger -> flush_log();
throw std::runtime_error("LogicalReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + ".");
throw std::runtime_error("LogicalReaclibReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + ".");
}
m_sources.push_back(std::string(reaction.sourceLabel()));
m_sources.emplace_back(reaction.sourceLabel());
m_rates.push_back(reaction.rateCoefficients());
}
double LogicalReaction::calculate_rate(const double T9) const {
double LogicalReaclibReaction::calculate_rate(const double T9, const double rho, const std::vector<double>& Y) const {
return calculate_rate<double>(T9);
}
double LogicalReaction::calculate_forward_rate_log_derivative(const double T9) const {
double LogicalReaclibReaction::calculate_forward_rate_log_derivative(const double T9, const double rho, const std::vector<double>& Y) const {
constexpr double r_p13 = 1.0 / 3.0;
constexpr double r_p53 = 5.0 / 3.0;
constexpr double r_p23 = 2.0 / 3.0;
@@ -266,26 +279,258 @@ namespace gridfire::reaction {
return totalRateDerivative / totalRate;
}
CppAD::AD<double> LogicalReaction::calculate_rate(const CppAD::AD<double> T9) const {
std::unique_ptr<Reaction> LogicalReaclibReaction::clone() const {
return std::make_unique<LogicalReaclibReaction>(*this);
}
CppAD::AD<double> LogicalReaclibReaction::calculate_rate(
const CppAD::AD<double> T9,
const CppAD::AD<double> rho,
const std::vector<CppAD::AD<double>>& Y
) const {
return calculate_rate<CppAD::AD<double>>(T9);
}
LogicalReactionSet packReactionSetToLogicalReactionSet(const ReactionSet& reactionSet) {
std::unordered_map<std::string_view, std::vector<Reaction>> groupedReactions;
for (const auto& reaction: reactionSet) {
groupedReactions[reaction.peName()].push_back(reaction);
ReactionSet::ReactionSet(
std::vector<std::unique_ptr<Reaction>>&& reactions
) :
m_reactions(std::move(reactions)) {
if (m_reactions.empty()) {
return; // Case where the reactions will be added later.
}
std::vector<LogicalReaction> reactions;
reactions.reserve(groupedReactions.size());
for (const auto &reactionsGroup: groupedReactions | std::views::values) {
LogicalReaction logicalReaction(reactionsGroup);
reactions.push_back(logicalReaction);
m_reactionNameMap.reserve(reactions.size());
size_t i = 0;
for (const auto& reaction : m_reactions) {
m_id += reaction->id();
m_reactionNameMap.emplace(std::string(reaction->id()), i);
i++;
}
return LogicalReactionSet(std::move(reactions));
}
ReactionSet::ReactionSet(const std::vector<Reaction *> &reactions) {
m_reactions.reserve(reactions.size());
m_reactionNameMap.reserve(reactions.size());
size_t i = 0;
for (const auto& reaction : reactions) {
m_reactions.push_back(reaction->clone());
m_id += reaction->id();
m_reactionNameMap.emplace(std::string(reaction->id()), i);
i++;
}
}
ReactionSet::ReactionSet() = default;
ReactionSet::ReactionSet(const ReactionSet &other) {
m_reactions.reserve(other.m_reactions.size());
for (const auto& reaction: other.m_reactions) {
m_reactions.push_back(reaction->clone());
}
m_reactionNameMap.reserve(other.m_reactionNameMap.size());
size_t i = 0;
for (const auto& reaction : m_reactions) {
m_reactionNameMap.emplace(std::string(reaction->id()), i);
i++;
}
}
ReactionSet& ReactionSet::operator=(const ReactionSet &other) {
if (this != &other) {
ReactionSet temp(other);
std::swap(m_reactions, temp.m_reactions);
std::swap(m_reactionNameMap, temp.m_reactionNameMap);
}
return *this;
}
void ReactionSet::add_reaction(const Reaction& reaction) {
const std::size_t new_index = m_reactions.size();
auto reaction_id = std::string(reaction.id());
m_reactions.emplace_back(reaction.clone());
m_id += reaction_id;
m_reactionNameMap.emplace(std::move(reaction_id), new_index);
}
void ReactionSet::add_reaction(std::unique_ptr<Reaction>&& reaction) {
const std::size_t new_index = m_reactionNameMap.size();
auto reaction_id = std::string(reaction->id());
m_reactions.emplace_back(std::move(reaction));
m_id += reaction_id;
m_reactionNameMap.emplace(std::move(reaction_id), new_index);
}
void ReactionSet::remove_reaction(const Reaction& reaction) {
const auto reaction_id = std::string(reaction.id());
if (!m_reactionNameMap.contains(reaction_id)) {
return;
}
std::erase_if(m_reactions, [&reaction_id](const auto& r_ptr) {
return r_ptr->id() == reaction_id;
});
m_reactionNameMap.clear();
m_reactionNameMap.reserve(m_reactions.size());
for (size_t i = 0; i < m_reactions.size(); ++i) {
m_reactionNameMap.emplace(std::string(m_reactions[i]->id()), i);
}
m_id.clear();
for (const auto& r_ptr : m_reactions) {
m_id += r_ptr->id();
}
}
bool ReactionSet::contains(const std::string_view& id) const {
for (const auto& reaction : m_reactions) {
if (reaction->id() == id) {
return true;
}
}
return false;
}
bool ReactionSet::contains(const Reaction& reaction) const {
for (const auto& r : m_reactions) {
if (r->id() == reaction.id()) {
return true;
}
}
return false;
}
void ReactionSet::clear() {
m_reactions.clear();
m_reactionNameMap.clear();
}
bool ReactionSet::contains_species(const Species& species) const {
for (const auto& reaction : m_reactions) {
if (reaction->contains(species)) {
return true;
}
}
return false;
}
bool ReactionSet::contains_reactant(const Species& species) const {
for (const auto& r : m_reactions) {
if (r->contains_reactant(species)) {
return true;
}
}
return false;
}
bool ReactionSet::contains_product(const Species& species) const {
for (const auto& r : m_reactions) {
if (r->contains_product(species)) {
return true;
}
}
return false;
}
const Reaction& ReactionSet::operator[](const size_t index) const {
if (index >= m_reactions.size()) {
m_logger -> flush_log();
throw std::out_of_range("Index" + std::to_string(index) + " out of range for ReactionSet of size " + std::to_string(m_reactions.size()) + ".");
}
return *m_reactions[index];
}
const Reaction& ReactionSet::operator[](const std::string_view& id) const {
if (auto it = m_reactionNameMap.find(std::string(id)); it != m_reactionNameMap.end()) {
return *m_reactions[it->second];
}
m_logger -> flush_log();
throw std::out_of_range("Species " + std::string(id) + " does not exist in ReactionSet.");
}
bool ReactionSet::operator==(const ReactionSet& other) const {
if (size() != other.size()) {
return false;
}
return hash(0) == other.hash(0);
}
bool ReactionSet::operator!=(const ReactionSet& other) const {
return !(*this == other);
}
uint64_t ReactionSet::hash(uint64_t seed) const {
if (m_reactions.empty()) {
return XXHash64::hash(nullptr, 0, seed);
}
std::vector<uint64_t> individualReactionHashes;
individualReactionHashes.reserve(m_reactions.size());
for (const auto& reaction : m_reactions) {
individualReactionHashes.push_back(reaction->hash(seed));
}
std::ranges::sort(individualReactionHashes);
const auto data = static_cast<const void*>(individualReactionHashes.data());
const size_t sizeInBytes = individualReactionHashes.size() * sizeof(uint64_t);
return XXHash64::hash(data, sizeInBytes, seed);
}
std::unordered_set<Species> ReactionSet::getReactionSetSpecies() const {
std::unordered_set<Species> species;
for (const auto& reaction : m_reactions) {
const auto reactionSpecies = reaction->all_species();
species.insert(reactionSpecies.begin(), reactionSpecies.end());
}
return species;
}
ReactionSet packReactionSet(const ReactionSet& reactionSet) {
std::unordered_map<std::string, std::vector<ReaclibReaction>> groupedReaclibReactions;
ReactionSet finalReactionSet;
for (const auto& reaction_ptr : reactionSet) {
switch (reaction_ptr->type()) {
case ReactionType::REACLIB: {
const auto& reaclib_cast_reaction = static_cast<const ReaclibReaction&>(*reaction_ptr); // NOLINT(*-pro-type-static-cast-downcast)
groupedReaclibReactions[std::string(reaclib_cast_reaction.peName())].push_back(reaclib_cast_reaction);
break;
}
case ReactionType::LOGICAL_REACLIB: {
// It doesn't make sense to pack an already-packed reaction.
throw std::runtime_error("packReactionSet: Cannot pack a LogicalReaclibReaction.");
}
case ReactionType::WEAK: {
finalReactionSet.add_reaction(*reaction_ptr);
break;
}
}
}
// Now, process the grouped REACLIB reactions
for (const auto &reactionsGroup: groupedReaclibReactions | std::views::values) {
if (reactionsGroup.empty()) {
continue;
}
if (reactionsGroup.size() == 1) {
finalReactionSet.add_reaction(reactionsGroup.front());
}
else {
const auto logicalReaction = std::make_unique<LogicalReaclibReaction>(reactionsGroup);
finalReactionSet.add_reaction(logicalReaction->clone());
}
}
return finalReactionSet;
}
}
namespace std {
@@ -302,11 +547,4 @@ namespace std {
return s.hash(0);
}
};
template<>
struct hash<gridfire::reaction::LogicalReactionSet> {
size_t operator()(const gridfire::reaction::LogicalReactionSet& s) const noexcept {
return s.hash(0);
}
};
} // namespace std

View File

@@ -0,0 +1,94 @@
#include "gridfire/reaction/weak/weak_rate_library.h"
#include "gridfire/reaction/weak/weak.h"
#include "fourdst/composition/species.h"
#include <array>
#include <ranges>
#include <unordered_map>
#include <expected>
#define GRIDFIRE_WEAK_REACTION_LIB_SENTINEL -60.0
namespace gridfire::rates::weak {
WeakReactionMap::WeakReactionMap() {
using namespace fourdst::atomic;
for (const auto& weak_reaction_record : UNIFIED_WEAK_DATA) {
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) {
m_weak_network[species].push_back(
WeakReaction{
WeakReactionType::BETA_MINUS_DECAY,
weak_reaction_record.t9,
weak_reaction_record.log_rhoye,
weak_reaction_record.mu_e,
weak_reaction_record.log_beta_minus,
weak_reaction_record.log_antineutrino_loss_bd
}
);
}
if (weak_reaction_record.log_beta_plus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
m_weak_network[species].push_back(
WeakReaction{
WeakReactionType::BETA_PLUS_DECAY,
weak_reaction_record.t9,
weak_reaction_record.log_rhoye,
weak_reaction_record.mu_e,
weak_reaction_record.log_beta_plus,
weak_reaction_record.log_neutrino_loss_ec
}
);
}
if (weak_reaction_record.log_electron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
m_weak_network[species].push_back(
WeakReaction{
WeakReactionType::ELECTRON_CAPTURE,
weak_reaction_record.t9,
weak_reaction_record.log_rhoye,
weak_reaction_record.mu_e,
weak_reaction_record.log_electron_capture,
weak_reaction_record.log_neutrino_loss_ec
}
);
}
if (weak_reaction_record.log_positron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
m_weak_network[species].push_back(
WeakReaction{
WeakReactionType::POSITRON_CAPTURE,
weak_reaction_record.t9,
weak_reaction_record.log_rhoye,
weak_reaction_record.mu_e,
weak_reaction_record.log_positron_capture,
weak_reaction_record.log_antineutrino_loss_bd
}
);
}
}
}
std::vector<WeakReaction> WeakReactionMap::get_all_reactions() const {
std::vector<WeakReaction> reactions;
for (const auto &species_reactions: m_weak_network | std::views::values) {
reactions.insert(reactions.end(), species_reactions.begin(), species_reactions.end());
}
return reactions;
}
std::expected<std::vector<WeakReaction>, bool> WeakReactionMap::get_species_reactions(const fourdst::atomic::Species &species) const {
if (m_weak_network.contains(species)) {
return m_weak_network.at(species);
}
return std::unexpected(false);
}
std::expected<std::vector<WeakReaction>, bool> WeakReactionMap::get_species_reactions(const std::string &species_name) const {
fourdst::atomic::Species species = fourdst::atomic::species.at(species_name);
if (m_weak_network.contains(species)) {
return m_weak_network.at(species);
}
return std::unexpected(false);
}
}

View File

@@ -10,7 +10,7 @@
namespace gridfire::screening {
using ADDouble = CppAD::AD<double>;
std::vector<ADDouble> BareScreeningModel::calculateScreeningFactors(
const reaction::LogicalReactionSet &reactions,
const reaction::ReactionSet &reactions,
const std::vector<fourdst::atomic::Species>& species,
const std::vector<ADDouble> &Y,
const ADDouble T9,
@@ -20,7 +20,7 @@ namespace gridfire::screening {
}
std::vector<double> BareScreeningModel::calculateScreeningFactors(
const reaction::LogicalReactionSet &reactions,
const reaction::ReactionSet &reactions,
const std::vector<fourdst::atomic::Species>& species,
const std::vector<double> &Y,
const double T9,

View File

@@ -12,8 +12,6 @@ namespace gridfire::screening {
return std::make_unique<WeakScreeningModel>();
case ScreeningType::BARE:
return std::make_unique<BareScreeningModel>();
default:
return std::make_unique<BareScreeningModel>();
}
}
}

View File

@@ -10,7 +10,7 @@
namespace gridfire::screening {
using ADDouble = CppAD::AD<double>;
std::vector<ADDouble> WeakScreeningModel::calculateScreeningFactors(
const reaction::LogicalReactionSet &reactions,
const reaction::ReactionSet &reactions,
const std::vector<fourdst::atomic::Species>& species,
const std::vector<ADDouble> &Y,
const ADDouble T9,
@@ -20,7 +20,7 @@ namespace gridfire::screening {
}
std::vector<double> WeakScreeningModel::calculateScreeningFactors(
const reaction::LogicalReactionSet &reactions,
const reaction::ReactionSet &reactions,
const std::vector<fourdst::atomic::Species>& species,
const std::vector<double> &Y,
const double T9,

View File

@@ -7,6 +7,10 @@
#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>
@@ -50,7 +54,6 @@ namespace gridfire::solver {
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
};
@@ -109,7 +112,7 @@ namespace gridfire::solver {
NetIn netInTemp = netIn;
netInTemp.temperature = e.temperature();
netInTemp.density = e.density();
netInTemp.composition = std::move(temp_comp);
netInTemp.composition = temp_comp;
Composition currentComposition = m_engine.update(netInTemp);
populateY(currentComposition);
@@ -220,6 +223,13 @@ namespace gridfire::solver {
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);

View File

@@ -7,7 +7,6 @@
#include <ranges>
#include <string_view>
#include <string>
#include <iostream>
#include <vector>
std::string gridfire::utils::formatNuclearTimescaleLogString(