feat(python): added robust python bindings covering the entire codebase
This commit is contained in:
8
src/include/gridfire/engine/engine.h
Normal file
8
src/include/gridfire/engine/engine.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/engine/engine_graph.h"
|
||||
|
||||
#include "gridfire/engine/views/engine_views.h"
|
||||
#include "gridfire/engine/procedures/engine_procedures.h"
|
||||
#include "gridfire/engine/types/engine_types.h"
|
||||
314
src/include/gridfire/engine/engine_abstract.h
Normal file
314
src/include/gridfire/engine/engine_abstract.h
Normal file
@@ -0,0 +1,314 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/reaction/reaction.h"
|
||||
#include "gridfire/network.h"
|
||||
#include "gridfire/screening/screening_abstract.h"
|
||||
#include "gridfire/screening/screening_types.h"
|
||||
|
||||
#include "gridfire/engine/types/reporting.h"
|
||||
#include "gridfire/engine/types/building.h"
|
||||
|
||||
#include "gridfire/expectations/expected_engine.h"
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <expected>
|
||||
|
||||
/**
|
||||
* @file engine_abstract.h
|
||||
* @brief Abstract interfaces for reaction network engines in GridFire.
|
||||
*
|
||||
* This header defines the abstract base classes and concepts for implementing
|
||||
* reaction network solvers in the GridFire framework. It provides the contract
|
||||
* for calculating right-hand sides, energy generation, Jacobians, stoichiometry,
|
||||
* and other core operations required for time integration of nuclear reaction networks.
|
||||
*
|
||||
* @author
|
||||
* Emily M. Boudreaux
|
||||
*/
|
||||
|
||||
namespace gridfire {
|
||||
|
||||
/**
|
||||
* @brief Concept for types allowed in engine calculations.
|
||||
*
|
||||
* This concept restricts template parameters to either double or CppAD::AD<double>,
|
||||
* enabling both standard and automatic differentiation types.
|
||||
*/
|
||||
template<typename T>
|
||||
concept IsArithmeticOrAD = std::is_same_v<T, double> || std::is_same_v<T, CppAD::AD<double>>;
|
||||
|
||||
/**
|
||||
* @brief Structure holding derivatives and energy generation for a network step.
|
||||
*
|
||||
* @tparam T Numeric type (double or CppAD::AD<double>).
|
||||
*
|
||||
* This struct is used to return both the time derivatives of all species abundances
|
||||
* and the specific nuclear energy generation rate for a single network evaluation.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* StepDerivatives<double> result = engine.calculateRHSAndEnergy(Y, T9, rho);
|
||||
* for (double dydt_i : result.dydt) {
|
||||
* // Use derivative
|
||||
* }
|
||||
* double energyRate = result.nuclearEnergyGenerationRate;
|
||||
* @endcode
|
||||
*/
|
||||
template <IsArithmeticOrAD T>
|
||||
struct StepDerivatives {
|
||||
std::vector<T> dydt; ///< Derivatives of abundances (dY/dt for each species).
|
||||
T nuclearEnergyGenerationRate = T(0.0); ///< Specific energy generation rate (e.g., erg/g/s).
|
||||
};
|
||||
|
||||
using SparsityPattern = std::vector<std::pair<size_t, size_t>>;
|
||||
|
||||
/**
|
||||
* @brief Abstract base class for a reaction network engine.
|
||||
*
|
||||
* This class defines the minimal interface for a reaction network engine,
|
||||
* which is responsible for evaluating the right-hand side (dY/dt) and
|
||||
* energy generation for a given set of abundances, temperature, and density.
|
||||
*
|
||||
* Intended usage: Derive from this class to implement a concrete engine
|
||||
* for a specific network or integration method.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* class MyEngine : public gridfire::Engine {
|
||||
* // Implement required methods...
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
class Engine {
|
||||
public:
|
||||
/**
|
||||
* @brief Virtual destructor.
|
||||
*/
|
||||
virtual ~Engine() = default;
|
||||
|
||||
/**
|
||||
* @brief Get the list of species in the network.
|
||||
* @return Vector of Species objects representing all network species.
|
||||
*/
|
||||
[[nodiscard]] virtual const std::vector<fourdst::atomic::Species>& getNetworkSpecies() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Calculate the right-hand side (dY/dt) and energy generation.
|
||||
*
|
||||
* @param Y Vector of current abundances for all species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
||||
*
|
||||
* This function must be implemented by derived classes to compute the
|
||||
* time derivatives of all species and the specific nuclear energy generation
|
||||
* rate for the current state.
|
||||
*/
|
||||
[[nodiscard]] virtual std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract class for engines supporting Jacobian and stoichiometry operations.
|
||||
*
|
||||
* Extends Engine with additional methods for:
|
||||
* - Generating and accessing the Jacobian matrix (for implicit solvers).
|
||||
* - Generating and accessing the stoichiometry matrix.
|
||||
* - Calculating molar reaction flows for individual reactions.
|
||||
* - Accessing the set of logical reactions in the network.
|
||||
* - Computing timescales for each species.
|
||||
*
|
||||
* Intended usage: Derive from this class to implement engines that support
|
||||
* advanced solver features such as implicit integration, sensitivity analysis,
|
||||
* QSE (Quasi-Steady-State Equilibrium) handling, and more.
|
||||
*/
|
||||
class DynamicEngine : public Engine {
|
||||
public:
|
||||
/**
|
||||
* @brief Generate the Jacobian matrix for the current state.
|
||||
*
|
||||
* @param Y_dynamic Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
*
|
||||
* This method must compute and store the Jacobian matrix (∂(dY/dt)_i/∂Y_j)
|
||||
* for the current state. The matrix can then be accessed via getJacobianMatrixEntry().
|
||||
*/
|
||||
virtual void generateJacobianMatrix(
|
||||
const std::vector<double>& Y_dynamic,
|
||||
double T9,
|
||||
double rho
|
||||
) const = 0;
|
||||
|
||||
virtual void generateJacobianMatrix(
|
||||
const std::vector<double>& Y_dynamic,
|
||||
double T9,
|
||||
double rho,
|
||||
const SparsityPattern& sparsityPattern
|
||||
) const {
|
||||
throw std::logic_error("Sparsity pattern not supported by this engine.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an entry from the previously generated Jacobian matrix.
|
||||
*
|
||||
* @param i Row index (species index).
|
||||
* @param j Column index (species index).
|
||||
* @return Value of the Jacobian matrix at (i, j).
|
||||
*
|
||||
* The Jacobian must have been generated by generateJacobianMatrix() before calling this.
|
||||
*/
|
||||
[[nodiscard]] virtual double getJacobianMatrixEntry(
|
||||
int i,
|
||||
int j
|
||||
) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generate the stoichiometry matrix for the network.
|
||||
*
|
||||
* This method must compute and store the stoichiometry matrix,
|
||||
* which encodes the net change of each species in each reaction.
|
||||
*/
|
||||
virtual void generateStoichiometryMatrix() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get an entry from the stoichiometry matrix.
|
||||
*
|
||||
* @param speciesIndex Index of the species.
|
||||
* @param reactionIndex Index of the reaction.
|
||||
* @return Stoichiometric coefficient for the species in the reaction.
|
||||
*
|
||||
* The stoichiometry matrix must have been generated by generateStoichiometryMatrix().
|
||||
*/
|
||||
[[nodiscard]] virtual int getStoichiometryMatrixEntry(
|
||||
int speciesIndex,
|
||||
int reactionIndex
|
||||
) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Calculate the molar reaction flow for a given reaction.
|
||||
*
|
||||
* @param reaction The reaction for which to calculate the flow.
|
||||
* @param Y Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||
*
|
||||
* This method computes the net rate at which the given reaction proceeds
|
||||
* under the current state.
|
||||
*/
|
||||
[[nodiscard]] virtual double calculateMolarReactionFlow(
|
||||
const reaction::Reaction& reaction,
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the set of logical reactions in the network.
|
||||
*
|
||||
* @return Reference to the LogicalReactionSet containing all reactions.
|
||||
*/
|
||||
[[nodiscard]] virtual const reaction::LogicalReactionSet& getNetworkReactions() const = 0;
|
||||
|
||||
virtual void setNetworkReactions(const reaction::LogicalReactionSet& reactions) = 0;
|
||||
|
||||
/**
|
||||
* @brief Compute timescales for all species in the network.
|
||||
*
|
||||
* @param Y Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Map from Species to their characteristic timescales (s).
|
||||
*
|
||||
* This method estimates the timescale for abundance change of each species,
|
||||
* which can be used for timestep control, diagnostics, and reaction network culling.
|
||||
*/
|
||||
[[nodiscard]] virtual std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Update the internal state of the engine.
|
||||
*
|
||||
* @param netIn A struct containing the current network input, such as
|
||||
* temperature, density, and composition.
|
||||
*
|
||||
* This method is intended to be implemented by derived classes to update
|
||||
* their internal state based on the provided network conditions. For example,
|
||||
* an adaptive engine might use this to re-evaluate which reactions and species
|
||||
* are active. For other engines that do not support manually updating, this
|
||||
* method might do nothing.
|
||||
*
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* NetIn input = { ... };
|
||||
* myEngine.update(input);
|
||||
* @endcode
|
||||
*
|
||||
* @post The internal state of the engine is updated to reflect the new conditions.
|
||||
*/
|
||||
virtual fourdst::composition::Composition update(const NetIn &netIn) = 0;
|
||||
|
||||
virtual bool isStale(const NetIn& netIn) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the electron screening model.
|
||||
*
|
||||
* @param model The type of screening model to use for reaction rate calculations.
|
||||
*
|
||||
* This method allows changing the screening model at runtime. Screening corrections
|
||||
* account for the electrostatic shielding of nuclei by electrons, which affects
|
||||
* reaction rates in dense stellar plasmas.
|
||||
*
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* myEngine.setScreeningModel(screening::ScreeningType::WEAK);
|
||||
* @endcode
|
||||
*
|
||||
* @post The engine will use the specified screening model for subsequent rate calculations.
|
||||
*/
|
||||
virtual void setScreeningModel(screening::ScreeningType model) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the current electron screening model.
|
||||
*
|
||||
* @return The currently active screening model type.
|
||||
*
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* screening::ScreeningType currentModel = myEngine.getScreeningModel();
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] virtual screening::ScreeningType getScreeningModel() const = 0;
|
||||
|
||||
[[nodiscard]] virtual int getSpeciesIndex(const fourdst::atomic::Species &species) const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const = 0;
|
||||
|
||||
[[nodiscard]] virtual PrimingReport primeEngine(const NetIn &netIn) = 0;
|
||||
|
||||
[[nodiscard]] virtual BuildDepthType getDepth() const {
|
||||
throw std::logic_error("Network depth not supported by this engine.");
|
||||
}
|
||||
|
||||
virtual void rebuild(const fourdst::composition::Composition& comp, BuildDepthType depth) {
|
||||
throw std::logic_error("Setting network depth not supported by this engine.");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
331
src/include/gridfire/engine/engine_approx8.h
Normal file
331
src/include/gridfire/engine/engine_approx8.h
Normal file
@@ -0,0 +1,331 @@
|
||||
/* ***********************************************************************
|
||||
//
|
||||
// Copyright (C) 2025 -- The 4D-STAR Collaboration
|
||||
// File Author: Emily Boudreaux
|
||||
// Last Modified: March 21, 2025
|
||||
//
|
||||
// 4DSSE is free software; you can use it and/or modify
|
||||
// it under the terms and restrictions the GNU General Library Public
|
||||
// License version 3 (GPLv3) as published by the Free Software Foundation.
|
||||
//
|
||||
// 4DSSE is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public License
|
||||
// along with this software; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// *********************************************************************** */
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <boost/numeric/odeint.hpp>
|
||||
|
||||
#include "gridfire/network.h"
|
||||
|
||||
/**
|
||||
* @file approx8.h
|
||||
* @brief Header file for the Approx8 nuclear reaction network.
|
||||
*
|
||||
* This file contains the definitions and declarations for the Approx8 nuclear reaction network.
|
||||
* The network is based on Frank Timmes' "approx8" and includes 8 isotopes and various nuclear reactions.
|
||||
* The rates are evaluated using a fitting function with coefficients from reaclib.jinaweb.org.
|
||||
*/
|
||||
|
||||
|
||||
namespace gridfire::approx8{
|
||||
|
||||
/**
|
||||
* @typedef vector_type
|
||||
* @brief Alias for a vector of doubles using Boost uBLAS.
|
||||
*/
|
||||
typedef boost::numeric::ublas::vector< double > vector_type;
|
||||
|
||||
/**
|
||||
* @typedef matrix_type
|
||||
* @brief Alias for a matrix of doubles using Boost uBLAS.
|
||||
*/
|
||||
typedef boost::numeric::ublas::matrix< double > matrix_type;
|
||||
|
||||
/**
|
||||
* @typedef vec7
|
||||
* @brief Alias for a std::array of 7 doubles.
|
||||
*/
|
||||
typedef std::array<double,7> vec7;
|
||||
|
||||
/**
|
||||
* @struct Approx8Net
|
||||
* @brief Contains constants and arrays related to the nuclear network.
|
||||
*/
|
||||
struct Approx8Net{
|
||||
static constexpr int ih1=0;
|
||||
static constexpr int ihe3=1;
|
||||
static constexpr int ihe4=2;
|
||||
static constexpr int ic12=3;
|
||||
static constexpr int in14=4;
|
||||
static constexpr int io16=5;
|
||||
static constexpr int ine20=6;
|
||||
static constexpr int img24=7;
|
||||
|
||||
static constexpr int iTemp=img24+1;
|
||||
static constexpr int iDensity =iTemp+1;
|
||||
static constexpr int iEnergy=iDensity+1;
|
||||
|
||||
static constexpr int nIso=img24+1; // number of isotopes
|
||||
static constexpr int nVar=iEnergy+1; // number of variables
|
||||
|
||||
static constexpr std::array<int,nIso> aIon = {
|
||||
1,
|
||||
3,
|
||||
4,
|
||||
12,
|
||||
14,
|
||||
16,
|
||||
20,
|
||||
24
|
||||
};
|
||||
|
||||
static constexpr std::array<double,nIso> mIon = {
|
||||
1.67262164e-24,
|
||||
5.00641157e-24,
|
||||
6.64465545e-24,
|
||||
1.99209977e-23,
|
||||
2.32462686e-23,
|
||||
2.65528858e-23,
|
||||
3.31891077e-23,
|
||||
3.98171594e-23
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Multiplies two arrays and sums the resulting elements.
|
||||
* @param a First array.
|
||||
* @param b Second array.
|
||||
* @return Sum of the product of the arrays.
|
||||
* @example
|
||||
* @code
|
||||
* vec7 a = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0};
|
||||
* vec7 b = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5};
|
||||
* double result = sum_product(a, b);
|
||||
* @endcode
|
||||
*/
|
||||
double sum_product( const vec7 &a, const vec7 &b);
|
||||
|
||||
/**
|
||||
* @brief Returns an array of T9 terms for the nuclear reaction rate fit.
|
||||
* @param T Temperature in GigaKelvin.
|
||||
* @return Array of T9 terms.
|
||||
* @example
|
||||
* @code
|
||||
* double T = 1.5;
|
||||
* vec7 T9_array = get_T9_array(T);
|
||||
* @endcode
|
||||
*/
|
||||
vec7 get_T9_array(const double &T);
|
||||
|
||||
/**
|
||||
* @brief Evaluates the nuclear reaction rate given the T9 array and coefficients.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @param coef Array of coefficients.
|
||||
* @return Evaluated rate.
|
||||
* @example
|
||||
* @code
|
||||
* vec7 T9 = get_T9_array(1.5);
|
||||
* vec7 coef = {1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001};
|
||||
* double rate = rate_fit(T9, coef);
|
||||
* @endcode
|
||||
*/
|
||||
double rate_fit(const vec7 &T9, const vec7 &coef);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction p + p -> d.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double pp_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction p + d -> he3.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double dp_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction he3 + he3 -> he4 + 2p.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double he3he3_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction he3(he3,2p)he4.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double he3he4_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction he4 + he4 + he4 -> c12.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double triple_alpha_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction c12 + p -> n13.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double c12p_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction c12 + he4 -> o16.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double c12a_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction n14(p,g)o15 - o15 + p -> c12 + he4.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double n14p_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction n14(a,g)f18 assumed to go on to ne20.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double n14a_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction n15(p,a)c12 (CNO I).
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double n15pa_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction n15(p,g)o16 (CNO II).
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double n15pg_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the fraction for the reaction n15(p,g)o16.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Fraction of the reaction.
|
||||
*/
|
||||
double n15pg_frac(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction o16(p,g)f17 then f17 -> o17(p,a)n14.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double o16p_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction o16(a,g)ne20.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double o16a_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction ne20(a,g)mg24.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double ne20a_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction c12(c12,a)ne20.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double c12c12_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @brief Calculates the rate for the reaction c12(o16,a)mg24.
|
||||
* @param T9 Array of T9 terms.
|
||||
* @return Rate of the reaction.
|
||||
*/
|
||||
double c12o16_rate(const vec7 &T9);
|
||||
|
||||
/**
|
||||
* @struct Jacobian
|
||||
* @brief Functor to calculate the Jacobian matrix for implicit solvers.
|
||||
*/
|
||||
struct Jacobian {
|
||||
/**
|
||||
* @brief Calculates the Jacobian matrix.
|
||||
* @param y State vector.
|
||||
* @param J Jacobian matrix.
|
||||
* @param dfdt Derivative of the state vector.
|
||||
*/
|
||||
void operator() ( const vector_type &y, matrix_type &J, double /* t */, vector_type &dfdt ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct ODE
|
||||
* @brief Functor to calculate the derivatives for the ODE solver.
|
||||
*/
|
||||
struct ODE {
|
||||
/**
|
||||
* @brief Calculates the derivatives of the state vector.
|
||||
* @param y State vector.
|
||||
* @param dydt Derivative of the state vector.
|
||||
*/
|
||||
void operator() ( const vector_type &y, vector_type &dydt, double /* t */) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Approx8Network
|
||||
* @brief Class for the Approx8 nuclear reaction network.
|
||||
*/
|
||||
class Approx8Network final : public Network {
|
||||
public:
|
||||
Approx8Network();
|
||||
|
||||
/**
|
||||
* @brief Evaluates the nuclear network.
|
||||
* @param netIn Input parameters for the network.
|
||||
* @return Output results from the network.
|
||||
*/
|
||||
NetOut evaluate(const NetIn &netIn) override;
|
||||
|
||||
/**
|
||||
* @brief Sets whether the solver should use a stiff method.
|
||||
* @param stiff Boolean indicating if a stiff method should be used.
|
||||
*/
|
||||
void setStiff(bool stiff) override;
|
||||
|
||||
/**
|
||||
* @brief Checks if the solver is using a stiff method.
|
||||
* @return Boolean indicating if a stiff method is being used.
|
||||
*/
|
||||
bool isStiff() const override { return m_stiff; }
|
||||
private:
|
||||
vector_type m_y;
|
||||
double m_tMax = 0;
|
||||
double m_dt0 = 0;
|
||||
bool m_stiff = false;
|
||||
|
||||
/**
|
||||
* @brief Converts the input parameters to the internal state vector.
|
||||
* @param netIn Input parameters for the network.
|
||||
* @return Internal state vector.
|
||||
*/
|
||||
static vector_type convert_netIn(const NetIn &netIn);
|
||||
};
|
||||
|
||||
|
||||
} // namespace nnApprox8
|
||||
887
src/include/gridfire/engine/engine_graph.h
Normal file
887
src/include/gridfire/engine/engine_graph.h
Normal file
@@ -0,0 +1,887 @@
|
||||
#pragma once
|
||||
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/logging/logging.h"
|
||||
#include "fourdst/config/config.h"
|
||||
|
||||
#include "gridfire/network.h"
|
||||
#include "gridfire/reaction/reaction.h"
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/screening/screening_abstract.h"
|
||||
#include "gridfire/screening/screening_types.h"
|
||||
#include "gridfire/partition/partition_abstract.h"
|
||||
#include "gridfire/engine/procedures/construction.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
|
||||
#include <boost/numeric/ublas/matrix_sparse.hpp>
|
||||
|
||||
#include "cppad/cppad.hpp"
|
||||
#include "cppad/utility/sparse_rc.hpp"
|
||||
#include "cppad/speed/sparse_jac_fun.hpp"
|
||||
|
||||
#include "procedures/priming.h"
|
||||
|
||||
|
||||
#include "quill/LogMacros.h"
|
||||
|
||||
// PERF: The function getNetReactionStoichiometry returns a map of species to their stoichiometric coefficients for a given reaction.
|
||||
// this makes extra copies of the species, which is not ideal and could be optimized further.
|
||||
// Even more relevant is the member m_reactionIDMap which makes copies of a REACLIBReaction for each reaction ID.
|
||||
// REACLIBReactions are quite large data structures, so this could be a performance bottleneck.
|
||||
// static bool isF17 = false;
|
||||
namespace gridfire {
|
||||
static bool s_debug = false; // Global debug flag for the GraphEngine
|
||||
/**
|
||||
* @brief Alias for CppAD AD type for double precision.
|
||||
*
|
||||
* This alias simplifies the use of the CppAD automatic differentiation type.
|
||||
*/
|
||||
typedef CppAD::AD<double> ADDouble;
|
||||
|
||||
using fourdst::config::Config;
|
||||
using fourdst::logging::LogManager;
|
||||
using fourdst::constant::Constants;
|
||||
|
||||
/**
|
||||
* @brief Minimum density threshold below which reactions are ignored.
|
||||
*
|
||||
* Reactions are not calculated if the density falls below this threshold.
|
||||
* This helps to improve performance by avoiding unnecessary calculations
|
||||
* in very low-density regimes.
|
||||
*/
|
||||
static constexpr double MIN_DENSITY_THRESHOLD = 1e-18;
|
||||
|
||||
/**
|
||||
* @brief Minimum abundance threshold below which species are ignored.
|
||||
*
|
||||
* Species with abundances below this threshold are treated as zero in
|
||||
* reaction rate calculations. This helps to improve performance by
|
||||
* avoiding unnecessary calculations for trace species.
|
||||
*/
|
||||
static constexpr double MIN_ABUNDANCE_THRESHOLD = 1e-18;
|
||||
|
||||
/**
|
||||
* @brief Minimum value for Jacobian matrix entries.
|
||||
*
|
||||
* Jacobian matrix entries with absolute values below this threshold are
|
||||
* treated as zero to maintain sparsity and improve performance.
|
||||
*/
|
||||
static constexpr double MIN_JACOBIAN_THRESHOLD = 1e-24;
|
||||
|
||||
|
||||
/**
|
||||
* @class GraphEngine
|
||||
* @brief A reaction network engine that uses a graph-based representation.
|
||||
*
|
||||
* The GraphEngine class implements the DynamicEngine interface using a
|
||||
* graph-based representation of the reaction network. It uses sparse
|
||||
* matrices for efficient storage and computation of the stoichiometry
|
||||
* and Jacobian matrices. Automatic differentiation (AD) is used to
|
||||
* calculate the Jacobian matrix.
|
||||
*
|
||||
* The engine supports:
|
||||
* - Calculation of the right-hand side (dY/dt) and energy generation rate.
|
||||
* - Generation and access to the Jacobian matrix.
|
||||
* - Generation and access to the stoichiometry matrix.
|
||||
* - Calculation of molar reaction flows.
|
||||
* - Access to the set of logical reactions in the network.
|
||||
* - Computation of timescales for each species.
|
||||
* - Exporting the network to DOT and CSV formats for visualization and analysis.
|
||||
*
|
||||
* @implements DynamicEngine
|
||||
*
|
||||
* @see engine_abstract.h
|
||||
*/
|
||||
class GraphEngine final : public DynamicEngine{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a GraphEngine from a composition.
|
||||
*
|
||||
* @param composition The composition of the material.
|
||||
*
|
||||
* This constructor builds the reaction network from the given composition
|
||||
* using the `build_reaclib_nuclear_network` function.
|
||||
*
|
||||
* @see build_reaclib_nuclear_network
|
||||
*/
|
||||
explicit GraphEngine(
|
||||
const fourdst::composition::Composition &composition,
|
||||
const BuildDepthType = NetworkBuildDepth::Full
|
||||
);
|
||||
|
||||
explicit GraphEngine(
|
||||
const fourdst::composition::Composition &composition,
|
||||
const partition::PartitionFunction& partitionFunction,
|
||||
const BuildDepthType buildDepth = NetworkBuildDepth::Full
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Constructs a GraphEngine from a set of reactions.
|
||||
*
|
||||
* @param reactions The set of reactions to use in the network.
|
||||
*
|
||||
* This constructor uses the given set of reactions to construct the
|
||||
* reaction network.
|
||||
*/
|
||||
explicit GraphEngine(const reaction::LogicalReactionSet &reactions);
|
||||
|
||||
/**
|
||||
* @brief Calculates the right-hand side (dY/dt) and energy generation rate.
|
||||
*
|
||||
* @param Y Vector of current abundances for all species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
||||
*
|
||||
* This method calculates the time derivatives of all species and the
|
||||
* specific nuclear energy generation rate for the current state.
|
||||
*
|
||||
* @see StepDerivatives
|
||||
*/
|
||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the current state.
|
||||
*
|
||||
* @param Y_dynamic Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
*
|
||||
* This method computes and stores the Jacobian matrix (∂(dY/dt)_i/∂Y_j)
|
||||
* for the current state using automatic differentiation. The matrix can
|
||||
* then be accessed via `getJacobianMatrixEntry()`.
|
||||
*
|
||||
* @see getJacobianMatrixEntry()
|
||||
*/
|
||||
void generateJacobianMatrix(
|
||||
const std::vector<double>& Y_dynamic,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
void generateJacobianMatrix(
|
||||
const std::vector<double> &Y_dynamic,
|
||||
double T9,
|
||||
double rho,
|
||||
const SparsityPattern &sparsityPattern
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the stoichiometry matrix for the network.
|
||||
*
|
||||
* This method computes and stores the stoichiometry matrix,
|
||||
* which encodes the net change of each species in each reaction.
|
||||
*/
|
||||
void generateStoichiometryMatrix() override;
|
||||
|
||||
/**
|
||||
* @brief Calculates the molar reaction flow for a given reaction.
|
||||
*
|
||||
* @param reaction The reaction for which to calculate the flow.
|
||||
* @param Y Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||
*
|
||||
* This method computes the net rate at which the given reaction proceeds
|
||||
* under the current state.
|
||||
*/
|
||||
[[nodiscard]] double calculateMolarReactionFlow(
|
||||
const reaction::Reaction& reaction,
|
||||
const std::vector<double>&Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the list of species in the network.
|
||||
* @return Vector of Species objects representing all network species.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& getNetworkSpecies() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the set of logical reactions in the network.
|
||||
* @return Reference to the LogicalReactionSet containing all reactions.
|
||||
*/
|
||||
[[nodiscard]] const reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(const reaction::LogicalReactionSet& reactions) override;
|
||||
|
||||
/**
|
||||
* @brief Gets an entry from the previously generated Jacobian matrix.
|
||||
*
|
||||
* @param i Row index (species index).
|
||||
* @param j Column index (species index).
|
||||
* @return Value of the Jacobian matrix at (i, j).
|
||||
*
|
||||
* The Jacobian must have been generated by `generateJacobianMatrix()` before calling this.
|
||||
*
|
||||
* @see generateJacobianMatrix()
|
||||
*/
|
||||
[[nodiscard]] double getJacobianMatrixEntry(
|
||||
const int i,
|
||||
const int j
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the net stoichiometry for a given reaction.
|
||||
*
|
||||
* @param reaction The reaction for which to get the stoichiometry.
|
||||
* @return Map of species to their stoichiometric coefficients.
|
||||
*/
|
||||
[[nodiscard]] static std::unordered_map<fourdst::atomic::Species, int> getNetReactionStoichiometry(
|
||||
const reaction::Reaction& reaction
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Gets an entry from the stoichiometry matrix.
|
||||
*
|
||||
* @param speciesIndex Index of the species.
|
||||
* @param reactionIndex Index of the reaction.
|
||||
* @return Stoichiometric coefficient for the species in the reaction.
|
||||
*
|
||||
* The stoichiometry matrix must have been generated by `generateStoichiometryMatrix()`.
|
||||
*
|
||||
* @see generateStoichiometryMatrix()
|
||||
*/
|
||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||
const int speciesIndex,
|
||||
const int reactionIndex
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Computes timescales for all species in the network.
|
||||
*
|
||||
* @param Y Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Map from Species to their characteristic timescales (s).
|
||||
*
|
||||
* This method estimates the timescale for abundance change of each species,
|
||||
* which can be used for timestep control or diagnostics.
|
||||
*/
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
fourdst::composition::Composition update(const NetIn &netIn) override;
|
||||
|
||||
bool isStale(const NetIn &netIn) override;
|
||||
|
||||
/**
|
||||
* @brief Checks if a given species is involved in the network.
|
||||
*
|
||||
* @param species The species to check.
|
||||
* @return True if the species is involved in the network, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool involvesSpecies(
|
||||
const fourdst::atomic::Species& species
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Exports the network to a DOT file for visualization.
|
||||
*
|
||||
* @param filename The name of the DOT file to create.
|
||||
*
|
||||
* This method generates a DOT file that can be used to visualize the
|
||||
* reaction network as a graph. The DOT file can be converted to a
|
||||
* graphical image using Graphviz.
|
||||
*
|
||||
* @throws std::runtime_error If the file cannot be opened for writing.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* engine.exportToDot("network.dot");
|
||||
* @endcode
|
||||
*/
|
||||
void exportToDot(
|
||||
const std::string& filename
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Exports the network to a CSV file for analysis.
|
||||
*
|
||||
* @param filename The name of the CSV file to create.
|
||||
*
|
||||
* This method generates a CSV file containing information about the
|
||||
* reactions in the network, including the reactants, products, Q-value,
|
||||
* and reaction rate coefficients.
|
||||
*
|
||||
* @throws std::runtime_error If the file cannot be opened for writing.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* engine.exportToCSV("network.csv");
|
||||
* @endcode
|
||||
*/
|
||||
void exportToCSV(
|
||||
const std::string& filename
|
||||
) const;
|
||||
|
||||
void setScreeningModel(screening::ScreeningType) override;
|
||||
|
||||
[[nodiscard]] screening::ScreeningType getScreeningModel() const override;
|
||||
|
||||
void setPrecomputation(bool precompute);
|
||||
|
||||
[[nodiscard]] bool isPrecomputationEnabled() const;
|
||||
|
||||
[[nodiscard]] const partition::PartitionFunction& getPartitionFunction() const;
|
||||
|
||||
[[nodiscard]] double calculateReverseRate(
|
||||
const reaction::Reaction &reaction,
|
||||
double T9
|
||||
) const;
|
||||
|
||||
[[nodiscard]] double calculateReverseRateTwoBody(
|
||||
const reaction::Reaction &reaction,
|
||||
const double T9,
|
||||
const double forwardRate,
|
||||
const double expFactor
|
||||
) const;
|
||||
|
||||
[[nodiscard]] double calculateReverseRateTwoBodyDerivative(
|
||||
const reaction::Reaction &reaction,
|
||||
const double T9,
|
||||
const double reverseRate
|
||||
) const;
|
||||
|
||||
[[nodiscard]] bool isUsingReverseReactions() const;
|
||||
|
||||
void setUseReverseReactions(bool useReverse);
|
||||
|
||||
[[nodiscard]] int getSpeciesIndex(
|
||||
const fourdst::atomic::Species& species
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const override;
|
||||
|
||||
[[nodiscard]] PrimingReport primeEngine(const NetIn &netIn) override;
|
||||
|
||||
[[nodiscard]] BuildDepthType getDepth() const override;
|
||||
|
||||
void rebuild(const fourdst::composition::Composition& comp, const BuildDepthType depth) override;
|
||||
|
||||
|
||||
private:
|
||||
struct PrecomputedReaction {
|
||||
// Forward cacheing
|
||||
size_t reaction_index;
|
||||
std::vector<size_t> unique_reactant_indices;
|
||||
std::vector<int> reactant_powers;
|
||||
double symmetry_factor;
|
||||
std::vector<size_t> affected_species_indices;
|
||||
std::vector<int> stoichiometric_coefficients;
|
||||
|
||||
// Reverse cacheing
|
||||
std::vector<size_t> unique_product_indices; ///< Unique product indices for reverse reactions.
|
||||
std::vector<int> product_powers; ///< Powers of each unique product in the reverse reaction.
|
||||
double reverse_symmetry_factor; ///< Symmetry factor for reverse reactions.
|
||||
};
|
||||
|
||||
struct constants {
|
||||
const double u = Constants::getInstance().get("u").value; ///< Atomic mass unit in g.
|
||||
const double Na = Constants::getInstance().get("N_a").value; ///< Avogadro's number.
|
||||
const double c = Constants::getInstance().get("c").value; ///< Speed of light in cm/s.
|
||||
const double kB = Constants::getInstance().get("kB").value; ///< Boltzmann constant in erg/K.
|
||||
};
|
||||
private:
|
||||
class AtomicReverseRate final : public CppAD::atomic_base<double> {
|
||||
public:
|
||||
AtomicReverseRate(
|
||||
const reaction::Reaction& reaction,
|
||||
const GraphEngine& engine
|
||||
):
|
||||
atomic_base<double>("AtomicReverseRate"),
|
||||
m_reaction(reaction),
|
||||
m_engine(engine) {}
|
||||
|
||||
bool forward(
|
||||
size_t p,
|
||||
size_t q,
|
||||
const CppAD::vector<bool>& vx,
|
||||
CppAD::vector<bool>& vy,
|
||||
const CppAD::vector<double>& tx,
|
||||
CppAD::vector<double>& ty
|
||||
) override;
|
||||
bool reverse(
|
||||
size_t q,
|
||||
const CppAD::vector<double>& tx,
|
||||
const CppAD::vector<double>& ty,
|
||||
CppAD::vector<double>& px,
|
||||
const CppAD::vector<double>& py
|
||||
) override;
|
||||
bool for_sparse_jac(
|
||||
size_t q,
|
||||
const CppAD::vector<std::set<size_t>>&r,
|
||||
CppAD::vector<std::set<size_t>>& s
|
||||
) override;
|
||||
bool rev_sparse_jac(
|
||||
size_t q,
|
||||
const CppAD::vector<std::set<size_t>>&rt,
|
||||
CppAD::vector<std::set<size_t>>& st
|
||||
) override;
|
||||
|
||||
private:
|
||||
const reaction::Reaction& m_reaction;
|
||||
const GraphEngine& m_engine;
|
||||
};
|
||||
private:
|
||||
Config& m_config = Config::getInstance();
|
||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||
|
||||
constants m_constants;
|
||||
|
||||
reaction::LogicalReactionSet m_reactions; ///< Set of REACLIB reactions in the network.
|
||||
std::unordered_map<std::string_view, reaction::Reaction*> m_reactionIDMap; ///< Map from reaction ID to REACLIBReaction. //PERF: This makes copies of REACLIBReaction and could be a performance bottleneck.
|
||||
|
||||
std::vector<fourdst::atomic::Species> m_networkSpecies; ///< Vector of unique species in the network.
|
||||
std::unordered_map<std::string_view, fourdst::atomic::Species> m_networkSpeciesMap; ///< Map from species name to Species object.
|
||||
std::unordered_map<fourdst::atomic::Species, size_t> m_speciesToIndexMap; ///< Map from species to their index in the stoichiometry matrix.
|
||||
|
||||
boost::numeric::ublas::compressed_matrix<int> m_stoichiometryMatrix; ///< Stoichiometry matrix (species x reactions).
|
||||
|
||||
mutable boost::numeric::ublas::compressed_matrix<double> m_jacobianMatrix; ///< Jacobian matrix (species x species).
|
||||
mutable CppAD::ADFun<double> m_rhsADFun; ///< CppAD function for the right-hand side of the ODE.
|
||||
mutable CppAD::sparse_jac_work m_jac_work; ///< Work object for sparse Jacobian calculations.
|
||||
CppAD::sparse_rc<std::vector<size_t>> m_full_jacobian_sparsity_pattern; ///< Full sparsity pattern for the Jacobian matrix.
|
||||
|
||||
std::vector<std::unique_ptr<AtomicReverseRate>> m_atomicReverseRates;
|
||||
|
||||
screening::ScreeningType m_screeningType = screening::ScreeningType::BARE; ///< Screening type for the reaction network. Default to no screening.
|
||||
std::unique_ptr<screening::ScreeningModel> m_screeningModel = screening::selectScreeningModel(m_screeningType);
|
||||
|
||||
bool m_usePrecomputation = true; ///< Flag to enable or disable using precomputed reactions for efficiency. Mathematically, this should not change the results. Generally end users should not need to change this.
|
||||
|
||||
bool m_useReverseReactions = true; ///< Flag to enable or disable reverse reactions. If false, only forward reactions are considered.
|
||||
|
||||
BuildDepthType m_depth;
|
||||
|
||||
std::vector<PrecomputedReaction> m_precomputedReactions; ///< Precomputed reactions for efficiency.
|
||||
std::unique_ptr<partition::PartitionFunction> m_partitionFunction; ///< Partition function for the network.
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Synchronizes the internal maps.
|
||||
*
|
||||
* This method synchronizes the internal maps used by the engine,
|
||||
* including the species map, reaction ID map, and species-to-index map.
|
||||
* It also generates the stoichiometry matrix and records the AD tape.
|
||||
*/
|
||||
void syncInternalMaps();
|
||||
|
||||
/**
|
||||
* @brief Collects the unique species in the network.
|
||||
*
|
||||
* This method collects the unique species in the network from the
|
||||
* reactants and products of all reactions.
|
||||
*/
|
||||
void collectNetworkSpecies();
|
||||
|
||||
/**
|
||||
* @brief Populates the reaction ID map.
|
||||
*
|
||||
* This method populates the reaction ID map, which maps reaction IDs
|
||||
* to REACLIBReaction objects.
|
||||
*/
|
||||
void populateReactionIDMap();
|
||||
|
||||
/**
|
||||
* @brief Populates the species-to-index map.
|
||||
*
|
||||
* This method populates the species-to-index map, which maps species
|
||||
* to their index in the stoichiometry matrix.
|
||||
*/
|
||||
void populateSpeciesToIndexMap();
|
||||
|
||||
/**
|
||||
* @brief Reserves space for the Jacobian matrix.
|
||||
*
|
||||
* This method reserves space for the Jacobian matrix, which is used
|
||||
* to store the partial derivatives of the right-hand side of the ODE
|
||||
* with respect to the species abundances.
|
||||
*/
|
||||
void reserveJacobianMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief Records the AD tape for the right-hand side of the ODE.
|
||||
*
|
||||
* This method records the AD tape for the right-hand side of the ODE,
|
||||
* which is used to calculate the Jacobian matrix using automatic
|
||||
* differentiation.
|
||||
*
|
||||
* @throws std::runtime_error If there are no species in the network.
|
||||
*/
|
||||
void recordADTape();
|
||||
|
||||
void collectAtomicReverseRateAtomicBases();
|
||||
|
||||
void precomputeNetwork();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Validates mass and charge conservation across all reactions.
|
||||
*
|
||||
* @return True if all reactions conserve mass and charge, false otherwise.
|
||||
*
|
||||
* This method checks that all reactions in the network conserve mass
|
||||
* and charge. If any reaction does not conserve mass or charge, an
|
||||
* error message is logged and false is returned.
|
||||
*/
|
||||
[[nodiscard]] bool validateConservation() const;
|
||||
|
||||
/**
|
||||
* @brief Validates the composition against the current reaction set.
|
||||
*
|
||||
* @param composition The composition to validate.
|
||||
* @param culling The culling threshold to use.
|
||||
* @param T9 The temperature to use.
|
||||
*
|
||||
* This method validates the composition against the current reaction set.
|
||||
* If the composition is not compatible with the reaction set, the
|
||||
* reaction set is rebuilt from the composition.
|
||||
*/
|
||||
void validateComposition(
|
||||
const fourdst::composition::Composition &composition,
|
||||
double culling,
|
||||
double T9
|
||||
);
|
||||
|
||||
|
||||
|
||||
[[nodiscard]] StepDerivatives<double> calculateAllDerivativesUsingPrecomputation(
|
||||
const std::vector<double> &Y_in,
|
||||
const std::vector<double>& bare_rates,
|
||||
const std::vector<double> &bare_reverse_rates,
|
||||
double T9, double rho
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates the molar reaction flow for a given reaction.
|
||||
*
|
||||
* @tparam T The numeric type to use for the calculation.
|
||||
* @param reaction The reaction for which to calculate the flow.
|
||||
* @param Y Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||
*
|
||||
* This method computes the net rate at which the given reaction proceeds
|
||||
* under the current state.
|
||||
*/
|
||||
template <IsArithmeticOrAD T>
|
||||
T calculateMolarReactionFlow(
|
||||
const reaction::Reaction &reaction,
|
||||
const std::vector<T> &Y,
|
||||
const T T9,
|
||||
const T rho
|
||||
) const;
|
||||
|
||||
template<IsArithmeticOrAD T>
|
||||
T calculateReverseMolarReactionFlow(
|
||||
T T9,
|
||||
T rho,
|
||||
std::vector<T> screeningFactors,
|
||||
std::vector<T> Y,
|
||||
size_t reactionIndex,
|
||||
const reaction::LogicalReaction &reaction
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates all derivatives (dY/dt) and the energy generation rate.
|
||||
*
|
||||
* @tparam T The numeric type to use for the calculation.
|
||||
* @param Y_in Vector of current abundances for all species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return StepDerivatives<T> containing dY/dt and energy generation rate.
|
||||
*
|
||||
* This method calculates the time derivatives of all species and the
|
||||
* specific nuclear energy generation rate for the current state.
|
||||
*/
|
||||
template<IsArithmeticOrAD T>
|
||||
[[nodiscard]] StepDerivatives<T> calculateAllDerivatives(
|
||||
const std::vector<T> &Y_in,
|
||||
T T9,
|
||||
T rho
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates all derivatives (dY/dt) and the energy generation rate (double precision).
|
||||
*
|
||||
* @param Y_in Vector of current abundances for all species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return StepDerivatives<double> containing dY/dt and energy generation rate.
|
||||
*
|
||||
* This method calculates the time derivatives of all species and the
|
||||
* specific nuclear energy generation rate for the current state using
|
||||
* double precision arithmetic.
|
||||
*/
|
||||
[[nodiscard]] StepDerivatives<double> calculateAllDerivatives(
|
||||
const std::vector<double>& Y_in,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates all derivatives (dY/dt) and the energy generation rate (automatic differentiation).
|
||||
*
|
||||
* @param Y_in Vector of current abundances for all species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return StepDerivatives<ADDouble> containing dY/dt and energy generation rate.
|
||||
*
|
||||
* This method calculates the time derivatives of all species and the
|
||||
* specific nuclear energy generation rate for the current state using
|
||||
* automatic differentiation.
|
||||
*/
|
||||
[[nodiscard]] StepDerivatives<ADDouble> calculateAllDerivatives(
|
||||
const std::vector<ADDouble>& Y_in,
|
||||
const ADDouble &T9,
|
||||
const ADDouble &rho
|
||||
) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <IsArithmeticOrAD T>
|
||||
T GraphEngine::calculateReverseMolarReactionFlow(
|
||||
T T9,
|
||||
T rho,
|
||||
std::vector<T> screeningFactors,
|
||||
std::vector<T> Y,
|
||||
size_t reactionIndex,
|
||||
const reaction::LogicalReaction &reaction
|
||||
) const {
|
||||
if (!m_useReverseReactions) {
|
||||
return static_cast<T>(0.0); // If reverse reactions are not used, return zero
|
||||
}
|
||||
s_debug = false;
|
||||
if (reaction.peName() == "p(p,e+)d" || reaction.peName() =="d(d,n)he3" || reaction.peName() == "c12(p,g)n13") {
|
||||
if constexpr (!std::is_same_v<T, ADDouble>) {
|
||||
s_debug = true;
|
||||
std::cout << "Calculating reverse molar flow for reaction: " << reaction.peName() << std::endl;
|
||||
std::cout << "\tT9: " << T9 << ", rho: " << rho << std::endl;
|
||||
}
|
||||
}
|
||||
T reverseMolarFlow = static_cast<T>(0.0);
|
||||
|
||||
if (reaction.qValue() != 0.0) {
|
||||
T reverseRateConstant = static_cast<T>(0.0);
|
||||
if constexpr (std::is_same_v<T, ADDouble>) { // Check if T is an AD type at compile time
|
||||
const auto& atomic_func_ptr = m_atomicReverseRates[reactionIndex];
|
||||
if (atomic_func_ptr != nullptr) {
|
||||
// A. Instantiate the atomic operator for the specific reaction
|
||||
// B. Marshal the input vector
|
||||
std::vector<T> ax = { T9 };
|
||||
|
||||
std::vector<T> ay(1);
|
||||
(*atomic_func_ptr)(ax, ay);
|
||||
reverseRateConstant = static_cast<T>(ay[0]);
|
||||
} else {
|
||||
return reverseMolarFlow; // If no atomic function is available, return zero
|
||||
}
|
||||
} else {
|
||||
// A,B If not calling with an AD type, calculate the reverse rate directly
|
||||
if (s_debug) {
|
||||
std::cout << "\tUsing double overload\n";
|
||||
}
|
||||
reverseRateConstant = calculateReverseRate(reaction, T9);
|
||||
}
|
||||
|
||||
// C. Get product multiplicities
|
||||
std::unordered_map<fourdst::atomic::Species, int> productCounts;
|
||||
for (const auto& product : reaction.products()) {
|
||||
productCounts[product]++;
|
||||
}
|
||||
|
||||
// D. Calculate the symmetry factor
|
||||
T reverseSymmetryFactor = static_cast<T>(1.0);
|
||||
for (const auto &count: productCounts | std::views::values) {
|
||||
reverseSymmetryFactor /= static_cast<T>(std::tgamma(static_cast<double>(count + 1))); // Gamma function for factorial
|
||||
}
|
||||
|
||||
// E. Calculate the abundance term
|
||||
T productAbundanceTerm = static_cast<T>(1.0);
|
||||
for (const auto& [species, count] : productCounts) {
|
||||
const unsigned long speciesIndex = m_speciesToIndexMap.at(species);
|
||||
productAbundanceTerm *= CppAD::pow(Y[speciesIndex], count);
|
||||
}
|
||||
|
||||
// F. Determine the power for the density term
|
||||
const size_t num_products = reaction.products().size();
|
||||
const T rho_power = CppAD::pow(rho, static_cast<T>(num_products > 1 ? num_products - 1 : 0)); // Density raised to the power of (N-1) for N products
|
||||
|
||||
// G. Assemble the reverse molar flow rate
|
||||
reverseMolarFlow = screeningFactors[reactionIndex] *
|
||||
reverseRateConstant *
|
||||
productAbundanceTerm *
|
||||
reverseSymmetryFactor *
|
||||
rho_power;
|
||||
}
|
||||
return reverseMolarFlow;
|
||||
}
|
||||
|
||||
template<IsArithmeticOrAD T>
|
||||
StepDerivatives<T> GraphEngine::calculateAllDerivatives(
|
||||
const std::vector<T> &Y_in, T T9, T rho) const {
|
||||
std::vector<T> screeningFactors = m_screeningModel->calculateScreeningFactors(
|
||||
m_reactions,
|
||||
m_networkSpecies,
|
||||
Y_in,
|
||||
T9,
|
||||
rho
|
||||
);
|
||||
|
||||
// --- Setup output derivatives structure ---
|
||||
StepDerivatives<T> result;
|
||||
result.dydt.resize(m_networkSpecies.size(), static_cast<T>(0.0));
|
||||
|
||||
// --- AD Pre-setup (flags to control conditionals in an AD safe / branch aware manner) ---
|
||||
// ----- Constants for AD safe calculations ---
|
||||
const T zero = static_cast<T>(0.0);
|
||||
const T one = static_cast<T>(1.0);
|
||||
|
||||
// ----- Initialize variables for molar concentration product and thresholds ---
|
||||
// Note: the logic here is that we use CppAD::CondExprLt to test thresholds and if they are less we set the flag
|
||||
// to zero so that the final returned reaction flow is 0. This is as opposed to standard if statements
|
||||
// which create branches that break the AD tape.
|
||||
const T rho_threshold = static_cast<T>(MIN_DENSITY_THRESHOLD);
|
||||
|
||||
// --- Check if the density is below the threshold where we ignore reactions ---
|
||||
T threshold_flag = CppAD::CondExpLt(rho, rho_threshold, zero, one); // If rho < threshold, set flag to 0
|
||||
|
||||
std::vector<T> Y = Y_in;
|
||||
for (size_t i = 0; i < m_networkSpecies.size(); ++i) {
|
||||
// We use CppAD::CondExpLt to handle AD taping and prevent branching
|
||||
// Note that while this is syntactically more complex this is equivalent to
|
||||
// if (Y[i] < 0) {Y[i] = 0;}
|
||||
// The issue is that this would introduce a branch which would require the auto diff tape to be re-recorded
|
||||
// each timestep, which is very inefficient.
|
||||
Y[i] = CppAD::CondExpLt(Y[i], zero, zero, Y[i]); // Ensure no negative abundances
|
||||
}
|
||||
|
||||
const T u = static_cast<T>(m_constants.u); // Atomic mass unit in grams
|
||||
const T N_A = static_cast<T>(m_constants.Na); // Avogadro's number in mol^-1
|
||||
const T c = static_cast<T>(m_constants.c); // Speed of light in cm/s
|
||||
|
||||
// --- SINGLE LOOP OVER ALL REACTIONS ---
|
||||
for (size_t reactionIndex = 0; reactionIndex < m_reactions.size(); ++reactionIndex) {
|
||||
const auto& reaction = m_reactions[reactionIndex];
|
||||
|
||||
// 1. Calculate forward reaction rate
|
||||
const T forwardMolarReactionFlow = screeningFactors[reactionIndex] *
|
||||
calculateMolarReactionFlow<T>(reaction, Y, T9, rho);
|
||||
|
||||
// 2. Calculate reverse reaction rate
|
||||
T reverseMolarFlow = calculateReverseMolarReactionFlow<T>(
|
||||
T9,
|
||||
rho,
|
||||
screeningFactors,
|
||||
Y,
|
||||
reactionIndex,
|
||||
reaction
|
||||
);
|
||||
|
||||
const T molarReactionFlow = forwardMolarReactionFlow - reverseMolarFlow; // Net molar reaction flow
|
||||
|
||||
// 3. Use the rate to update all relevant species derivatives (dY/dt)
|
||||
for (size_t speciesIndex = 0; speciesIndex < m_networkSpecies.size(); ++speciesIndex) {
|
||||
const T nu_ij = static_cast<T>(m_stoichiometryMatrix(speciesIndex, reactionIndex));
|
||||
result.dydt[speciesIndex] += threshold_flag * nu_ij * molarReactionFlow;
|
||||
}
|
||||
}
|
||||
|
||||
T massProductionRate = static_cast<T>(0.0); // [mol][s^-1]
|
||||
for (const auto& [species, index] : m_speciesToIndexMap) {
|
||||
massProductionRate += result.dydt[index] * species.mass() * u;
|
||||
}
|
||||
|
||||
result.nuclearEnergyGenerationRate = -massProductionRate * N_A * c * c; // [cm^2][s^-3] = [erg][s^-1][g^-1]
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <IsArithmeticOrAD T>
|
||||
T GraphEngine::calculateMolarReactionFlow(
|
||||
const reaction::Reaction &reaction,
|
||||
const std::vector<T> &Y,
|
||||
const T T9,
|
||||
const T rho
|
||||
) const {
|
||||
|
||||
// --- Pre-setup (flags to control conditionals in an AD safe / branch aware manner) ---
|
||||
// ----- Constants for AD safe calculations ---
|
||||
const T zero = static_cast<T>(0.0);
|
||||
const T one = static_cast<T>(1.0);
|
||||
|
||||
// ----- Initialize variables for molar concentration product and thresholds ---
|
||||
// Note: the logic here is that we use CppAD::CondExprLt to test thresholds and if they are less we set the flag
|
||||
// to zero so that the final returned reaction flow is 0. This is as opposed to standard if statements
|
||||
// which create branches that break the AD tape.
|
||||
const T Y_threshold = static_cast<T>(MIN_ABUNDANCE_THRESHOLD);
|
||||
T threshold_flag = one;
|
||||
|
||||
// --- Calculate the molar reaction rate (in units of [s^-1][cm^3(N-1)][mol^(1-N)] for N reactants) ---
|
||||
const T k_reaction = reaction.calculate_rate(T9);
|
||||
|
||||
// --- Cound the number of each reactant species to account for species multiplicity ---
|
||||
std::unordered_map<std::string, int> reactant_counts;
|
||||
reactant_counts.reserve(reaction.reactants().size());
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
reactant_counts[std::string(reactant.name())]++;
|
||||
}
|
||||
const int totalReactants = static_cast<int>(reaction.reactants().size());
|
||||
|
||||
// --- Accumulator for the molar concentration ---
|
||||
auto molar_concentration_product = static_cast<T>(1.0);
|
||||
|
||||
// --- Loop through each unique reactant species and calculate the molar concentration for that species then multiply that into the accumulator ---
|
||||
for (const auto& [species_name, count] : reactant_counts) {
|
||||
// --- Resolve species to molar abundance ---
|
||||
// PERF: Could probably optimize out this lookup
|
||||
const auto species_it = m_speciesToIndexMap.find(m_networkSpeciesMap.at(species_name));
|
||||
const size_t species_index = species_it->second;
|
||||
const T Yi = Y[species_index];
|
||||
|
||||
// --- Check if the species abundance is below the threshold where we ignore reactions ---
|
||||
// threshold_flag *= CppAD::CondExpLt(Yi, Y_threshold, zero, one);
|
||||
|
||||
// --- If count is > 1 , we need to raise the molar concentration to the power of count since there are really count bodies in that reaction ---
|
||||
molar_concentration_product *= CppAD::pow(Yi, static_cast<T>(count)); // ni^count
|
||||
|
||||
// --- Apply factorial correction for identical reactions ---
|
||||
if (count > 1) {
|
||||
molar_concentration_product /= static_cast<T>(std::tgamma(static_cast<double>(count + 1))); // Gamma function for factorial
|
||||
}
|
||||
}
|
||||
// --- Final reaction flow calculation [mol][s^-1][g^-1] ---
|
||||
// Note: If the threshold flag ever gets set to zero this will return zero.
|
||||
// This will result basically in multiple branches being written to the AD tape, which will make
|
||||
// the tape more expensive to record, but it will also mean that we only need to record it once for
|
||||
// the entire network.
|
||||
const T densityTerm = CppAD::pow(rho, totalReactants > 1 ? static_cast<T>(totalReactants - 1) : zero); // Density raised to the power of (N-1) for N reactants
|
||||
return molar_concentration_product * k_reaction * threshold_flag * densityTerm;
|
||||
}
|
||||
|
||||
};
|
||||
17
src/include/gridfire/engine/procedures/construction.h
Normal file
17
src/include/gridfire/engine/procedures/construction.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/reaction/reaction.h"
|
||||
#include "gridfire/engine/types/building.h"
|
||||
|
||||
#include "fourdst/composition/composition.h"
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace gridfire {
|
||||
|
||||
reaction::LogicalReactionSet build_reaclib_nuclear_network(
|
||||
const fourdst::composition::Composition &composition,
|
||||
BuildDepthType maxLayers = NetworkBuildDepth::Full,
|
||||
bool reverse = false
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/procedures/construction.h"
|
||||
#include "gridfire/engine/procedures/priming.h"
|
||||
37
src/include/gridfire/engine/procedures/priming.h
Normal file
37
src/include/gridfire/engine/procedures/priming.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/network.h"
|
||||
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace gridfire {
|
||||
|
||||
|
||||
PrimingReport primeNetwork(
|
||||
const NetIn&,
|
||||
DynamicEngine& engine
|
||||
);
|
||||
|
||||
double calculateDestructionRateConstant(
|
||||
const DynamicEngine& engine,
|
||||
const fourdst::atomic::Species& species,
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
|
||||
double calculateCreationRate(
|
||||
const DynamicEngine& engine,
|
||||
const fourdst::atomic::Species& species,
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
}
|
||||
16
src/include/gridfire/engine/types/building.h
Normal file
16
src/include/gridfire/engine/types/building.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace gridfire {
|
||||
enum class NetworkBuildDepth {
|
||||
Full = -1,
|
||||
Shallow = 1,
|
||||
SecondOrder = 2,
|
||||
ThirdOrder = 3,
|
||||
FourthOrder = 4,
|
||||
FifthOrder = 5
|
||||
};
|
||||
|
||||
using BuildDepthType = std::variant<NetworkBuildDepth, int>;
|
||||
}
|
||||
4
src/include/gridfire/engine/types/engine_types.h
Normal file
4
src/include/gridfire/engine/types/engine_types.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/types/building.h"
|
||||
#include "gridfire/engine/types/reporting.h"
|
||||
42
src/include/gridfire/engine/types/reporting.h
Normal file
42
src/include/gridfire/engine/types/reporting.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <ranges>
|
||||
|
||||
namespace gridfire {
|
||||
enum class PrimingReportStatus {
|
||||
FULL_SUCCESS = 0,
|
||||
NO_SPECIES_TO_PRIME = 1,
|
||||
MAX_ITERATIONS_REACHED = 2,
|
||||
FAILED_TO_FINALIZE_COMPOSITION = 3,
|
||||
FAILED_TO_FIND_CREATION_CHANNEL = 4,
|
||||
FAILED_TO_FIND_PRIMING_REACTIONS = 5,
|
||||
BASE_NETWORK_TOO_SHALLOW = 6
|
||||
};
|
||||
|
||||
inline std::map<PrimingReportStatus, std::string> PrimingReportStatusStrings = {
|
||||
{PrimingReportStatus::FULL_SUCCESS, "Full Success"},
|
||||
{PrimingReportStatus::NO_SPECIES_TO_PRIME, "No Species to Prime"},
|
||||
{PrimingReportStatus::MAX_ITERATIONS_REACHED, "Max Iterations Reached"},
|
||||
{PrimingReportStatus::FAILED_TO_FINALIZE_COMPOSITION, "Failed to Finalize Composition"},
|
||||
{PrimingReportStatus::FAILED_TO_FIND_CREATION_CHANNEL, "Failed to Find Creation Channel"},
|
||||
{PrimingReportStatus::FAILED_TO_FIND_PRIMING_REACTIONS, "Failed to Find Priming Reactions"},
|
||||
{PrimingReportStatus::BASE_NETWORK_TOO_SHALLOW, "Base Network Too Shallow"}
|
||||
};
|
||||
|
||||
struct PrimingReport {
|
||||
fourdst::composition::Composition primedComposition;
|
||||
std::vector<std::pair<fourdst::atomic::Species, double>> massFractionChanges; ///< Species and their destruction/creation rates
|
||||
bool success;
|
||||
PrimingReportStatus status;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const PrimingReport& report) {
|
||||
std::stringstream ss;
|
||||
const std::string successStr = report.success ? "true" : "false";
|
||||
ss << "PrimingReport(success=" << successStr
|
||||
<< ", status=" << PrimingReportStatusStrings[report.status] << ")";
|
||||
return os << ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
479
src/include/gridfire/engine/views/engine_adaptive.h
Normal file
479
src/include/gridfire/engine/views/engine_adaptive.h
Normal file
@@ -0,0 +1,479 @@
|
||||
#pragma once
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/engine/views/engine_view_abstract.h"
|
||||
#include "gridfire/screening/screening_abstract.h"
|
||||
#include "gridfire/screening/screening_types.h"
|
||||
#include "gridfire/network.h"
|
||||
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/config/config.h"
|
||||
#include "fourdst/logging/logging.h"
|
||||
|
||||
#include "gridfire/engine/procedures/priming.h"
|
||||
#include "gridfire/engine/procedures/construction.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
|
||||
namespace gridfire {
|
||||
/**
|
||||
* @class AdaptiveEngineView
|
||||
* @brief An engine view that dynamically adapts the reaction network based on runtime conditions.
|
||||
*
|
||||
* This class implements an EngineView that dynamically culls species and reactions from the
|
||||
* full reaction network based on their reaction flow rates and connectivity. This allows for
|
||||
* efficient simulation of reaction networks by focusing computational effort on the most
|
||||
* important species and reactions.
|
||||
*
|
||||
* The AdaptiveEngineView maintains a subset of "active" species and reactions, and maps
|
||||
* between the full network indices and the active subset indices. This allows the base engine
|
||||
* to operate on the full network data, while the AdaptiveEngineView provides a reduced view
|
||||
* for external clients.
|
||||
*
|
||||
* The adaptation process is driven by the `update()` method, which performs the following steps:
|
||||
* 1. **Reaction Flow Calculation:** Calculates the molar reaction flow rate for each reaction
|
||||
* in the full network based on the current temperature, density, and composition.
|
||||
* 2. **Reaction Culling:** Culls reactions with flow rates below a threshold, determined by
|
||||
* a relative culling threshold multiplied by the maximum flow rate.
|
||||
* 3. **Connectivity Analysis:** Performs a connectivity analysis to identify species that are
|
||||
* reachable from the initial fuel species through the culled reaction network.
|
||||
* 4. **Species Culling:** Culls species that are not reachable from the initial fuel.
|
||||
* 5. **Index Map Construction:** Constructs index maps to map between the full network indices
|
||||
* and the active subset indices for species and reactions.
|
||||
*
|
||||
* @implements DynamicEngine
|
||||
* @implements EngineView<DynamicEngine>
|
||||
*
|
||||
* @see engine_abstract.h
|
||||
* @see engine_view_abstract.h
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
class AdaptiveEngineView final : public DynamicEngine, public EngineView<DynamicEngine> {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs an AdaptiveEngineView.
|
||||
*
|
||||
* @param baseEngine The underlying DynamicEngine to which this view delegates calculations.
|
||||
*
|
||||
* Initializes the active species and reactions to the full network, and constructs the
|
||||
* initial index maps.
|
||||
*/
|
||||
explicit AdaptiveEngineView(DynamicEngine& baseEngine);
|
||||
|
||||
/**
|
||||
* @brief Updates the active species and reactions based on the current conditions.
|
||||
*
|
||||
* @param netIn The current network input, containing temperature, density, and composition.
|
||||
*
|
||||
* This method performs the reaction flow calculation, reaction culling, connectivity analysis,
|
||||
* and index map construction steps described above.
|
||||
*
|
||||
* The culling thresholds are read from the configuration using the following keys:
|
||||
* - `gridfire:AdaptiveEngineView:RelativeCullingThreshold` (default: 1e-75)
|
||||
*
|
||||
* @throws std::runtime_error If there is a mismatch between the active reactions and the base engine.
|
||||
* @post The active species and reactions are updated, and the index maps are reconstructed.
|
||||
* @see AdaptiveEngineView
|
||||
* @see AdaptiveEngineView::constructSpeciesIndexMap()
|
||||
* @see AdaptiveEngineView::constructReactionIndexMap()
|
||||
*/
|
||||
fourdst::composition::Composition update(const NetIn &netIn) override;
|
||||
|
||||
bool isStale(const NetIn& netIn) override;
|
||||
|
||||
/**
|
||||
* @brief Gets the list of active species in the network.
|
||||
* @return A const reference to the vector of active species.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& getNetworkSpecies() const override;
|
||||
|
||||
/**
|
||||
* @brief Calculates the right-hand side (dY/dt) and energy generation for the active species.
|
||||
*
|
||||
* @param Y_culled A vector of abundances for the active species.
|
||||
* @param T9 The temperature in units of 10^9 K.
|
||||
* @param rho The density in g/cm^3.
|
||||
* @return A StepDerivatives struct containing the derivatives of the active species and the
|
||||
* nuclear energy generation rate.
|
||||
*
|
||||
* This method maps the culled abundances to the full network abundances, calls the base engine
|
||||
* to calculate the RHS and energy generation, and then maps the full network derivatives back
|
||||
* to the culled derivatives.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||
const std::vector<double> &Y_culled,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the active species.
|
||||
*
|
||||
* @param Y_dynamic A vector of abundances for the active species.
|
||||
* @param T9 The temperature in units of 10^9 K.
|
||||
* @param rho The density in g/cm^3.
|
||||
*
|
||||
* This method maps the culled abundances to the full network abundances and calls the base engine
|
||||
* to generate the Jacobian matrix.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
void generateJacobianMatrix(
|
||||
const std::vector<double> &Y_dynamic,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets an entry from the Jacobian matrix for the active species.
|
||||
*
|
||||
* @param i_culled The row index (species index) in the culled matrix.
|
||||
* @param j_culled The column index (species index) in the culled matrix.
|
||||
* @return The value of the Jacobian matrix at (i_culled, j_culled).
|
||||
*
|
||||
* This method maps the culled indices to the full network indices and calls the base engine
|
||||
* to get the Jacobian matrix entry.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
* @throws std::out_of_range If the culled index is out of bounds for the species index map.
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
[[nodiscard]] double getJacobianMatrixEntry(
|
||||
const int i_culled,
|
||||
const int j_culled
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the stoichiometry matrix for the active reactions and species.
|
||||
*
|
||||
* This method calls the base engine to generate the stoichiometry matrix.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
* @note The stoichiometry matrix generated by the base engine is assumed to be consistent with
|
||||
* the active species and reactions in this view.
|
||||
*/
|
||||
void generateStoichiometryMatrix() override;
|
||||
|
||||
/**
|
||||
* @brief Gets an entry from the stoichiometry matrix for the active species and reactions.
|
||||
*
|
||||
* @param speciesIndex_culled The index of the species in the culled species list.
|
||||
* @param reactionIndex_culled The index of the reaction in the culled reaction list.
|
||||
* @return The stoichiometric coefficient for the given species and reaction.
|
||||
*
|
||||
* This method maps the culled indices to the full network indices and calls the base engine
|
||||
* to get the stoichiometry matrix entry.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
* @throws std::out_of_range If the culled index is out of bounds for the species or reaction index map.
|
||||
* @see AdaptiveEngineView::update()
|
||||
*/
|
||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||
const int speciesIndex_culled,
|
||||
const int reactionIndex_culled
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Calculates the molar reaction flow for a given reaction in the active network.
|
||||
*
|
||||
* @param reaction The reaction for which to calculate the flow.
|
||||
* @param Y_culled Vector of current abundances for the active species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||
*
|
||||
* This method maps the culled abundances to the full network abundances and calls the base engine
|
||||
* to calculate the molar reaction flow.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
* @throws std::runtime_error If the reaction is not part of the active reactions in the adaptive engine view.
|
||||
*/
|
||||
[[nodiscard]] double calculateMolarReactionFlow(
|
||||
const reaction::Reaction &reaction,
|
||||
const std::vector<double> &Y_culled,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the set of active logical reactions in the network.
|
||||
*
|
||||
* @return Reference to the LogicalReactionSet containing all active reactions.
|
||||
*/
|
||||
[[nodiscard]] const reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(const reaction::LogicalReactionSet& reactions) override;
|
||||
|
||||
/**
|
||||
* @brief Computes timescales for all active species in the network.
|
||||
*
|
||||
* @param Y_culled Vector of current abundances for the active species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Map from Species to their characteristic timescales (s).
|
||||
*
|
||||
* This method maps the culled abundances to the full network abundances and calls the base engine
|
||||
* to compute the species timescales.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
*/
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||
const std::vector<double> &Y_culled,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the base engine.
|
||||
* @return A const reference to the base engine.
|
||||
*/
|
||||
[[nodiscard]] const DynamicEngine& getBaseEngine() const override { return m_baseEngine; }
|
||||
|
||||
/**
|
||||
* @brief Sets the screening model for the base engine.
|
||||
*
|
||||
* This method delegates the call to the base engine to set the electron screening model.
|
||||
*
|
||||
* @param model The electron screening model to set.
|
||||
*
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* AdaptiveEngineView engineView(...);
|
||||
* engineView.setScreeningModel(screening::ScreeningType::WEAK);
|
||||
* @endcode
|
||||
*
|
||||
* @post The screening model of the base engine is updated.
|
||||
*/
|
||||
void setScreeningModel(screening::ScreeningType model) override;
|
||||
|
||||
/**
|
||||
* @brief Gets the screening model from the base engine.
|
||||
*
|
||||
* This method delegates the call to the base engine to get the screening model.
|
||||
*
|
||||
* @return The current screening model type.
|
||||
*
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* AdaptiveEngineView engineView(...);
|
||||
* screening::ScreeningType model = engineView.getScreeningModel();
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] screening::ScreeningType getScreeningModel() const override;
|
||||
|
||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
[[nodiscard]] std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const override;
|
||||
|
||||
[[nodiscard]] PrimingReport primeEngine(const NetIn &netIn) override;
|
||||
private:
|
||||
using Config = fourdst::config::Config;
|
||||
using LogManager = fourdst::logging::LogManager;
|
||||
/** @brief A reference to the singleton Config instance, used for retrieving configuration parameters. */
|
||||
Config& m_config = Config::getInstance();
|
||||
/** @brief A pointer to the logger instance, used for logging messages. */
|
||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||
|
||||
/** @brief The underlying engine to which this view delegates calculations. */
|
||||
DynamicEngine& m_baseEngine;
|
||||
|
||||
/** @brief The set of species that are currently active in the network. */
|
||||
std::vector<fourdst::atomic::Species> m_activeSpecies;
|
||||
/** @brief The set of reactions that are currently active in the network. */
|
||||
reaction::LogicalReactionSet m_activeReactions;
|
||||
|
||||
/** @brief A map from the indices of the active species to the indices of the corresponding species in the full network. */
|
||||
std::vector<size_t> m_speciesIndexMap;
|
||||
/** @brief A map from the indices of the active reactions to the indices of the corresponding reactions in the full network. */
|
||||
std::vector<size_t> m_reactionIndexMap;
|
||||
|
||||
/** @brief A flag indicating whether the view is stale and needs to be updated. */
|
||||
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.
|
||||
*
|
||||
* @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()
|
||||
*/
|
||||
[[nodiscard]] 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()
|
||||
*/
|
||||
[[nodiscard]] 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.
|
||||
*/
|
||||
[[nodiscard]] 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.
|
||||
*/
|
||||
[[nodiscard]] 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.
|
||||
*/
|
||||
[[nodiscard]] 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.
|
||||
*/
|
||||
[[nodiscard]] size_t mapCulledToFullReactionIndex(size_t culledReactionIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Validates that the AdaptiveEngineView is not stale.
|
||||
*
|
||||
* @throws std::runtime_error If the AdaptiveEngineView is stale (i.e., `update()` has not been called).
|
||||
*/
|
||||
void validateState() const;
|
||||
|
||||
/**
|
||||
* @brief Calculates the molar reaction flow rate for all reactions in the full network.
|
||||
*
|
||||
* This method iterates through all reactions in the base engine's network and calculates
|
||||
* their molar flow rates based on the provided network input conditions (temperature, density,
|
||||
* and composition). It also constructs a vector of molar abundances for all species in the
|
||||
* full network.
|
||||
*
|
||||
* @param netIn The current network input, containing temperature, density, and composition.
|
||||
* @param out_Y_Full A vector that will be populated with the molar abundances of all species in the full network.
|
||||
* @return A vector of ReactionFlow structs, each containing a pointer to a reaction and its calculated flow rate.
|
||||
*
|
||||
* @par Algorithm:
|
||||
* 1. Clears and reserves space in `out_Y_Full`.
|
||||
* 2. Iterates through all species in the base engine's network.
|
||||
* 3. For each species, it retrieves the molar abundance from `netIn.composition`. If the species is not found, its abundance is set to 0.0.
|
||||
* 4. Converts the temperature from Kelvin to T9.
|
||||
* 5. Iterates through all reactions in the base engine's network.
|
||||
* 6. For each reaction, it calls the base engine's `calculateMolarReactionFlow` to get the flow rate.
|
||||
* 7. Stores the reaction pointer and its flow rate in a `ReactionFlow` struct and adds it to the returned vector.
|
||||
*/
|
||||
std::vector<ReactionFlow> calculateAllReactionFlows(
|
||||
const NetIn& netIn,
|
||||
std::vector<double>& out_Y_Full
|
||||
) const;
|
||||
/**
|
||||
* @brief Finds all species that are reachable from the initial fuel through the reaction network.
|
||||
*
|
||||
* This method performs a connectivity analysis to identify all species that can be produced
|
||||
* starting from the initial fuel species. A species is considered part of the initial fuel if its
|
||||
* mass fraction is above a certain threshold (`ABUNDANCE_FLOOR`).
|
||||
*
|
||||
* @param netIn The current network input, containing the initial composition.
|
||||
* @return An unordered set of all reachable species.
|
||||
*
|
||||
* @par Algorithm:
|
||||
* 1. Initializes a set `reachable` and a queue `to_visit` with the initial fuel species.
|
||||
* 2. Iteratively processes the reaction network until no new species can be reached.
|
||||
* 3. In each pass, it iterates through all reactions in the base engine's network.
|
||||
* 4. If all reactants of a reaction are in the `reachable` set, all products of that reaction are added to the `reachable` set.
|
||||
* 5. The process continues until a full pass over all reactions does not add any new species to the `reachable` set.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> findReachableSpecies(
|
||||
const NetIn& netIn
|
||||
) const;
|
||||
/**
|
||||
* @brief Culls reactions from the network based on their flow rates.
|
||||
*
|
||||
* This method filters the list of all reactions, keeping only those with a flow rate
|
||||
* above an absolute culling threshold. The threshold is calculated by multiplying the
|
||||
* maximum flow rate by a relative culling threshold read from the configuration.
|
||||
*
|
||||
* @param allFlows A vector of all reactions and their flow rates.
|
||||
* @param reachableSpecies A set of all species reachable from the initial fuel.
|
||||
* @param Y_full A vector of molar abundances for all species in the full network.
|
||||
* @param maxFlow The maximum reaction flow rate in the network.
|
||||
* @return A vector of pointers to the reactions that have been kept after culling.
|
||||
*
|
||||
* @par Algorithm:
|
||||
* 1. Retrieves the `RelativeCullingThreshold` from the configuration.
|
||||
* 2. Calculates the `absoluteCullingThreshold` by multiplying `maxFlow` with the relative threshold.
|
||||
* 3. Iterates through `allFlows`.
|
||||
* 4. A reaction is kept if its `flowRate` is greater than the `absoluteCullingThreshold`.
|
||||
* 5. The pointers to the kept reactions are stored in a vector and returned.
|
||||
*/
|
||||
[[nodiscard]] 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;
|
||||
|
||||
typedef std::pair<std::unordered_set<const reaction::LogicalReaction*>, std::unordered_set<fourdst::atomic::Species>> RescueSet;
|
||||
[[nodiscard]] RescueSet rescueEdgeSpeciesDestructionChannel(
|
||||
const std::vector<double>& Y_full,
|
||||
const double T9,
|
||||
const double rho,
|
||||
const std::vector<fourdst::atomic::Species>& activeSpecies,
|
||||
const reaction::LogicalReactionSet& activeReactions
|
||||
) const;
|
||||
/**
|
||||
* @brief Finalizes the set of active species and reactions.
|
||||
*
|
||||
* This method takes the final list of culled reactions and populates the
|
||||
* `m_activeReactions` and `m_activeSpecies` members. The active species are
|
||||
* determined by collecting all reactants and products from the final reactions.
|
||||
* The active species list is then sorted by mass.
|
||||
*
|
||||
* @param finalReactions A vector of pointers to the reactions to be included in the active set.
|
||||
*
|
||||
* @post
|
||||
* - `m_activeReactions` is cleared and populated with the reactions from `finalReactions`.
|
||||
* - `m_activeSpecies` is cleared and populated with all unique species present in `finalReactions`.
|
||||
* - `m_activeSpecies` is sorted by atomic mass.
|
||||
*/
|
||||
void finalizeActiveSet(
|
||||
const std::vector<const reaction::LogicalReaction*>& finalReactions
|
||||
);
|
||||
};
|
||||
}
|
||||
277
src/include/gridfire/engine/views/engine_defined.h
Normal file
277
src/include/gridfire/engine/views/engine_defined.h
Normal file
@@ -0,0 +1,277 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/views/engine_view_abstract.h"
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/io/network_file.h"
|
||||
#include "gridfire/network.h"
|
||||
|
||||
#include "fourdst/config/config.h"
|
||||
#include "fourdst/logging/logging.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gridfire{
|
||||
class DefinedEngineView : public DynamicEngine, public EngineView<DynamicEngine> {
|
||||
public:
|
||||
DefinedEngineView(const std::vector<std::string>& peNames, DynamicEngine& baseEngine);
|
||||
const DynamicEngine& getBaseEngine() const override;
|
||||
|
||||
// --- Engine Interface ---
|
||||
/**
|
||||
* @brief Gets the list of active species in the network defined by the file.
|
||||
* @return A const reference to the vector of active species.
|
||||
*/
|
||||
const std::vector<fourdst::atomic::Species>& getNetworkSpecies() const override;
|
||||
|
||||
// --- DynamicEngine Interface ---
|
||||
/**
|
||||
* @brief Calculates the right-hand side (dY/dt) and energy generation for the active species.
|
||||
*
|
||||
* @param Y_defined A vector of abundances for the active species.
|
||||
* @param T9 The temperature in units of 10^9 K.
|
||||
* @param rho The density in g/cm^3.
|
||||
* @return A StepDerivatives struct containing the derivatives of the active species and the
|
||||
* nuclear energy generation rate.
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale (i.e., `update()` has not been called after `setNetworkFile()`).
|
||||
*/
|
||||
std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the active species.
|
||||
*
|
||||
* @param Y_dynamic A vector of abundances for the active species.
|
||||
* @param T9 The temperature in units of 10^9 K.
|
||||
* @param rho The density in g/cm^3.
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
*/
|
||||
void generateJacobianMatrix(
|
||||
const std::vector<double>& Y_dynamic,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
/**
|
||||
* @brief Gets an entry from the Jacobian matrix for the active species.
|
||||
*
|
||||
* @param i_defined The row index (species index) in the defined matrix.
|
||||
* @param j_defined The column index (species index) in the defined matrix.
|
||||
* @return The value of the Jacobian matrix at (i_defined, j_defined).
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
* @throws std::out_of_range If an index is out of bounds.
|
||||
*/
|
||||
double getJacobianMatrixEntry(
|
||||
const int i_defined,
|
||||
const int j_defined
|
||||
) const override;
|
||||
/**
|
||||
* @brief Generates the stoichiometry matrix for the active reactions and species.
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
*/
|
||||
void generateStoichiometryMatrix() override;
|
||||
/**
|
||||
* @brief Gets an entry from the stoichiometry matrix for the active species and reactions.
|
||||
*
|
||||
* @param speciesIndex_defined The index of the species in the defined species list.
|
||||
* @param reactionIndex_defined The index of the reaction in the defined reaction list.
|
||||
* @return The stoichiometric coefficient for the given species and reaction.
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
* @throws std::out_of_range If an index is out of bounds.
|
||||
*/
|
||||
int getStoichiometryMatrixEntry(
|
||||
const int speciesIndex_defined,
|
||||
const int reactionIndex_defined
|
||||
) const override;
|
||||
/**
|
||||
* @brief Calculates the molar reaction flow for a given reaction in the active network.
|
||||
*
|
||||
* @param reaction The reaction for which to calculate the flow.
|
||||
* @param Y_defined Vector of current abundances for the active species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Molar flow rate for the reaction (e.g., mol/g/s).
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale or if the reaction is not in the active set.
|
||||
*/
|
||||
double calculateMolarReactionFlow(
|
||||
const reaction::Reaction& reaction,
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
/**
|
||||
* @brief Gets the set of active logical reactions in the network.
|
||||
*
|
||||
* @return Reference to the LogicalReactionSet containing all active reactions.
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
*/
|
||||
const reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(const reaction::LogicalReactionSet& reactions) override;
|
||||
/**
|
||||
* @brief Computes timescales for all active species in the network.
|
||||
*
|
||||
* @param Y_defined Vector of current abundances for the active species.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return Map from Species to their characteristic timescales (s).
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
*/
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Updates the engine view if it is marked as stale.
|
||||
*
|
||||
* This method checks if the view is stale (e.g., after `setNetworkFile` was called).
|
||||
* If it is, it rebuilds the active network from the currently set file.
|
||||
* The `netIn` parameter is not used by this implementation but is required by the interface.
|
||||
*
|
||||
* @param netIn The current network input (unused).
|
||||
*
|
||||
* @post If the view was stale, it is rebuilt and is no longer stale.
|
||||
*/
|
||||
fourdst::composition::Composition update(const NetIn &netIn) override;
|
||||
|
||||
bool isStale(const NetIn& netIn) override;
|
||||
|
||||
/**
|
||||
* @brief Sets the screening model for the base engine.
|
||||
*
|
||||
* @param model The screening model to set.
|
||||
*/
|
||||
void setScreeningModel(screening::ScreeningType model) override;
|
||||
|
||||
/**
|
||||
* @brief Gets the screening model from the base engine.
|
||||
*
|
||||
* @return The current screening model type.
|
||||
*/
|
||||
[[nodiscard]] screening::ScreeningType getScreeningModel() const override;
|
||||
|
||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
[[nodiscard]] std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const override;
|
||||
|
||||
[[nodiscard]] PrimingReport primeEngine(const NetIn &netIn) override;
|
||||
protected:
|
||||
bool m_isStale = true;
|
||||
DynamicEngine& m_baseEngine;
|
||||
private:
|
||||
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log"); ///< Logger instance for trace and debug information.
|
||||
///< Active species in the defined engine.
|
||||
std::vector<fourdst::atomic::Species> m_activeSpecies;
|
||||
///< Active reactions in the defined engine.
|
||||
reaction::LogicalReactionSet m_activeReactions;
|
||||
|
||||
///< Maps indices of active species to indices in the full network.
|
||||
std::vector<size_t> m_speciesIndexMap;
|
||||
///< Maps indices of active reactions to indices in the full network.
|
||||
std::vector<size_t> m_reactionIndexMap;
|
||||
private:
|
||||
/**
|
||||
* @brief Constructs the species index map.
|
||||
*
|
||||
* @return A vector mapping defined 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.
|
||||
*
|
||||
* @throws std::runtime_error If an active species is not found in the base engine's species list.
|
||||
*/
|
||||
std::vector<size_t> constructSpeciesIndexMap() const;
|
||||
|
||||
/**
|
||||
* @brief Constructs the reaction index map.
|
||||
*
|
||||
* @return A vector mapping defined 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.
|
||||
*
|
||||
* @throws std::runtime_error If an active reaction is not found in the base engine's reaction list.
|
||||
*/
|
||||
std::vector<size_t> constructReactionIndexMap() const;
|
||||
|
||||
/**
|
||||
* @brief Maps a vector of culled abundances to a vector of full abundances.
|
||||
*
|
||||
* @param defined 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 defined vector.
|
||||
*/
|
||||
std::vector<double> mapViewToFull(const std::vector<double>& defined) 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> mapFullToView(const std::vector<double>& full) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a culled species index to a full species index.
|
||||
*
|
||||
* @param definedSpeciesIndex The index of the species in the defined species list.
|
||||
* @return The index of the corresponding species in the full network.
|
||||
*
|
||||
* @throws std::out_of_range If the defined index is out of bounds for the species index map.
|
||||
*/
|
||||
size_t mapViewToFullSpeciesIndex(size_t definedSpeciesIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a culled reaction index to a full reaction index.
|
||||
*
|
||||
* @param definedReactionIndex The index of the reaction in the defined reaction list.
|
||||
* @return The index of the corresponding reaction in the full network.
|
||||
*
|
||||
* @throws std::out_of_range If the defined index is out of bounds for the reaction index map.
|
||||
*/
|
||||
size_t mapViewToFullReactionIndex(size_t definedReactionIndex) const;
|
||||
|
||||
void validateNetworkState() const;
|
||||
|
||||
void collect(const std::vector<std::string>& peNames);
|
||||
|
||||
};
|
||||
|
||||
class FileDefinedEngineView final: public DefinedEngineView {
|
||||
public:
|
||||
explicit FileDefinedEngineView(
|
||||
DynamicEngine& baseEngine,
|
||||
const std::string& fileName,
|
||||
const io::NetworkFileParser& parser
|
||||
);
|
||||
std::string getNetworkFile() const { return m_fileName; }
|
||||
const io::NetworkFileParser& getParser() const { return m_parser; }
|
||||
private:
|
||||
using Config = fourdst::config::Config;
|
||||
using LogManager = fourdst::logging::LogManager;
|
||||
Config& m_config = Config::getInstance();
|
||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||
std::string m_fileName;
|
||||
///< Parser for the network file.
|
||||
const io::NetworkFileParser& m_parser;
|
||||
};
|
||||
}
|
||||
392
src/include/gridfire/engine/views/engine_multiscale.h
Normal file
392
src/include/gridfire/engine/views/engine_multiscale.h
Normal file
@@ -0,0 +1,392 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/engine/views/engine_view_abstract.h"
|
||||
#include "gridfire/engine/engine_graph.h"
|
||||
|
||||
#include "unsupported/Eigen/NonLinearOptimization"
|
||||
|
||||
namespace gridfire {
|
||||
struct QSECacheConfig {
|
||||
double T9_tol; ///< Absolute tolerance to produce the same hash for T9.
|
||||
double rho_tol; ///< Absolute tolerance to produce the same hash for rho.
|
||||
double Yi_tol; ///< Absolute tolerance to produce the same hash for species abundances.
|
||||
};
|
||||
|
||||
struct QSECacheKey {
|
||||
double m_T9;
|
||||
double m_rho;
|
||||
std::vector<double> m_Y; ///< Note that the ordering of Y must match the dynamic species indices in the view.
|
||||
|
||||
std::size_t m_hash = 0; ///< Precomputed hash value for this key.
|
||||
|
||||
// TODO: We should probably sort out how to adjust these from absolute to relative tolerances.
|
||||
QSECacheConfig m_cacheConfig = {
|
||||
1e-3, // Default tolerance for T9
|
||||
1e-1, // Default tolerance for rho
|
||||
1e-3 // Default tolerance for species abundances
|
||||
};
|
||||
|
||||
QSECacheKey(
|
||||
const double T9,
|
||||
const double rho,
|
||||
const std::vector<double>& Y
|
||||
);
|
||||
|
||||
size_t hash() const;
|
||||
|
||||
static long bin(double value, double tol);
|
||||
|
||||
bool operator==(const QSECacheKey& other) const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// Needs to be in this order (splitting gridfire namespace up) to avoid some issues with forward declarations and the () operator.
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<gridfire::QSECacheKey> {
|
||||
/**
|
||||
* @brief Computes the hash of a QSECacheKey.
|
||||
* @param key The QSECacheKey to hash.
|
||||
* @return The pre-computed hash value of the key.
|
||||
*/
|
||||
size_t operator()(const gridfire::QSECacheKey& key) const noexcept {
|
||||
// The hash is pre-computed, so we just return it.
|
||||
return key.m_hash;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace gridfire {
|
||||
class MultiscalePartitioningEngineView final: public DynamicEngine, public EngineView<DynamicEngine> {
|
||||
typedef std::tuple<std::vector<fourdst::atomic::Species>, std::vector<size_t>, std::vector<fourdst::atomic::Species>, std::vector<size_t>> QSEPartition;
|
||||
public:
|
||||
explicit MultiscalePartitioningEngineView(GraphEngine& baseEngine);
|
||||
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species> & getNetworkSpecies() const override;
|
||||
|
||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||
const std::vector<double> &Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
void generateJacobianMatrix(
|
||||
const std::vector<double> &Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] double getJacobianMatrixEntry(
|
||||
int i_full,
|
||||
int j_full
|
||||
) const override;
|
||||
|
||||
void generateStoichiometryMatrix() override;
|
||||
|
||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||
int speciesIndex,
|
||||
int reactionIndex
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] double calculateMolarReactionFlow(
|
||||
const reaction::Reaction &reaction,
|
||||
const std::vector<double> &Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] const reaction::LogicalReactionSet & getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(
|
||||
const reaction::LogicalReactionSet &reactions
|
||||
) override;
|
||||
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesTimescales(
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> getSpeciesDestructionTimescales(
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
fourdst::composition::Composition update(
|
||||
const NetIn &netIn
|
||||
) override;
|
||||
|
||||
bool isStale(const NetIn& netIn) override;
|
||||
|
||||
void setScreeningModel(
|
||||
screening::ScreeningType model
|
||||
) override;
|
||||
|
||||
[[nodiscard]] screening::ScreeningType getScreeningModel() const override;
|
||||
|
||||
const DynamicEngine & getBaseEngine() const override;
|
||||
|
||||
std::vector<std::vector<size_t>> analyzeTimescalePoolConnectivity(
|
||||
const std::vector<std::vector<size_t>> ×cale_pools,
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const;
|
||||
|
||||
void partitionNetwork(
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
|
||||
void partitionNetwork(
|
||||
const NetIn& netIn
|
||||
);
|
||||
|
||||
void exportToDot(
|
||||
const std::string& filename,
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const;
|
||||
|
||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
[[nodiscard]] std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const override;
|
||||
|
||||
[[nodiscard]] PrimingReport primeEngine(const NetIn &netIn) override;
|
||||
|
||||
[[nodiscard]] std::vector<fourdst::atomic::Species> getFastSpecies() const;
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& getDynamicSpecies() const;
|
||||
|
||||
fourdst::composition::Composition equilibrateNetwork(
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
|
||||
fourdst::composition::Composition equilibrateNetwork(
|
||||
const NetIn &netIn
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
struct QSEGroup {
|
||||
std::set<size_t> species_indices; ///< Indices of all species in this group.
|
||||
bool is_in_equilibrium = false; ///< Flag set by flux analysis.
|
||||
std::set<size_t> algebraic_indices; ///< Indices of algebraic species in this group.
|
||||
std::set<size_t> seed_indices; ///< Indices of dynamic species in this group.
|
||||
double mean_timescale; ///< Mean timescale of the group.
|
||||
|
||||
bool operator<(const QSEGroup& other) const;
|
||||
bool operator>(const QSEGroup& other) const;
|
||||
bool operator==(const QSEGroup& other) const;
|
||||
bool operator!=(const QSEGroup& other) const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const QSEGroup& group) {
|
||||
os << "QSEGroup(species_indices: [";
|
||||
int count = 0;
|
||||
for (const auto& idx : group.species_indices) {
|
||||
os << idx;
|
||||
if (count < group.species_indices.size() - 1) {
|
||||
os << ", ";
|
||||
}
|
||||
count++;
|
||||
}
|
||||
count = 0;
|
||||
os << "], is_in_equilibrium: " << group.is_in_equilibrium
|
||||
<< ", mean_timescale: " << group.mean_timescale
|
||||
<< " s, algebraic_indices: [";
|
||||
for (const auto& idx : group.algebraic_indices) {
|
||||
os << idx;
|
||||
if (count < group.algebraic_indices.size() - 1) {
|
||||
os << ", ";
|
||||
}
|
||||
count++;
|
||||
}
|
||||
count = 0;
|
||||
os << "], seed_indices: [";
|
||||
for (const auto& idx : group.seed_indices) {
|
||||
os << idx;
|
||||
if (count < group.seed_indices.size() - 1) {
|
||||
os << ", ";
|
||||
}
|
||||
count++;
|
||||
}
|
||||
os << "])";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
struct EigenFunctor {
|
||||
using InputType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
|
||||
using OutputType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
|
||||
using JacobianType = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
|
||||
enum {
|
||||
InputsAtCompileTime = Eigen::Dynamic,
|
||||
ValuesAtCompileTime = Eigen::Dynamic
|
||||
};
|
||||
|
||||
MultiscalePartitioningEngineView* m_view;
|
||||
const std::vector<size_t>& m_qse_solve_indices;
|
||||
const std::vector<double>& m_Y_full_initial;
|
||||
const double m_T9;
|
||||
const double m_rho;
|
||||
const Eigen::VectorXd& m_Y_scale;
|
||||
|
||||
EigenFunctor(
|
||||
MultiscalePartitioningEngineView& view,
|
||||
const std::vector<size_t>& qse_solve_indices,
|
||||
const std::vector<double>& Y_full_initial,
|
||||
const double T9,
|
||||
const double rho,
|
||||
const Eigen::VectorXd& Y_scale
|
||||
) :
|
||||
m_view(&view),
|
||||
m_qse_solve_indices(qse_solve_indices),
|
||||
m_Y_full_initial(Y_full_initial),
|
||||
m_T9(T9),
|
||||
m_rho(rho),
|
||||
m_Y_scale(Y_scale) {}
|
||||
|
||||
[[nodiscard]] int values() const { return m_qse_solve_indices.size(); }
|
||||
[[nodiscard]] int inputs() const { return m_qse_solve_indices.size(); }
|
||||
|
||||
int operator()(const InputType& v_qse, OutputType& f_qse) const;
|
||||
int df(const InputType& v_qse, JacobianType& J_qse) const;
|
||||
};
|
||||
|
||||
|
||||
struct CacheStats {
|
||||
enum class operators {
|
||||
CalculateRHSAndEnergy,
|
||||
GenerateJacobianMatrix,
|
||||
CalculateMolarReactionFlow,
|
||||
GetSpeciesTimescales,
|
||||
GetSpeciesDestructionTimescales,
|
||||
Other,
|
||||
All
|
||||
};
|
||||
|
||||
std::map<operators, std::string> operatorsNameMap = {
|
||||
{operators::CalculateRHSAndEnergy, "calculateRHSAndEnergy"},
|
||||
{operators::GenerateJacobianMatrix, "generateJacobianMatrix"},
|
||||
{operators::CalculateMolarReactionFlow, "calculateMolarReactionFlow"},
|
||||
{operators::GetSpeciesTimescales, "getSpeciesTimescales"},
|
||||
{operators::GetSpeciesDestructionTimescales, "getSpeciesDestructionTimescales"},
|
||||
{operators::Other, "other"}
|
||||
};
|
||||
|
||||
size_t m_hit = 0;
|
||||
size_t m_miss = 0;
|
||||
|
||||
std::map<operators, size_t> m_operatorHits = {
|
||||
{operators::CalculateRHSAndEnergy, 0},
|
||||
{operators::GenerateJacobianMatrix, 0},
|
||||
{operators::CalculateMolarReactionFlow, 0},
|
||||
{operators::GetSpeciesTimescales, 0},
|
||||
{operators::GetSpeciesDestructionTimescales, 0},
|
||||
{operators::Other, 0}
|
||||
};
|
||||
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const CacheStats& stats) {
|
||||
os << "CacheStats(hit: " << stats.m_hit << ", miss: " << stats.m_miss << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
void hit(const operators op=operators::Other) {
|
||||
if (op==operators::All) {
|
||||
throw std::invalid_argument("Cannot use 'All' as an operator for hit/miss.");
|
||||
}
|
||||
m_hit++;
|
||||
m_operatorHits[op]++;
|
||||
}
|
||||
void miss(const operators op=operators::Other) {
|
||||
if (op==operators::All) {
|
||||
throw std::invalid_argument("Cannot use 'All' as an operator for hit/miss.");
|
||||
}
|
||||
m_miss++;
|
||||
m_operatorHits[op]++;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t hits(const operators op=operators::All) const {
|
||||
if (op==operators::All) {
|
||||
return m_hit;
|
||||
}
|
||||
return m_operatorHits.at(op);
|
||||
}
|
||||
[[nodiscard]] size_t misses(const operators op=operators::All) const {
|
||||
if (op==operators::All) {
|
||||
return m_miss;
|
||||
}
|
||||
return m_operatorHits.at(op);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||
GraphEngine& m_baseEngine; ///< The base engine to which this view delegates calculations.
|
||||
std::vector<QSEGroup> m_qse_groups; ///< The list of identified equilibrium groups.
|
||||
std::vector<fourdst::atomic::Species> m_dynamic_species; ///< The simplified set of species presented to the solver.
|
||||
std::vector<size_t> m_dynamic_species_indices; ///< Indices mapping the dynamic species back to the master engine's list.
|
||||
std::vector<fourdst::atomic::Species> m_algebraic_species; ///< Species that are algebraic in the QSE groups.
|
||||
std::vector<size_t> m_algebraic_species_indices; ///< Indices of algebraic species in the full network.
|
||||
|
||||
std::vector<size_t> m_activeSpeciesIndices; ///< Indices of active species in the full network.
|
||||
std::vector<size_t> m_activeReactionIndices; ///< Indices of active reactions in the full network.
|
||||
|
||||
// TODO: Enhance the hashing for the cache to consider not just T and rho but also the current abundance in some careful way that automatically ignores small changes (i.e. network should only be repartitioned sometimes)
|
||||
std::unordered_map<QSECacheKey, std::vector<double>> m_qse_abundance_cache; ///< Cache for QSE abundances based on T9 and rho.
|
||||
mutable CacheStats m_cacheStats; ///< Statistics for the QSE abundance cache.
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
std::vector<std::vector<size_t>> partitionByTimescale(
|
||||
const std::vector<double> &Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
) const;
|
||||
|
||||
std::unordered_map<size_t, std::vector<size_t>> buildConnectivityGraph(
|
||||
const std::unordered_set<size_t> &fast_reaction_indices
|
||||
) const;
|
||||
|
||||
std::vector<QSEGroup> validateGroupsWithFluxAnalysis(
|
||||
const std::vector<QSEGroup> &candidate_groups,
|
||||
const std::vector<double>& Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const;
|
||||
|
||||
std::vector<double> solveQSEAbundances(
|
||||
const std::vector<double> &Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
|
||||
size_t identifyMeanSlowestPool(
|
||||
const std::vector<std::vector<size_t>>& pools,
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const;
|
||||
|
||||
std::unordered_map<size_t, std::vector<size_t>> buildConnectivityGraph(
|
||||
const std::vector<size_t>& species_pool
|
||||
) const;
|
||||
|
||||
std::vector<QSEGroup> constructCandidateGroups(
|
||||
const std::vector<std::vector<size_t>>& candidate_pools,
|
||||
const std::vector<double>& Y,
|
||||
double T9, double rho
|
||||
) const;
|
||||
};
|
||||
}
|
||||
|
||||
35
src/include/gridfire/engine/views/engine_priming.h
Normal file
35
src/include/gridfire/engine/views/engine_priming.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
#include "gridfire/engine/views/engine_defined.h"
|
||||
|
||||
#include "gridfire/network.h"
|
||||
|
||||
#include "fourdst/logging/logging.h"
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/composition/composition.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace gridfire {
|
||||
|
||||
class NetworkPrimingEngineView final : public DefinedEngineView {
|
||||
public:
|
||||
NetworkPrimingEngineView(const std::string& primingSymbol, DynamicEngine& baseEngine);
|
||||
NetworkPrimingEngineView(const fourdst::atomic::Species& primingSpecies, DynamicEngine& baseEngine);
|
||||
|
||||
|
||||
private:
|
||||
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||
fourdst::atomic::Species m_primingSpecies; ///< The priming species, if specified.
|
||||
private:
|
||||
std::vector<std::string> constructPrimingReactionSet(
|
||||
const fourdst::atomic::Species& primingSpecies,
|
||||
const DynamicEngine& baseEngine
|
||||
) const;
|
||||
};
|
||||
|
||||
}
|
||||
98
src/include/gridfire/engine/views/engine_view_abstract.h
Normal file
98
src/include/gridfire/engine/views/engine_view_abstract.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
|
||||
/**
|
||||
* @file engine_view_abstract.h
|
||||
* @brief Abstract interfaces for engine "views" in GridFire.
|
||||
*
|
||||
* This header defines the abstract base classes and concepts for "views" of reaction network engines.
|
||||
* The primary purpose of an EngineView is to enable dynamic or adaptive network topologies
|
||||
* (such as species/reaction culling, masking, or remapping) without modifying the underlying
|
||||
* physics engine or its implementation. Engine views act as a flexible interface layer,
|
||||
* allowing the network structure to be changed at runtime while preserving the core
|
||||
* physics and solver logic in the base engine.
|
||||
*
|
||||
* Typical use cases include:
|
||||
* - Adaptive or reduced networks for computational efficiency.
|
||||
* - Dynamic masking or culling of species/reactions based on runtime criteria.
|
||||
* - Providing a filtered or remapped view of the network for integration or analysis.
|
||||
* - Supporting dynamic network reconfiguration in multi-zone or multi-physics contexts.
|
||||
*
|
||||
* The base engine types referenced here are defined in @ref engine_abstract.h.
|
||||
*
|
||||
* @author
|
||||
* Emily M. Boudreaux
|
||||
*/
|
||||
|
||||
namespace gridfire {
|
||||
|
||||
/**
|
||||
* @brief Concept for types allowed as engine bases in EngineView.
|
||||
*
|
||||
* This concept restricts template parameters to types derived from either
|
||||
* gridfire::Engine or gridfire::DynamicEngine, as defined in engine_abstract.h.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* static_assert(EngineType<MyEngine>);
|
||||
* @endcode
|
||||
*/
|
||||
template<typename EngineT>
|
||||
concept EngineType = std::is_base_of_v<Engine, EngineT> || std::is_base_of_v<DynamicEngine, EngineT>;
|
||||
|
||||
/**
|
||||
* @brief Abstract base class for a "view" of a reaction network engine.
|
||||
*
|
||||
* @tparam EngineT The engine type being viewed (must satisfy EngineType).
|
||||
*
|
||||
* EngineView provides an interface for accessing an underlying engine instance,
|
||||
* while presenting a potentially modified or reduced network structure to the user.
|
||||
* This enables dynamic or adaptive network topologies (e.g., culling, masking, or
|
||||
* remapping of species and reactions) without altering the core physics engine.
|
||||
*
|
||||
* Intended usage: Derive from this class to implement a custom view or wrapper
|
||||
* that manages a dynamic or adaptive network structure, delegating core calculations
|
||||
* to the base engine. The contract is that getBaseEngine() must return a reference
|
||||
* to the underlying engine instance, which remains responsible for the full physics.
|
||||
*
|
||||
* Example (see also AdaptiveEngineView):
|
||||
* @code
|
||||
* class MyAdaptiveView : public gridfire::EngineView<DynamicEngine> {
|
||||
* public:
|
||||
* MyAdaptiveView(DynamicEngine& engine) : engine_(engine) {}
|
||||
* const DynamicEngine& getBaseEngine() const override { return engine_; }
|
||||
* // Implement dynamic masking/culling logic...
|
||||
* private:
|
||||
* DynamicEngine& engine_;
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* @see gridfire::AdaptiveEngineView for a concrete example of dynamic culling.
|
||||
*/
|
||||
template<EngineType EngineT>
|
||||
class EngineView {
|
||||
public:
|
||||
/**
|
||||
* @brief Virtual destructor.
|
||||
*/
|
||||
virtual ~EngineView() = default;
|
||||
|
||||
/**
|
||||
* @brief Access the underlying engine instance.
|
||||
*
|
||||
* @return Const reference to the underlying engine.
|
||||
*
|
||||
* This method must be implemented by derived classes to provide access
|
||||
* to the base engine. The returned reference should remain valid for the
|
||||
* lifetime of the EngineView.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* const DynamicEngine& engine = myView.getBaseEngine();
|
||||
* @endcode
|
||||
*/
|
||||
virtual const EngineT& getBaseEngine() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
7
src/include/gridfire/engine/views/engine_views.h
Normal file
7
src/include/gridfire/engine/views/engine_views.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/views/engine_adaptive.h"
|
||||
#include "gridfire/engine/views/engine_defined.h"
|
||||
#include "gridfire/engine/views/engine_multiscale.h"
|
||||
#include "gridfire/engine/views/engine_priming.h"
|
||||
#include "gridfire/engine/views/engine_view_abstract.h"
|
||||
Reference in New Issue
Block a user