docs(docs): added doxygen html directory

This commit is contained in:
2025-07-01 07:24:18 -04:00
parent 58a0007351
commit 40b28477ed
410 changed files with 231801 additions and 128 deletions

View File

@@ -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
);
};
}

View 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;
};
}

View 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(); }
);
}
}

View File

@@ -0,0 +1,3 @@
//
// Created by Emily Boudreaux on 6/30/25.
//

View File

@@ -0,0 +1,3 @@
//
// Created by Emily Boudreaux on 6/30/25.
//