refactor(reaction): refactored to an abstract reaction class in prep for weak reactions
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user