docs(docs): added doxygen html directory
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/engine/engine_view_abstract.h"
|
||||
#include "engine_view_abstract.h"
|
||||
#include "gridfire/network.h"
|
||||
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
@@ -238,6 +238,14 @@ namespace gridfire {
|
||||
|
||||
bool m_isStale = true;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief A struct to hold a reaction and its flow rate.
|
||||
*/
|
||||
struct ReactionFlow {
|
||||
const reaction::LogicalReaction* reactionPtr;
|
||||
double flowRate;
|
||||
};
|
||||
private:
|
||||
/**
|
||||
* @brief Constructs the species index map.
|
||||
@@ -307,13 +315,22 @@ namespace gridfire {
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
*/
|
||||
void validateState() const;
|
||||
private:
|
||||
/**
|
||||
* @brief A struct to hold a reaction and its flow rate.
|
||||
*/
|
||||
struct ReactionFlow {
|
||||
const reaction::Reaction* reactionPtr;
|
||||
double flowRate;
|
||||
};
|
||||
|
||||
std::vector<ReactionFlow> calculateAllReactionFlows(
|
||||
const NetIn& netIn,
|
||||
std::vector<double>& out_Y_Full
|
||||
) const;
|
||||
std::unordered_set<fourdst::atomic::Species> findReachableSpecies(
|
||||
const NetIn& netIn
|
||||
) const;
|
||||
std::vector<const reaction::LogicalReaction*> cullReactionsByFlow(
|
||||
const std::vector<ReactionFlow>& allFlows,
|
||||
const std::unordered_set<fourdst::atomic::Species>& reachableSpecies,
|
||||
const std::vector<double>& Y_full,
|
||||
double maxFlow
|
||||
) const;
|
||||
void finalizeActiveSet(
|
||||
const std::vector<const reaction::LogicalReaction*>& finalReactions
|
||||
);
|
||||
};
|
||||
}
|
||||
135
src/network/include/gridfire/engine/views/engine_defined.h
Normal file
135
src/network/include/gridfire/engine/views/engine_defined.h
Normal file
@@ -0,0 +1,135 @@
|
||||
#pragma once
|
||||
|
||||
#include "engine_view_abstract.h"
|
||||
#include "../engine_abstract.h"
|
||||
|
||||
#include "fourdst/config/config.h"
|
||||
#include "fourdst/logging/logging.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gridfire{
|
||||
class FileDefinedEngineView final: public DynamicEngine, public EngineView<DynamicEngine> {
|
||||
public:
|
||||
explicit FileDefinedEngineView(DynamicEngine& baseEngine, const std::string& fileName);
|
||||
|
||||
// --- EngineView Interface ---
|
||||
const DynamicEngine& getBaseEngine() const override;
|
||||
|
||||
// --- Engine Interface ---
|
||||
const std::vector<fourdst::atomic::Species>& getNetworkSpecies() const override;
|
||||
|
||||
// --- DynamicEngine Interface ---
|
||||
StepDerivatives<double> calculateRHSAndEnergy(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
void generateJacobianMatrix(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) override;
|
||||
double getJacobianMatrixEntry(
|
||||
const int i_defined,
|
||||
const int j_defined
|
||||
) const override;
|
||||
void generateStoichiometryMatrix() override;
|
||||
int getStoichiometryMatrixEntry(
|
||||
const int speciesIndex_defined,
|
||||
const int reactionIndex_defined
|
||||
) const override;
|
||||
double calculateMolarReactionFlow(
|
||||
const reaction::Reaction& reaction,
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
const reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
std::unordered_map<fourdst::atomic::Species, double> getSpeciesTimescales(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
private:
|
||||
using Config = fourdst::config::Config;
|
||||
using LogManager = fourdst::logging::LogManager;
|
||||
Config& m_config = Config::getInstance();
|
||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||
|
||||
DynamicEngine& m_baseEngine;
|
||||
|
||||
std::vector<fourdst::atomic::Species> m_activeSpecies; ///< Active species in the defined engine.
|
||||
reaction::LogicalReactionSet m_activeReactions; ///< Active reactions in the defined engine.
|
||||
|
||||
std::vector<size_t> m_speciesIndexMap; ///< Maps indices of active species to indices in the full network.
|
||||
std::vector<size_t> m_reactionIndexMap; ///< Maps indices of active reactions to indices in the full network.
|
||||
private:
|
||||
void buildFromFile(const std::string& fileName);
|
||||
|
||||
/**
|
||||
* @brief Constructs the species index map.
|
||||
*
|
||||
* @return A vector mapping culled species indices to full species indices.
|
||||
*
|
||||
* This method creates a map from the indices of the active species to the indices of the
|
||||
* corresponding species in the full network.
|
||||
*
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
std::vector<size_t> constructSpeciesIndexMap() const;
|
||||
|
||||
/**
|
||||
* @brief Constructs the reaction index map.
|
||||
*
|
||||
* @return A vector mapping culled reaction indices to full reaction indices.
|
||||
*
|
||||
* This method creates a map from the indices of the active reactions to the indices of the
|
||||
* corresponding reactions in the full network.
|
||||
*
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
std::vector<size_t> constructReactionIndexMap() const;
|
||||
|
||||
/**
|
||||
* @brief Maps a vector of culled abundances to a vector of full abundances.
|
||||
*
|
||||
* @param culled A vector of abundances for the active species.
|
||||
* @return A vector of abundances for the full network, with the abundances of the active
|
||||
* species copied from the culled vector.
|
||||
*/
|
||||
std::vector<double> mapCulledToFull(const std::vector<double>& culled) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a vector of full abundances to a vector of culled abundances.
|
||||
*
|
||||
* @param full A vector of abundances for the full network.
|
||||
* @return A vector of abundances for the active species, with the abundances of the active
|
||||
* species copied from the full vector.
|
||||
*/
|
||||
std::vector<double> mapFullToCulled(const std::vector<double>& full) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a culled species index to a full species index.
|
||||
*
|
||||
* @param culledSpeciesIndex The index of the species in the culled species list.
|
||||
* @return The index of the corresponding species in the full network.
|
||||
*
|
||||
* @throws std::out_of_range If the culled index is out of bounds for the species index map.
|
||||
*/
|
||||
size_t mapCulledToFullSpeciesIndex(size_t culledSpeciesIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a culled reaction index to a full reaction index.
|
||||
*
|
||||
* @param culledReactionIndex The index of the reaction in the culled reaction list.
|
||||
* @return The index of the corresponding reaction in the full network.
|
||||
*
|
||||
* @throws std::out_of_range If the culled index is out of bounds for the reaction index map.
|
||||
*/
|
||||
size_t mapCulledToFullReactionIndex(size_t culledReactionIndex) const;
|
||||
|
||||
};
|
||||
}
|
||||
0
src/network/include/gridfire/io/network_file.h
Normal file
0
src/network/include/gridfire/io/network_file.h
Normal file
@@ -1,4 +1,4 @@
|
||||
#include "gridfire/engine/engine_adaptive.h"
|
||||
#include "../../../include/gridfire/engine/views/engine_adaptive.h"
|
||||
|
||||
#include <ranges>
|
||||
#include <queue>
|
||||
@@ -83,137 +83,34 @@ namespace gridfire {
|
||||
}
|
||||
|
||||
void AdaptiveEngineView::update(const NetIn& netIn) {
|
||||
LOG_TRACE_L1(m_logger, "Updating adaptive engine view...");
|
||||
LOG_TRACE_L1(m_logger, "Updating AdaptiveEngineView with new network input...");
|
||||
|
||||
const auto& fullSpeciesList = m_baseEngine.getNetworkSpecies();
|
||||
std::vector<double>Y_full;
|
||||
Y_full.reserve(fullSpeciesList.size());
|
||||
std::vector<double> Y_Full;
|
||||
std::vector<ReactionFlow> allFlows = calculateAllReactionFlows(netIn, Y_Full);
|
||||
|
||||
for (const auto& species : fullSpeciesList) {
|
||||
if (netIn.composition.contains(species)) {
|
||||
Y_full.push_back(netIn.composition.getMolarAbundance(std::string(species.name())));
|
||||
} else {
|
||||
LOG_TRACE_L2(m_logger, "Species '{}' not found in composition. Setting abundance to 0.0.", species.name());
|
||||
Y_full.push_back(0.0);
|
||||
double maxFlow = 0.0;
|
||||
|
||||
for (const auto&[reactionPtr, flowRate]: allFlows) {
|
||||
if (flowRate > maxFlow) {
|
||||
maxFlow = flowRate;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(m_logger, "Maximum reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", maxFlow);
|
||||
|
||||
const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
|
||||
const double rho = netIn.density; // Density in g/cm^3
|
||||
const std::unordered_set<Species> reachableSpecies = findReachableSpecies(netIn);
|
||||
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);
|
||||
|
||||
std::vector<ReactionFlow> reactionFlows;
|
||||
const auto& fullReactionSet = m_baseEngine.getNetworkReactions();
|
||||
reactionFlows.reserve(fullReactionSet.size());
|
||||
finalizeActiveSet(finalReactions);
|
||||
|
||||
for (const auto& reactionPtr : fullReactionSet) {
|
||||
const double flow = m_baseEngine.calculateMolarReactionFlow(reactionPtr, Y_full, T9, rho);
|
||||
reactionFlows.push_back({&reactionPtr, flow});
|
||||
}
|
||||
|
||||
double max_flow = 0.0;
|
||||
double min_flow = std::numeric_limits<double>::max();
|
||||
double flowSum = 0.0;
|
||||
for (const auto&[reactionPtr, flowRate] : reactionFlows) {
|
||||
if (flowRate > max_flow) {
|
||||
max_flow = flowRate;
|
||||
} else if (flowRate < min_flow) {
|
||||
min_flow = flowRate;
|
||||
}
|
||||
flowSum += flowRate;
|
||||
LOG_TRACE_L2(m_logger, "Reaction '{}' has flow rate: {:0.3E} [mol/s]", reactionPtr->id(), flowRate);
|
||||
}
|
||||
flowSum /= reactionFlows.size();
|
||||
|
||||
LOG_DEBUG(m_logger, "Maximum reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", max_flow);
|
||||
LOG_DEBUG(m_logger, "Minimum reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", min_flow);
|
||||
LOG_DEBUG(m_logger, "Average reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", flowSum);
|
||||
|
||||
const double relative_culling_threshold = m_config.get<double>("gridfire:AdaptiveEngineView:RelativeCullingThreshold", 1e-75);
|
||||
|
||||
double absoluteCullingThreshold = relative_culling_threshold * max_flow;
|
||||
LOG_DEBUG(m_logger, "Relative culling threshold: {:0.3E} ({})", relative_culling_threshold, absoluteCullingThreshold);
|
||||
|
||||
// --- Reaction Culling ---
|
||||
LOG_TRACE_L1(m_logger, "Culling reactions based on reaction flow rates...");
|
||||
std::vector<const reaction::Reaction*> flowCulledReactions;
|
||||
for (const auto&[reactionPtr, flowRate] : reactionFlows) {
|
||||
if (flowRate > absoluteCullingThreshold) {
|
||||
LOG_TRACE_L2(m_logger, "Maintaining reaction '{}' with relative (abs) flow rate: {:0.3E} ({:0.3E} [mol/s])", reactionPtr->id(), flowRate/max_flow, flowRate);
|
||||
flowCulledReactions.push_back(reactionPtr);
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(m_logger, "Selected {} (total: {}, culled: {}) reactions based on flow rates.", flowCulledReactions.size(), fullReactionSet.size(), fullReactionSet.size() - flowCulledReactions.size());
|
||||
|
||||
// --- Connectivity Analysis ---
|
||||
std::queue<Species> species_to_visit;
|
||||
std::unordered_set<Species> reachable_species;
|
||||
|
||||
constexpr double ABUNDANCE_FLOOR = 1e-12; // Abundance floor for a species to be considered part of the initial fuel
|
||||
for (const auto& species : fullSpeciesList) {
|
||||
if (netIn.composition.contains(species) && netIn.composition.getMassFraction(std::string(species.name())) > ABUNDANCE_FLOOR) {
|
||||
species_to_visit.push(species);
|
||||
reachable_species.insert(species);
|
||||
LOG_TRACE_L2(m_logger, "Species '{}' is part of the initial fuel.", species.name());
|
||||
}
|
||||
}
|
||||
std::unordered_map<Species, std::vector<const reaction::Reaction*>> reactant_to_reactions_map;
|
||||
for (const auto* reaction_ptr : flowCulledReactions) {
|
||||
for (const auto& reactant : reaction_ptr->reactants()) {
|
||||
reactant_to_reactions_map[reactant].push_back(reaction_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
while (!species_to_visit.empty()) {
|
||||
Species currentSpecies = species_to_visit.front();
|
||||
species_to_visit.pop();
|
||||
|
||||
auto it = reactant_to_reactions_map.find(currentSpecies);
|
||||
if (it == reactant_to_reactions_map.end()) {
|
||||
continue; // The species does not initiate any further reactions
|
||||
}
|
||||
|
||||
const auto& reactions = it->second;
|
||||
for (const auto* reaction_ptr : reactions) {
|
||||
for (const auto& product : reaction_ptr->products()) {
|
||||
if (!reachable_species.contains(product)) {
|
||||
reachable_species.insert(product);
|
||||
species_to_visit.push(product);
|
||||
LOG_TRACE_L2(m_logger, "Species '{}' is reachable via reaction '{}'.", product.name(), reaction_ptr->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(m_logger, "Reachable species count: {}", reachable_species.size());
|
||||
|
||||
m_activeSpecies.assign(reachable_species.begin(), reachable_species.end());
|
||||
std::ranges::sort(m_activeSpecies,
|
||||
[](const Species &a, const Species &b) { return a.mass() < b.mass(); });
|
||||
|
||||
m_activeReactions.clear();
|
||||
for (const auto* reaction_ptr : flowCulledReactions) {
|
||||
bool all_reactants_present = true;
|
||||
for (const auto& reactant : reaction_ptr->reactants()) {
|
||||
if (!reachable_species.contains(reactant)) {
|
||||
all_reactants_present = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_reactants_present) {
|
||||
m_activeReactions.add_reaction(*reaction_ptr);
|
||||
LOG_TRACE_L2(m_logger, "Maintaining reaction '{}' with all reactants present.", reaction_ptr->id());
|
||||
} else {
|
||||
LOG_TRACE_L1(m_logger, "Culling reaction '{}' due to missing reactants.", reaction_ptr->id());
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(m_logger, "Active reactions count: {} (total: {}, culled: {}, culled due to connectivity: {})", m_activeReactions.size(),
|
||||
fullReactionSet.size(), fullReactionSet.size() - m_activeReactions.size(), flowCulledReactions.size() - m_activeReactions.size());
|
||||
|
||||
m_speciesIndexMap = constructSpeciesIndexMap();
|
||||
m_reactionIndexMap = constructReactionIndexMap();
|
||||
|
||||
m_isStale = false;
|
||||
|
||||
LOG_INFO(m_logger, "AdaptiveEngineView updated successfully with {} active species and {} active reactions.", m_activeSpecies.size(), m_activeReactions.size());
|
||||
}
|
||||
|
||||
const std::vector<Species> & AdaptiveEngineView::getNetworkSpecies() const {
|
||||
@@ -359,5 +256,143 @@ namespace gridfire {
|
||||
throw std::runtime_error("AdaptiveEngineView is stale. Please call update() before calculating RHS and energy.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AdaptiveEngineView::ReactionFlow> AdaptiveEngineView::calculateAllReactionFlows(
|
||||
const NetIn &netIn,
|
||||
std::vector<double> &out_Y_Full
|
||||
) const {
|
||||
const auto& fullSpeciesList = m_baseEngine.getNetworkSpecies();
|
||||
out_Y_Full.clear();
|
||||
out_Y_Full.reserve(fullSpeciesList.size());
|
||||
|
||||
for (const auto& species: fullSpeciesList) {
|
||||
if (netIn.composition.contains(species)) {
|
||||
out_Y_Full.push_back(netIn.composition.getMolarAbundance(std::string(species.name())));
|
||||
} else {
|
||||
LOG_TRACE_L2(m_logger, "Species '{}' not found in composition. Setting abundance to 0.0.", species.name());
|
||||
out_Y_Full.push_back(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
|
||||
const double rho = netIn.density; // Density in g/cm^3
|
||||
|
||||
std::vector<ReactionFlow> reactionFlows;
|
||||
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});
|
||||
LOG_TRACE_L2(m_logger, "Reaction '{}' has flow rate: {:0.3E} [mol/s]", reaction.id(), flow);
|
||||
}
|
||||
return reactionFlows;
|
||||
}
|
||||
|
||||
std::unordered_set<Species> AdaptiveEngineView::findReachableSpecies(
|
||||
const NetIn &netIn
|
||||
) const {
|
||||
std::unordered_set<Species> reachable;
|
||||
std::queue<Species> to_vist;
|
||||
|
||||
constexpr double ABUNDANCE_FLOOR = 1e-12; // Abundance floor for a species to be considered part of the initial fuel
|
||||
for (const auto& species: m_baseEngine.getNetworkSpecies()) {
|
||||
if (netIn.composition.contains(species) && netIn.composition.getMassFraction(std::string(species.name())) > ABUNDANCE_FLOOR) {
|
||||
if (!reachable.contains(species)) {
|
||||
to_vist.push(species);
|
||||
reachable.insert(species);
|
||||
LOG_TRACE_L2(m_logger, "Network Connectivity Analysis: Species '{}' is part of the initial fuel.", species.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool new_species_found_in_pass = true;
|
||||
while (new_species_found_in_pass) {
|
||||
new_species_found_in_pass = false;
|
||||
for (const auto& reaction: m_baseEngine.getNetworkReactions()) {
|
||||
bool all_reactants_reachable = true;
|
||||
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()) {
|
||||
if (!reachable.contains(product)) {
|
||||
reachable.insert(product);
|
||||
new_species_found_in_pass = true;
|
||||
LOG_TRACE_L2(m_logger, "Network Connectivity Analysis: Species '{}' is reachable via reaction '{}'.", product.name(), reaction.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reachable;
|
||||
}
|
||||
|
||||
std::vector<const reaction::LogicalReaction *> AdaptiveEngineView::cullReactionsByFlow(
|
||||
const std::vector<ReactionFlow> &allFlows,
|
||||
const std::unordered_set<fourdst::atomic::Species> &reachableSpecies,
|
||||
const std::vector<double> &Y_full,
|
||||
const double maxFlow
|
||||
) const {
|
||||
LOG_TRACE_L1(m_logger, "Culling reactions based on flow rates...");
|
||||
const double 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;
|
||||
for (const auto& [reactionPtr, flowRate]: allFlows) {
|
||||
bool keepReaction = false;
|
||||
if (flowRate > absoluteCullingThreshold) {
|
||||
LOG_TRACE_L2(m_logger, "Maintaining reaction '{}' with relative (abs) flow rate: {:0.3E} ({:0.3E} [mol/s])", reactionPtr->id(), flowRate/maxFlow, flowRate);
|
||||
keepReaction = true;
|
||||
} else {
|
||||
bool zero_flow_due_to_reachable_reactants = false;
|
||||
if (flowRate < 1e-99) {
|
||||
for (const auto& reactant: reactionPtr->reactants()) {
|
||||
const auto it = std::ranges::find(m_baseEngine.getNetworkSpecies(), reactant);
|
||||
const size_t index = std::distance(m_baseEngine.getNetworkSpecies().begin(), it);
|
||||
if (Y_full[index] < 1e-99 && reachableSpecies.contains(reactant)) {
|
||||
LOG_TRACE_L2(m_logger, "Maintaining reaction '{}' with zero flow due to reachable reactant '{}'.", reactionPtr->id(), reactant.name());
|
||||
zero_flow_due_to_reachable_reactants = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zero_flow_due_to_reachable_reactants) {
|
||||
keepReaction = true;
|
||||
}
|
||||
}
|
||||
if (keepReaction) {
|
||||
culledReactions.push_back(reactionPtr);
|
||||
} else {
|
||||
LOG_TRACE_L1(m_logger, "Culling reaction '{}' due to low flow rate or lack of connectivity.", reactionPtr->id());
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(m_logger, "Selected {} (total: {}, culled: {}) reactions based on flow rates.", culledReactions.size(), allFlows.size(), allFlows.size() - culledReactions.size());
|
||||
return culledReactions;
|
||||
}
|
||||
|
||||
void AdaptiveEngineView::finalizeActiveSet(
|
||||
const std::vector<const reaction::LogicalReaction *> &finalReactions
|
||||
) {
|
||||
std::unordered_set<Species>finalSpeciesSet;
|
||||
m_activeReactions.clear();
|
||||
for (const auto* reactionPtr: finalReactions) {
|
||||
m_activeReactions.add_reaction(*reactionPtr);
|
||||
for (const auto& reactant : reactionPtr->reactants()) {
|
||||
finalSpeciesSet.insert(reactant);
|
||||
}
|
||||
for (const auto& product : reactionPtr->products()) {
|
||||
finalSpeciesSet.insert(product);
|
||||
}
|
||||
}
|
||||
m_activeSpecies.assign(finalSpeciesSet.begin(), finalSpeciesSet.end());
|
||||
std::ranges::sort(
|
||||
m_activeSpecies,
|
||||
[](const Species &a, const Species &b) { return a.mass() < b.mass(); }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
3
src/network/lib/engine/views/engine_defined.cpp
Normal file
3
src/network/lib/engine/views/engine_defined.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
//
|
||||
// Created by Emily Boudreaux on 6/30/25.
|
||||
//
|
||||
3
src/network/lib/io/network_file.cpp
Normal file
3
src/network/lib/io/network_file.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
//
|
||||
// Created by Emily Boudreaux on 6/30/25.
|
||||
//
|
||||
Reference in New Issue
Block a user