refactor(reaction): refactored to an abstract reaction class in prep for weak reactions
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -76,6 +76,9 @@ subprojects/libconstants/
|
||||
subprojects/liblogging/
|
||||
subprojects/eigen-*/
|
||||
subprojects/fourdst/
|
||||
subprojects/libplugin/
|
||||
subprojects/minizip-ng-4.0.10/
|
||||
*.fbundle
|
||||
|
||||
*.csv
|
||||
*.dot
|
||||
|
||||
5
build-config/libplugin/meson.build
Normal file
5
build-config/libplugin/meson.build
Normal file
@@ -0,0 +1,5 @@
|
||||
libplugin_sp = subproject('libplugin')
|
||||
|
||||
plugin_dep = libplugin_sp.get_variable('plugin_dep')
|
||||
libplugin = libplugin_sp.get_variable('libplugin')
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
cmake = import('cmake')
|
||||
|
||||
subdir('fourdst')
|
||||
subdir('libplugin')
|
||||
|
||||
subdir('boost')
|
||||
subdir('cppad')
|
||||
subdir('xxHash')
|
||||
|
||||
@@ -215,9 +215,9 @@ namespace gridfire {
|
||||
*
|
||||
* @return Reference to the LogicalReactionSet containing all reactions.
|
||||
*/
|
||||
[[nodiscard]] virtual const reaction::LogicalReactionSet& getNetworkReactions() const = 0;
|
||||
[[nodiscard]] virtual const reaction::ReactionSet& getNetworkReactions() const = 0;
|
||||
|
||||
virtual void setNetworkReactions(const reaction::LogicalReactionSet& reactions) = 0;
|
||||
virtual void setNetworkReactions(const reaction::ReactionSet& reactions) = 0;
|
||||
|
||||
/**
|
||||
* @brief Compute timescales for all species in the network.
|
||||
@@ -305,7 +305,7 @@ namespace gridfire {
|
||||
* engine's internal representation. It is useful for accessing species
|
||||
* data efficiently.
|
||||
*/
|
||||
[[nodiscard]] virtual int getSpeciesIndex(const fourdst::atomic::Species &species) const = 0;
|
||||
[[nodiscard]] virtual size_t getSpeciesIndex(const fourdst::atomic::Species &species) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Map a NetIn object to a vector of molar abundances.
|
||||
@@ -357,6 +357,7 @@ namespace gridfire {
|
||||
*/
|
||||
virtual void rebuild(const fourdst::composition::Composition& comp, BuildDepthType depth) {
|
||||
throw std::logic_error("Setting network depth not supported by this engine.");
|
||||
// ReSharper disable once CppDFAUnreachableCode
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -25,16 +25,10 @@
|
||||
#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 {
|
||||
/**
|
||||
* @brief Alias for CppAD AD type for double precision.
|
||||
@@ -128,7 +122,7 @@ namespace gridfire {
|
||||
* This constructor uses the given set of reactions to construct the
|
||||
* reaction network.
|
||||
*/
|
||||
explicit GraphEngine(const reaction::LogicalReactionSet &reactions);
|
||||
explicit GraphEngine(const reaction::ReactionSet &reactions);
|
||||
|
||||
/**
|
||||
* @brief Calculates the right-hand side (dY/dt) and energy generation rate.
|
||||
@@ -212,9 +206,9 @@ namespace gridfire {
|
||||
* @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;
|
||||
[[nodiscard]] const reaction::ReactionSet& getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(const reaction::LogicalReactionSet& reactions) override;
|
||||
void setNetworkReactions(const reaction::ReactionSet& reactions) override;
|
||||
|
||||
/**
|
||||
* @brief Gets an entry from the previously generated Jacobian matrix.
|
||||
@@ -394,6 +388,8 @@ namespace gridfire {
|
||||
*
|
||||
* @param reaction The reaction for which to calculate the reverse rate.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho
|
||||
* @param Y
|
||||
* @return Reverse rate for the reaction (e.g., mol/g/s).
|
||||
*
|
||||
* This method computes the reverse rate based on the forward rate and
|
||||
@@ -401,7 +397,7 @@ namespace gridfire {
|
||||
*/
|
||||
[[nodiscard]] double calculateReverseRate(
|
||||
const reaction::Reaction &reaction,
|
||||
double T9
|
||||
double T9, double rho, const std::vector<double> &Y
|
||||
) const;
|
||||
|
||||
/**
|
||||
@@ -426,7 +422,7 @@ namespace gridfire {
|
||||
[[nodiscard]] double calculateReverseRateTwoBodyDerivative(
|
||||
const reaction::Reaction &reaction,
|
||||
const double T9,
|
||||
const double reverseRate
|
||||
double rho, const std::vector<double> &Y, const double reverseRate
|
||||
) const;
|
||||
|
||||
/**
|
||||
@@ -458,7 +454,7 @@ namespace gridfire {
|
||||
* This method returns the index of the given species in the network's
|
||||
* species vector. If the species is not found, it returns -1.
|
||||
*/
|
||||
[[nodiscard]] int getSpeciesIndex(
|
||||
[[nodiscard]] size_t getSpeciesIndex(
|
||||
const fourdst::atomic::Species &species
|
||||
) const override;
|
||||
|
||||
@@ -574,7 +570,7 @@ namespace gridfire {
|
||||
|
||||
constants m_constants;
|
||||
|
||||
reaction::LogicalReactionSet m_reactions; ///< Set of REACLIB reactions in the network.
|
||||
reaction::ReactionSet 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.
|
||||
@@ -654,7 +650,7 @@ namespace gridfire {
|
||||
*
|
||||
* @throws std::runtime_error If there are no species in the network.
|
||||
*/
|
||||
void recordADTape();
|
||||
void recordADTape() const;
|
||||
|
||||
void collectAtomicReverseRateAtomicBases();
|
||||
|
||||
@@ -708,7 +704,7 @@ namespace gridfire {
|
||||
std::vector<T> screeningFactors,
|
||||
std::vector<T> Y,
|
||||
size_t reactionIndex,
|
||||
const reaction::LogicalReaction &reaction
|
||||
const reaction::Reaction &reaction
|
||||
) const;
|
||||
|
||||
/**
|
||||
@@ -776,7 +772,7 @@ namespace gridfire {
|
||||
std::vector<T> screeningFactors,
|
||||
std::vector<T> Y,
|
||||
size_t reactionIndex,
|
||||
const reaction::LogicalReaction &reaction
|
||||
const reaction::Reaction &reaction
|
||||
) const {
|
||||
if (!m_useReverseReactions) {
|
||||
return static_cast<T>(0.0); // If reverse reactions are not used, return zero
|
||||
@@ -800,7 +796,7 @@ namespace gridfire {
|
||||
}
|
||||
} else {
|
||||
// A,B If not calling with an AD type, calculate the reverse rate directly
|
||||
reverseRateConstant = calculateReverseRate(reaction, T9);
|
||||
reverseRateConstant = calculateReverseRate(reaction, T9, 0, {});
|
||||
}
|
||||
|
||||
// C. Get product multiplicities
|
||||
@@ -888,7 +884,10 @@ namespace gridfire {
|
||||
calculateMolarReactionFlow<T>(reaction, Y, T9, rho);
|
||||
|
||||
// 2. Calculate reverse reaction rate
|
||||
T reverseMolarFlow = calculateReverseMolarReactionFlow<T>(
|
||||
T reverseMolarFlow = static_cast<T>(0.0);
|
||||
// Do not calculate reverse flow for weak reactions
|
||||
if (reaction.type() == reaction::ReactionType::LOGICAL_REACLIB || reaction.type() == reaction::ReactionType::REACLIB) {
|
||||
reverseMolarFlow = calculateReverseMolarReactionFlow<T>(
|
||||
T9,
|
||||
rho,
|
||||
screeningFactors,
|
||||
@@ -896,6 +895,7 @@ namespace gridfire {
|
||||
reactionIndex,
|
||||
reaction
|
||||
);
|
||||
}
|
||||
|
||||
const T molarReactionFlow = forwardMolarReactionFlow - reverseMolarFlow; // Net molar reaction flow
|
||||
|
||||
@@ -930,7 +930,7 @@ namespace gridfire {
|
||||
const T zero = static_cast<T>(0.0);
|
||||
|
||||
// --- 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);
|
||||
const T k_reaction = reaction.calculate_rate(T9, rho, Y);
|
||||
|
||||
// --- Cound the number of each reactant species to account for species multiplicity ---
|
||||
std::unordered_map<std::string, int> reactant_counts;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace gridfire {
|
||||
* @return A LogicalReactionSet encapsulating the collected reactions for graph-based engines.
|
||||
* @throws std::logic_error If the resolved network depth is zero (no reactions can be collected).
|
||||
*/
|
||||
reaction::LogicalReactionSet build_reaclib_nuclear_network(
|
||||
reaction::ReactionSet build_reaclib_nuclear_network(
|
||||
const fourdst::composition::Composition &composition,
|
||||
BuildDepthType maxLayers = NetworkBuildDepth::Full,
|
||||
bool reverse = false
|
||||
|
||||
@@ -3,13 +3,8 @@
|
||||
#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 {
|
||||
|
||||
@@ -30,7 +25,7 @@ namespace gridfire {
|
||||
* @return PrimingReport encapsulating the results of the priming operation.
|
||||
*/
|
||||
PrimingReport primeNetwork(
|
||||
const NetIn&,
|
||||
const NetIn& netIn,
|
||||
DynamicEngine& engine
|
||||
);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#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"
|
||||
@@ -203,9 +202,9 @@ namespace gridfire {
|
||||
*
|
||||
* @return Reference to the LogicalReactionSet containing all active reactions.
|
||||
*/
|
||||
[[nodiscard]] const reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
[[nodiscard]] const reaction::ReactionSet& getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(const reaction::LogicalReactionSet& reactions) override;
|
||||
void setNetworkReactions(const reaction::ReactionSet& reactions) override;
|
||||
|
||||
/**
|
||||
* @brief Computes timescales for all active species in the network.
|
||||
@@ -270,7 +269,7 @@ namespace gridfire {
|
||||
*/
|
||||
[[nodiscard]] screening::ScreeningType getScreeningModel() const override;
|
||||
|
||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
[[nodiscard]] size_t getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
[[nodiscard]] std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const override;
|
||||
|
||||
@@ -289,7 +288,7 @@ namespace gridfire {
|
||||
/** @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;
|
||||
reaction::ReactionSet 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;
|
||||
@@ -304,7 +303,7 @@ namespace gridfire {
|
||||
* @brief A struct to hold a reaction and its flow rate.
|
||||
*/
|
||||
struct ReactionFlow {
|
||||
const reaction::LogicalReaction* reactionPtr;
|
||||
const reaction::Reaction* reactionPtr;
|
||||
double flowRate;
|
||||
};
|
||||
private:
|
||||
@@ -442,20 +441,20 @@ namespace gridfire {
|
||||
* 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(
|
||||
[[nodiscard]] std::vector<const reaction::Reaction*> 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;
|
||||
typedef std::pair<std::unordered_set<const reaction::Reaction*>, 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 reaction::ReactionSet& activeReactions
|
||||
) const;
|
||||
/**
|
||||
* @brief Finalizes the set of active species and reactions.
|
||||
@@ -473,7 +472,7 @@ namespace gridfire {
|
||||
* - `m_activeSpecies` is sorted by atomic mass.
|
||||
*/
|
||||
void finalizeActiveSet(
|
||||
const std::vector<const reaction::LogicalReaction*>& finalReactions
|
||||
const std::vector<const reaction::Reaction*>& finalReactions
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace gridfire{
|
||||
class DefinedEngineView : public DynamicEngine, public EngineView<DynamicEngine> {
|
||||
public:
|
||||
DefinedEngineView(const std::vector<std::string>& peNames, DynamicEngine& baseEngine);
|
||||
const DynamicEngine& getBaseEngine() const override;
|
||||
[[nodiscard]] 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;
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& getNetworkSpecies() const override;
|
||||
|
||||
// --- DynamicEngine Interface ---
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ namespace gridfire{
|
||||
*
|
||||
* @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(
|
||||
[[nodiscard]] std::expected<StepDerivatives<double>, expectations::StaleEngineError> calculateRHSAndEnergy(
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
const double rho
|
||||
@@ -66,7 +66,7 @@ namespace gridfire{
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
* @throws std::out_of_range If an index is out of bounds.
|
||||
*/
|
||||
double getJacobianMatrixEntry(
|
||||
[[nodiscard]] double getJacobianMatrixEntry(
|
||||
const int i_defined,
|
||||
const int j_defined
|
||||
) const override;
|
||||
@@ -86,7 +86,7 @@ namespace gridfire{
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
* @throws std::out_of_range If an index is out of bounds.
|
||||
*/
|
||||
int getStoichiometryMatrixEntry(
|
||||
[[nodiscard]] int getStoichiometryMatrixEntry(
|
||||
const int speciesIndex_defined,
|
||||
const int reactionIndex_defined
|
||||
) const override;
|
||||
@@ -101,7 +101,7 @@ namespace gridfire{
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale or if the reaction is not in the active set.
|
||||
*/
|
||||
double calculateMolarReactionFlow(
|
||||
[[nodiscard]] double calculateMolarReactionFlow(
|
||||
const reaction::Reaction& reaction,
|
||||
const std::vector<double>& Y_defined,
|
||||
const double T9,
|
||||
@@ -114,9 +114,9 @@ namespace gridfire{
|
||||
*
|
||||
* @throws std::runtime_error If the view is stale.
|
||||
*/
|
||||
const reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
[[nodiscard]] const reaction::ReactionSet& getNetworkReactions() const override;
|
||||
|
||||
void setNetworkReactions(const reaction::LogicalReactionSet& reactions) override;
|
||||
void setNetworkReactions(const reaction::ReactionSet& reactions) override;
|
||||
/**
|
||||
* @brief Computes timescales for all active species in the network.
|
||||
*
|
||||
@@ -168,7 +168,7 @@ namespace gridfire{
|
||||
*/
|
||||
[[nodiscard]] screening::ScreeningType getScreeningModel() const override;
|
||||
|
||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
[[nodiscard]] size_t getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
[[nodiscard]] std::vector<double> mapNetInToMolarAbundanceVector(const NetIn &netIn) const override;
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace gridfire{
|
||||
///< Active species in the defined engine.
|
||||
std::vector<fourdst::atomic::Species> m_activeSpecies;
|
||||
///< Active reactions in the defined engine.
|
||||
reaction::LogicalReactionSet m_activeReactions;
|
||||
reaction::ReactionSet m_activeReactions;
|
||||
|
||||
///< Maps indices of active species to indices in the full network.
|
||||
std::vector<size_t> m_speciesIndexMap;
|
||||
@@ -198,7 +198,7 @@ namespace gridfire{
|
||||
*
|
||||
* @throws std::runtime_error If an active species is not found in the base engine's species list.
|
||||
*/
|
||||
std::vector<size_t> constructSpeciesIndexMap() const;
|
||||
[[nodiscard]] std::vector<size_t> constructSpeciesIndexMap() const;
|
||||
|
||||
/**
|
||||
* @brief Constructs the reaction index map.
|
||||
@@ -210,7 +210,7 @@ namespace gridfire{
|
||||
*
|
||||
* @throws std::runtime_error If an active reaction is not found in the base engine's reaction list.
|
||||
*/
|
||||
std::vector<size_t> constructReactionIndexMap() const;
|
||||
[[nodiscard]] std::vector<size_t> constructReactionIndexMap() const;
|
||||
|
||||
/**
|
||||
* @brief Maps a vector of culled abundances to a vector of full abundances.
|
||||
@@ -219,7 +219,7 @@ namespace gridfire{
|
||||
* @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;
|
||||
[[nodiscard]] std::vector<double> mapViewToFull(const std::vector<double>& defined) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a vector of full abundances to a vector of culled abundances.
|
||||
@@ -228,7 +228,7 @@ namespace gridfire{
|
||||
* @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;
|
||||
[[nodiscard]] std::vector<double> mapFullToView(const std::vector<double>& full) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a culled species index to a full species index.
|
||||
@@ -238,7 +238,7 @@ namespace gridfire{
|
||||
*
|
||||
* @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;
|
||||
[[nodiscard]] size_t mapViewToFullSpeciesIndex(size_t definedSpeciesIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Maps a culled reaction index to a full reaction index.
|
||||
@@ -248,7 +248,7 @@ namespace gridfire{
|
||||
*
|
||||
* @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;
|
||||
[[nodiscard]] size_t mapViewToFullReactionIndex(size_t definedReactionIndex) const;
|
||||
|
||||
void validateNetworkState() const;
|
||||
|
||||
@@ -263,8 +263,8 @@ namespace gridfire{
|
||||
const std::string& fileName,
|
||||
const io::NetworkFileParser& parser
|
||||
);
|
||||
std::string getNetworkFile() const { return m_fileName; }
|
||||
const io::NetworkFileParser& getParser() const { return m_parser; }
|
||||
[[nodiscard]] std::string getNetworkFile() const { return m_fileName; }
|
||||
[[nodiscard]] const io::NetworkFileParser& getParser() const { return m_parser; }
|
||||
private:
|
||||
using Config = fourdst::config::Config;
|
||||
using LogManager = fourdst::logging::LogManager;
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace gridfire {
|
||||
* This method combines the hashes of the binned temperature, density, and
|
||||
* each species abundance. The `bin()` static method is used for discretization.
|
||||
*/
|
||||
size_t hash() const;
|
||||
[[nodiscard]] size_t hash() const;
|
||||
|
||||
/**
|
||||
* @brief Converts a value to a discrete bin based on a tolerance.
|
||||
@@ -110,9 +110,8 @@ namespace gridfire {
|
||||
}
|
||||
|
||||
// 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> {
|
||||
struct std::hash<gridfire::QSECacheKey> {
|
||||
/**
|
||||
* @brief Computes the hash of a QSECacheKey for use in `std::unordered_map`.
|
||||
* @param key The QSECacheKey to hash.
|
||||
@@ -122,8 +121,7 @@ namespace std {
|
||||
// The hash is pre-computed, so we just return it.
|
||||
return key.m_hash;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
}; // namespace std
|
||||
|
||||
namespace gridfire {
|
||||
/**
|
||||
@@ -356,7 +354,7 @@ namespace gridfire {
|
||||
* @return A const reference to the `LogicalReactionSet` from the base engine,
|
||||
* containing all reactions in the full network.
|
||||
*/
|
||||
[[nodiscard]] const reaction::LogicalReactionSet & getNetworkReactions() const override;
|
||||
[[nodiscard]] const reaction::ReactionSet & getNetworkReactions() const override;
|
||||
|
||||
/**
|
||||
* @brief Sets the set of logical reactions in the network.
|
||||
@@ -375,7 +373,7 @@ namespace gridfire {
|
||||
* @throws exceptions::UnableToSetNetworkReactionsError Always.
|
||||
*/
|
||||
void setNetworkReactions(
|
||||
const reaction::LogicalReactionSet &reactions
|
||||
const reaction::ReactionSet &reactions
|
||||
) override;
|
||||
|
||||
/**
|
||||
@@ -615,7 +613,7 @@ namespace gridfire {
|
||||
* @par How
|
||||
* This method delegates directly to the base engine's `getSpeciesIndex()`.
|
||||
*/
|
||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
[[nodiscard]] size_t getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
/**
|
||||
* @brief Maps a `NetIn` struct to a molar abundance vector for the full network.
|
||||
@@ -841,12 +839,12 @@ namespace gridfire {
|
||||
* @brief Gets the number of output values from the functor (size of the residual vector).
|
||||
* @return The number of algebraic species being solved.
|
||||
*/
|
||||
[[nodiscard]] int values() const { return m_qse_solve_indices.size(); }
|
||||
[[nodiscard]] size_t values() const { return m_qse_solve_indices.size(); }
|
||||
/**
|
||||
* @brief Gets the number of input values to the functor (size of the variable vector).
|
||||
* @return The number of algebraic species being solved.
|
||||
*/
|
||||
[[nodiscard]] int inputs() const { return m_qse_solve_indices.size(); }
|
||||
[[nodiscard]] size_t inputs() const { return m_qse_solve_indices.size(); }
|
||||
|
||||
/**
|
||||
* @brief Evaluates the functor's residual vector `f_qse = dY_alg/dt`.
|
||||
@@ -1038,25 +1036,6 @@ namespace gridfire {
|
||||
double rho
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Builds a connectivity graph from a set of fast reaction indices.
|
||||
*
|
||||
* @param fast_reaction_indices A set of indices for reactions considered "fast".
|
||||
* @return An unordered map representing the adjacency list of the connectivity graph,
|
||||
* where keys are species indices and values are vectors of connected species indices.
|
||||
*
|
||||
* @par Purpose
|
||||
* To represent the reaction pathways among a subset of reactions.
|
||||
*
|
||||
* @par How
|
||||
* It iterates through the specified fast reactions. For each reaction, it creates
|
||||
* a two-way edge in the graph between every reactant and every product, signifying
|
||||
* that mass can flow between them.
|
||||
*/
|
||||
std::unordered_map<size_t, std::vector<size_t>> buildConnectivityGraph(
|
||||
const std::unordered_set<size_t> &fast_reaction_indices
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Validates candidate QSE groups using flux analysis.
|
||||
*
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
#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"
|
||||
|
||||
@@ -66,7 +64,7 @@ namespace gridfire {
|
||||
* @return Vector of reaction name strings containing the priming species.
|
||||
* @throws std::runtime_error If no reactions involve the priming species.
|
||||
*/
|
||||
std::vector<std::string> constructPrimingReactionSet(
|
||||
[[nodiscard]] std::vector<std::string> constructPrimingReactionSet(
|
||||
const fourdst::atomic::Species& primingSpecies,
|
||||
const DynamicEngine& baseEngine
|
||||
) const;
|
||||
|
||||
11
src/include/gridfire/interfaces/solver/solver_interfaces.h
Normal file
11
src/include/gridfire/interfaces/solver/solver_interfaces.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "fourdst/plugin/plugin.h"
|
||||
|
||||
class SolverPluginInterface : public fourdst::plugin::PluginBase {
|
||||
public:
|
||||
using PluginBase::PluginBase;
|
||||
|
||||
~SolverPluginInterface() override = default;
|
||||
virtual void log_time(double t, double dt) = 0;
|
||||
};
|
||||
@@ -28,8 +28,6 @@
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/constants/const.h"
|
||||
|
||||
#include "gridfire/reaction/reaction.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace gridfire::partition {
|
||||
* @return Dimensionless partition function value = 2*spin + 1.
|
||||
* @throws std::out_of_range If the isotope key is not found in m_ground_state_spin.
|
||||
+ */
|
||||
double evaluate(
|
||||
[[nodiscard]] double evaluate(
|
||||
const int z,
|
||||
const int a,
|
||||
const double T9
|
||||
@@ -57,7 +57,7 @@ namespace gridfire::partition {
|
||||
* @return Zero.
|
||||
* @throws std::out_of_range If the isotope key is not found.
|
||||
+ */
|
||||
double evaluateDerivative(
|
||||
[[nodiscard]] double evaluateDerivative(
|
||||
const int z,
|
||||
const int a,
|
||||
const double T9
|
||||
@@ -70,7 +70,7 @@ namespace gridfire::partition {
|
||||
* @return True if m_ground_state_spin contains the key; false otherwise.
|
||||
* @post No side effects.
|
||||
+ */
|
||||
bool supports(
|
||||
[[nodiscard]] bool supports(
|
||||
const int z,
|
||||
const int a
|
||||
) const override;
|
||||
@@ -79,13 +79,13 @@ namespace gridfire::partition {
|
||||
* @return The string literal "GroundState".
|
||||
* @post No side effects.
|
||||
+ */
|
||||
std::string type() const override { return "GroundState"; }
|
||||
[[nodiscard]] std::string type() const override { return "GroundState"; }
|
||||
/**
|
||||
* @brief Create a deep copy of this partition function.
|
||||
* @return Unique_ptr to a new GroundStatePartitionFunction cloned from this object.
|
||||
* @post Caller owns the returned instance.
|
||||
+ */
|
||||
std::unique_ptr<PartitionFunction> clone() const override {
|
||||
[[nodiscard]] std::unique_ptr<PartitionFunction> clone() const override {
|
||||
return std::make_unique<GroundStatePartitionFunction>(*this);
|
||||
}
|
||||
private:
|
||||
@@ -94,15 +94,13 @@ namespace gridfire::partition {
|
||||
/**
|
||||
* @brief Generate a unique lookup key for an isotope.
|
||||
+ *
|
||||
* Combines atomic number z and mass number a into a single integer.
|
||||
* Combines atomic number z and mass number an into a single integer.
|
||||
* @param z Proton number of the isotope.
|
||||
* @param a Mass number of the isotope; should be < 1000 to avoid collisions.
|
||||
* @pre a < 1000.
|
||||
* @return Integer key = z * 1000 + a.
|
||||
+ */
|
||||
static constexpr int make_key(
|
||||
const int z,
|
||||
const int a);
|
||||
static constexpr int make_key(int z, int a);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
#include "fourdst/logging/logging.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
namespace gridfire::partition {
|
||||
@@ -45,7 +43,7 @@ namespace gridfire::partition {
|
||||
* @post No side effects.
|
||||
* @throws std::out_of_range If isotope key not found in m_partitionData.
|
||||
*/
|
||||
double evaluate(int z, int a, double T9) const override;
|
||||
[[nodiscard]] double evaluate(int z, int a, double T9) const override;
|
||||
/**
|
||||
* @brief Evaluate temperature derivative of partition function.
|
||||
*
|
||||
@@ -58,7 +56,7 @@ namespace gridfire::partition {
|
||||
* @post No side effects.
|
||||
* @throws std::out_of_range If isotope data is missing.
|
||||
*/
|
||||
double evaluateDerivative(int z, int a, double T9) const override;
|
||||
[[nodiscard]] double evaluateDerivative(int z, int a, double T9) const override;
|
||||
/**
|
||||
* @brief Check if partition data exists for given isotope.
|
||||
* @param z Atomic number.
|
||||
@@ -66,19 +64,19 @@ namespace gridfire::partition {
|
||||
* @return true if data available; false otherwise.
|
||||
* @post No side effects.
|
||||
*/
|
||||
bool supports(int z, int a) const override;
|
||||
[[nodiscard]] bool supports(int z, int a) const override;
|
||||
/**
|
||||
* @brief Get type identifier for this partition function.
|
||||
* @return Literal string "RauscherThielemann".
|
||||
* @post No side effects.
|
||||
*/
|
||||
std::string type() const override { return "RauscherThielemann"; }
|
||||
[[nodiscard]] std::string type() const override { return "RauscherThielemann"; }
|
||||
/**
|
||||
* @brief Clone this partition function instance.
|
||||
* @return Unique pointer to a copy of this object.
|
||||
* @post Caller owns the returned object.
|
||||
*/
|
||||
std::unique_ptr<PartitionFunction> clone() const override {
|
||||
[[nodiscard]] std::unique_ptr<PartitionFunction> clone() const override {
|
||||
return std::make_unique<RauscherThielemannPartitionFunction>(*this);
|
||||
}
|
||||
private:
|
||||
@@ -132,7 +130,7 @@ namespace gridfire::partition {
|
||||
* @return IdentifiedIsotope with data reference and indices.
|
||||
* @throws std::out_of_range If isotope not found in m_partitionData.
|
||||
*/
|
||||
IdentifiedIsotope find(int z, int a, double T9) const;
|
||||
[[nodiscard]] IdentifiedIsotope find(int z, int a, double T9) const;
|
||||
/**
|
||||
* @brief Generate integer key for isotope (z,a).
|
||||
* @param z Atomic number.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// ReSharper disable once CppUnusedIncludeDirective
|
||||
#include <cstdint>
|
||||
|
||||
namespace gridfire::partition::record {
|
||||
|
||||
@@ -14,6 +14,6 @@ namespace gridfire::reaclib {
|
||||
*
|
||||
* @return A constant reference to the application-wide reaction set.
|
||||
*/
|
||||
const reaction::LogicalReactionSet& get_all_reactions();
|
||||
const reaction::ReactionSet &get_all_reaclib_reactions();
|
||||
|
||||
} // namespace gridfire::reaclib
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
|
||||
#include "cppad/cppad.hpp"
|
||||
#include "xxhash64.h"
|
||||
|
||||
/**
|
||||
* @file reaction.h
|
||||
@@ -20,9 +19,14 @@
|
||||
* This file contains the core data structures for handling nuclear reactions,
|
||||
* including individual reactions from specific sources (`Reaction`), collections
|
||||
* of reactions (`ReactionSet`), and logical reactions that aggregate rates from
|
||||
* multiple sources (`LogicalReaction`, `LogicalReactionSet`).
|
||||
* multiple sources (`LogicalReaclibReaction`, `LogicalReactionSet`).
|
||||
*/
|
||||
namespace gridfire::reaction {
|
||||
enum class ReactionType {
|
||||
WEAK,
|
||||
REACLIB,
|
||||
LOGICAL_REACLIB,
|
||||
};
|
||||
/**
|
||||
* @struct RateCoefficientSet
|
||||
* @brief Holds the seven coefficients for the REACLIB rate equation.
|
||||
@@ -69,13 +73,51 @@ namespace gridfire::reaction {
|
||||
* double rate = p_gamma_d.calculate_rate(0.1); // T9 = 0.1
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
class Reaction {
|
||||
public:
|
||||
/**
|
||||
* @brief Virtual destructor.
|
||||
*/
|
||||
virtual ~Reaction() = default;
|
||||
|
||||
[[nodiscard]] virtual double calculate_rate(double T9, double rho, const std::vector<double>& Y) const = 0;
|
||||
[[nodiscard]] virtual CppAD::AD<double> calculate_rate(CppAD::AD<double> T9, CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::string_view id() const = 0;
|
||||
[[nodiscard]] virtual const std::vector<fourdst::atomic::Species>& reactants() const = 0;
|
||||
[[nodiscard]] virtual const std::vector<fourdst::atomic::Species>& products() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool contains(const fourdst::atomic::Species& species) const = 0;
|
||||
[[nodiscard]] virtual bool contains_reactant(const fourdst::atomic::Species& species) const = 0;
|
||||
[[nodiscard]] virtual bool contains_product(const fourdst::atomic::Species& species) const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool is_reverse() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::unordered_set<fourdst::atomic::Species> all_species() const = 0;
|
||||
[[nodiscard]] virtual std::unordered_set<fourdst::atomic::Species> reactant_species() const = 0;
|
||||
[[nodiscard]] virtual std::unordered_set<fourdst::atomic::Species> product_species() const = 0;
|
||||
|
||||
[[nodiscard]] virtual size_t num_species() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::unordered_map<fourdst::atomic::Species, int> stoichiometry() const = 0;
|
||||
[[nodiscard]] virtual int stoichiometry(const fourdst::atomic::Species& species) const = 0;
|
||||
|
||||
[[nodiscard]] virtual uint64_t hash(uint64_t seed) const = 0;
|
||||
|
||||
[[nodiscard]] virtual double qValue() const = 0;
|
||||
[[nodiscard]] virtual double calculate_forward_rate_log_derivative(double T9, double rho, const std::vector<double>& Y) const = 0;
|
||||
|
||||
[[nodiscard]] virtual ReactionType type() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::unique_ptr<Reaction> clone() const = 0;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Reaction& r) {
|
||||
os << "Reaction(ID: " << r.id() << ")";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
class ReaclibReaction : public Reaction {
|
||||
public:
|
||||
~ReaclibReaction() override = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a Reaction object.
|
||||
* @param id A unique identifier for the reaction.
|
||||
@@ -88,7 +130,7 @@ namespace gridfire::reaction {
|
||||
* @param sets The set of rate coefficients.
|
||||
* @param reverse True if this is a reverse reaction rate.
|
||||
*/
|
||||
Reaction(
|
||||
ReaclibReaction(
|
||||
const std::string_view id,
|
||||
const std::string_view peName,
|
||||
const int chapter,
|
||||
@@ -102,18 +144,22 @@ namespace gridfire::reaction {
|
||||
/**
|
||||
* @brief Calculates the reaction rate for a given temperature.
|
||||
* @param T9 The temperature in units of 10^9 K.
|
||||
* @param rho Density [Not used in this implementation].
|
||||
* @param Y Molar abundances of species [Not used in this implementation].
|
||||
* @return The calculated reaction rate.
|
||||
*/
|
||||
[[nodiscard]] virtual double calculate_rate(const double T9) const;
|
||||
[[nodiscard]] double calculate_rate(double T9, double rho, const std::vector<double>& Y) const override;
|
||||
|
||||
/**
|
||||
* @brief Calculates the reaction rate for a given temperature using CppAD types.
|
||||
* @param T9 The temperature in units of 10^9 K, as a CppAD::AD<double>.
|
||||
* @param rho Density, as a CppAD::AD<double> [Not used in this implementation].
|
||||
* @param Y Molar abundances of species, as a vector of CppAD::AD<double> [Not used in this implementation].
|
||||
* @return The calculated reaction rate, as a CppAD::AD<double>.
|
||||
*/
|
||||
[[nodiscard]] virtual CppAD::AD<double> calculate_rate(const CppAD::AD<double> T9) const;
|
||||
[[nodiscard]] CppAD::AD<double> calculate_rate(CppAD::AD<double> T9, CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const override;
|
||||
|
||||
[[nodiscard]] virtual double calculate_forward_rate_log_derivative(const double T9) const;
|
||||
[[nodiscard]] double calculate_forward_rate_log_derivative(double T9, double rho, const std::vector<double>& Y) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the reaction name in (projectile, ejectile) notation.
|
||||
@@ -133,6 +179,8 @@ namespace gridfire::reaction {
|
||||
*/
|
||||
[[nodiscard]] std::string_view sourceLabel() const { return m_sourceLabel; }
|
||||
|
||||
[[nodiscard]] ReactionType type() const override { return ReactionType::REACLIB; }
|
||||
|
||||
/**
|
||||
* @brief Gets the set of rate coefficients.
|
||||
* @return A const reference to the RateCoefficientSet.
|
||||
@@ -144,88 +192,88 @@ namespace gridfire::reaction {
|
||||
* @param species The species to check for.
|
||||
* @return True if the species is involved, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const fourdst::atomic::Species& species) const;
|
||||
[[nodiscard]] bool contains(const fourdst::atomic::Species& species) const override;
|
||||
|
||||
/**
|
||||
* @brief Checks if the reaction involves a given species as a reactant.
|
||||
* @param species The species to check for.
|
||||
* @return True if the species is a reactant, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains_reactant(const fourdst::atomic::Species& species) const;
|
||||
[[nodiscard]] bool contains_reactant(const fourdst::atomic::Species& species) const override;
|
||||
|
||||
/**
|
||||
* @brief Checks if the reaction involves a given species as a product.
|
||||
* @param species The species to check for.
|
||||
* @return True if the species is a product, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains_product(const fourdst::atomic::Species& species) const;
|
||||
[[nodiscard]] bool contains_product(const fourdst::atomic::Species& species) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets a set of all unique species involved in the reaction.
|
||||
* @return An unordered_set of all reactant and product species.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> all_species() const;
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> all_species() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets a set of all unique reactant species.
|
||||
* @return An unordered_set of reactant species.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> reactant_species() const;
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> reactant_species() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets a set of all unique product species.
|
||||
* @return An unordered_set of product species.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> product_species() const;
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> product_species() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of unique species involved in the reaction.
|
||||
* @return The count of unique species.
|
||||
*/
|
||||
[[nodiscard]] size_t num_species() const;
|
||||
[[nodiscard]] size_t num_species() const override;
|
||||
|
||||
/**
|
||||
* @brief Calculates the stoichiometric coefficient for a given species.
|
||||
* @param species The species for which to find the coefficient.
|
||||
* @return The stoichiometric coefficient (negative for reactants, positive for products).
|
||||
*/
|
||||
[[nodiscard]] int stoichiometry(const fourdst::atomic::Species& species) const;
|
||||
[[nodiscard]] int stoichiometry(const fourdst::atomic::Species& species) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets a map of all species to their stoichiometric coefficients.
|
||||
* @return An unordered_map from species to their integer coefficients.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_map<fourdst::atomic::Species, int> stoichiometry() const;
|
||||
[[nodiscard]] std::unordered_map<fourdst::atomic::Species, int> stoichiometry() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the unique identifier of the reaction.
|
||||
* @return The reaction ID.
|
||||
*/
|
||||
[[nodiscard]] std::string_view id() const { return m_id; }
|
||||
[[nodiscard]] std::string_view id() const override { return m_id; }
|
||||
|
||||
/**
|
||||
* @brief Gets the Q-value of the reaction.
|
||||
* @return The Q-value in whatever units the reaction was defined in (usually MeV).
|
||||
*/
|
||||
[[nodiscard]] double qValue() const { return m_qValue; }
|
||||
[[nodiscard]] double qValue() const override { return m_qValue; }
|
||||
|
||||
/**
|
||||
* @brief Gets the vector of reactant species.
|
||||
* @return A const reference to the vector of reactants.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& reactants() const { return m_reactants; }
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& reactants() const override { return m_reactants; }
|
||||
|
||||
/**
|
||||
* @brief Gets the vector of product species.
|
||||
* @return A const reference to the vector of products.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& products() const { return m_products; }
|
||||
[[nodiscard]] const std::vector<fourdst::atomic::Species>& products() const override { return m_products; }
|
||||
|
||||
/**
|
||||
* @brief Checks if this is a reverse reaction rate.
|
||||
* @return True if it is a reverse rate, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_reverse() const { return m_reverse; }
|
||||
[[nodiscard]] bool is_reverse() const override { return m_reverse; }
|
||||
|
||||
/**
|
||||
* @brief Calculates the excess energy from the mass difference of reactants and products.
|
||||
@@ -238,14 +286,14 @@ namespace gridfire::reaction {
|
||||
* @param other The other Reaction to compare with.
|
||||
* @return True if the reaction IDs are the same.
|
||||
*/
|
||||
bool operator==(const Reaction& other) const { return m_id == other.m_id; }
|
||||
bool operator==(const ReaclibReaction& other) const { return m_id == other.m_id; }
|
||||
|
||||
/**
|
||||
* @brief Compares this reaction with another for inequality.
|
||||
* @param other The other Reaction to compare with.
|
||||
* @return True if the reactions are not equal.
|
||||
*/
|
||||
bool operator!=(const Reaction& other) const { return !(*this == other); }
|
||||
bool operator!=(const ReaclibReaction& other) const { return !(*this == other); }
|
||||
|
||||
/**
|
||||
* @brief Computes a hash for the reaction based on its ID.
|
||||
@@ -253,10 +301,12 @@ namespace gridfire::reaction {
|
||||
* @return A 64-bit hash value.
|
||||
* @details Uses the XXHash64 algorithm on the reaction's ID string.
|
||||
*/
|
||||
[[nodiscard]] uint64_t hash(uint64_t seed = 0) const;
|
||||
[[nodiscard]] uint64_t hash(uint64_t seed) const override;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Reaction& r) {
|
||||
return os << "(Reaction:" << r.m_id << ")";
|
||||
[[nodiscard]] std::unique_ptr<Reaction> clone() const override;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const ReaclibReaction& r) {
|
||||
return os << "(ReaclibReaction:" << r.m_id << ")";
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -296,25 +346,24 @@ namespace gridfire::reaction {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @class LogicalReaction
|
||||
* @class LogicalReaclibReaction
|
||||
* @brief Represents a "logical" reaction that aggregates rates from multiple sources.
|
||||
*
|
||||
* A LogicalReaction shares the same reactants and products but combines rates
|
||||
* A LogicalReaclibReaction shares the same reactants and products but combines rates
|
||||
* from different evaluations (e.g., "wc12" and "st08" for the same physical
|
||||
* reaction). The total rate is the sum of the individual rates.
|
||||
* It inherits from Reaction, using the properties of the first provided reaction
|
||||
* as its base properties (reactants, products, Q-value, etc.).
|
||||
*/
|
||||
class LogicalReaction final : public Reaction {
|
||||
class LogicalReaclibReaction final : public ReaclibReaction {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a LogicalReaction from a vector of `Reaction` objects.
|
||||
* @param reactions A vector of reactions that represent the same logical process.
|
||||
* @throws std::runtime_error if the provided reactions have inconsistent Q-values.
|
||||
*/
|
||||
explicit LogicalReaction(const std::vector<Reaction> &reactions);
|
||||
explicit LogicalReaclibReaction(const std::vector<ReaclibReaction> &reactions);
|
||||
|
||||
/**
|
||||
* @brief Adds another `Reaction` source to this logical reaction.
|
||||
@@ -322,7 +371,7 @@ namespace gridfire::reaction {
|
||||
* @throws std::runtime_error if the reaction has a different `peName`, a duplicate
|
||||
* source label, or an inconsistent Q-value.
|
||||
*/
|
||||
void add_reaction(const Reaction& reaction);
|
||||
void add_reaction(const ReaclibReaction& reaction);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of source rates contributing to this logical reaction.
|
||||
@@ -339,18 +388,26 @@ namespace gridfire::reaction {
|
||||
/**
|
||||
* @brief Calculates the total reaction rate by summing all source rates.
|
||||
* @param T9 The temperature in units of 10^9 K.
|
||||
* @param rho
|
||||
* @param Y
|
||||
* @return The total calculated reaction rate.
|
||||
*/
|
||||
[[nodiscard]] double calculate_rate(const double T9) const override;
|
||||
[[nodiscard]] double calculate_rate(double T9, double rho, const std::vector<double>& Y) const override;
|
||||
|
||||
[[nodiscard]] virtual double calculate_forward_rate_log_derivative(const double T9) const override;
|
||||
[[nodiscard]] double calculate_forward_rate_log_derivative(double T9, double rho, const std::vector<double>& Y) const override;
|
||||
|
||||
[[nodiscard]] ReactionType type() const override { return ReactionType::LOGICAL_REACLIB; }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Reaction> clone() const override;
|
||||
|
||||
/**
|
||||
* @brief Calculates the total reaction rate using CppAD types.
|
||||
* @param T9 The temperature in units of 10^9 K, as a CppAD::AD<double>.
|
||||
* @param rho
|
||||
* @param Y
|
||||
* @return The total calculated reaction rate, as a CppAD::AD<double>.
|
||||
*/
|
||||
[[nodiscard]] CppAD::AD<double> calculate_rate(const CppAD::AD<double> T9) const override;
|
||||
[[nodiscard]] CppAD::AD<double> calculate_rate(CppAD::AD<double> T9, CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const override;
|
||||
|
||||
/** @name Iterators
|
||||
* Provides iterators to loop over the rate coefficient sets.
|
||||
@@ -363,8 +420,8 @@ namespace gridfire::reaction {
|
||||
///@}
|
||||
///
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const LogicalReaction& r) {
|
||||
os << "(LogicalReaction: " << r.id() << ", reverse: " << r.is_reverse() << ")";
|
||||
friend std::ostream& operator<<(std::ostream& os, const LogicalReaclibReaction& r) {
|
||||
os << "(LogicalReaclibReaction: " << r.id() << ", reverse: " << r.is_reverse() << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -402,41 +459,44 @@ namespace gridfire::reaction {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ReactionT>
|
||||
class TemplatedReactionSet final {
|
||||
class ReactionSet final {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a ReactionSet from a vector of reactions.
|
||||
* @param reactions The initial vector of Reaction objects.
|
||||
*/
|
||||
explicit TemplatedReactionSet(std::vector<ReactionT> reactions);
|
||||
explicit ReactionSet(std::vector<std::unique_ptr<Reaction>>&& reactions);
|
||||
|
||||
TemplatedReactionSet();
|
||||
explicit ReactionSet(const std::vector<Reaction*>& reactions);
|
||||
|
||||
ReactionSet();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The ReactionSet to copy.
|
||||
*/
|
||||
TemplatedReactionSet(const TemplatedReactionSet<ReactionT>& other);
|
||||
ReactionSet(const ReactionSet& other);
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The ReactionSet to assign from.
|
||||
* @return A reference to this ReactionSet.
|
||||
*/
|
||||
TemplatedReactionSet<ReactionT>& operator=(const TemplatedReactionSet<ReactionT>& other);
|
||||
ReactionSet& operator=(const ReactionSet& other);
|
||||
|
||||
/**
|
||||
* @brief Adds a reaction to the set.
|
||||
* @param reaction The Reaction to add.
|
||||
*/
|
||||
void add_reaction(ReactionT reaction);
|
||||
void add_reaction(const Reaction& reaction);
|
||||
|
||||
void add_reaction(std::unique_ptr<Reaction>&& reaction);
|
||||
|
||||
/**
|
||||
* @brief Removes a reaction from the set.
|
||||
* @param reaction The Reaction to remove.
|
||||
*/
|
||||
void remove_reaction(const ReactionT& reaction);
|
||||
void remove_reaction(const Reaction& reaction);
|
||||
|
||||
/**
|
||||
* @brief Checks if the set contains a reaction with the given ID.
|
||||
@@ -490,7 +550,7 @@ namespace gridfire::reaction {
|
||||
* @return A const reference to the Reaction.
|
||||
* @throws std::out_of_range if the index is out of bounds.
|
||||
*/
|
||||
[[nodiscard]] const ReactionT& operator[](size_t index) const;
|
||||
[[nodiscard]] const Reaction& operator[](size_t index) const;
|
||||
|
||||
/**
|
||||
* @brief Accesses a reaction by its ID.
|
||||
@@ -498,21 +558,21 @@ namespace gridfire::reaction {
|
||||
* @return A const reference to the Reaction.
|
||||
* @throws std::out_of_range if no reaction with the given ID exists.
|
||||
*/
|
||||
[[nodiscard]] const ReactionT& operator[](const std::string_view& id) const;
|
||||
[[nodiscard]] const Reaction& operator[](const std::string_view& id) const;
|
||||
|
||||
/**
|
||||
* @brief Compares this set with another for equality.
|
||||
* @param other The other ReactionSet to compare with.
|
||||
* @return True if the sets are equal (same size and hash).
|
||||
*/
|
||||
bool operator==(const TemplatedReactionSet& other) const;
|
||||
bool operator==(const ReactionSet& other) const;
|
||||
|
||||
/**
|
||||
* @brief Compares this set with another for inequality.
|
||||
* @param other The other ReactionSet to compare with.
|
||||
* @return True if the sets are not equal.
|
||||
*/
|
||||
bool operator!=(const TemplatedReactionSet& other) const;
|
||||
bool operator!=(const ReactionSet& other) const;
|
||||
|
||||
/**
|
||||
* @brief Computes a hash for the entire set.
|
||||
@@ -522,7 +582,7 @@ namespace gridfire::reaction {
|
||||
* sorts the hashes, and then computes a final hash over the sorted list
|
||||
* of hashes. This ensures the hash is order-independent.
|
||||
*/
|
||||
[[nodiscard]] uint64_t hash(uint64_t seed = 0) const;
|
||||
[[nodiscard]] uint64_t hash(uint64_t seed) const;
|
||||
|
||||
/** @name Iterators
|
||||
* Provides iterators to loop over the reactions in the set.
|
||||
@@ -534,210 +594,30 @@ namespace gridfire::reaction {
|
||||
[[nodiscard]] auto end() const { return m_reactions.cend(); }
|
||||
///@}
|
||||
///
|
||||
friend std::ostream& operator<<(std::ostream& os, const TemplatedReactionSet<ReactionT>& r) {
|
||||
os << "(ReactionSet: [";
|
||||
size_t counter = 0;
|
||||
for (const auto& reaction : r.m_reactions) {
|
||||
os << reaction;
|
||||
if (counter < r.m_reactions.size() - 2) {
|
||||
os << ", ";
|
||||
} else if (counter == r.m_reactions.size() - 2) {
|
||||
os << " and ";
|
||||
}
|
||||
++counter;
|
||||
}
|
||||
os << "])";
|
||||
return os;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unordered_set<fourdst::atomic::Species> getReactionSetSpecies() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const ReactionSet& rs) {
|
||||
os << "(ReactionSet: {";
|
||||
int i = 0;
|
||||
for (const auto& reaction : rs.m_reactions) {
|
||||
os << *reaction;
|
||||
if (i < rs.m_reactions.size() - 1) {
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
os << "})";
|
||||
return os;
|
||||
}
|
||||
private:
|
||||
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||
std::vector<ReactionT> m_reactions;
|
||||
std::vector<std::unique_ptr<Reaction>> m_reactions;
|
||||
std::string m_id;
|
||||
std::unordered_map<std::string, ReactionT> m_reactionNameMap; ///< Maps reaction IDs to Reaction objects for quick lookup.
|
||||
std::unordered_map<std::string, size_t> m_reactionNameMap; ///< Maps reaction IDs to Reaction objects for quick lookup.
|
||||
|
||||
};
|
||||
|
||||
using ReactionSet = TemplatedReactionSet<Reaction>; ///< A set of reactions, typically from a single source like REACLIB.
|
||||
using LogicalReactionSet = TemplatedReactionSet<LogicalReaction>; ///< A set of logical reactions.
|
||||
ReactionSet packReactionSet(const ReactionSet& reactionSet);
|
||||
|
||||
LogicalReactionSet packReactionSetToLogicalReactionSet(const ReactionSet& reactionSet);
|
||||
|
||||
template <typename ReactionT>
|
||||
TemplatedReactionSet<ReactionT>::TemplatedReactionSet(
|
||||
std::vector<ReactionT> reactions
|
||||
) :
|
||||
m_reactions(std::move(reactions)) {
|
||||
if (m_reactions.empty()) {
|
||||
return; // Case where the reactions will be added later.
|
||||
}
|
||||
m_reactionNameMap.reserve(reactions.size());
|
||||
for (const auto& reaction : m_reactions) {
|
||||
m_id += reaction.id();
|
||||
m_reactionNameMap.emplace(reaction.id(), reaction);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ReactionT>
|
||||
TemplatedReactionSet<ReactionT>::TemplatedReactionSet() {}
|
||||
|
||||
template <typename ReactionT>
|
||||
TemplatedReactionSet<ReactionT>::TemplatedReactionSet(const TemplatedReactionSet<ReactionT> &other) {
|
||||
m_reactions.reserve(other.m_reactions.size());
|
||||
for (const auto& reaction_ptr: other.m_reactions) {
|
||||
m_reactions.push_back(reaction_ptr);
|
||||
}
|
||||
|
||||
m_reactionNameMap.reserve(other.m_reactionNameMap.size());
|
||||
for (const auto& reaction_ptr : m_reactions) {
|
||||
m_reactionNameMap.emplace(reaction_ptr.id(), reaction_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
TemplatedReactionSet<ReactionT>& TemplatedReactionSet<ReactionT>::operator=(const TemplatedReactionSet<ReactionT> &other) {
|
||||
if (this != &other) {
|
||||
TemplatedReactionSet temp(other);
|
||||
std::swap(m_reactions, temp.m_reactions);
|
||||
std::swap(m_reactionNameMap, temp.m_reactionNameMap);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
void TemplatedReactionSet<ReactionT>::add_reaction(ReactionT reaction) {
|
||||
m_reactions.emplace_back(reaction);
|
||||
m_id += m_reactions.back().id();
|
||||
m_reactionNameMap.emplace(m_reactions.back().id(), m_reactions.back());
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
void TemplatedReactionSet<ReactionT>::remove_reaction(const ReactionT& reaction) {
|
||||
if (!m_reactionNameMap.contains(std::string(reaction.id()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_reactionNameMap.erase(std::string(reaction.id()));
|
||||
|
||||
std::erase_if(m_reactions, [&reaction](const Reaction& r) {
|
||||
return r == reaction;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::contains(const std::string_view& id) const {
|
||||
for (const auto& reaction : m_reactions) {
|
||||
if (reaction.id() == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::contains(const Reaction& reaction) const {
|
||||
for (const auto& r : m_reactions) {
|
||||
if (r == reaction) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
void TemplatedReactionSet<ReactionT>::clear() {
|
||||
m_reactions.clear();
|
||||
m_reactionNameMap.clear();
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::contains_species(const fourdst::atomic::Species& species) const {
|
||||
for (const auto& reaction : m_reactions) {
|
||||
if (reaction.contains(species)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::contains_reactant(const fourdst::atomic::Species& species) const {
|
||||
for (const auto& r : m_reactions) {
|
||||
if (r.contains_reactant(species)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::contains_product(const fourdst::atomic::Species& species) const {
|
||||
for (const auto& r : m_reactions) {
|
||||
if (r.contains_product(species)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
const ReactionT& TemplatedReactionSet<ReactionT>::operator[](const size_t index) const {
|
||||
if (index >= m_reactions.size()) {
|
||||
m_logger -> flush_log();
|
||||
throw std::out_of_range("Index" + std::to_string(index) + " out of range for ReactionSet of size " + std::to_string(m_reactions.size()) + ".");
|
||||
}
|
||||
return m_reactions[index];
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
const ReactionT& TemplatedReactionSet<ReactionT>::operator[](const std::string_view& id) const {
|
||||
if (auto it = m_reactionNameMap.find(std::string(id)); it != m_reactionNameMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
m_logger -> flush_log();
|
||||
throw std::out_of_range("Species " + std::string(id) + " does not exist in ReactionSet.");
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::operator==(const TemplatedReactionSet<ReactionT>& other) const {
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
return hash() == other.hash();
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
bool TemplatedReactionSet<ReactionT>::operator!=(const TemplatedReactionSet<ReactionT>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename ReactionT>
|
||||
uint64_t TemplatedReactionSet<ReactionT>::hash(uint64_t seed) const {
|
||||
if (m_reactions.empty()) {
|
||||
return XXHash64::hash(nullptr, 0, seed);
|
||||
}
|
||||
std::vector<uint64_t> individualReactionHashes;
|
||||
individualReactionHashes.reserve(m_reactions.size());
|
||||
for (const auto& reaction : m_reactions) {
|
||||
individualReactionHashes.push_back(reaction.hash(seed));
|
||||
}
|
||||
|
||||
std::ranges::sort(individualReactionHashes);
|
||||
|
||||
const auto data = static_cast<const void*>(individualReactionHashes.data());
|
||||
const size_t sizeInBytes = individualReactionHashes.size() * sizeof(uint64_t);
|
||||
return XXHash64::hash(data, sizeInBytes, seed);
|
||||
}
|
||||
|
||||
template<typename ReactionT>
|
||||
std::unordered_set<fourdst::atomic::Species> TemplatedReactionSet<ReactionT>::getReactionSetSpecies() const {
|
||||
std::unordered_set<fourdst::atomic::Species> species;
|
||||
for (const auto& reaction : m_reactions) {
|
||||
const auto reactionSpecies = reaction.all_species();
|
||||
species.insert(reactionSpecies.begin(), reactionSpecies.end());
|
||||
}
|
||||
return species;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
58
src/include/gridfire/reaction/weak/weak.h
Normal file
58
src/include/gridfire/reaction/weak/weak.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <expected>
|
||||
|
||||
namespace gridfire::rates::weak {
|
||||
enum class WeakReactionType {
|
||||
BETA_PLUS_DECAY,
|
||||
BETA_MINUS_DECAY,
|
||||
ELECTRON_CAPTURE,
|
||||
POSITRON_CAPTURE,
|
||||
};
|
||||
|
||||
inline std::unordered_map<WeakReactionType, std::string> WeakReactionTypeNames = {
|
||||
{WeakReactionType::BETA_PLUS_DECAY, "β+ Decay"},
|
||||
{WeakReactionType::BETA_MINUS_DECAY, "β- Decay"},
|
||||
{WeakReactionType::ELECTRON_CAPTURE, "e- Capture"},
|
||||
{WeakReactionType::POSITRON_CAPTURE, "e+ Capture"},
|
||||
};
|
||||
|
||||
struct WeakReaction {
|
||||
WeakReactionType type;
|
||||
float T9;
|
||||
float log_rhoYe;
|
||||
float mu_e;
|
||||
float log_rate;
|
||||
float log_neutrino_loss;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const WeakReaction& reaction) {
|
||||
os << "WeakReaction(type=" << WeakReactionTypeNames[reaction.type]
|
||||
<< ", T9=" << reaction.T9
|
||||
<< ", log_rhoYe=" << reaction.log_rhoYe
|
||||
<< ", mu_e=" << reaction.mu_e
|
||||
<< ", log_rate=" << reaction.log_rate
|
||||
<< ", log_neutrino_loss=" << reaction.log_neutrino_loss
|
||||
<< ")";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
class WeakReactionMap {
|
||||
public:
|
||||
WeakReactionMap();
|
||||
~WeakReactionMap() = default;
|
||||
|
||||
std::vector<WeakReaction> get_all_reactions() const;
|
||||
|
||||
std::expected<std::vector<WeakReaction>, bool> get_species_reactions(const fourdst::atomic::Species &species) const;
|
||||
std::expected<std::vector<WeakReaction>, bool> get_species_reactions(const std::string& species_name) const;
|
||||
private:
|
||||
std::unordered_map<fourdst::atomic::Species, std::vector<WeakReaction>> m_weak_network;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
77434
src/include/gridfire/reaction/weak/weak_rate_library.h
Normal file
77434
src/include/gridfire/reaction/weak/weak_rate_library.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -70,8 +70,8 @@ namespace gridfire::screening {
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
virtual std::vector<double> calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
[[nodiscard]] virtual std::vector<double> calculateScreeningFactors(
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
@@ -97,8 +97,8 @@ namespace gridfire::screening {
|
||||
* This method is essential for including the effects of screening in the
|
||||
* Jacobian matrix of the reaction network.
|
||||
*/
|
||||
virtual std::vector<ADDouble> calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
[[nodiscard]] virtual std::vector<ADDouble> calculateScreeningFactors(
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<ADDouble>& Y,
|
||||
const ADDouble T9,
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace gridfire::screening {
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
@@ -75,7 +75,7 @@ namespace gridfire::screening {
|
||||
* size as the `reactions` set.
|
||||
*/
|
||||
[[nodiscard]] std::vector<ADDouble> calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<ADDouble>& Y,
|
||||
const ADDouble T9,
|
||||
@@ -99,7 +99,7 @@ namespace gridfire::screening {
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] std::vector<T> calculateFactors_impl(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<T>& Y,
|
||||
const T T9,
|
||||
@@ -124,7 +124,7 @@ namespace gridfire::screening {
|
||||
*/
|
||||
template<typename T>
|
||||
std::vector<T> BareScreeningModel::calculateFactors_impl(
|
||||
const reaction::LogicalReactionSet &reactions,
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<T> &Y,
|
||||
const T T9,
|
||||
|
||||
49
src/include/gridfire/screening/screening_intermediate.h
Normal file
49
src/include/gridfire/screening/screening_intermediate.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/screening/screening_abstract.h"
|
||||
#include "gridfire/reaction/reaction.h"
|
||||
|
||||
#include "cppad/cppad.hpp"
|
||||
|
||||
namespace gridfire::screening {
|
||||
class IntermediateScreeningModel final : public ScreeningModel {
|
||||
public:
|
||||
std::vector<double> calculateScreeningFactors(
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
std::vector<ADDouble> calculateScreeningFactors(
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<ADDouble> &Y,
|
||||
ADDouble T9,
|
||||
ADDouble rho
|
||||
) const override;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
[[nodiscard]] std::vector<T> calculateFactors_impl(
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<T>& Y,
|
||||
T T9,
|
||||
T rho
|
||||
) const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> IntermediateScreeningModel::calculateFactors_impl(
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<T> &Y,
|
||||
const T T9,
|
||||
const T rho
|
||||
) const {
|
||||
// TODO: Implement the intermediate screening model logic here. Follow the prescription from Graboske et al. (1973)
|
||||
return std::vector<T>(species.size(), 0);
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace gridfire::screening {
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
@@ -70,7 +70,7 @@ namespace gridfire::screening {
|
||||
* @return A vector of screening factors as AD types.
|
||||
*/
|
||||
[[nodiscard]] std::vector<CppAD::AD<double>> calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<CppAD::AD<double>>& Y,
|
||||
const CppAD::AD<double> T9,
|
||||
@@ -98,7 +98,7 @@ namespace gridfire::screening {
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] std::vector<T> calculateFactors_impl(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<T>& Y,
|
||||
const T T9,
|
||||
@@ -139,7 +139,7 @@ namespace gridfire::screening {
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> WeakScreeningModel::calculateFactors_impl(
|
||||
const reaction::LogicalReactionSet& reactions,
|
||||
const reaction::ReactionSet& reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<T>& Y,
|
||||
const T T9,
|
||||
@@ -177,7 +177,7 @@ namespace gridfire::screening {
|
||||
factors.reserve(reactions.size());
|
||||
for (const auto& reaction : reactions) {
|
||||
T H_12(0.0); // screening abundance term
|
||||
const auto& reactants = reaction.reactants();
|
||||
const auto& reactants = reaction->reactants();
|
||||
const bool isTripleAlpha = (
|
||||
reactants.size() == 3 &&
|
||||
reactants[0].m_z == 2 &&
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace gridfire::solver {
|
||||
* the context that will be passed to the callback function, and use this information to craft their own
|
||||
* callback function.
|
||||
*/
|
||||
virtual std::vector<std::tuple<std::string, std::string>> describe() const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::tuple<std::string, std::string>> describe() const = 0;
|
||||
};
|
||||
/**
|
||||
* @class NetworkSolverStrategy
|
||||
@@ -92,7 +92,7 @@ namespace gridfire::solver {
|
||||
* the context that will be passed to the callback function, and use this information to craft their own
|
||||
* callback function.
|
||||
*/
|
||||
virtual std::vector<std::tuple<std::string, std::string>> describe_callback_context() const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::tuple<std::string, std::string>> describe_callback_context() const = 0;
|
||||
protected:
|
||||
EngineT& m_engine; ///< The engine used by this solver strategy.
|
||||
};
|
||||
@@ -191,7 +191,7 @@ namespace gridfire::solver {
|
||||
*
|
||||
* @implements SolverContextBase::describe
|
||||
*/
|
||||
std::vector<std::tuple<std::string, std::string>> describe() const override;
|
||||
[[nodiscard]] std::vector<std::tuple<std::string, std::string>> describe() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -228,7 +228,7 @@ namespace gridfire::solver {
|
||||
*
|
||||
* @implements SolverContextBase::describe
|
||||
*/
|
||||
std::vector<std::tuple<std::string, std::string>> describe_callback_context() const override;
|
||||
[[nodiscard]] std::vector<std::tuple<std::string, std::string>> describe_callback_context() const override;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -447,10 +447,10 @@ namespace gridfire::approx8{
|
||||
m_tMax = netIn.tMax;
|
||||
m_dt0 = netIn.dt0;
|
||||
|
||||
const double stiff_abs_tol = m_config.get<double>("Network:Approx8:Stiff:AbsTol", 1.0e-6);
|
||||
const double stiff_rel_tol = m_config.get<double>("Network:Approx8:Stiff:RelTol", 1.0e-6);
|
||||
const double nonstiff_abs_tol = m_config.get<double>("Network:Approx8:NonStiff:AbsTol", 1.0e-6);
|
||||
const double nonstiff_rel_tol = m_config.get<double>("Network:Approx8:NonStiff:RelTol", 1.0e-6);
|
||||
const auto stiff_abs_tol = m_config.get<double>("Network:Approx8:Stiff:AbsTol", 1.0e-6);
|
||||
const auto stiff_rel_tol = m_config.get<double>("Network:Approx8:Stiff:RelTol", 1.0e-6);
|
||||
const auto nonstiff_abs_tol = m_config.get<double>("Network:Approx8:NonStiff:AbsTol", 1.0e-6);
|
||||
const auto nonstiff_rel_tol = m_config.get<double>("Network:Approx8:NonStiff:RelTol", 1.0e-6);
|
||||
|
||||
int num_steps = -1;
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace gridfire {
|
||||
}
|
||||
|
||||
GraphEngine::GraphEngine(
|
||||
const reaction::LogicalReactionSet &reactions
|
||||
const reaction::ReactionSet &reactions
|
||||
) :
|
||||
m_reactions(reactions) {
|
||||
syncInternalMaps();
|
||||
@@ -67,8 +67,8 @@ namespace gridfire {
|
||||
|
||||
// TODO: Add cache to this
|
||||
for (const auto& reaction: m_reactions) {
|
||||
bare_rates.push_back(reaction.calculate_rate(T9));
|
||||
bare_reverse_rates.push_back(calculateReverseRate(reaction, T9));
|
||||
bare_rates.push_back(reaction->calculate_rate(T9, rho, Y));
|
||||
bare_reverse_rates.push_back(calculateReverseRate(*reaction, T9, rho, Y));
|
||||
}
|
||||
|
||||
// --- The public facing interface can always use the precomputed version since taping is done internally ---
|
||||
@@ -110,10 +110,10 @@ namespace gridfire {
|
||||
std::set<std::string_view> uniqueSpeciesNames;
|
||||
|
||||
for (const auto& reaction: m_reactions) {
|
||||
for (const auto& reactant: reaction.reactants()) {
|
||||
for (const auto& reactant: reaction->reactants()) {
|
||||
uniqueSpeciesNames.insert(reactant.name());
|
||||
}
|
||||
for (const auto& product: reaction.products()) {
|
||||
for (const auto& product: reaction->products()) {
|
||||
uniqueSpeciesNames.insert(product.name());
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace gridfire {
|
||||
LOG_TRACE_L1(m_logger, "Populating reaction ID map for REACLIB graph network (serif::network::GraphNetwork)...");
|
||||
m_reactionIDMap.clear();
|
||||
for (auto& reaction: m_reactions) {
|
||||
m_reactionIDMap.emplace(reaction.id(), &reaction);
|
||||
m_reactionIDMap.emplace(reaction->id(), reaction.get());
|
||||
}
|
||||
LOG_TRACE_L1(m_logger, "Populated {} reactions in the reaction ID map.", m_reactionIDMap.size());
|
||||
}
|
||||
@@ -165,13 +165,13 @@ namespace gridfire {
|
||||
return m_networkSpecies;
|
||||
}
|
||||
|
||||
const reaction::LogicalReactionSet& GraphEngine::getNetworkReactions() const {
|
||||
const reaction::ReactionSet& GraphEngine::getNetworkReactions() const {
|
||||
// Returns a constant reference to the set of reactions in the network.
|
||||
LOG_TRACE_L3(m_logger, "Providing access to network reactions set. Size: {}.", m_reactions.size());
|
||||
return m_reactions;
|
||||
}
|
||||
|
||||
void GraphEngine::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
|
||||
void GraphEngine::setNetworkReactions(const reaction::ReactionSet &reactions) {
|
||||
m_reactions = reactions;
|
||||
syncInternalMaps();
|
||||
}
|
||||
@@ -194,7 +194,7 @@ namespace gridfire {
|
||||
uint64_t totalProductZ = 0;
|
||||
|
||||
// Calculate total A and Z for reactants
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
auto it = m_networkSpeciesMap.find(reactant.name());
|
||||
if (it != m_networkSpeciesMap.end()) {
|
||||
totalReactantA += it->second.a();
|
||||
@@ -203,13 +203,13 @@ namespace gridfire {
|
||||
// This scenario indicates a severe data integrity issue:
|
||||
// a reactant is part of a reaction but not in the network's species map.
|
||||
LOG_ERROR(m_logger, "CRITICAL ERROR: Reactant species '{}' in reaction '{}' not found in network species map during conservation validation.",
|
||||
reactant.name(), reaction.id());
|
||||
reactant.name(), reaction->id());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate total A and Z for products
|
||||
for (const auto& product : reaction.products()) {
|
||||
for (const auto& product : reaction->products()) {
|
||||
auto it = m_networkSpeciesMap.find(product.name());
|
||||
if (it != m_networkSpeciesMap.end()) {
|
||||
totalProductA += it->second.a();
|
||||
@@ -217,7 +217,7 @@ namespace gridfire {
|
||||
} else {
|
||||
// Similar critical error for product species
|
||||
LOG_ERROR(m_logger, "CRITICAL ERROR: Product species '{}' in reaction '{}' not found in network species map during conservation validation.",
|
||||
product.name(), reaction.id());
|
||||
product.name(), reaction->id());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -225,12 +225,12 @@ namespace gridfire {
|
||||
// Compare totals for conservation
|
||||
if (totalReactantA != totalProductA) {
|
||||
LOG_ERROR(m_logger, "Mass number (A) not conserved for reaction '{}': Reactants A={} vs Products A={}.",
|
||||
reaction.id(), totalReactantA, totalProductA);
|
||||
reaction->id(), totalReactantA, totalProductA);
|
||||
return false;
|
||||
}
|
||||
if (totalReactantZ != totalProductZ) {
|
||||
LOG_ERROR(m_logger, "Atomic number (Z) not conserved for reaction '{}': Reactants Z={} vs Products Z={}.",
|
||||
reaction.id(), totalReactantZ, totalProductZ);
|
||||
reaction->id(), totalReactantZ, totalProductZ);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,9 @@ namespace gridfire {
|
||||
|
||||
double GraphEngine::calculateReverseRate(
|
||||
const reaction::Reaction &reaction,
|
||||
const double T9
|
||||
const double T9,
|
||||
const double rho,
|
||||
const std::vector<double> &Y
|
||||
) const {
|
||||
if (!m_useReverseReactions) {
|
||||
LOG_TRACE_L3_LIMIT_EVERY_N(std::numeric_limits<int>::max(), m_logger, "Reverse reactions are disabled. Returning 0.0 for reverse rate of reaction '{}'.", reaction.id());
|
||||
@@ -255,12 +257,12 @@ namespace gridfire {
|
||||
const double kBMeV = m_constants.kB * 624151; // Convert kB to MeV/K NOTE: This relies on the fact that m_constants.kB is in erg/K!
|
||||
const double expFactor = std::exp(-reaction.qValue() / (kBMeV * temp));
|
||||
double reverseRate = 0.0;
|
||||
const double forwardRate = reaction.calculate_rate(T9);
|
||||
const double forwardRate = reaction.calculate_rate(T9, rho, Y);
|
||||
|
||||
if (reaction.reactants().size() == 2 && reaction.products().size() == 2) {
|
||||
reverseRate = calculateReverseRateTwoBody(reaction, T9, forwardRate, expFactor);
|
||||
} else {
|
||||
LOG_WARNING_LIMIT_EVERY_N(1000000, m_logger, "Reverse rate calculation for reactions with more than two reactants or products is not implemented (reaction id {}).", reaction.peName());
|
||||
LOG_WARNING_LIMIT_EVERY_N(1000000, m_logger, "Reverse rate calculation for reactions with more than two reactants or products is not implemented (reaction id {}).", reaction.id());
|
||||
}
|
||||
LOG_TRACE_L2_LIMIT_EVERY_N(1000, m_logger, "Calculated reverse rate for reaction '{}': {:.3E} at T9={:.3E}.", reaction.id(), reverseRate, T9);
|
||||
return reverseRate;
|
||||
@@ -346,13 +348,15 @@ namespace gridfire {
|
||||
double GraphEngine::calculateReverseRateTwoBodyDerivative(
|
||||
const reaction::Reaction &reaction,
|
||||
const double T9,
|
||||
const double rho,
|
||||
const std::vector<double> &Y,
|
||||
const double reverseRate
|
||||
) const {
|
||||
if (!m_useReverseReactions) {
|
||||
LOG_TRACE_L3_LIMIT_EVERY_N(std::numeric_limits<int>::max(), m_logger, "Reverse reactions are disabled. Returning 0.0 for reverse rate of reaction '{}'.", reaction.id());
|
||||
return 0.0; // If reverse reactions are not used, return 0.0
|
||||
}
|
||||
const double d_log_kFwd = reaction.calculate_forward_rate_log_derivative(T9);
|
||||
const double d_log_kFwd = reaction.calculate_forward_rate_log_derivative(T9, rho, Y);
|
||||
|
||||
auto log_deriv_pf_op = [&](double acc, const auto& species) {
|
||||
const double g = m_partitionFunction->evaluate(species.z(), species.a(), T9);
|
||||
@@ -392,7 +396,7 @@ namespace gridfire {
|
||||
m_useReverseReactions = useReverse;
|
||||
}
|
||||
|
||||
int GraphEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
size_t GraphEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
return m_speciesToIndexMap.at(species); // Returns the index of the species in the stoichiometry matrix
|
||||
}
|
||||
|
||||
@@ -494,7 +498,7 @@ namespace gridfire {
|
||||
bare_rate *
|
||||
precomp.symmetry_factor *
|
||||
forwardAbundanceProduct *
|
||||
std::pow(rho, numReactants > 1 ? numReactants - 1 : 0.0);
|
||||
std::pow(rho, numReactants > 1 ? static_cast<double>(numReactants) - 1 : 0.0);
|
||||
|
||||
double reverseMolarReactionFlow = 0.0;
|
||||
if (precomp.reverse_symmetry_factor != 0.0 and m_useReverseReactions) {
|
||||
@@ -507,7 +511,7 @@ namespace gridfire {
|
||||
bare_reverse_rate *
|
||||
precomp.reverse_symmetry_factor *
|
||||
reverseAbundanceProduct *
|
||||
std::pow(rho, numProducts > 1 ? numProducts - 1 : 0.0);
|
||||
std::pow(rho, numProducts > 1 ? static_cast<double>(numProducts) - 1 : 0.0);
|
||||
}
|
||||
|
||||
molarReactionFlows.push_back(forwardMolarReactionFlow - reverseMolarReactionFlow);
|
||||
@@ -558,7 +562,7 @@ namespace gridfire {
|
||||
size_t reactionColumnIndex = 0;
|
||||
for (const auto& reaction : m_reactions) {
|
||||
// Get the net stoichiometry for the current reaction
|
||||
std::unordered_map<fourdst::atomic::Species, int> netStoichiometry = reaction.stoichiometry();
|
||||
std::unordered_map<fourdst::atomic::Species, int> netStoichiometry = reaction->stoichiometry();
|
||||
|
||||
// Iterate through the species and their coefficients in the stoichiometry map
|
||||
for (const auto& [species, coefficient] : netStoichiometry) {
|
||||
@@ -571,7 +575,7 @@ namespace gridfire {
|
||||
} else {
|
||||
// This scenario should ideally not happen if m_networkSpeciesMap and m_speciesToIndexMap are correctly synced
|
||||
LOG_ERROR(m_logger, "CRITICAL ERROR: Species '{}' from reaction '{}' stoichiometry not found in species to index map.",
|
||||
species.name(), reaction.id());
|
||||
species.name(), reaction->id());
|
||||
m_logger -> flush_log();
|
||||
throw std::runtime_error("Species not found in species to index map: " + std::string(species.name()));
|
||||
}
|
||||
@@ -763,19 +767,19 @@ namespace gridfire {
|
||||
dotFile << " // --- Reaction Edges ---\n";
|
||||
for (const auto& reaction : m_reactions) {
|
||||
// Create a unique ID for the reaction node
|
||||
std::string reactionNodeId = "reaction_" + std::string(reaction.id());
|
||||
std::string reactionNodeId = "reaction_" + std::string(reaction->id());
|
||||
|
||||
// Define the reaction node (small, black dot)
|
||||
dotFile << " \"" << reactionNodeId << "\" [shape=point, fillcolor=black, width=0.1, height=0.1, label=\"\"];\n";
|
||||
|
||||
// Draw edges from reactants to the reaction node
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
dotFile << " \"" << reactant.name() << "\" -> \"" << reactionNodeId << "\";\n";
|
||||
}
|
||||
|
||||
// Draw edges from the reaction node to products
|
||||
for (const auto& product : reaction.products()) {
|
||||
dotFile << " \"" << reactionNodeId << "\" -> \"" << product.name() << "\" [label=\"" << reaction.qValue() << " MeV\"];\n";
|
||||
for (const auto& product : reaction->products()) {
|
||||
dotFile << " \"" << reactionNodeId << "\" -> \"" << product.name() << "\" [label=\"" << reaction->qValue() << " MeV\"];\n";
|
||||
}
|
||||
dotFile << "\n";
|
||||
}
|
||||
@@ -797,42 +801,25 @@ namespace gridfire {
|
||||
csvFile << "Reaction;Reactants;Products;Q-value;sources;rates\n";
|
||||
for (const auto& reaction : m_reactions) {
|
||||
// Dynamic cast to REACLIBReaction to access specific properties
|
||||
csvFile << reaction.id() << ";";
|
||||
csvFile << reaction->id() << ";";
|
||||
// Reactants
|
||||
size_t count = 0;
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
csvFile << reactant.name();
|
||||
if (++count < reaction.reactants().size()) {
|
||||
if (++count < reaction->reactants().size()) {
|
||||
csvFile << ",";
|
||||
}
|
||||
}
|
||||
csvFile << ";";
|
||||
count = 0;
|
||||
for (const auto& product : reaction.products()) {
|
||||
for (const auto& product : reaction->products()) {
|
||||
csvFile << product.name();
|
||||
if (++count < reaction.products().size()) {
|
||||
if (++count < reaction->products().size()) {
|
||||
csvFile << ",";
|
||||
}
|
||||
}
|
||||
csvFile << ";" << reaction.qValue() << ";";
|
||||
csvFile << ";" << reaction->qValue() << ";";
|
||||
// Reaction coefficients
|
||||
auto sources = reaction.sources();
|
||||
count = 0;
|
||||
for (const auto& source : sources) {
|
||||
csvFile << source;
|
||||
if (++count < sources.size()) {
|
||||
csvFile << ",";
|
||||
}
|
||||
}
|
||||
csvFile << ";";
|
||||
// Reaction coefficients
|
||||
count = 0;
|
||||
for (const auto& rates : reaction) {
|
||||
csvFile << rates;
|
||||
if (++count < reaction.size()) {
|
||||
csvFile << ",";
|
||||
}
|
||||
}
|
||||
csvFile << "\n";
|
||||
}
|
||||
csvFile.close();
|
||||
@@ -869,8 +856,8 @@ namespace gridfire {
|
||||
for (const auto& species : m_networkSpecies) {
|
||||
double netDestructionFlow = 0.0;
|
||||
for (const auto& reaction : m_reactions) {
|
||||
if (reaction.stoichiometry(species) < 0) {
|
||||
const double flow = calculateMolarReactionFlow<double>(reaction, Y, T9, rho);
|
||||
if (reaction->stoichiometry(species) < 0) {
|
||||
const auto flow = calculateMolarReactionFlow<double>(*reaction, Y, T9, rho);
|
||||
netDestructionFlow += flow;
|
||||
}
|
||||
}
|
||||
@@ -899,7 +886,7 @@ namespace gridfire {
|
||||
return false;
|
||||
}
|
||||
|
||||
void GraphEngine::recordADTape() {
|
||||
void GraphEngine::recordADTape() const {
|
||||
LOG_TRACE_L1(m_logger, "Recording AD tape for the RHS calculation...");
|
||||
|
||||
// Task 1: Set dimensions and initialize the matrix
|
||||
@@ -949,8 +936,8 @@ namespace gridfire {
|
||||
m_atomicReverseRates.reserve(m_reactions.size());
|
||||
|
||||
for (const auto& reaction: m_reactions) {
|
||||
if (reaction.qValue() != 0.0) {
|
||||
m_atomicReverseRates.push_back(std::make_unique<AtomicReverseRate>(reaction, *this));
|
||||
if (reaction->qValue() != 0.0) {
|
||||
m_atomicReverseRates.push_back(std::make_unique<AtomicReverseRate>(*reaction, *this));
|
||||
} else {
|
||||
m_atomicReverseRates.push_back(nullptr);
|
||||
}
|
||||
@@ -1038,7 +1025,8 @@ namespace gridfire {
|
||||
if ( p != 0) { return false; }
|
||||
const double T9 = tx[0];
|
||||
|
||||
const double reverseRate = m_engine.calculateReverseRate(m_reaction, T9);
|
||||
// TODO: Handle rho and Y
|
||||
const double reverseRate = m_engine.calculateReverseRate(m_reaction, T9, 0, {});
|
||||
// std::cout << m_reaction.peName() << " reverseRate: " << reverseRate << " at T9: " << T9 << "\n";
|
||||
ty[0] = reverseRate; // Store the reverse rate in the output vector
|
||||
|
||||
@@ -1058,8 +1046,8 @@ namespace gridfire {
|
||||
const double T9 = tx[0];
|
||||
const double reverseRate = ty[0];
|
||||
|
||||
const double derivative = m_engine.calculateReverseRateTwoBodyDerivative(m_reaction, T9, reverseRate);
|
||||
// std::cout << m_reaction.peName() << " reverseRate Derivative: " << derivative << "\n";
|
||||
// TODO: Handle rho and Y
|
||||
const double derivative = m_engine.calculateReverseRateTwoBodyDerivative(m_reaction, T9, 0, {}, reverseRate);
|
||||
|
||||
px[0] = py[0] * derivative; // Return the derivative of the reverse rate with respect to T9
|
||||
|
||||
|
||||
@@ -14,14 +14,13 @@
|
||||
#include "quill/LogMacros.h"
|
||||
|
||||
namespace gridfire {
|
||||
using reaction::LogicalReactionSet;
|
||||
using reaction::ReactionSet;
|
||||
using reaction::Reaction;
|
||||
using fourdst::composition::Composition;
|
||||
using fourdst::atomic::Species;
|
||||
|
||||
|
||||
LogicalReactionSet build_reaclib_nuclear_network(
|
||||
ReactionSet build_reaclib_nuclear_network(
|
||||
const Composition &composition,
|
||||
BuildDepthType maxLayers,
|
||||
bool reverse
|
||||
@@ -38,18 +37,18 @@ namespace gridfire {
|
||||
throw std::logic_error("Network build depth is set to 0. No reactions will be collected.");
|
||||
}
|
||||
|
||||
const auto allReactions = reaclib::get_all_reactions();
|
||||
std::vector<Reaction> remainingReactions;
|
||||
const auto& allReactions = reaclib::get_all_reaclib_reactions();
|
||||
std::vector<Reaction*> remainingReactions;
|
||||
for (const auto& reaction : allReactions) {
|
||||
if (reaction.is_reverse() == reverse) {
|
||||
remainingReactions.push_back(reaction);
|
||||
if (reaction->is_reverse() == reverse) {
|
||||
remainingReactions.push_back(reaction.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (depth == static_cast<int>(NetworkBuildDepth::Full)) {
|
||||
LOG_INFO(logger, "Building full nuclear network with a total of {} reactions.", allReactions.size());
|
||||
const ReactionSet reactionSet(remainingReactions);
|
||||
return reaction::packReactionSetToLogicalReactionSet(reactionSet);
|
||||
return reaction::packReactionSet(reactionSet);
|
||||
}
|
||||
|
||||
std::unordered_set<Species> availableSpecies;
|
||||
@@ -60,12 +59,12 @@ namespace gridfire {
|
||||
}
|
||||
|
||||
|
||||
std::vector<Reaction> collectedReactions;
|
||||
std::vector<Reaction*> collectedReactions;
|
||||
|
||||
LOG_INFO(logger, "Starting network construction with {} available species.", availableSpecies.size());
|
||||
for (int layer = 0; layer < depth && !remainingReactions.empty(); ++layer) {
|
||||
LOG_TRACE_L1(logger, "Collecting reactions for layer {} with {} remaining reactions. Currently there are {} available species", layer, remainingReactions.size(), availableSpecies.size());
|
||||
std::vector<Reaction> reactionsForNextPass;
|
||||
std::vector<Reaction*> reactionsForNextPass;
|
||||
std::unordered_set<Species> newProductsThisLayer;
|
||||
bool newReactionsAdded = false;
|
||||
|
||||
@@ -73,7 +72,7 @@ namespace gridfire {
|
||||
|
||||
for (const auto &reaction : remainingReactions) {
|
||||
bool allReactantsAvailable = true;
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
if (!availableSpecies.contains(reactant)) {
|
||||
allReactantsAvailable = false;
|
||||
break;
|
||||
@@ -84,7 +83,7 @@ namespace gridfire {
|
||||
collectedReactions.push_back(reaction);
|
||||
newReactionsAdded = true;
|
||||
|
||||
for (const auto& product : reaction.products()) {
|
||||
for (const auto& product : reaction->products()) {
|
||||
newProductsThisLayer.insert(product);
|
||||
}
|
||||
} else {
|
||||
@@ -105,9 +104,7 @@ namespace gridfire {
|
||||
|
||||
LOG_INFO(logger, "Network construction completed with {} reactions collected.", collectedReactions.size());
|
||||
const ReactionSet reactionSet(collectedReactions);
|
||||
return reaction::packReactionSetToLogicalReactionSet(reactionSet);
|
||||
return reaction::packReactionSet(reactionSet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -24,11 +24,11 @@ namespace gridfire {
|
||||
const reaction::Reaction* dominateReaction = nullptr;
|
||||
double maxFlow = -1.0;
|
||||
for (const auto& reaction : engine.getNetworkReactions()) {
|
||||
if (reaction.contains(species) && reaction.stoichiometry(species) > 0) {
|
||||
const double flow = engine.calculateMolarReactionFlow(reaction, Y, T9, rho);
|
||||
if (reaction->contains(species) && reaction->stoichiometry(species) > 0) {
|
||||
const double flow = engine.calculateMolarReactionFlow(*reaction, Y, T9, rho);
|
||||
if (flow > maxFlow) {
|
||||
maxFlow = flow;
|
||||
dominateReaction = &reaction;
|
||||
dominateReaction = reaction.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,9 +105,8 @@ namespace gridfire {
|
||||
const auto Y = primer.mapNetInToMolarAbundanceVector(tempNetIn);
|
||||
const double destructionRateConstant = calculateDestructionRateConstant(primer, primingSpecies, Y, T9, rho);
|
||||
|
||||
double equilibriumMassFraction = 0.0;
|
||||
|
||||
if (destructionRateConstant > 1e-99) {
|
||||
double equilibriumMassFraction = 0.0;
|
||||
const double creationRate = calculateCreationRate(primer, primingSpecies, Y, T9, rho);
|
||||
equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
|
||||
if (std::isnan(equilibriumMassFraction)) {
|
||||
@@ -116,9 +115,7 @@ namespace gridfire {
|
||||
}
|
||||
LOG_TRACE_L3(logger, "Found equilibrium for {}: X_eq = {:.4e}", primingSpecies.name(), equilibriumMassFraction);
|
||||
|
||||
const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho);
|
||||
|
||||
if (dominantChannel) {
|
||||
if (const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho)) {
|
||||
LOG_TRACE_L3(logger, "Dominant creation channel for {}: {}", primingSpecies.name(), dominantChannel->peName());
|
||||
|
||||
double totalReactantMass = 0.0;
|
||||
@@ -170,7 +167,7 @@ namespace gridfire {
|
||||
std::vector<std::string> final_symbols;
|
||||
std::vector<double> final_mass_fractions;
|
||||
for(const auto& [species, mass_fraction] : currentMassFractions) {
|
||||
final_symbols.push_back(std::string(species.name()));
|
||||
final_symbols.emplace_back(species.name());
|
||||
if (mass_fraction < 0.0 && std::abs(mass_fraction) < 1e-16) {
|
||||
final_mass_fractions.push_back(0.0); // Avoid negative mass fractions
|
||||
} else {
|
||||
@@ -197,14 +194,14 @@ namespace gridfire {
|
||||
const double T9,
|
||||
const double rho
|
||||
) {
|
||||
const int speciesIndex = engine.getSpeciesIndex(species);
|
||||
const size_t speciesIndex = engine.getSpeciesIndex(species);
|
||||
std::vector<double> Y_scaled(Y.begin(), Y.end());
|
||||
Y_scaled[speciesIndex] = 1.0; // Set the abundance of the species to 1.0 for rate constant calculation
|
||||
double destructionRateConstant = 0.0;
|
||||
for (const auto& reaction: engine.getNetworkReactions()) {
|
||||
if (reaction.contains_reactant(species)) {
|
||||
const int stoichiometry = reaction.stoichiometry(species);
|
||||
destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(reaction, Y_scaled, T9, rho);
|
||||
if (reaction->contains_reactant(species)) {
|
||||
const int stoichiometry = reaction->stoichiometry(species);
|
||||
destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(*reaction, Y_scaled, T9, rho);
|
||||
}
|
||||
}
|
||||
return destructionRateConstant;
|
||||
@@ -219,9 +216,9 @@ namespace gridfire {
|
||||
) {
|
||||
double creationRate = 0.0;
|
||||
for (const auto& reaction: engine.getNetworkReactions()) {
|
||||
const int stoichiometry = reaction.stoichiometry(species);
|
||||
const int stoichiometry = reaction->stoichiometry(species);
|
||||
if (stoichiometry > 0) {
|
||||
creationRate += stoichiometry * engine.calculateMolarReactionFlow(reaction, Y, T9, rho);
|
||||
creationRate += stoichiometry * engine.calculateMolarReactionFlow(*reaction, Y, T9, rho);
|
||||
}
|
||||
}
|
||||
return creationRate;
|
||||
|
||||
@@ -70,12 +70,12 @@ namespace gridfire {
|
||||
reactionIndexMap.reserve(m_activeReactions.size());
|
||||
|
||||
for (const auto& active_reaction_ptr : m_activeReactions) {
|
||||
auto it = fullReactionReverseMap.find(active_reaction_ptr.id());
|
||||
auto it = fullReactionReverseMap.find(active_reaction_ptr->id());
|
||||
|
||||
if (it != fullReactionReverseMap.end()) {
|
||||
reactionIndexMap.push_back(it->second);
|
||||
} else {
|
||||
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr.id());
|
||||
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr->id());
|
||||
m_logger->flush_log();
|
||||
throw std::runtime_error("Mismatch between active reactions and base engine.");
|
||||
}
|
||||
@@ -89,11 +89,6 @@ namespace gridfire {
|
||||
fourdst::composition::Composition baseUpdatedComposition = m_baseEngine.update(netIn);
|
||||
NetIn updatedNetIn = netIn;
|
||||
|
||||
// for (const auto &entry: netIn.composition | std::views::values) {
|
||||
// if (baseUpdatedComposition.contains(entry.isotope())) {
|
||||
// updatedNetIn.composition.setMassFraction(entry.isotope(), baseUpdatedComposition.getMassFraction(entry.isotope()));
|
||||
// }
|
||||
// }
|
||||
updatedNetIn.composition = baseUpdatedComposition;
|
||||
|
||||
updatedNetIn.composition.finalize(false);
|
||||
@@ -115,7 +110,7 @@ namespace gridfire {
|
||||
const std::unordered_set<Species> reachableSpecies = findReachableSpecies(updatedNetIn);
|
||||
LOG_DEBUG(m_logger, "Found {} reachable species in adaptive engine view.", reachableSpecies.size());
|
||||
|
||||
const std::vector<const reaction::LogicalReaction*> finalReactions = cullReactionsByFlow(allFlows, reachableSpecies, Y_Full, maxFlow);
|
||||
const std::vector<const reaction::Reaction*> finalReactions = cullReactionsByFlow(allFlows, reachableSpecies, Y_Full, maxFlow);
|
||||
|
||||
finalizeActiveSet(finalReactions);
|
||||
|
||||
@@ -191,7 +186,7 @@ namespace gridfire {
|
||||
const size_t i_full = mapCulledToFullSpeciesIndex(i_culled);
|
||||
const size_t j_full = mapCulledToFullSpeciesIndex(j_culled);
|
||||
|
||||
return m_baseEngine.getJacobianMatrixEntry(i_full, j_full);
|
||||
return m_baseEngine.getJacobianMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
|
||||
}
|
||||
|
||||
void AdaptiveEngineView::generateStoichiometryMatrix() {
|
||||
@@ -206,7 +201,7 @@ namespace gridfire {
|
||||
validateState();
|
||||
const size_t speciesIndex_full = mapCulledToFullSpeciesIndex(speciesIndex_culled);
|
||||
const size_t reactionIndex_full = mapCulledToFullReactionIndex(reactionIndex_culled);
|
||||
return m_baseEngine.getStoichiometryMatrixEntry(speciesIndex_full, reactionIndex_full);
|
||||
return m_baseEngine.getStoichiometryMatrixEntry(static_cast<int>(speciesIndex_full), static_cast<int>(reactionIndex_full));
|
||||
}
|
||||
|
||||
double AdaptiveEngineView::calculateMolarReactionFlow(
|
||||
@@ -226,11 +221,11 @@ namespace gridfire {
|
||||
return m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho);
|
||||
}
|
||||
|
||||
const reaction::LogicalReactionSet & AdaptiveEngineView::getNetworkReactions() const {
|
||||
const reaction::ReactionSet & AdaptiveEngineView::getNetworkReactions() const {
|
||||
return m_activeReactions;
|
||||
}
|
||||
|
||||
void AdaptiveEngineView::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
|
||||
void AdaptiveEngineView::setNetworkReactions(const reaction::ReactionSet &reactions) {
|
||||
LOG_CRITICAL(m_logger, "AdaptiveEngineView does not support setting network reactions directly. Use update() with NetIn instead. Perhaps you meant to call this on the base engine?");
|
||||
throw exceptions::UnableToSetNetworkReactionsError("AdaptiveEngineView does not support setting network reactions directly. Use update() with NetIn instead. Perhaps you meant to call this on the base engine?");
|
||||
}
|
||||
@@ -248,7 +243,7 @@ namespace gridfire {
|
||||
return std::unexpected{result.error()};
|
||||
}
|
||||
|
||||
const std::unordered_map<Species, double> fullTimescales = result.value();
|
||||
const std::unordered_map<Species, double>& fullTimescales = result.value();
|
||||
|
||||
|
||||
std::unordered_map<Species, double> culledTimescales;
|
||||
@@ -262,22 +257,21 @@ namespace gridfire {
|
||||
|
||||
}
|
||||
|
||||
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError>
|
||||
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError>
|
||||
AdaptiveEngineView::getSpeciesDestructionTimescales(
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
const double T9,
|
||||
const double rho
|
||||
) const {
|
||||
validateState();
|
||||
|
||||
const auto Y_full = mapCulledToFull(Y);
|
||||
const auto result = m_baseEngine.getSpeciesDestructionTimescales(Y_full, T9, rho);
|
||||
const std::vector<double> Y_full = mapCulledToFull(Y);
|
||||
|
||||
const auto result = m_baseEngine.getSpeciesDestructionTimescales(Y_full, T9, rho);
|
||||
if (!result) {
|
||||
return std::unexpected{result.error()};
|
||||
}
|
||||
|
||||
const std::unordered_map<Species, double> destructionTimescales = result.value();
|
||||
const std::unordered_map<Species, double>& destructionTimescales = result.value();
|
||||
|
||||
std::unordered_map<Species, double> culledTimescales;
|
||||
culledTimescales.reserve(m_activeSpecies.size());
|
||||
@@ -309,7 +303,7 @@ namespace gridfire {
|
||||
return m_baseEngine.primeEngine(netIn);
|
||||
}
|
||||
|
||||
int AdaptiveEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
size_t AdaptiveEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
const auto it = std::ranges::find(m_activeSpecies, species);
|
||||
if (it != m_activeSpecies.end()) {
|
||||
return static_cast<int>(std::distance(m_activeSpecies.begin(), it));
|
||||
@@ -389,8 +383,8 @@ namespace gridfire {
|
||||
const auto& fullReactionSet = m_baseEngine.getNetworkReactions();
|
||||
reactionFlows.reserve(fullReactionSet.size());
|
||||
for (const auto& reaction : fullReactionSet) {
|
||||
const double flow = m_baseEngine.calculateMolarReactionFlow(reaction, out_Y_Full, T9, rho);
|
||||
reactionFlows.push_back({&reaction, flow});
|
||||
const double flow = m_baseEngine.calculateMolarReactionFlow(*reaction, out_Y_Full, T9, rho);
|
||||
reactionFlows.push_back({reaction.get(), flow});
|
||||
LOG_TRACE_L1(m_logger, "Reaction '{}' has flow rate: {:0.3E} [mol/s/g]", reaction.id(), flow);
|
||||
}
|
||||
return reactionFlows;
|
||||
@@ -418,14 +412,14 @@ namespace gridfire {
|
||||
new_species_found_in_pass = false;
|
||||
for (const auto& reaction: m_baseEngine.getNetworkReactions()) {
|
||||
bool all_reactants_reachable = true;
|
||||
for (const auto& reactant: reaction.reactants()) {
|
||||
for (const auto& reactant: reaction->reactants()) {
|
||||
if (!reachable.contains(reactant)) {
|
||||
all_reactants_reachable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_reactants_reachable) {
|
||||
for (const auto& product: reaction.products()) {
|
||||
for (const auto& product: reaction->products()) {
|
||||
if (!reachable.contains(product)) {
|
||||
reachable.insert(product);
|
||||
new_species_found_in_pass = true;
|
||||
@@ -439,7 +433,7 @@ namespace gridfire {
|
||||
return reachable;
|
||||
}
|
||||
|
||||
std::vector<const reaction::LogicalReaction *> AdaptiveEngineView::cullReactionsByFlow(
|
||||
std::vector<const reaction::Reaction *> AdaptiveEngineView::cullReactionsByFlow(
|
||||
const std::vector<ReactionFlow> &allFlows,
|
||||
const std::unordered_set<fourdst::atomic::Species> &reachableSpecies,
|
||||
const std::vector<double> &Y_full,
|
||||
@@ -449,7 +443,7 @@ namespace gridfire {
|
||||
const auto relative_culling_threshold = m_config.get<double>("gridfire:AdaptiveEngineView:RelativeCullingThreshold", 1e-75);
|
||||
double absoluteCullingThreshold = relative_culling_threshold * maxFlow;
|
||||
LOG_DEBUG(m_logger, "Relative culling threshold: {:0.3E} ({})", relative_culling_threshold, absoluteCullingThreshold);
|
||||
std::vector<const reaction::LogicalReaction*> culledReactions;
|
||||
std::vector<const reaction::Reaction*> culledReactions;
|
||||
for (const auto& [reactionPtr, flowRate]: allFlows) {
|
||||
bool keepReaction = false;
|
||||
if (flowRate > absoluteCullingThreshold) {
|
||||
@@ -487,7 +481,7 @@ namespace gridfire {
|
||||
const double T9,
|
||||
const double rho,
|
||||
const std::vector<Species> &activeSpecies,
|
||||
const reaction::LogicalReactionSet &activeReactions
|
||||
const reaction::ReactionSet &activeReactions
|
||||
) const {
|
||||
const auto result = m_baseEngine.getSpeciesTimescales(Y_full, T9, rho);
|
||||
if (!result) {
|
||||
@@ -497,7 +491,7 @@ namespace gridfire {
|
||||
std::unordered_map<Species, double> timescales = result.value();
|
||||
std::set<Species> onlyProducedSpecies;
|
||||
for (const auto& reaction : activeReactions) {
|
||||
const std::vector<Species> products = reaction.products();
|
||||
const std::vector<Species>& products = reaction->products();
|
||||
onlyProducedSpecies.insert(products.begin(), products.end());
|
||||
}
|
||||
|
||||
@@ -506,7 +500,7 @@ namespace gridfire {
|
||||
onlyProducedSpecies,
|
||||
[&](const Species &species) {
|
||||
for (const auto& reaction : activeReactions) {
|
||||
if (reaction.contains_reactant(species)) {
|
||||
if (reaction->contains_reactant(species)) {
|
||||
return true; // If any active reaction consumes the species then erase it from the set.
|
||||
}
|
||||
}
|
||||
@@ -545,26 +539,26 @@ namespace gridfire {
|
||||
}()
|
||||
);
|
||||
|
||||
std::unordered_map<Species, const reaction::LogicalReaction*> reactionsToRescue;
|
||||
std::unordered_map<Species, const reaction::Reaction*> reactionsToRescue;
|
||||
for (const auto& species : onlyProducedSpecies) {
|
||||
double maxSpeciesConsumptionRate = 0.0;
|
||||
for (const auto& reaction : m_baseEngine.getNetworkReactions()) {
|
||||
const bool speciesToCheckIsConsumed = reaction.contains_reactant(species);
|
||||
const bool speciesToCheckIsConsumed = reaction->contains_reactant(species);
|
||||
if (!speciesToCheckIsConsumed) {
|
||||
continue; // If the species is not consumed by this reaction, skip it.
|
||||
}
|
||||
bool allOtherReactantsAreAvailable = true;
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
const bool reactantIsAvailable = std::ranges::contains(activeSpecies, reactant);
|
||||
if (!reactantIsAvailable && reactant != species) {
|
||||
allOtherReactantsAreAvailable = false;
|
||||
}
|
||||
}
|
||||
if (allOtherReactantsAreAvailable && speciesToCheckIsConsumed) {
|
||||
double rate = reaction.calculate_rate(T9);
|
||||
double rate = reaction->calculate_rate(T9, rho, Y_full);
|
||||
if (rate > maxSpeciesConsumptionRate) {
|
||||
maxSpeciesConsumptionRate = rate;
|
||||
reactionsToRescue[species] = &reaction;
|
||||
reactionsToRescue[species] = reaction.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -626,7 +620,7 @@ namespace gridfire {
|
||||
);
|
||||
|
||||
RescueSet rescueSet;
|
||||
std::unordered_set<const reaction::LogicalReaction*> newReactions;
|
||||
std::unordered_set<const reaction::Reaction*> newReactions;
|
||||
std::unordered_set<Species> newSpecies;
|
||||
|
||||
for (const auto &reactionPtr: reactionsToRescue | std::views::values) {
|
||||
@@ -639,7 +633,7 @@ namespace gridfire {
|
||||
}
|
||||
|
||||
void AdaptiveEngineView::finalizeActiveSet(
|
||||
const std::vector<const reaction::LogicalReaction *> &finalReactions
|
||||
const std::vector<const reaction::Reaction *> &finalReactions
|
||||
) {
|
||||
std::unordered_set<Species>finalSpeciesSet;
|
||||
m_activeReactions.clear();
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace gridfire {
|
||||
const size_t i_full = mapViewToFullSpeciesIndex(i_defined);
|
||||
const size_t j_full = mapViewToFullSpeciesIndex(j_defined);
|
||||
|
||||
return m_baseEngine.getJacobianMatrixEntry(i_full, j_full);
|
||||
return m_baseEngine.getJacobianMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
|
||||
}
|
||||
|
||||
void DefinedEngineView::generateStoichiometryMatrix() {
|
||||
@@ -85,7 +85,7 @@ namespace gridfire {
|
||||
|
||||
const size_t i_full = mapViewToFullSpeciesIndex(speciesIndex_defined);
|
||||
const size_t j_full = mapViewToFullReactionIndex(reactionIndex_defined);
|
||||
return m_baseEngine.getStoichiometryMatrixEntry(i_full, j_full);
|
||||
return m_baseEngine.getStoichiometryMatrixEntry(static_cast<int>(i_full), static_cast<int>(j_full));
|
||||
}
|
||||
|
||||
double DefinedEngineView::calculateMolarReactionFlow(
|
||||
@@ -105,16 +105,16 @@ namespace gridfire {
|
||||
return m_baseEngine.calculateMolarReactionFlow(reaction, Y_full, T9, rho);
|
||||
}
|
||||
|
||||
const reaction::LogicalReactionSet & DefinedEngineView::getNetworkReactions() const {
|
||||
const reaction::ReactionSet & DefinedEngineView::getNetworkReactions() const {
|
||||
validateNetworkState();
|
||||
|
||||
return m_activeReactions;
|
||||
}
|
||||
|
||||
void DefinedEngineView::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
|
||||
void DefinedEngineView::setNetworkReactions(const reaction::ReactionSet &reactions) {
|
||||
std::vector<std::string> peNames;
|
||||
for (const auto& reaction : reactions) {
|
||||
peNames.push_back(std::string(reaction.id()));
|
||||
peNames.emplace_back(reaction->id());
|
||||
}
|
||||
collect(peNames);
|
||||
}
|
||||
@@ -185,7 +185,7 @@ namespace gridfire {
|
||||
return m_baseEngine.getScreeningModel();
|
||||
}
|
||||
|
||||
int DefinedEngineView::getSpeciesIndex(const Species &species) const {
|
||||
size_t DefinedEngineView::getSpeciesIndex(const Species &species) const {
|
||||
validateNetworkState();
|
||||
|
||||
const auto it = std::ranges::find(m_activeSpecies, species);
|
||||
@@ -259,12 +259,12 @@ namespace gridfire {
|
||||
reactionIndexMap.reserve(m_activeReactions.size());
|
||||
|
||||
for (const auto& active_reaction_ptr : m_activeReactions) {
|
||||
auto it = fullReactionReverseMap.find(active_reaction_ptr.id());
|
||||
auto it = fullReactionReverseMap.find(active_reaction_ptr->id());
|
||||
|
||||
if (it != fullReactionReverseMap.end()) {
|
||||
reactionIndexMap.push_back(it->second);
|
||||
} else {
|
||||
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr.id());
|
||||
LOG_ERROR(m_logger, "Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr->id());
|
||||
m_logger->flush_log();
|
||||
throw std::runtime_error("Mismatch between active reactions and base engine.");
|
||||
}
|
||||
@@ -328,20 +328,20 @@ namespace gridfire {
|
||||
m_logger->flush_log();
|
||||
throw std::runtime_error("Reaction with name '" + std::string(peName) + "' not found in the base engine's network reactions.");
|
||||
}
|
||||
auto reaction = fullNetworkReactionSet[peName];
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
const reaction::Reaction* reaction = &fullNetworkReactionSet[peName];
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
if (!seenSpecies.contains(reactant)) {
|
||||
seenSpecies.insert(reactant);
|
||||
m_activeSpecies.push_back(reactant);
|
||||
}
|
||||
}
|
||||
for (const auto& product : reaction.products()) {
|
||||
for (const auto& product : reaction->products()) {
|
||||
if (!seenSpecies.contains(product)) {
|
||||
seenSpecies.insert(product);
|
||||
m_activeSpecies.push_back(product);
|
||||
}
|
||||
}
|
||||
m_activeReactions.add_reaction(reaction);
|
||||
m_activeReactions.add_reaction(*reaction);
|
||||
}
|
||||
LOG_TRACE_L3(m_logger, "DefinedEngineView built with {} active species and {} active reactions.", m_activeSpecies.size(), m_activeReactions.size());
|
||||
LOG_TRACE_L3(m_logger, "Active species: {}", [this]() -> std::string {
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace {
|
||||
std::unordered_set<size_t> visited;
|
||||
|
||||
for (const size_t& start_node : nodes) {
|
||||
if (visited.find(start_node) == visited.end()) {
|
||||
if (!visited.contains(start_node)) {
|
||||
std::vector<size_t> current_component;
|
||||
std::queue<size_t> q;
|
||||
|
||||
@@ -56,9 +56,9 @@ namespace {
|
||||
q.pop();
|
||||
current_component.push_back(u);
|
||||
|
||||
if (graph.count(u)) {
|
||||
if (graph.contains(u)) {
|
||||
for (const auto& v : graph.at(u)) {
|
||||
if (visited.find(v) == visited.end()) {
|
||||
if (!visited.contains(v)) {
|
||||
visited.insert(v);
|
||||
q.push(v);
|
||||
}
|
||||
@@ -194,8 +194,7 @@ namespace gridfire {
|
||||
}
|
||||
auto deriv = result.value();
|
||||
|
||||
for (size_t i = 0; i < m_algebraic_species_indices.size(); ++i) {
|
||||
const size_t species_index = m_algebraic_species_indices[i];
|
||||
for (const size_t species_index : m_algebraic_species_indices) {
|
||||
deriv.dydt[species_index] = 0.0; // Fix the algebraic species to the equilibrium abundances we calculate.
|
||||
}
|
||||
return deriv;
|
||||
@@ -283,11 +282,11 @@ namespace gridfire {
|
||||
return m_baseEngine.calculateMolarReactionFlow(reaction, Y_mutable, T9, rho);
|
||||
}
|
||||
|
||||
const reaction::LogicalReactionSet & MultiscalePartitioningEngineView::getNetworkReactions() const {
|
||||
const reaction::ReactionSet & MultiscalePartitioningEngineView::getNetworkReactions() const {
|
||||
return m_baseEngine.getNetworkReactions();
|
||||
}
|
||||
|
||||
void MultiscalePartitioningEngineView::setNetworkReactions(const reaction::LogicalReactionSet &reactions) {
|
||||
void MultiscalePartitioningEngineView::setNetworkReactions(const reaction::ReactionSet &reactions) {
|
||||
LOG_CRITICAL(m_logger, "setNetworkReactions is not supported in MultiscalePartitioningEngineView. Did you mean to call this on the base engine?");
|
||||
throw exceptions::UnableToSetNetworkReactionsError("setNetworkReactions is not supported in MultiscalePartitioningEngineView. Did you mean to call this on the base engine?");
|
||||
}
|
||||
@@ -508,7 +507,7 @@ namespace gridfire {
|
||||
}()
|
||||
);
|
||||
|
||||
m_qse_groups = std::move(validated_groups);
|
||||
m_qse_groups = validated_groups;
|
||||
LOG_TRACE_L1(m_logger, "Identified {} QSE groups.", m_qse_groups.size());
|
||||
|
||||
for (const auto& group : m_qse_groups) {
|
||||
@@ -589,7 +588,7 @@ namespace gridfire {
|
||||
double max_log_flow = std::numeric_limits<double>::lowest();
|
||||
|
||||
for (const auto& reaction : all_reactions) {
|
||||
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho));
|
||||
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, Y, T9, rho));
|
||||
reaction_flows.push_back(flow);
|
||||
if (flow > 1e-99) { // Avoid log(0)
|
||||
double log_flow = std::log10(flow);
|
||||
@@ -627,7 +626,7 @@ namespace gridfire {
|
||||
|
||||
// Group species by mass number for ranked layout.
|
||||
// If species.a() returns incorrect values (e.g., 0 for many species), they will be grouped together here.
|
||||
species_by_mass[species.a()].push_back(std::string(species.name()));
|
||||
species_by_mass[species.a()].emplace_back(species.name());
|
||||
}
|
||||
dotFile << "\n";
|
||||
|
||||
@@ -843,7 +842,7 @@ namespace gridfire {
|
||||
return equilibrateNetwork(Y, T9, rho);
|
||||
}
|
||||
|
||||
int MultiscalePartitioningEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
size_t MultiscalePartitioningEngineView::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
return m_baseEngine.getSpeciesIndex(species);
|
||||
}
|
||||
|
||||
@@ -859,14 +858,14 @@ namespace gridfire {
|
||||
m_logger->flush_log();
|
||||
throw exceptions::StaleEngineError("Failed to get species timescales due to stale engine state");
|
||||
}
|
||||
std::unordered_map<Species, double> all_timescales = result.value();
|
||||
const std::unordered_map<Species, double>& all_timescales = result.value();
|
||||
const auto& all_species = m_baseEngine.getNetworkSpecies();
|
||||
|
||||
std::vector<std::pair<double, size_t>> sorted_timescales;
|
||||
for (size_t i = 0; i < all_species.size(); ++i) {
|
||||
double timescale = all_timescales.at(all_species[i]);
|
||||
if (std::isfinite(timescale) && timescale > 0) {
|
||||
sorted_timescales.push_back({timescale, i});
|
||||
sorted_timescales.emplace_back(timescale, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,32 +971,6 @@ namespace gridfire {
|
||||
|
||||
}
|
||||
|
||||
// std::unordered_map<size_t, std::vector<size_t>> MultiscalePartitioningEngineView::buildConnectivityGraph(
|
||||
// const std::unordered_set<size_t> &fast_reaction_indices
|
||||
// ) const {
|
||||
// const auto& all_reactions = m_baseEngine.getNetworkReactions();
|
||||
// std::unordered_map<size_t, std::vector<size_t>> connectivity;
|
||||
// for (const size_t reaction_idx : fast_reaction_indices) {
|
||||
// const auto& reaction = all_reactions[reaction_idx];
|
||||
// const auto& reactants = reaction.reactants();
|
||||
// const auto& products = reaction.products();
|
||||
//
|
||||
// // For each fast reaction, create edges between all reactants and all products.
|
||||
// // This represents that nucleons can flow quickly between these species.
|
||||
// for (const auto& reactant : reactants) {
|
||||
// const size_t reactant_idx = m_baseEngine.getSpeciesIndex(reactant);
|
||||
// for (const auto& product : products) {
|
||||
// const size_t product_idx = m_baseEngine.getSpeciesIndex(product);
|
||||
//
|
||||
// // Add a two-way edge to the adjacency list.
|
||||
// connectivity[reactant_idx].push_back(product_idx);
|
||||
// connectivity[product_idx].push_back(reactant_idx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return connectivity;
|
||||
// }
|
||||
|
||||
std::vector<MultiscalePartitioningEngineView::QSEGroup>
|
||||
MultiscalePartitioningEngineView::validateGroupsWithFluxAnalysis(
|
||||
const std::vector<QSEGroup> &candidate_groups,
|
||||
@@ -1016,14 +989,14 @@ namespace gridfire {
|
||||
);
|
||||
|
||||
for (const auto& reaction: m_baseEngine.getNetworkReactions()) {
|
||||
const double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho));
|
||||
const double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, Y, T9, rho));
|
||||
if (flow == 0.0) {
|
||||
continue; // Skip reactions with zero flow
|
||||
}
|
||||
bool has_internal_reactant = false;
|
||||
bool has_external_reactant = false;
|
||||
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
if (group_members.contains(m_baseEngine.getSpeciesIndex(reactant))) {
|
||||
has_internal_reactant = true;
|
||||
} else {
|
||||
@@ -1034,7 +1007,7 @@ namespace gridfire {
|
||||
bool has_internal_product = false;
|
||||
bool has_external_product = false;
|
||||
|
||||
for (const auto& product : reaction.products()) {
|
||||
for (const auto& product : reaction->products()) {
|
||||
if (group_members.contains(m_baseEngine.getSpeciesIndex(product))) {
|
||||
has_internal_product = true;
|
||||
} else {
|
||||
@@ -1231,7 +1204,7 @@ namespace gridfire {
|
||||
|
||||
Eigen::VectorXd Y_scale(qse_solve_indices.size());
|
||||
Eigen::VectorXd v_initial(qse_solve_indices.size());
|
||||
for (size_t i = 0; i < qse_solve_indices.size(); ++i) {
|
||||
for (long i = 0; i < qse_solve_indices.size(); ++i) {
|
||||
constexpr double abundance_floor = 1.0e-15;
|
||||
const double initial_abundance = Y_full[qse_solve_indices[i]];
|
||||
Y_scale(i) = std::max(initial_abundance, abundance_floor);
|
||||
@@ -1273,7 +1246,7 @@ namespace gridfire {
|
||||
}
|
||||
LOG_TRACE_L1(m_logger, "Minimization succeeded!");
|
||||
Eigen::VectorXd Y_final_qse = Y_scale.array() * v_initial.array().sinh(); // Convert back to physical abundances using asinh scaling
|
||||
for (size_t i = 0; i < qse_solve_indices.size(); ++i) {
|
||||
for (long i = 0; i < qse_solve_indices.size(); ++i) {
|
||||
LOG_TRACE_L1(
|
||||
m_logger,
|
||||
"Species {} (index {}) started with abundance {} and ended with {}.",
|
||||
@@ -1314,7 +1287,7 @@ namespace gridfire {
|
||||
const double timescale = all_timescales.at(all_species[species_idx]);
|
||||
mean_timescale += timescale;
|
||||
}
|
||||
mean_timescale = mean_timescale / pool.size();
|
||||
mean_timescale = mean_timescale / static_cast<double>(pool.size());
|
||||
if (std::isinf(mean_timescale)) {
|
||||
LOG_CRITICAL(m_logger, "Encountered infinite mean timescale for pool {} with species: {}",
|
||||
count, [&]() -> std::string {
|
||||
@@ -1355,8 +1328,8 @@ namespace gridfire {
|
||||
return result;
|
||||
}();
|
||||
|
||||
std::map<size_t, std::vector<reaction::LogicalReaction*>> speciesReactionMap;
|
||||
std::vector<const reaction::LogicalReaction*> candidate_reactions;
|
||||
std::map<size_t, std::vector<reaction::LogicalReaclibReaction*>> speciesReactionMap;
|
||||
std::vector<const reaction::LogicalReaclibReaction*> candidate_reactions;
|
||||
|
||||
auto getSpeciesIdx = [&](const std::vector<Species> &species) -> std::vector<size_t> {
|
||||
std::vector<size_t> result;
|
||||
@@ -1369,8 +1342,8 @@ namespace gridfire {
|
||||
};
|
||||
|
||||
for (const auto& reaction : m_baseEngine.getNetworkReactions()) {
|
||||
const std::vector<Species> &reactants = reaction.reactants();
|
||||
const std::vector<Species> &products = reaction.products();
|
||||
const std::vector<Species> &reactants = reaction->reactants();
|
||||
const std::vector<Species> &products = reaction->products();
|
||||
|
||||
std::unordered_set<Species> reactant_set(reactants.begin(), reactants.end());
|
||||
std::unordered_set<Species> product_set(products.begin(), products.end());
|
||||
@@ -1422,15 +1395,15 @@ namespace gridfire {
|
||||
if (pool.empty()) continue; // Skip empty pools
|
||||
|
||||
// For each pool first identify all topological bridge connections
|
||||
std::vector<std::pair<reaction::LogicalReaction, double>> bridge_reactions;
|
||||
std::vector<std::pair<const reaction::Reaction*, double>> bridge_reactions;
|
||||
for (const auto& species_idx : pool) {
|
||||
Species ash = all_species[species_idx];
|
||||
for (const auto& reaction : all_reactions) {
|
||||
if (reaction.contains(ash)) {
|
||||
if (reaction->contains(ash)) {
|
||||
// Check to make sure there is at least one reactant that is not in the pool
|
||||
// This lets seed nuclei bring mass into the QSE group.
|
||||
bool has_external_reactant = false;
|
||||
for (const auto& reactant : reaction.reactants()) {
|
||||
for (const auto& reactant : reaction->reactants()) {
|
||||
if (std::ranges::find(pool, m_baseEngine.getSpeciesIndex(reactant)) == pool.end()) {
|
||||
has_external_reactant = true;
|
||||
LOG_TRACE_L3(m_logger, "Found external reactant {} in reaction {} for species {}.", reactant.name(), reaction.id(), ash.name());
|
||||
@@ -1438,9 +1411,9 @@ namespace gridfire {
|
||||
}
|
||||
}
|
||||
if (has_external_reactant) {
|
||||
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(reaction, Y, T9, rho));
|
||||
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, Y, T9, rho));
|
||||
LOG_TRACE_L3(m_logger, "Found bridge reaction {} with flow {} for species {}.", reaction.id(), flow, ash.name());
|
||||
bridge_reactions.push_back({reaction, flow});
|
||||
bridge_reactions.emplace_back(reaction.get(), flow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1467,8 +1440,8 @@ namespace gridfire {
|
||||
}
|
||||
|
||||
std::vector<size_t> seed_indices;
|
||||
for (size_t i = 0; i < bridge_reactions.size(); ++i) {
|
||||
for (const auto& fuel : bridge_reactions[i].first.reactants()) {
|
||||
for (auto &reaction: bridge_reactions | std::views::keys) {
|
||||
for (const auto& fuel : reaction->reactants()) {
|
||||
size_t fuel_idx = m_baseEngine.getSpeciesIndex(fuel);
|
||||
// Only add the fuel if it is not already in the pool
|
||||
if (std::ranges::find(pool, fuel_idx) == pool.end()) {
|
||||
@@ -1492,7 +1465,7 @@ namespace gridfire {
|
||||
mean_timescale += species.halfLife();
|
||||
}
|
||||
}
|
||||
mean_timescale /= poolSet.size();
|
||||
mean_timescale /= static_cast<double>(poolSet.size());
|
||||
QSEGroup qse_group(all_indices, false, poolSet, seedSet, mean_timescale);
|
||||
candidate_groups.push_back(qse_group);
|
||||
}
|
||||
@@ -1505,7 +1478,7 @@ namespace gridfire {
|
||||
std::vector<double> y_trial = m_Y_full_initial;
|
||||
Eigen::VectorXd y_qse = m_Y_scale.array() * v_qse.array().sinh(); // Convert to physical abundances using asinh scaling
|
||||
|
||||
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
y_trial[m_qse_solve_indices[i]] = y_qse(i);
|
||||
}
|
||||
|
||||
@@ -1514,8 +1487,8 @@ namespace gridfire {
|
||||
throw exceptions::StaleEngineError("Failed to calculate RHS and energy due to stale engine state");
|
||||
}
|
||||
const auto&[dydt, nuclearEnergyGenerationRate] = result.value();
|
||||
f_qse.resize(m_qse_solve_indices.size());
|
||||
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
f_qse.resize(static_cast<long>(m_qse_solve_indices.size()));
|
||||
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
f_qse(i) = dydt[m_qse_solve_indices[i]];
|
||||
}
|
||||
|
||||
@@ -1526,20 +1499,18 @@ namespace gridfire {
|
||||
std::vector<double> y_trial = m_Y_full_initial;
|
||||
Eigen::VectorXd y_qse = m_Y_scale.array() * v_qse.array().sinh(); // Convert to physical abundances using asinh scaling
|
||||
|
||||
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
y_trial[m_qse_solve_indices[i]] = y_qse(i);
|
||||
}
|
||||
|
||||
// TODO: Think about if the jacobian matrix should be mutable so that generateJacobianMatrix can be const
|
||||
m_view->getBaseEngine().generateJacobianMatrix(y_trial, m_T9, m_rho);
|
||||
|
||||
// TODO: Think very carefully about the indices here.
|
||||
J_qse.resize(m_qse_solve_indices.size(), m_qse_solve_indices.size());
|
||||
for (size_t i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
for (size_t j = 0; j < m_qse_solve_indices.size(); ++j) {
|
||||
J_qse.resize(static_cast<long>(m_qse_solve_indices.size()), static_cast<long>(m_qse_solve_indices.size()));
|
||||
for (long i = 0; i < m_qse_solve_indices.size(); ++i) {
|
||||
for (long j = 0; j < m_qse_solve_indices.size(); ++j) {
|
||||
J_qse(i, j) = m_view->getBaseEngine().getJacobianMatrixEntry(
|
||||
m_qse_solve_indices[i],
|
||||
m_qse_solve_indices[j]
|
||||
static_cast<int>(m_qse_solve_indices[i]),
|
||||
static_cast<int>(m_qse_solve_indices[j])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "gridfire/solver/solver.h"
|
||||
|
||||
#include "fourdst/composition/species.h"
|
||||
#include "fourdst/logging/logging.h"
|
||||
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/Logger.h"
|
||||
@@ -12,9 +11,6 @@
|
||||
#include <unordered_set>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <ranges>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace gridfire {
|
||||
@@ -54,8 +50,8 @@ namespace gridfire {
|
||||
) const {
|
||||
std::unordered_set<std::string> primeReactions;
|
||||
for (const auto &reaction : baseEngine.getNetworkReactions()) {
|
||||
if (reaction.contains(primingSpecies)) {
|
||||
primeReactions.insert(std::string(reaction.peName()));
|
||||
if (reaction->contains(primingSpecies)) {
|
||||
primeReactions.insert(std::string(reaction->id()));
|
||||
}
|
||||
}
|
||||
if (primeReactions.empty()) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "fourdst/logging/logging.h"
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/composition/species.h"
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ namespace gridfire::partition {
|
||||
const auto* records = reinterpret_cast<const record::RauscherThielemannPartitionDataRecord*>(rauscher_thielemann_partition_data);
|
||||
for (size_t i = 0; i < numRecords; ++i) {
|
||||
const auto&[z, a, ground_state_spin, normalized_g_values] = records[i];
|
||||
IsotopeData data;
|
||||
IsotopeData data{};
|
||||
data.ground_state_spin = ground_state_spin;
|
||||
std::ranges::copy(normalized_g_values, data.normalized_g_values.begin());
|
||||
const int key = make_key(z, a);
|
||||
const int key = make_key(static_cast<int>(z), static_cast<int>(a));
|
||||
LOG_TRACE_L3_LIMIT_EVERY_N(
|
||||
100,
|
||||
m_logger,
|
||||
@@ -36,7 +36,7 @@ namespace gridfire::partition {
|
||||
key
|
||||
);
|
||||
|
||||
m_partitionData[key] = std::move(data);
|
||||
m_partitionData[key] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ std::string trim_whitespace(const std::string& str) {
|
||||
}
|
||||
|
||||
namespace gridfire::reaclib {
|
||||
static reaction::LogicalReactionSet* s_all_reaclib_reactions_ptr = nullptr;
|
||||
static reaction::ReactionSet* s_all_reaclib_reactions_ptr = nullptr;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ReactionRecord {
|
||||
@@ -85,7 +85,7 @@ namespace gridfire::reaclib {
|
||||
const auto* records = reinterpret_cast<const ReactionRecord*>(raw_reactions_data);
|
||||
constexpr size_t num_reactions = raw_reactions_data_len / sizeof(ReactionRecord);
|
||||
|
||||
std::vector<reaction::Reaction> reaction_list;
|
||||
std::vector<std::unique_ptr<reaction::Reaction>> reaction_list;
|
||||
reaction_list.reserve(num_reactions);
|
||||
|
||||
for (size_t i = 0; i < num_reactions; ++i) {
|
||||
@@ -108,7 +108,7 @@ namespace gridfire::reaclib {
|
||||
};
|
||||
|
||||
// Construct the Reaction object. We use rpName for both the unique ID and the human-readable name.
|
||||
reaction_list.emplace_back(
|
||||
reaction_list.emplace_back(std::make_unique<reaction::ReaclibReaction>(
|
||||
rpName_sv,
|
||||
rpName_sv,
|
||||
chapter,
|
||||
@@ -118,15 +118,15 @@ namespace gridfire::reaclib {
|
||||
label_sv,
|
||||
rate_coeffs,
|
||||
reverse
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
// The ReactionSet takes the vector of all individual reactions.
|
||||
const reaction::ReactionSet reaction_set(std::move(reaction_list));
|
||||
|
||||
// The LogicalReactionSet groups reactions by their peName, which is what we want.
|
||||
s_all_reaclib_reactions_ptr = new reaction::LogicalReactionSet(
|
||||
reaction::packReactionSetToLogicalReactionSet(reaction_set)
|
||||
s_all_reaclib_reactions_ptr = new reaction::ReactionSet(
|
||||
reaction::packReactionSet(reaction_set)
|
||||
);
|
||||
|
||||
s_initialized = true;
|
||||
@@ -135,7 +135,7 @@ namespace gridfire::reaclib {
|
||||
|
||||
// --- Public Interface Implementation ---
|
||||
|
||||
const reaction::LogicalReactionSet& get_all_reactions() {
|
||||
const reaction::ReactionSet &get_all_reaclib_reactions() {
|
||||
// This ensures that the initialization happens only on the first call.
|
||||
if (!s_initialized) {
|
||||
initializeAllReaclibReactions();
|
||||
|
||||
@@ -13,10 +13,19 @@
|
||||
|
||||
#include "xxhash64.h"
|
||||
|
||||
namespace {
|
||||
std::string_view safe_check_reactant_id(const std::vector<gridfire::reaction::ReaclibReaction>& reactions) {
|
||||
if (reactions.empty()) {
|
||||
throw std::runtime_error("No reactions found in the REACLIB reaction set.");
|
||||
}
|
||||
return reactions.front().peName();
|
||||
}
|
||||
}
|
||||
|
||||
namespace gridfire::reaction {
|
||||
using namespace fourdst::atomic;
|
||||
|
||||
Reaction::Reaction(
|
||||
ReaclibReaction::ReaclibReaction(
|
||||
const std::string_view id,
|
||||
const std::string_view peName,
|
||||
const int chapter,
|
||||
@@ -36,15 +45,15 @@ namespace gridfire::reaction {
|
||||
m_rateCoefficients(sets),
|
||||
m_reverse(reverse) {}
|
||||
|
||||
double Reaction::calculate_rate(const double T9) const {
|
||||
double ReaclibReaction::calculate_rate(const double T9, const double rho, const std::vector<double>& Y) const {
|
||||
return calculate_rate<double>(T9);
|
||||
}
|
||||
|
||||
CppAD::AD<double> Reaction::calculate_rate(const CppAD::AD<double> T9) const {
|
||||
CppAD::AD<double> ReaclibReaction::calculate_rate(const CppAD::AD<double> T9, const CppAD::AD<double> rho, const std::vector<CppAD::AD<double>>& Y) const {
|
||||
return calculate_rate<CppAD::AD<double>>(T9);
|
||||
}
|
||||
|
||||
double Reaction::calculate_forward_rate_log_derivative(const double T9) const {
|
||||
double ReaclibReaction::calculate_forward_rate_log_derivative(const double T9, const double rho, const std::vector<double>& Y) const {
|
||||
constexpr double r_p13 = 1.0 / 3.0;
|
||||
constexpr double r_p53 = 5.0 / 3.0;
|
||||
constexpr double r_p23 = 2.0 / 3.0;
|
||||
@@ -65,12 +74,12 @@ namespace gridfire::reaction {
|
||||
return d_log_k_fwd_dT9; // Return the derivative of the log rate with respect to T9
|
||||
}
|
||||
|
||||
bool Reaction::contains(const Species &species) const {
|
||||
bool ReaclibReaction::contains(const Species &species) const {
|
||||
return contains_reactant(species) || contains_product(species);
|
||||
}
|
||||
|
||||
|
||||
bool Reaction::contains_reactant(const Species& species) const {
|
||||
bool ReaclibReaction::contains_reactant(const Species& species) const {
|
||||
for (const auto& reactant : m_reactants) {
|
||||
if (reactant == species) {
|
||||
return true;
|
||||
@@ -79,7 +88,7 @@ namespace gridfire::reaction {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Reaction::contains_product(const Species& species) const {
|
||||
bool ReaclibReaction::contains_product(const Species& species) const {
|
||||
for (const auto& product : m_products) {
|
||||
if (product == species) {
|
||||
return true;
|
||||
@@ -88,14 +97,14 @@ namespace gridfire::reaction {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_set<Species> Reaction::all_species() const {
|
||||
std::unordered_set<Species> ReaclibReaction::all_species() const {
|
||||
auto rs = reactant_species();
|
||||
auto ps = product_species();
|
||||
rs.insert(ps.begin(), ps.end());
|
||||
return rs;
|
||||
}
|
||||
|
||||
std::unordered_set<Species> Reaction::reactant_species() const {
|
||||
std::unordered_set<Species> ReaclibReaction::reactant_species() const {
|
||||
std::unordered_set<Species> reactantsSet;
|
||||
for (const auto& reactant : m_reactants) {
|
||||
reactantsSet.insert(reactant);
|
||||
@@ -103,7 +112,7 @@ namespace gridfire::reaction {
|
||||
return reactantsSet;
|
||||
}
|
||||
|
||||
std::unordered_set<Species> Reaction::product_species() const {
|
||||
std::unordered_set<Species> ReaclibReaction::product_species() const {
|
||||
std::unordered_set<Species> productsSet;
|
||||
for (const auto& product : m_products) {
|
||||
productsSet.insert(product);
|
||||
@@ -111,7 +120,7 @@ namespace gridfire::reaction {
|
||||
return productsSet;
|
||||
}
|
||||
|
||||
int Reaction::stoichiometry(const Species& species) const {
|
||||
int ReaclibReaction::stoichiometry(const Species& species) const {
|
||||
int s = 0;
|
||||
for (const auto& reactant : m_reactants) {
|
||||
if (reactant == species) {
|
||||
@@ -126,11 +135,11 @@ namespace gridfire::reaction {
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t Reaction::num_species() const {
|
||||
size_t ReaclibReaction::num_species() const {
|
||||
return all_species().size();
|
||||
}
|
||||
|
||||
std::unordered_map<Species, int> Reaction::stoichiometry() const {
|
||||
std::unordered_map<Species, int> ReaclibReaction::stoichiometry() const {
|
||||
std::unordered_map<Species, int> stoichiometryMap;
|
||||
for (const auto& reactant : m_reactants) {
|
||||
stoichiometryMap[reactant]--;
|
||||
@@ -141,7 +150,7 @@ namespace gridfire::reaction {
|
||||
return stoichiometryMap;
|
||||
}
|
||||
|
||||
double Reaction::excess_energy() const {
|
||||
double ReaclibReaction::excess_energy() const {
|
||||
double reactantMass = 0.0;
|
||||
double productMass = 0.0;
|
||||
constexpr double AMU2MeV = 931.494893; // Conversion factor from atomic mass unit to MeV
|
||||
@@ -154,14 +163,18 @@ namespace gridfire::reaction {
|
||||
return (reactantMass - productMass) * AMU2MeV;
|
||||
}
|
||||
|
||||
uint64_t Reaction::hash(const uint64_t seed) const {
|
||||
uint64_t ReaclibReaction::hash(const uint64_t seed) const {
|
||||
return XXHash64::hash(m_id.data(), m_id.size(), seed);
|
||||
}
|
||||
|
||||
std::unique_ptr<Reaction> ReaclibReaction::clone() const {
|
||||
return std::make_unique<ReaclibReaction>(*this);
|
||||
}
|
||||
|
||||
|
||||
LogicalReaction::LogicalReaction(const std::vector<Reaction>& reactants) :
|
||||
Reaction(reactants.front().peName(),
|
||||
LogicalReaclibReaction::LogicalReaclibReaction(const std::vector<ReaclibReaction>& reactants) :
|
||||
ReaclibReaction(
|
||||
safe_check_reactant_id(reactants), // Use this first to check if the reactants array is empty and safely exit if so
|
||||
reactants.front().peName(),
|
||||
reactants.front().chapter(),
|
||||
reactants.front().reactants(),
|
||||
@@ -177,45 +190,45 @@ namespace gridfire::reaction {
|
||||
if (std::abs(std::abs(reaction.qValue()) - std::abs(m_qValue)) > 1e-6) {
|
||||
LOG_ERROR(
|
||||
m_logger,
|
||||
"LogicalReaction constructed with reactions having different Q-values. Expected {} got {}.",
|
||||
"LogicalReaclibReaction constructed with reactions having different Q-values. Expected {} got {}.",
|
||||
m_qValue,
|
||||
reaction.qValue()
|
||||
);
|
||||
m_logger -> flush_log();
|
||||
throw std::runtime_error("LogicalReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + " (difference : " + std::to_string(std::abs(reaction.qValue() - m_qValue)) + ").");
|
||||
throw std::runtime_error("LogicalReaclibReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + " (difference : " + std::to_string(std::abs(reaction.qValue() - m_qValue)) + ").");
|
||||
}
|
||||
m_sources.push_back(std::string(reaction.sourceLabel()));
|
||||
m_sources.emplace_back(reaction.sourceLabel());
|
||||
m_rates.push_back(reaction.rateCoefficients());
|
||||
}
|
||||
}
|
||||
|
||||
void LogicalReaction::add_reaction(const Reaction& reaction) {
|
||||
void LogicalReaclibReaction::add_reaction(const ReaclibReaction& reaction) {
|
||||
if (reaction.peName() != m_id) {
|
||||
LOG_ERROR(m_logger, "Cannot add reaction with different peName to LogicalReaction. Expected {} got {}.", m_id, reaction.peName());
|
||||
LOG_ERROR(m_logger, "Cannot add reaction with different peName to LogicalReaclibReaction. Expected {} got {}.", m_id, reaction.peName());
|
||||
m_logger -> flush_log();
|
||||
throw std::runtime_error("Cannot add reaction with different peName to LogicalReaction. Expected " + std::string(m_id) + " got " + std::string(reaction.peName()) + ".");
|
||||
throw std::runtime_error("Cannot add reaction with different peName to LogicalReaclibReaction. Expected " + std::string(m_id) + " got " + std::string(reaction.peName()) + ".");
|
||||
}
|
||||
for (const auto& source : m_sources) {
|
||||
if (source == reaction.sourceLabel()) {
|
||||
LOG_ERROR(m_logger, "Cannot add reaction with duplicate source label {} to LogicalReaction.", reaction.sourceLabel());
|
||||
LOG_ERROR(m_logger, "Cannot add reaction with duplicate source label {} to LogicalReaclibReaction.", reaction.sourceLabel());
|
||||
m_logger -> flush_log();
|
||||
throw std::runtime_error("Cannot add reaction with duplicate source label " + std::string(reaction.sourceLabel()) + " to LogicalReaction.");
|
||||
throw std::runtime_error("Cannot add reaction with duplicate source label " + std::string(reaction.sourceLabel()) + " to LogicalReaclibReaction.");
|
||||
}
|
||||
}
|
||||
if (std::abs(reaction.qValue() - m_qValue) > 1e-6) {
|
||||
LOG_ERROR(m_logger, "LogicalReaction constructed with reactions having different Q-values. Expected {} got {}.", m_qValue, reaction.qValue());
|
||||
LOG_ERROR(m_logger, "LogicalReaclibReaction constructed with reactions having different Q-values. Expected {} got {}.", m_qValue, reaction.qValue());
|
||||
m_logger -> flush_log();
|
||||
throw std::runtime_error("LogicalReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + ".");
|
||||
throw std::runtime_error("LogicalReaclibReaction constructed with reactions having different Q-values. Expected " + std::to_string(m_qValue) + " got " + std::to_string(reaction.qValue()) + ".");
|
||||
}
|
||||
m_sources.push_back(std::string(reaction.sourceLabel()));
|
||||
m_sources.emplace_back(reaction.sourceLabel());
|
||||
m_rates.push_back(reaction.rateCoefficients());
|
||||
}
|
||||
|
||||
double LogicalReaction::calculate_rate(const double T9) const {
|
||||
double LogicalReaclibReaction::calculate_rate(const double T9, const double rho, const std::vector<double>& Y) const {
|
||||
return calculate_rate<double>(T9);
|
||||
}
|
||||
|
||||
double LogicalReaction::calculate_forward_rate_log_derivative(const double T9) const {
|
||||
double LogicalReaclibReaction::calculate_forward_rate_log_derivative(const double T9, const double rho, const std::vector<double>& Y) const {
|
||||
constexpr double r_p13 = 1.0 / 3.0;
|
||||
constexpr double r_p53 = 5.0 / 3.0;
|
||||
constexpr double r_p23 = 2.0 / 3.0;
|
||||
@@ -266,28 +279,260 @@ namespace gridfire::reaction {
|
||||
return totalRateDerivative / totalRate;
|
||||
}
|
||||
|
||||
CppAD::AD<double> LogicalReaction::calculate_rate(const CppAD::AD<double> T9) const {
|
||||
std::unique_ptr<Reaction> LogicalReaclibReaction::clone() const {
|
||||
return std::make_unique<LogicalReaclibReaction>(*this);
|
||||
}
|
||||
|
||||
CppAD::AD<double> LogicalReaclibReaction::calculate_rate(
|
||||
const CppAD::AD<double> T9,
|
||||
const CppAD::AD<double> rho,
|
||||
const std::vector<CppAD::AD<double>>& Y
|
||||
) const {
|
||||
return calculate_rate<CppAD::AD<double>>(T9);
|
||||
}
|
||||
|
||||
LogicalReactionSet packReactionSetToLogicalReactionSet(const ReactionSet& reactionSet) {
|
||||
std::unordered_map<std::string_view, std::vector<Reaction>> groupedReactions;
|
||||
|
||||
for (const auto& reaction: reactionSet) {
|
||||
groupedReactions[reaction.peName()].push_back(reaction);
|
||||
ReactionSet::ReactionSet(
|
||||
std::vector<std::unique_ptr<Reaction>>&& reactions
|
||||
) :
|
||||
m_reactions(std::move(reactions)) {
|
||||
if (m_reactions.empty()) {
|
||||
return; // Case where the reactions will be added later.
|
||||
}
|
||||
m_reactionNameMap.reserve(reactions.size());
|
||||
size_t i = 0;
|
||||
for (const auto& reaction : m_reactions) {
|
||||
m_id += reaction->id();
|
||||
m_reactionNameMap.emplace(std::string(reaction->id()), i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<LogicalReaction> reactions;
|
||||
reactions.reserve(groupedReactions.size());
|
||||
ReactionSet::ReactionSet(const std::vector<Reaction *> &reactions) {
|
||||
m_reactions.reserve(reactions.size());
|
||||
m_reactionNameMap.reserve(reactions.size());
|
||||
size_t i = 0;
|
||||
for (const auto& reaction : reactions) {
|
||||
m_reactions.push_back(reaction->clone());
|
||||
m_id += reaction->id();
|
||||
m_reactionNameMap.emplace(std::string(reaction->id()), i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &reactionsGroup: groupedReactions | std::views::values) {
|
||||
LogicalReaction logicalReaction(reactionsGroup);
|
||||
reactions.push_back(logicalReaction);
|
||||
ReactionSet::ReactionSet() = default;
|
||||
|
||||
ReactionSet::ReactionSet(const ReactionSet &other) {
|
||||
m_reactions.reserve(other.m_reactions.size());
|
||||
for (const auto& reaction: other.m_reactions) {
|
||||
m_reactions.push_back(reaction->clone());
|
||||
}
|
||||
return LogicalReactionSet(std::move(reactions));
|
||||
|
||||
m_reactionNameMap.reserve(other.m_reactionNameMap.size());
|
||||
size_t i = 0;
|
||||
for (const auto& reaction : m_reactions) {
|
||||
m_reactionNameMap.emplace(std::string(reaction->id()), i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
ReactionSet& ReactionSet::operator=(const ReactionSet &other) {
|
||||
if (this != &other) {
|
||||
ReactionSet temp(other);
|
||||
std::swap(m_reactions, temp.m_reactions);
|
||||
std::swap(m_reactionNameMap, temp.m_reactionNameMap);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ReactionSet::add_reaction(const Reaction& reaction) {
|
||||
const std::size_t new_index = m_reactions.size();
|
||||
|
||||
auto reaction_id = std::string(reaction.id());
|
||||
|
||||
m_reactions.emplace_back(reaction.clone());
|
||||
m_id += reaction_id;
|
||||
|
||||
m_reactionNameMap.emplace(std::move(reaction_id), new_index);
|
||||
}
|
||||
|
||||
void ReactionSet::add_reaction(std::unique_ptr<Reaction>&& reaction) {
|
||||
const std::size_t new_index = m_reactionNameMap.size();
|
||||
|
||||
auto reaction_id = std::string(reaction->id());
|
||||
|
||||
m_reactions.emplace_back(std::move(reaction));
|
||||
|
||||
m_id += reaction_id;
|
||||
|
||||
m_reactionNameMap.emplace(std::move(reaction_id), new_index);
|
||||
}
|
||||
|
||||
void ReactionSet::remove_reaction(const Reaction& reaction) {
|
||||
const auto reaction_id = std::string(reaction.id());
|
||||
if (!m_reactionNameMap.contains(reaction_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::erase_if(m_reactions, [&reaction_id](const auto& r_ptr) {
|
||||
return r_ptr->id() == reaction_id;
|
||||
});
|
||||
|
||||
m_reactionNameMap.clear();
|
||||
m_reactionNameMap.reserve(m_reactions.size());
|
||||
for (size_t i = 0; i < m_reactions.size(); ++i) {
|
||||
m_reactionNameMap.emplace(std::string(m_reactions[i]->id()), i);
|
||||
}
|
||||
|
||||
m_id.clear();
|
||||
for (const auto& r_ptr : m_reactions) {
|
||||
m_id += r_ptr->id();
|
||||
}
|
||||
}
|
||||
|
||||
bool ReactionSet::contains(const std::string_view& id) const {
|
||||
for (const auto& reaction : m_reactions) {
|
||||
if (reaction->id() == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReactionSet::contains(const Reaction& reaction) const {
|
||||
for (const auto& r : m_reactions) {
|
||||
if (r->id() == reaction.id()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReactionSet::clear() {
|
||||
m_reactions.clear();
|
||||
m_reactionNameMap.clear();
|
||||
}
|
||||
|
||||
bool ReactionSet::contains_species(const Species& species) const {
|
||||
for (const auto& reaction : m_reactions) {
|
||||
if (reaction->contains(species)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReactionSet::contains_reactant(const Species& species) const {
|
||||
for (const auto& r : m_reactions) {
|
||||
if (r->contains_reactant(species)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReactionSet::contains_product(const Species& species) const {
|
||||
for (const auto& r : m_reactions) {
|
||||
if (r->contains_product(species)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Reaction& ReactionSet::operator[](const size_t index) const {
|
||||
if (index >= m_reactions.size()) {
|
||||
m_logger -> flush_log();
|
||||
throw std::out_of_range("Index" + std::to_string(index) + " out of range for ReactionSet of size " + std::to_string(m_reactions.size()) + ".");
|
||||
}
|
||||
return *m_reactions[index];
|
||||
}
|
||||
|
||||
const Reaction& ReactionSet::operator[](const std::string_view& id) const {
|
||||
if (auto it = m_reactionNameMap.find(std::string(id)); it != m_reactionNameMap.end()) {
|
||||
return *m_reactions[it->second];
|
||||
}
|
||||
m_logger -> flush_log();
|
||||
throw std::out_of_range("Species " + std::string(id) + " does not exist in ReactionSet.");
|
||||
}
|
||||
|
||||
bool ReactionSet::operator==(const ReactionSet& other) const {
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
return hash(0) == other.hash(0);
|
||||
}
|
||||
|
||||
bool ReactionSet::operator!=(const ReactionSet& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
uint64_t ReactionSet::hash(uint64_t seed) const {
|
||||
if (m_reactions.empty()) {
|
||||
return XXHash64::hash(nullptr, 0, seed);
|
||||
}
|
||||
std::vector<uint64_t> individualReactionHashes;
|
||||
individualReactionHashes.reserve(m_reactions.size());
|
||||
for (const auto& reaction : m_reactions) {
|
||||
individualReactionHashes.push_back(reaction->hash(seed));
|
||||
}
|
||||
|
||||
std::ranges::sort(individualReactionHashes);
|
||||
|
||||
const auto data = static_cast<const void*>(individualReactionHashes.data());
|
||||
const size_t sizeInBytes = individualReactionHashes.size() * sizeof(uint64_t);
|
||||
return XXHash64::hash(data, sizeInBytes, seed);
|
||||
}
|
||||
|
||||
std::unordered_set<Species> ReactionSet::getReactionSetSpecies() const {
|
||||
std::unordered_set<Species> species;
|
||||
for (const auto& reaction : m_reactions) {
|
||||
const auto reactionSpecies = reaction->all_species();
|
||||
species.insert(reactionSpecies.begin(), reactionSpecies.end());
|
||||
}
|
||||
return species;
|
||||
}
|
||||
|
||||
ReactionSet packReactionSet(const ReactionSet& reactionSet) {
|
||||
std::unordered_map<std::string, std::vector<ReaclibReaction>> groupedReaclibReactions;
|
||||
ReactionSet finalReactionSet;
|
||||
|
||||
for (const auto& reaction_ptr : reactionSet) {
|
||||
switch (reaction_ptr->type()) {
|
||||
case ReactionType::REACLIB: {
|
||||
const auto& reaclib_cast_reaction = static_cast<const ReaclibReaction&>(*reaction_ptr); // NOLINT(*-pro-type-static-cast-downcast)
|
||||
groupedReaclibReactions[std::string(reaclib_cast_reaction.peName())].push_back(reaclib_cast_reaction);
|
||||
break;
|
||||
}
|
||||
case ReactionType::LOGICAL_REACLIB: {
|
||||
// It doesn't make sense to pack an already-packed reaction.
|
||||
throw std::runtime_error("packReactionSet: Cannot pack a LogicalReaclibReaction.");
|
||||
}
|
||||
case ReactionType::WEAK: {
|
||||
finalReactionSet.add_reaction(*reaction_ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, process the grouped REACLIB reactions
|
||||
for (const auto &reactionsGroup: groupedReaclibReactions | std::views::values) {
|
||||
if (reactionsGroup.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (reactionsGroup.size() == 1) {
|
||||
finalReactionSet.add_reaction(reactionsGroup.front());
|
||||
}
|
||||
else {
|
||||
const auto logicalReaction = std::make_unique<LogicalReaclibReaction>(reactionsGroup);
|
||||
finalReactionSet.add_reaction(logicalReaction->clone());
|
||||
}
|
||||
}
|
||||
|
||||
return finalReactionSet;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<gridfire::reaction::Reaction> {
|
||||
@@ -302,11 +547,4 @@ namespace std {
|
||||
return s.hash(0);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<gridfire::reaction::LogicalReactionSet> {
|
||||
size_t operator()(const gridfire::reaction::LogicalReactionSet& s) const noexcept {
|
||||
return s.hash(0);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
94
src/lib/reaction/weak/weak.cpp
Normal file
94
src/lib/reaction/weak/weak.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "gridfire/reaction/weak/weak_rate_library.h"
|
||||
#include "gridfire/reaction/weak/weak.h"
|
||||
|
||||
#include "fourdst/composition/species.h"
|
||||
|
||||
#include <array>
|
||||
#include <ranges>
|
||||
#include <unordered_map>
|
||||
#include <expected>
|
||||
|
||||
#define GRIDFIRE_WEAK_REACTION_LIB_SENTINEL -60.0
|
||||
|
||||
namespace gridfire::rates::weak {
|
||||
WeakReactionMap::WeakReactionMap() {
|
||||
using namespace fourdst::atomic;
|
||||
|
||||
|
||||
for (const auto& weak_reaction_record : UNIFIED_WEAK_DATA) {
|
||||
Species species = az_to_species(weak_reaction_record.A, weak_reaction_record.Z);
|
||||
|
||||
if (weak_reaction_record.log_beta_minus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||
m_weak_network[species].push_back(
|
||||
WeakReaction{
|
||||
WeakReactionType::BETA_MINUS_DECAY,
|
||||
weak_reaction_record.t9,
|
||||
weak_reaction_record.log_rhoye,
|
||||
weak_reaction_record.mu_e,
|
||||
weak_reaction_record.log_beta_minus,
|
||||
weak_reaction_record.log_antineutrino_loss_bd
|
||||
}
|
||||
);
|
||||
}
|
||||
if (weak_reaction_record.log_beta_plus > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||
m_weak_network[species].push_back(
|
||||
WeakReaction{
|
||||
WeakReactionType::BETA_PLUS_DECAY,
|
||||
weak_reaction_record.t9,
|
||||
weak_reaction_record.log_rhoye,
|
||||
weak_reaction_record.mu_e,
|
||||
weak_reaction_record.log_beta_plus,
|
||||
weak_reaction_record.log_neutrino_loss_ec
|
||||
}
|
||||
);
|
||||
}
|
||||
if (weak_reaction_record.log_electron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||
m_weak_network[species].push_back(
|
||||
WeakReaction{
|
||||
WeakReactionType::ELECTRON_CAPTURE,
|
||||
weak_reaction_record.t9,
|
||||
weak_reaction_record.log_rhoye,
|
||||
weak_reaction_record.mu_e,
|
||||
weak_reaction_record.log_electron_capture,
|
||||
weak_reaction_record.log_neutrino_loss_ec
|
||||
}
|
||||
);
|
||||
}
|
||||
if (weak_reaction_record.log_positron_capture > GRIDFIRE_WEAK_REACTION_LIB_SENTINEL) {
|
||||
m_weak_network[species].push_back(
|
||||
WeakReaction{
|
||||
WeakReactionType::POSITRON_CAPTURE,
|
||||
weak_reaction_record.t9,
|
||||
weak_reaction_record.log_rhoye,
|
||||
weak_reaction_record.mu_e,
|
||||
weak_reaction_record.log_positron_capture,
|
||||
weak_reaction_record.log_antineutrino_loss_bd
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<WeakReaction> WeakReactionMap::get_all_reactions() const {
|
||||
std::vector<WeakReaction> reactions;
|
||||
for (const auto &species_reactions: m_weak_network | std::views::values) {
|
||||
reactions.insert(reactions.end(), species_reactions.begin(), species_reactions.end());
|
||||
}
|
||||
return reactions;
|
||||
}
|
||||
|
||||
std::expected<std::vector<WeakReaction>, bool> WeakReactionMap::get_species_reactions(const fourdst::atomic::Species &species) const {
|
||||
if (m_weak_network.contains(species)) {
|
||||
return m_weak_network.at(species);
|
||||
}
|
||||
return std::unexpected(false);
|
||||
}
|
||||
|
||||
std::expected<std::vector<WeakReaction>, bool> WeakReactionMap::get_species_reactions(const std::string &species_name) const {
|
||||
fourdst::atomic::Species species = fourdst::atomic::species.at(species_name);
|
||||
if (m_weak_network.contains(species)) {
|
||||
return m_weak_network.at(species);
|
||||
}
|
||||
return std::unexpected(false);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace gridfire::screening {
|
||||
using ADDouble = CppAD::AD<double>;
|
||||
std::vector<ADDouble> BareScreeningModel::calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet &reactions,
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<ADDouble> &Y,
|
||||
const ADDouble T9,
|
||||
@@ -20,7 +20,7 @@ namespace gridfire::screening {
|
||||
}
|
||||
|
||||
std::vector<double> BareScreeningModel::calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet &reactions,
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<double> &Y,
|
||||
const double T9,
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace gridfire::screening {
|
||||
return std::make_unique<WeakScreeningModel>();
|
||||
case ScreeningType::BARE:
|
||||
return std::make_unique<BareScreeningModel>();
|
||||
default:
|
||||
return std::make_unique<BareScreeningModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace gridfire::screening {
|
||||
using ADDouble = CppAD::AD<double>;
|
||||
std::vector<ADDouble> WeakScreeningModel::calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet &reactions,
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<ADDouble> &Y,
|
||||
const ADDouble T9,
|
||||
@@ -20,7 +20,7 @@ namespace gridfire::screening {
|
||||
}
|
||||
|
||||
std::vector<double> WeakScreeningModel::calculateScreeningFactors(
|
||||
const reaction::LogicalReactionSet &reactions,
|
||||
const reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species>& species,
|
||||
const std::vector<double> &Y,
|
||||
const double T9,
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/config/config.h"
|
||||
|
||||
#include "fourdst/plugin/plugin.h"
|
||||
|
||||
#include "gridfire/interfaces/solver/solver_interfaces.h"
|
||||
|
||||
#include "unsupported/Eigen/NonLinearOptimization"
|
||||
|
||||
#include <boost/numeric/odeint.hpp>
|
||||
@@ -50,7 +54,6 @@ namespace gridfire::solver {
|
||||
Y(i) = comp.getMolarAbundance(species);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: a good starting point to make the temperature, density, and energy self consistent would be to turn this into an accumulator
|
||||
Y(numSpeciesInternal) = 0.0; // Specific energy rate, initialized to zero
|
||||
};
|
||||
@@ -109,7 +112,7 @@ namespace gridfire::solver {
|
||||
NetIn netInTemp = netIn;
|
||||
netInTemp.temperature = e.temperature();
|
||||
netInTemp.density = e.density();
|
||||
netInTemp.composition = std::move(temp_comp);
|
||||
netInTemp.composition = temp_comp;
|
||||
|
||||
Composition currentComposition = m_engine.update(netInTemp);
|
||||
populateY(currentComposition);
|
||||
@@ -220,6 +223,13 @@ namespace gridfire::solver {
|
||||
oss << "(Step: " << std::setw(10) << m_num_steps << ") t = " << t << " (dt = " << dt << ", eps_nuc: " << state(state.size() - 1) << " [erg])\n";
|
||||
std::cout << oss.str();
|
||||
|
||||
fourdst::plugin::manager::PluginManager &pluginManager = fourdst::plugin::manager::PluginManager::getInstance();
|
||||
|
||||
if (pluginManager.has("gridfire/solver")) {
|
||||
auto* plugin = pluginManager.get<SolverPluginInterface>("gridfire/solver");
|
||||
plugin -> log_time(t, dt);
|
||||
}
|
||||
|
||||
// Callback logic
|
||||
if (m_callback) {
|
||||
LOG_TRACE_L1(m_logger, "Calling user callback function at t = {:0.3E} with dt = {:0.3E}", t, dt);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
std::string gridfire::utils::formatNuclearTimescaleLogString(
|
||||
|
||||
@@ -32,6 +32,7 @@ gridfire_build_dependencies = [
|
||||
log_dep,
|
||||
xxhash_dep,
|
||||
eigen_dep,
|
||||
plugin_dep,
|
||||
]
|
||||
|
||||
# Define the libnetwork library so it can be linked against by other parts of the build system
|
||||
@@ -77,4 +78,10 @@ gridfire_headers = files(
|
||||
)
|
||||
install_headers(gridfire_headers, subdir : 'gridfire')
|
||||
|
||||
solver_interface_headers = files(
|
||||
'include/gridfire/interfaces/solver/solver_interfaces.h',
|
||||
)
|
||||
|
||||
install_headers(solver_interface_headers, subdir : 'gridfire/interfaces/solver')
|
||||
|
||||
subdir('python')
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "types/bindings.h"
|
||||
#include "partition/bindings.h"
|
||||
#include "expectations/bindings.h"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
|
||||
|
||||
#include <iostream>
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
@@ -152,7 +150,7 @@ void register_engine_bindings(py::module &m) {
|
||||
);
|
||||
}
|
||||
|
||||
void register_base_engine_bindings(pybind11::module &m) {
|
||||
void register_base_engine_bindings(const pybind11::module &m) {
|
||||
|
||||
py::class_<gridfire::StepDerivatives<double>>(m, "StepDerivatives")
|
||||
.def_readonly("dYdt", &gridfire::StepDerivatives<double>::dydt, "The right-hand side (dY/dt) of the ODE system.")
|
||||
@@ -165,15 +163,15 @@ void register_base_engine_bindings(pybind11::module &m) {
|
||||
con_stype_register_graph_engine_bindings(m);
|
||||
}
|
||||
|
||||
void abs_stype_register_engine_bindings(pybind11::module &m) {
|
||||
void abs_stype_register_engine_bindings(const pybind11::module &m) {
|
||||
py::class_<gridfire::Engine, PyEngine>(m, "Engine");
|
||||
}
|
||||
|
||||
void abs_stype_register_dynamic_engine_bindings(pybind11::module &m) {
|
||||
void abs_stype_register_dynamic_engine_bindings(const pybind11::module &m) {
|
||||
const auto a = py::class_<gridfire::DynamicEngine, PyDynamicEngine>(m, "DynamicEngine");
|
||||
}
|
||||
|
||||
void con_stype_register_graph_engine_bindings(pybind11::module &m) {
|
||||
void con_stype_register_graph_engine_bindings(const pybind11::module &m) {
|
||||
py::enum_<gridfire::NetworkBuildDepth>(m, "NetworkBuildDepth")
|
||||
.value("Full", gridfire::NetworkBuildDepth::Full, "Full network build depth")
|
||||
.value("Shallow", gridfire::NetworkBuildDepth::Shallow, "Shallow network build depth")
|
||||
@@ -199,7 +197,7 @@ void con_stype_register_graph_engine_bindings(pybind11::module &m) {
|
||||
py::arg("depth") = gridfire::NetworkBuildDepth::Full,
|
||||
"Initialize GraphEngine with a composition, partition function and build depth."
|
||||
);
|
||||
py_dynamic_engine_bindings.def(py::init<const gridfire::reaction::LogicalReactionSet &>(),
|
||||
py_dynamic_engine_bindings.def(py::init<const gridfire::reaction::ReactionSet &>(),
|
||||
py::arg("reactions"),
|
||||
"Initialize GraphEngine with a set of reactions."
|
||||
);
|
||||
@@ -267,7 +265,7 @@ void con_stype_register_graph_engine_bindings(pybind11::module &m) {
|
||||
registerDynamicEngineDefs<gridfire::GraphEngine, gridfire::DynamicEngine>(py_dynamic_engine_bindings);
|
||||
}
|
||||
|
||||
void register_engine_view_bindings(pybind11::module &m) {
|
||||
void register_engine_view_bindings(const pybind11::module &m) {
|
||||
auto py_defined_engine_view_bindings = py::class_<gridfire::DefinedEngineView, gridfire::DynamicEngine>(m, "DefinedEngineView");
|
||||
|
||||
py_defined_engine_view_bindings.def(py::init<std::vector<std::string>, gridfire::DynamicEngine&>(),
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
void register_engine_bindings(pybind11::module &m);
|
||||
|
||||
void register_base_engine_bindings(pybind11::module &m);
|
||||
void register_base_engine_bindings(const pybind11::module &m);
|
||||
|
||||
void register_engine_view_bindings(pybind11::module &m);
|
||||
void register_engine_view_bindings(const pybind11::module &m);
|
||||
|
||||
void abs_stype_register_engine_bindings(pybind11::module &m);
|
||||
void abs_stype_register_dynamic_engine_bindings(pybind11::module &m);
|
||||
void abs_stype_register_engine_bindings(const pybind11::module &m);
|
||||
void abs_stype_register_dynamic_engine_bindings(const pybind11::module &m);
|
||||
|
||||
void con_stype_register_graph_engine_bindings(pybind11::module &m);
|
||||
void con_stype_register_graph_engine_bindings(const pybind11::module &m);
|
||||
|
||||
|
||||
|
||||
@@ -23,10 +23,9 @@ const std::vector<fourdst::atomic::Species>& PyEngine::getNetworkSpecies() const
|
||||
/*
|
||||
* get_override() looks for a Python method that overrides this C++ one.
|
||||
*/
|
||||
py::function override = py::get_override(this, "getNetworkSpecies");
|
||||
|
||||
if (override) {
|
||||
py::object result = override();
|
||||
if (const py::function override = py::get_override(this, "getNetworkSpecies")) {
|
||||
const py::object result = override();
|
||||
m_species_cache = result.cast<std::vector<fourdst::atomic::Species>>();
|
||||
return m_species_cache;
|
||||
}
|
||||
@@ -57,10 +56,9 @@ const std::vector<fourdst::atomic::Species>& PyDynamicEngine::getNetworkSpecies(
|
||||
/*
|
||||
* get_override() looks for a Python method that overrides this C++ one.
|
||||
*/
|
||||
py::function override = py::get_override(this, "getNetworkSpecies");
|
||||
|
||||
if (override) {
|
||||
py::object result = override();
|
||||
if (const py::function override = py::get_override(this, "getNetworkSpecies")) {
|
||||
const py::object result = override();
|
||||
m_species_cache = result.cast<std::vector<fourdst::atomic::Species>>();
|
||||
return m_species_cache;
|
||||
}
|
||||
@@ -129,15 +127,15 @@ double PyDynamicEngine::calculateMolarReactionFlow(const gridfire::reaction::Rea
|
||||
);
|
||||
}
|
||||
|
||||
const gridfire::reaction::LogicalReactionSet& PyDynamicEngine::getNetworkReactions() const {
|
||||
const gridfire::reaction::ReactionSet& PyDynamicEngine::getNetworkReactions() const {
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
const gridfire::reaction::LogicalReactionSet&,
|
||||
const gridfire::reaction::ReactionSet&,
|
||||
gridfire::DynamicEngine,
|
||||
getNetworkReactions
|
||||
);
|
||||
}
|
||||
|
||||
void PyDynamicEngine::setNetworkReactions(const gridfire::reaction::LogicalReactionSet& reactions) {
|
||||
void PyDynamicEngine::setNetworkReactions(const gridfire::reaction::ReactionSet& reactions) {
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
void,
|
||||
gridfire::DynamicEngine,
|
||||
@@ -199,7 +197,7 @@ gridfire::screening::ScreeningType PyDynamicEngine::getScreeningModel() const {
|
||||
);
|
||||
}
|
||||
|
||||
int PyDynamicEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
size_t PyDynamicEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const {
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
int,
|
||||
gridfire::DynamicEngine,
|
||||
|
||||
@@ -27,15 +27,16 @@ public:
|
||||
void generateStoichiometryMatrix() override;
|
||||
int getStoichiometryMatrixEntry(int speciesIndex, int reactionIndex) const override;
|
||||
double calculateMolarReactionFlow(const gridfire::reaction::Reaction &reaction, const std::vector<double> &Y, double T9, double rho) const override;
|
||||
const gridfire::reaction::LogicalReactionSet& getNetworkReactions() const override;
|
||||
void setNetworkReactions(const gridfire::reaction::LogicalReactionSet& reactions) override;
|
||||
const gridfire::reaction::ReactionSet& getNetworkReactions() const override;
|
||||
void setNetworkReactions(const gridfire::reaction::ReactionSet& reactions) override;
|
||||
std::expected<std::unordered_map<fourdst::atomic::Species, double>, gridfire::expectations::StaleEngineError> getSpeciesTimescales(const std::vector<double> &Y, double T9, double rho) const override;
|
||||
std::expected<std::unordered_map<fourdst::atomic::Species, double>, gridfire::expectations::StaleEngineError> getSpeciesDestructionTimescales(const std::vector<double> &Y, double T9, double rho) const override;
|
||||
fourdst::composition::Composition update(const gridfire::NetIn &netIn) override;
|
||||
bool isStale(const gridfire::NetIn &netIn) override;
|
||||
void setScreeningModel(gridfire::screening::ScreeningType model) override;
|
||||
gridfire::screening::ScreeningType getScreeningModel() const override;
|
||||
int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
size_t getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||
std::vector<double> mapNetInToMolarAbundanceVector(const gridfire::NetIn &netIn) const override;
|
||||
gridfire::PrimingReport primeEngine(const gridfire::NetIn &netIn) override;
|
||||
gridfire::BuildDepthType getDepth() const override {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
@@ -10,7 +6,7 @@ namespace py = pybind11;
|
||||
|
||||
#include "gridfire/exceptions/exceptions.h"
|
||||
|
||||
void register_exception_bindings(py::module &m) {
|
||||
void register_exception_bindings(const py::module &m) {
|
||||
py::register_exception<gridfire::exceptions::EngineError>(m, "GridFireEngineError");
|
||||
|
||||
// TODO: Make it so that we can grab the stale state in python
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
void register_exception_bindings(pybind11::module &m);
|
||||
void register_exception_bindings(const pybind11::module &m);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace py = pybind11;
|
||||
|
||||
#include "gridfire/expectations/expectations.h"
|
||||
|
||||
void register_expectation_bindings(py::module &m) {
|
||||
void register_expectation_bindings(const py::module &m) {
|
||||
py::enum_<gridfire::expectations::EngineErrorTypes>(m, "EngineErrorTypes")
|
||||
.value("FAILURE", gridfire::expectations::EngineErrorTypes::FAILURE)
|
||||
.value("INDEX", gridfire::expectations::EngineErrorTypes::INDEX)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
void register_expectation_bindings(pybind11::module &m);
|
||||
void register_expectation_bindings(const pybind11::module &m);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "bindings.h"
|
||||
@@ -12,12 +10,12 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
void register_io_bindings(py::module &m) {
|
||||
py::class_<gridfire::io::ParsedNetworkData>(m, "ParsedNetworkData");
|
||||
auto register_io_bindings(const py::module &m) -> void {
|
||||
auto ParsedNetworkData = py::class_<gridfire::io::ParsedNetworkData>(m, "ParsedNetworkData");
|
||||
|
||||
py::class_<gridfire::io::NetworkFileParser, PyNetworkFileParser>(m, "NetworkFileParser");
|
||||
auto NetworkFileParser = py::class_<gridfire::io::NetworkFileParser, PyNetworkFileParser>(m, "NetworkFileParser");
|
||||
|
||||
py::class_<gridfire::io::SimpleReactionListFileParser, gridfire::io::NetworkFileParser>(m, "SimpleReactionListFileParser")
|
||||
auto SimpleReactionListFileParser = py::class_<gridfire::io::SimpleReactionListFileParser, gridfire::io::NetworkFileParser>(m, "SimpleReactionListFileParser")
|
||||
.def("parse", &gridfire::io::SimpleReactionListFileParser::parse,
|
||||
py::arg("filename"),
|
||||
"Parse a simple reaction list file and return a ParsedNetworkData object.");
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
void register_io_bindings(pybind11::module &m);
|
||||
void register_io_bindings(const pybind11::module &m);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -19,7 +19,7 @@ namespace py = pybind11;
|
||||
|
||||
void register_partition_bindings(pybind11::module &m) {
|
||||
using PF = gridfire::partition::PartitionFunction;
|
||||
py::class_<PF, PyPartitionFunction>(m, "PartitionFunction");
|
||||
auto TrampPartitionFunction = py::class_<PF, PyPartitionFunction>(m, "PartitionFunction");
|
||||
|
||||
register_partition_types_bindings(m);
|
||||
register_ground_state_partition_bindings(m);
|
||||
@@ -44,7 +44,7 @@ void register_partition_types_bindings(pybind11::module &m) {
|
||||
}, py::arg("typeStr"), "Convert string to BasePartitionType.");
|
||||
}
|
||||
|
||||
void register_ground_state_partition_bindings(pybind11::module &m) {
|
||||
void register_ground_state_partition_bindings(const pybind11::module &m) {
|
||||
using GSPF = gridfire::partition::GroundStatePartitionFunction;
|
||||
using PF = gridfire::partition::PartitionFunction;
|
||||
py::class_<GSPF, PF>(m, "GroundStatePartitionFunction")
|
||||
@@ -62,7 +62,7 @@ void register_ground_state_partition_bindings(pybind11::module &m) {
|
||||
"Get the type of the partition function (should return 'GroundState').");
|
||||
}
|
||||
|
||||
void register_rauscher_thielemann_partition_data_record_bindings(pybind11::module &m) {
|
||||
void register_rauscher_thielemann_partition_data_record_bindings(const pybind11::module &m) {
|
||||
py::class_<gridfire::partition::record::RauscherThielemannPartitionDataRecord>(m, "RauscherThielemannPartitionDataRecord")
|
||||
.def_readonly("z", &gridfire::partition::record::RauscherThielemannPartitionDataRecord::z, "Atomic number")
|
||||
.def_readonly("a", &gridfire::partition::record::RauscherThielemannPartitionDataRecord::a, "Mass number")
|
||||
@@ -71,7 +71,7 @@ void register_rauscher_thielemann_partition_data_record_bindings(pybind11::modul
|
||||
}
|
||||
|
||||
|
||||
void register_rauscher_thielemann_partition_bindings(pybind11::module &m) {
|
||||
void register_rauscher_thielemann_partition_bindings(const pybind11::module &m) {
|
||||
using RTPF = gridfire::partition::RauscherThielemannPartitionFunction;
|
||||
using PF = gridfire::partition::PartitionFunction;
|
||||
py::class_<RTPF, PF>(m, "RauscherThielemannPartitionFunction")
|
||||
@@ -89,7 +89,7 @@ void register_rauscher_thielemann_partition_bindings(pybind11::module &m) {
|
||||
"Get the type of the partition function (should return 'RauscherThielemann').");
|
||||
}
|
||||
|
||||
void register_composite_partition_bindings(pybind11::module &m) {
|
||||
void register_composite_partition_bindings(const pybind11::module &m) {
|
||||
py::class_<gridfire::partition::CompositePartitionFunction>(m, "CompositePartitionFunction")
|
||||
.def(py::init<const std::vector<gridfire::partition::BasePartitionType>&>(),
|
||||
py::arg("partitionFunctions"),
|
||||
|
||||
@@ -6,11 +6,11 @@ void register_partition_bindings(pybind11::module &m);
|
||||
|
||||
void register_partition_types_bindings(pybind11::module &m);
|
||||
|
||||
void register_ground_state_partition_bindings(pybind11::module &m);
|
||||
void register_ground_state_partition_bindings(const pybind11::module &m);
|
||||
|
||||
void register_rauscher_thielemann_partition_data_record_bindings(pybind11::module &m);
|
||||
void register_rauscher_thielemann_partition_data_record_bindings(const pybind11::module &m);
|
||||
|
||||
void register_rauscher_thielemann_partition_bindings(pybind11::module &m);
|
||||
void register_rauscher_thielemann_partition_bindings(const pybind11::module &m);
|
||||
|
||||
void register_composite_partition_bindings(pybind11::module &m);
|
||||
void register_composite_partition_bindings(const pybind11::module &m);
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
|
||||
class PyPartitionFunction final : public gridfire::partition::PartitionFunction {
|
||||
double evaluate(int z, int a, double T9) const override;
|
||||
double evaluateDerivative(int z, int a, double T9) const override;
|
||||
bool supports(int z, int a) const override;
|
||||
std::string type() const override;
|
||||
std::unique_ptr<gridfire::partition::PartitionFunction> clone() const override;
|
||||
[[nodiscard]] double evaluate(int z, int a, double T9) const override;
|
||||
[[nodiscard]] double evaluateDerivative(int z, int a, double T9) const override;
|
||||
[[nodiscard]] bool supports(int z, int a) const override;
|
||||
[[nodiscard]] std::string type() const override;
|
||||
[[nodiscard]] std::unique_ptr<PartitionFunction> clone() const override;
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -22,150 +22,332 @@ void register_reaction_bindings(py::module &m) {
|
||||
);
|
||||
|
||||
using fourdst::atomic::Species;
|
||||
py::class_<gridfire::reaction::Reaction>(m, "Reaction")
|
||||
.def(py::init<const std::string_view, const std::string_view, int, const std::vector<Species>&, const std::vector<Species>&, double, std::string_view, gridfire::reaction::RateCoefficientSet, bool>(),
|
||||
py::arg("id"), py::arg("peName"), py::arg("chapter"),
|
||||
py::arg("reactants"), py::arg("products"), py::arg("qValue"),
|
||||
py::arg("label"), py::arg("sets"), py::arg("reverse") = false,
|
||||
"Construct a Reaction with the given parameters.")
|
||||
.def("calculate_rate", static_cast<double (gridfire::reaction::Reaction::*)(double) const>(&gridfire::reaction::Reaction::calculate_rate),
|
||||
py::arg("T9"), "Calculate the reaction rate at a given temperature T9 (in units of 10^9 K).")
|
||||
.def("peName", &gridfire::reaction::Reaction::peName,
|
||||
"Get the reaction name in (projectile, ejectile) notation (e.g., 'p(p,g)d').")
|
||||
.def("chapter", &gridfire::reaction::Reaction::chapter,
|
||||
"Get the REACLIB chapter number defining the reaction structure.")
|
||||
.def("sourceLabel", &gridfire::reaction::Reaction::sourceLabel,
|
||||
"Get the source label for the rate data (e.g., 'wc12w', 'st08').")
|
||||
.def("rateCoefficients", &gridfire::reaction::Reaction::rateCoefficients,
|
||||
"get the set of rate coefficients.")
|
||||
.def("contains", &gridfire::reaction::Reaction::contains,
|
||||
py::arg("species"), "Check if the reaction contains a specific species.")
|
||||
.def("contains_reactant", &gridfire::reaction::Reaction::contains_reactant,
|
||||
"Check if the reaction contains a specific reactant species.")
|
||||
.def("contains_product", &gridfire::reaction::Reaction::contains_product,
|
||||
"Check if the reaction contains a specific product species.")
|
||||
.def("all_species", &gridfire::reaction::Reaction::all_species,
|
||||
"Get all species involved in the reaction (both reactants and products) as a set.")
|
||||
.def("reactant_species", &gridfire::reaction::Reaction::reactant_species,
|
||||
"Get the reactant species of the reaction as a set.")
|
||||
.def("product_species", &gridfire::reaction::Reaction::product_species,
|
||||
"Get the product species of the reaction as a set.")
|
||||
.def("num_species", &gridfire::reaction::Reaction::num_species,
|
||||
"Count the number of species in the reaction.")
|
||||
.def("stoichiometry", static_cast<int (gridfire::reaction::Reaction::*)(const Species&) const>(&gridfire::reaction::Reaction::stoichiometry),
|
||||
py::class_<gridfire::reaction::ReaclibReaction>(m, "ReaclibReaction")
|
||||
.def(
|
||||
py::init<
|
||||
const std::string_view,
|
||||
const std::string_view,
|
||||
int,
|
||||
const std::vector<Species>&,
|
||||
const std::vector<Species>&,
|
||||
double, std::string_view,
|
||||
gridfire::reaction::RateCoefficientSet,
|
||||
bool
|
||||
>(),
|
||||
py::arg("id"),
|
||||
py::arg("peName"),
|
||||
py::arg("chapter"),
|
||||
py::arg("reactants"),
|
||||
py::arg("products"),
|
||||
py::arg("qValue"),
|
||||
py::arg("label"),
|
||||
py::arg("sets"),
|
||||
py::arg("reverse") = false,
|
||||
"Construct a Reaction with the given parameters."
|
||||
)
|
||||
.def(
|
||||
"calculate_rate",
|
||||
[](const gridfire::reaction::ReaclibReaction& self, const double T9, const double rho, const std::vector<double>& Y) -> double {
|
||||
return self.calculate_rate(T9, rho, Y);
|
||||
},
|
||||
py::arg("T9"),
|
||||
py::arg("rho"),
|
||||
py::arg("Y"),
|
||||
"Calculate the reaction rate at a given temperature T9 (in units of 10^9 K)."
|
||||
)
|
||||
.def(
|
||||
"peName",
|
||||
&gridfire::reaction::ReaclibReaction::peName,
|
||||
"Get the reaction name in (projectile, ejectile) notation (e.g., 'p(p,g)d')."
|
||||
)
|
||||
.def(
|
||||
"chapter",
|
||||
&gridfire::reaction::ReaclibReaction::chapter,
|
||||
"Get the REACLIB chapter number defining the reaction structure."
|
||||
)
|
||||
.def(
|
||||
"sourceLabel",
|
||||
&gridfire::reaction::ReaclibReaction::sourceLabel,
|
||||
"Get the source label for the rate data (e.g., 'wc12w', 'st08')."
|
||||
)
|
||||
.def(
|
||||
"rateCoefficients",
|
||||
&gridfire::reaction::ReaclibReaction::rateCoefficients,
|
||||
"get the set of rate coefficients."
|
||||
)
|
||||
.def(
|
||||
"contains",
|
||||
&gridfire::reaction::ReaclibReaction::contains,
|
||||
py::arg("species"),
|
||||
"Get the stoichiometry of the reaction as a map from species to their coefficients.")
|
||||
.def("stoichiometry", static_cast<std::unordered_map<Species, int> (gridfire::reaction::Reaction::*)() const>(&gridfire::reaction::Reaction::stoichiometry),
|
||||
"Get the stoichiometry of the reaction as a map from species to their coefficients.")
|
||||
.def("id", &gridfire::reaction::Reaction::id,
|
||||
"Get the unique identifier of the reaction.")
|
||||
.def("qValue", &gridfire::reaction::Reaction::qValue,
|
||||
"Get the Q-value of the reaction in MeV.")
|
||||
.def("reactants", &gridfire::reaction::Reaction::reactants,
|
||||
"Get a list of reactant species in the reaction.")
|
||||
.def("products", &gridfire::reaction::Reaction::products,
|
||||
"Get a list of product species in the reaction.")
|
||||
.def("is_reverse", &gridfire::reaction::Reaction::is_reverse,
|
||||
"Check if this is a reverse reaction rate.")
|
||||
.def("excess_energy", &gridfire::reaction::Reaction::excess_energy,
|
||||
"Calculate the excess energy from the mass difference of reactants and products.")
|
||||
.def("__eq__", &gridfire::reaction::Reaction::operator==,
|
||||
"Equality operator for reactions based on their IDs.")
|
||||
.def("__neq__", &gridfire::reaction::Reaction::operator!=,
|
||||
"Inequality operator for reactions based on their IDs.")
|
||||
.def("hash", &gridfire::reaction::Reaction::hash,
|
||||
"Check if the reaction contains a specific species."
|
||||
)
|
||||
.def(
|
||||
"contains_reactant",
|
||||
&gridfire::reaction::ReaclibReaction::contains_reactant,
|
||||
"Check if the reaction contains a specific reactant species."
|
||||
)
|
||||
.def(
|
||||
"contains_product",
|
||||
&gridfire::reaction::ReaclibReaction::contains_product,
|
||||
"Check if the reaction contains a specific product species."
|
||||
)
|
||||
.def(
|
||||
"all_species",
|
||||
&gridfire::reaction::ReaclibReaction::all_species,
|
||||
"Get all species involved in the reaction (both reactants and products) as a set."
|
||||
)
|
||||
.def(
|
||||
"reactant_species",
|
||||
&gridfire::reaction::ReaclibReaction::reactant_species,
|
||||
"Get the reactant species of the reaction as a set."
|
||||
)
|
||||
.def(
|
||||
"product_species",
|
||||
&gridfire::reaction::ReaclibReaction::product_species,
|
||||
"Get the product species of the reaction as a set."
|
||||
)
|
||||
.def(
|
||||
"num_species",
|
||||
&gridfire::reaction::ReaclibReaction::num_species,
|
||||
"Count the number of species in the reaction."
|
||||
)
|
||||
.def(
|
||||
"stoichiometry",
|
||||
[](const gridfire::reaction::ReaclibReaction& self, const Species& species) -> int {
|
||||
return self.stoichiometry(species);
|
||||
},
|
||||
py::arg("species"),
|
||||
"Get the stoichiometry of the reaction as a map from species to their coefficients."
|
||||
)
|
||||
.def(
|
||||
"stoichiometry",
|
||||
[](const gridfire::reaction::ReaclibReaction& self) -> std::unordered_map<Species, int> {
|
||||
return self.stoichiometry();
|
||||
},
|
||||
"Get the stoichiometry of the reaction as a map from species to their coefficients."
|
||||
)
|
||||
.def(
|
||||
"id",
|
||||
&gridfire::reaction::ReaclibReaction::id,
|
||||
"Get the unique identifier of the reaction."
|
||||
)
|
||||
.def(
|
||||
"qValue",
|
||||
&gridfire::reaction::ReaclibReaction::qValue,
|
||||
"Get the Q-value of the reaction in MeV."
|
||||
)
|
||||
.def(
|
||||
"reactants",
|
||||
&gridfire::reaction::ReaclibReaction::reactants,
|
||||
"Get a list of reactant species in the reaction."
|
||||
)
|
||||
.def(
|
||||
"products",
|
||||
&gridfire::reaction::ReaclibReaction::products,
|
||||
"Get a list of product species in the reaction."
|
||||
)
|
||||
.def(
|
||||
"is_reverse",
|
||||
&gridfire::reaction::ReaclibReaction::is_reverse,
|
||||
"Check if this is a reverse reaction rate."
|
||||
)
|
||||
.def(
|
||||
"excess_energy",
|
||||
&gridfire::reaction::ReaclibReaction::excess_energy,
|
||||
"Calculate the excess energy from the mass difference of reactants and products."
|
||||
)
|
||||
.def(
|
||||
"__eq__",
|
||||
&gridfire::reaction::ReaclibReaction::operator==,
|
||||
"Equality operator for reactions based on their IDs."
|
||||
)
|
||||
.def(
|
||||
"__neq__",
|
||||
&gridfire::reaction::ReaclibReaction::operator!=,
|
||||
"Inequality operator for reactions based on their IDs."
|
||||
)
|
||||
.def(
|
||||
"hash",
|
||||
&gridfire::reaction::ReaclibReaction::hash,
|
||||
py::arg("seed") = 0,
|
||||
"Compute a hash for the reaction based on its ID.")
|
||||
.def("__repr__", [](const gridfire::reaction::Reaction& self) {
|
||||
"Compute a hash for the reaction based on its ID."
|
||||
)
|
||||
.def(
|
||||
"__repr__",
|
||||
[](const gridfire::reaction::ReaclibReaction& self) {
|
||||
std::stringstream ss;
|
||||
ss << self; // Use the existing operator<< for Reaction
|
||||
return ss.str();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
py::class_<gridfire::reaction::LogicalReaction, gridfire::reaction::Reaction>(m, "LogicalReaction")
|
||||
.def(py::init<const std::vector<gridfire::reaction::Reaction>>(),
|
||||
py::class_<gridfire::reaction::LogicalReaclibReaction, gridfire::reaction::ReaclibReaction>(m, "LogicalReaclibReaction")
|
||||
.def(
|
||||
py::init<const std::vector<gridfire::reaction::Reaction>>(),
|
||||
py::arg("reactions"),
|
||||
"Construct a LogicalReaction from a vector of Reaction objects.")
|
||||
.def("add_reaction", &gridfire::reaction::LogicalReaction::add_reaction,
|
||||
"Construct a LogicalReaclibReaction from a vector of Reaction objects."
|
||||
)
|
||||
.def(
|
||||
"add_reaction",
|
||||
&gridfire::reaction::LogicalReaclibReaction::add_reaction,
|
||||
py::arg("reaction"),
|
||||
"Add another Reaction source to this logical reaction.")
|
||||
.def("size", &gridfire::reaction::LogicalReaction::size,
|
||||
"Get the number of source rates contributing to this logical reaction.")
|
||||
.def("__len__", &gridfire::reaction::LogicalReaction::size,
|
||||
"Overload len() to return the number of source rates.")
|
||||
.def("sources", &gridfire::reaction::LogicalReaction::sources,
|
||||
"Get the list of source labels for the aggregated rates.")
|
||||
.def("calculate_rate", static_cast<double (gridfire::reaction::LogicalReaction::*)(double) const>(&gridfire::reaction::LogicalReaction::calculate_rate),
|
||||
py::arg("T9"), "Calculate the reaction rate at a given temperature T9 (in units of 10^9 K).")
|
||||
.def("calculate_forward_rate_log_derivative", &gridfire::reaction::LogicalReaction::calculate_forward_rate_log_derivative,
|
||||
py::arg("T9"), "Calculate the forward rate log derivative at a given temperature T9 (in units of 10^9 K).");
|
||||
"Add another Reaction source to this logical reaction."
|
||||
)
|
||||
.def(
|
||||
"size",
|
||||
&gridfire::reaction::LogicalReaclibReaction::size,
|
||||
"Get the number of source rates contributing to this logical reaction."
|
||||
)
|
||||
.def(
|
||||
"__len__",
|
||||
&gridfire::reaction::LogicalReaclibReaction::size,
|
||||
"Overload len() to return the number of source rates."
|
||||
)
|
||||
.def(
|
||||
"sources",
|
||||
&gridfire::reaction::LogicalReaclibReaction::sources,
|
||||
"Get the list of source labels for the aggregated rates."
|
||||
)
|
||||
.def(
|
||||
"calculate_rate",
|
||||
[](const gridfire::reaction::LogicalReaclibReaction& self, const double T9, const double rho, const std::vector<double>& Y) -> double {
|
||||
return self.calculate_rate(T9, rho, Y);
|
||||
},
|
||||
py::arg("T9"),
|
||||
"Calculate the reaction rate at a given temperature T9 (in units of 10^9 K)."
|
||||
)
|
||||
.def(
|
||||
"calculate_forward_rate_log_derivative",
|
||||
&gridfire::reaction::LogicalReaclibReaction::calculate_forward_rate_log_derivative,
|
||||
py::arg("T9"),
|
||||
"Calculate the forward rate log derivative at a given temperature T9 (in units of 10^9 K)."
|
||||
);
|
||||
|
||||
py::class_<gridfire::reaction::LogicalReactionSet>(m, "LogicalReactionSet")
|
||||
.def(py::init<const std::vector<gridfire::reaction::LogicalReaction>>(),
|
||||
py::class_<gridfire::reaction::ReactionSet>(m, "ReactionSet")
|
||||
// TODO: Fix the constructor to accept a vector of unique ptrs to Reaclib Reactions
|
||||
.def(
|
||||
py::init<const std::vector<gridfire::reaction::Reaction>>(),
|
||||
py::arg("reactions"),
|
||||
"Construct a LogicalReactionSet from a vector of LogicalReaction objects.")
|
||||
.def(py::init<>(),
|
||||
"Default constructor for an empty LogicalReactionSet.")
|
||||
.def(py::init<const gridfire::reaction::LogicalReactionSet&>(),
|
||||
"Construct a LogicalReactionSet from a vector of LogicalReaclibReaction objects."
|
||||
)
|
||||
.def(
|
||||
py::init<>(),
|
||||
"Default constructor for an empty LogicalReactionSet."
|
||||
)
|
||||
.def(
|
||||
py::init<const gridfire::reaction::ReactionSet&>(),
|
||||
py::arg("other"),
|
||||
"Copy constructor for LogicalReactionSet.")
|
||||
.def("add_reaction", &gridfire::reaction::LogicalReactionSet::add_reaction,
|
||||
"Copy constructor for LogicalReactionSet."
|
||||
)
|
||||
.def(
|
||||
"add_reaction",
|
||||
py::overload_cast<const gridfire::reaction::Reaction&>(&gridfire::reaction::ReactionSet::add_reaction),
|
||||
py::arg("reaction"),
|
||||
"Add a LogicalReaction to the set.")
|
||||
.def("remove_reaction", &gridfire::reaction::LogicalReactionSet::remove_reaction,
|
||||
"Add a LogicalReaclibReaction to the set."
|
||||
)
|
||||
.def(
|
||||
"remove_reaction",
|
||||
&gridfire::reaction::ReactionSet::remove_reaction,
|
||||
py::arg("reaction"),
|
||||
"Remove a LogicalReaction from the set.")
|
||||
.def("contains", py::overload_cast<const std::string_view&>(&gridfire::reaction::LogicalReactionSet::contains, py::const_),
|
||||
"Remove a LogicalReaclibReaction from the set."
|
||||
)
|
||||
.def(
|
||||
"contains",
|
||||
py::overload_cast<const std::string_view&>(&gridfire::reaction::ReactionSet::contains, py::const_),
|
||||
py::arg("id"),
|
||||
"Check if the set contains a specific LogicalReaction.")
|
||||
.def("contains", py::overload_cast<const gridfire::reaction::Reaction&>(&gridfire::reaction::LogicalReactionSet::contains, py::const_),
|
||||
"Check if the set contains a specific LogicalReaclibReaction."
|
||||
)
|
||||
.def(
|
||||
"contains",
|
||||
py::overload_cast<const gridfire::reaction::Reaction&>(&gridfire::reaction::ReactionSet::contains, py::const_),
|
||||
py::arg("reaction"),
|
||||
"Check if the set contains a specific Reaction.")
|
||||
.def("size", &gridfire::reaction::LogicalReactionSet::size,
|
||||
"Get the number of LogicalReactions in the set.")
|
||||
.def("__len__", &gridfire::reaction::LogicalReactionSet::size,
|
||||
"Overload len() to return the number of LogicalReactions.")
|
||||
.def("clear", &gridfire::reaction::LogicalReactionSet::clear,
|
||||
"Remove all LogicalReactions from the set.")
|
||||
.def("containes_species", &gridfire::reaction::LogicalReactionSet::contains_species,
|
||||
"Check if the set contains a specific Reaction."
|
||||
)
|
||||
.def(
|
||||
"size",
|
||||
&gridfire::reaction::ReactionSet::size,
|
||||
"Get the number of LogicalReactions in the set."
|
||||
)
|
||||
.def(
|
||||
"__len__", &gridfire::reaction::ReactionSet::size,
|
||||
"Overload len() to return the number of LogicalReactions."
|
||||
)
|
||||
.def(
|
||||
"clear",
|
||||
&gridfire::reaction::ReactionSet::clear,
|
||||
"Remove all LogicalReactions from the set."
|
||||
)
|
||||
.def("contains_species",
|
||||
&gridfire::reaction::ReactionSet::contains_species,
|
||||
py::arg("species"),
|
||||
"Check if any reaction in the set involves the given species.")
|
||||
.def("contains_reactant", &gridfire::reaction::LogicalReactionSet::contains_reactant,
|
||||
"Check if any reaction in the set involves the given species."
|
||||
)
|
||||
.def(
|
||||
"contains_reactant",
|
||||
&gridfire::reaction::ReactionSet::contains_reactant,
|
||||
py::arg("species"),
|
||||
"Check if any reaction in the set has the species as a reactant.")
|
||||
.def("contains_product", &gridfire::reaction::LogicalReactionSet::contains_product,
|
||||
"Check if any reaction in the set has the species as a reactant."
|
||||
)
|
||||
.def(
|
||||
"contains_product",
|
||||
&gridfire::reaction::ReactionSet::contains_product,
|
||||
py::arg("species"),
|
||||
"Check if any reaction in the set has the species as a product.")
|
||||
.def("__getitem__", py::overload_cast<size_t>(&gridfire::reaction::LogicalReactionSet::operator[], py::const_),
|
||||
"Check if any reaction in the set has the species as a product."
|
||||
)
|
||||
.def(
|
||||
"__getitem__",
|
||||
py::overload_cast<size_t>(&gridfire::reaction::ReactionSet::operator[], py::const_),
|
||||
py::arg("index"),
|
||||
"Get a LogicalReaction by index.")
|
||||
.def("__getitem___", py::overload_cast<const std::string_view&>(&gridfire::reaction::LogicalReactionSet::operator[], py::const_),
|
||||
"Get a LogicalReaclibReaction by index."
|
||||
)
|
||||
.def(
|
||||
"__getitem___",
|
||||
py::overload_cast<const std::string_view&>(&gridfire::reaction::ReactionSet::operator[], py::const_),
|
||||
py::arg("id"),
|
||||
"Get a LogicalReaction by its ID.")
|
||||
.def("__eq__", &gridfire::reaction::LogicalReactionSet::operator==,
|
||||
"Get a LogicalReaclibReaction by its ID."
|
||||
)
|
||||
.def(
|
||||
"__eq__",
|
||||
&gridfire::reaction::ReactionSet::operator==,
|
||||
py::arg("LogicalReactionSet"),
|
||||
"Equality operator for LogicalReactionSets based on their contents.")
|
||||
.def("__ne__", &gridfire::reaction::LogicalReactionSet::operator!=,
|
||||
"Equality operator for LogicalReactionSets based on their contents."
|
||||
)
|
||||
.def(
|
||||
"__ne__",
|
||||
&gridfire::reaction::ReactionSet::operator!=,
|
||||
py::arg("LogicalReactionSet"),
|
||||
"Inequality operator for LogicalReactionSets based on their contents.")
|
||||
.def("hash", &gridfire::reaction::LogicalReactionSet::hash,
|
||||
"Inequality operator for LogicalReactionSets based on their contents."
|
||||
)
|
||||
.def(
|
||||
"hash",
|
||||
&gridfire::reaction::ReactionSet::hash,
|
||||
py::arg("seed") = 0,
|
||||
"Compute a hash for the LogicalReactionSet based on its contents."
|
||||
)
|
||||
.def("__repr__", [](const gridfire::reaction::LogicalReactionSet& self) {
|
||||
.def(
|
||||
"__repr__",
|
||||
[](const gridfire::reaction::ReactionSet& self) {
|
||||
std::stringstream ss;
|
||||
ss << self;
|
||||
return ss.str();
|
||||
})
|
||||
.def("getReactionSetSpecies", &gridfire::reaction::LogicalReactionSet::getReactionSetSpecies,
|
||||
"Get all species involved in the reactions of the set as a set of Species objects.");
|
||||
}
|
||||
)
|
||||
.def(
|
||||
"getReactionSetSpecies",
|
||||
&gridfire::reaction::ReactionSet::getReactionSetSpecies,
|
||||
"Get all species involved in the reactions of the set as a set of Species objects."
|
||||
);
|
||||
|
||||
m.def("packReactionSetToLogicalReactionSet",
|
||||
&gridfire::reaction::packReactionSetToLogicalReactionSet,
|
||||
m.def(
|
||||
"packReactionSet",
|
||||
&gridfire::reaction::packReactionSet,
|
||||
py::arg("reactionSet"),
|
||||
"Convert a ReactionSet to a LogicalReactionSet by aggregating reactions with the same peName."
|
||||
);
|
||||
|
||||
m.def("get_all_reactions", &gridfire::reaclib::get_all_reactions,
|
||||
"Get all reactions from the REACLIB database.");
|
||||
m.def(
|
||||
"get_all_reactions",
|
||||
&gridfire::reaclib::get_all_reaclib_reactions,
|
||||
"Get all reactions from the REACLIB database."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "bindings.h"
|
||||
@@ -13,30 +12,53 @@
|
||||
namespace py = pybind11;
|
||||
|
||||
void register_screening_bindings(py::module &m) {
|
||||
py::class_<gridfire::screening::ScreeningModel, PyScreening>(m, "ScreeningModel");
|
||||
auto screening_model = py::class_<gridfire::screening::ScreeningModel, PyScreening>(m, "ScreeningModel");
|
||||
|
||||
py::enum_<gridfire::screening::ScreeningType>(m, "ScreeningType")
|
||||
.value("BARE", gridfire::screening::ScreeningType::BARE)
|
||||
.value("WEAK", gridfire::screening::ScreeningType::WEAK)
|
||||
.export_values();
|
||||
|
||||
m.def("selectScreeningModel", &gridfire::screening::selectScreeningModel,
|
||||
m.def(
|
||||
"selectScreeningModel",
|
||||
&gridfire::screening::selectScreeningModel,
|
||||
py::arg("type"),
|
||||
"Select a screening model based on the specified type. Returns a pointer to the selected model.");
|
||||
"Select a screening model based on the specified type. Returns a pointer to the selected model."
|
||||
);
|
||||
|
||||
py::class_<gridfire::screening::BareScreeningModel>(m, "BareScreeningModel")
|
||||
.def(py::init<>())
|
||||
.def("calculateScreeningFactors",
|
||||
py::overload_cast<const gridfire::reaction::LogicalReactionSet&, const std::vector<fourdst::atomic::Species>&, const std::vector<double>&, double, double>(&gridfire::screening::BareScreeningModel::calculateScreeningFactors, py::const_),
|
||||
py::arg("reactions"), py::arg("species"), py::arg("Y"), py::arg("T9"), py::arg("rho"),
|
||||
py::overload_cast<
|
||||
const gridfire::reaction::ReactionSet&,
|
||||
const std::vector<fourdst::atomic::Species>&,
|
||||
const std::vector<double>&,
|
||||
double,
|
||||
double
|
||||
>(&gridfire::screening::BareScreeningModel::calculateScreeningFactors, py::const_),
|
||||
py::arg("reactions"),
|
||||
py::arg("species"),
|
||||
py::arg("Y"),
|
||||
py::arg("T9"),
|
||||
py::arg("rho"),
|
||||
"Calculate the bare plasma screening factors. This always returns 1.0 (bare)"
|
||||
);
|
||||
|
||||
py::class_<gridfire::screening::WeakScreeningModel>(m, "WeakScreeningModel")
|
||||
.def(py::init<>())
|
||||
.def("calculateScreeningFactors",
|
||||
py::overload_cast<const gridfire::reaction::LogicalReactionSet&, const std::vector<fourdst::atomic::Species>&, const std::vector<double>&, double, double>(&gridfire::screening::WeakScreeningModel::calculateScreeningFactors, py::const_),
|
||||
py::arg("reactions"), py::arg("species"), py::arg("Y"), py::arg("T9"), py::arg("rho"),
|
||||
py::overload_cast<
|
||||
const gridfire::reaction::ReactionSet&,
|
||||
const std::vector<fourdst::atomic::Species>&,
|
||||
const std::vector<double>&,
|
||||
double,
|
||||
double
|
||||
>(&gridfire::screening::WeakScreeningModel::calculateScreeningFactors, py::const_),
|
||||
py::arg("reactions"),
|
||||
py::arg("species"),
|
||||
py::arg("Y"),
|
||||
py::arg("T9"),
|
||||
py::arg("rho"),
|
||||
"Calculate the weak plasma screening factors using the Salpeter (1954) model."
|
||||
);
|
||||
}
|
||||
@@ -13,7 +13,13 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
std::vector<double> PyScreening::calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector<fourdst::atomic::Species> &species, const std::vector<double> &Y, const double T9, const double rho) const {
|
||||
std::vector<double> PyScreening::calculateScreeningFactors(
|
||||
const gridfire::reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<double> &Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const {
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
std::vector<double>, // Return type
|
||||
gridfire::screening::ScreeningModel,
|
||||
@@ -22,7 +28,13 @@ std::vector<double> PyScreening::calculateScreeningFactors(const gridfire::react
|
||||
}
|
||||
|
||||
using ADDouble = gridfire::screening::ScreeningModel::ADDouble;
|
||||
std::vector<ADDouble> PyScreening::calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector<fourdst::atomic::Species> &species, const std::vector<ADDouble> &Y, const ADDouble T9, const ADDouble rho) const {
|
||||
std::vector<ADDouble> PyScreening::calculateScreeningFactors(
|
||||
const gridfire::reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<ADDouble> &Y,
|
||||
const ADDouble T9,
|
||||
const ADDouble rho
|
||||
) const {
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
std::vector<ADDouble>, // Return type
|
||||
gridfire::screening::ScreeningModel,
|
||||
|
||||
@@ -2,15 +2,24 @@
|
||||
|
||||
#include "gridfire/screening/screening.h"
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/functional.h> // Needed for std::function
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "cppad/cppad.hpp"
|
||||
|
||||
class PyScreening final : public gridfire::screening::ScreeningModel {
|
||||
std::vector<double> calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector<fourdst::atomic::Species> &species, const std::vector<double> &Y, const double T9, const double rho) const override;
|
||||
std::vector<ADDouble> calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector<fourdst::atomic::Species> &species, const std::vector<ADDouble> &Y, const ADDouble T9, const ADDouble rho) const override;
|
||||
[[nodiscard]] std::vector<double> calculateScreeningFactors(
|
||||
const gridfire::reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] std::vector<ADDouble> calculateScreeningFactors(
|
||||
const gridfire::reaction::ReactionSet &reactions,
|
||||
const std::vector<fourdst::atomic::Species> &species,
|
||||
const std::vector<ADDouble> &Y,
|
||||
ADDouble T9,
|
||||
ADDouble rho
|
||||
) const override;
|
||||
};
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/functional.h> // Needed for std::function
|
||||
|
||||
#include <boost/numeric/ublas/vector.hpp>
|
||||
|
||||
@@ -30,7 +29,7 @@ void register_solver_bindings(const py::module &m) {
|
||||
);
|
||||
|
||||
py_direct_network_solver.def("set_callback",
|
||||
[](gridfire::solver::DirectNetworkSolver &self, gridfire::solver::DirectNetworkSolver::TimestepCallback cb) {
|
||||
[](gridfire::solver::DirectNetworkSolver &self, const gridfire::solver::DirectNetworkSolver::TimestepCallback& cb) {
|
||||
self.set_callback(cb);
|
||||
},
|
||||
py::arg("callback"),
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/functional.h> // Needed for std::function
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
@@ -11,5 +11,5 @@ class PyDynamicNetworkSolverStrategy final : public gridfire::solver::DynamicNet
|
||||
explicit PyDynamicNetworkSolverStrategy(gridfire::DynamicEngine &engine) : gridfire::solver::DynamicNetworkSolverStrategy(engine) {}
|
||||
gridfire::NetOut evaluate(const gridfire::NetIn &netIn) override;
|
||||
void set_callback(const std::any &callback) override;
|
||||
std::vector<std::tuple<std::string, std::string>> describe_callback_context() const override;
|
||||
[[nodiscard]] std::vector<std::tuple<std::string, std::string>> describe_callback_context() const override;
|
||||
};
|
||||
@@ -8,7 +8,7 @@ namespace py = pybind11;
|
||||
|
||||
#include "gridfire/network.h"
|
||||
|
||||
void register_type_bindings(pybind11::module &m) {
|
||||
void register_type_bindings(const pybind11::module &m) {
|
||||
py::class_<gridfire::NetIn>(m, "NetIn")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("composition", &gridfire::NetIn::composition)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
void register_type_bindings(pybind11::module &m);
|
||||
void register_type_bindings(const pybind11::module &m);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
|
||||
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
|
||||
|
||||
#include "bindings.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/4D-STAR/fourdst
|
||||
revision = v0.5.3
|
||||
revision = v0.7.0
|
||||
depth = 1
|
||||
|
||||
4
subprojects/libplugin.wrap
Normal file
4
subprojects/libplugin.wrap
Normal file
@@ -0,0 +1,4 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/4D-STAR/libplugin
|
||||
revision = v0.3.4
|
||||
depth = 1
|
||||
2
subprojects/minizip-ng.wrap
Normal file
2
subprojects/minizip-ng.wrap
Normal file
@@ -0,0 +1,2 @@
|
||||
[wrap-redirect]
|
||||
filename = libplugin/subprojects/minizip-ng.wrap
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "fourdst/composition/composition.h"
|
||||
|
||||
#include "fourdst/plugin/bundle/bundle.h"
|
||||
|
||||
#include "fourdst/logging/logging.h"
|
||||
#include "quill/Logger.h"
|
||||
#include "quill/LogMacros.h"
|
||||
@@ -29,7 +31,7 @@
|
||||
|
||||
static std::terminate_handler g_previousHandler = nullptr;
|
||||
|
||||
static std::ofstream consumptionFile("consumption.txt");
|
||||
|
||||
|
||||
void callback(const gridfire::solver::DirectNetworkSolver::TimestepContext& ctx) {
|
||||
const auto H1IndexPtr = std::ranges::find(ctx.engine.getNetworkSpecies(), fourdst::atomic::H_1);
|
||||
@@ -38,10 +40,10 @@ void callback(const gridfire::solver::DirectNetworkSolver::TimestepContext& ctx)
|
||||
const size_t H1Index = H1IndexPtr != ctx.engine.getNetworkSpecies().end() ? std::distance(ctx.engine.getNetworkSpecies().begin(), H1IndexPtr) : -1;
|
||||
const size_t He4Index = He4IndexPtr != ctx.engine.getNetworkSpecies().end() ? std::distance(ctx.engine.getNetworkSpecies().begin(), He4IndexPtr) : -1;
|
||||
|
||||
if (H1Index != -1 && He4Index != -1) {
|
||||
std::cout << "Found H-1 at index: " << H1Index << ", He-4 at index: " << He4Index << "\n";
|
||||
consumptionFile << ctx.t << "," << ctx.state(H1Index) << "," << ctx.state(He4Index) << "\n";
|
||||
}
|
||||
std::cout << "Time: " << ctx.t << ", H-1: " << ctx.state(H1Index) << ", He-4: " << ctx.state(He4Index) << "\n";
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
}
|
||||
|
||||
void measure_execution_time(const std::function<void()>& callback, const std::string& name)
|
||||
@@ -63,7 +65,39 @@ void quill_terminate_handler()
|
||||
std::abort();
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main(int argc, char* argv[]){
|
||||
|
||||
// Valid usages are either
|
||||
// ./graphnet_sandbox
|
||||
//or
|
||||
// ./graphnet_sandbox --plug <plugin_bundle_path>
|
||||
if (argc == 3 && std::string(argv[1]) == "--plug") {
|
||||
std::filesystem::path pluginBundlePath(argv[2]);
|
||||
if (!std::filesystem::exists(pluginBundlePath)) {
|
||||
std::cerr << "Error: Plugin bundle path does not exist: " << pluginBundlePath << "\n";
|
||||
std::cerr << "Usage: " << argv[0] << " [--plug <plugin_bundle_path>]\n";
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Loading plugin bundle from: " << pluginBundlePath << "\n";
|
||||
fourdst::plugin::bundle::PluginBundle pluginBundle(pluginBundlePath);
|
||||
}
|
||||
if (argc == 2 && std::string(argv[1]) != "--plug") {
|
||||
std::cerr << "Invalid argument: " << argv[1] << "\n";
|
||||
std::cerr << "Usage: " << argv[0] << " [--plug <plugin_bundle_path>]\n";
|
||||
return 1;
|
||||
}
|
||||
if (argc == 2 && std::string(argv[1]) == "--plug") {
|
||||
std::cerr << "Error: No plugin bundle path provided.\n";
|
||||
std::cerr << "Usage: " << argv[0] << " [--plug <plugin_bundle_path>]\n";
|
||||
return 1;
|
||||
}
|
||||
if (argc > 3) {
|
||||
std::cerr << "Too many arguments provided.\n";
|
||||
std::cerr << "Usage: " << argv[0] << " [--plug <plugin_bundle_path>]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
g_previousHandler = std::set_terminate(quill_terminate_handler);
|
||||
quill::Logger* logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
||||
logger->set_log_level(quill::LogLevel::Info);
|
||||
@@ -101,13 +135,13 @@ int main() {
|
||||
AdaptiveEngineView adaptiveView(partitioningView);
|
||||
//
|
||||
solver::DirectNetworkSolver solver(adaptiveView);
|
||||
consumptionFile << "t,X,a,b,c\n";
|
||||
// consumptionFile << "t,X,a,b,c\n";
|
||||
solver.set_callback(callback);
|
||||
NetOut netOut;
|
||||
|
||||
|
||||
netOut = solver.evaluate(netIn);
|
||||
consumptionFile.close();
|
||||
// consumptionFile.close();
|
||||
std::cout << "Initial H-1: " << netIn.composition.getMassFraction("H-1") << std::endl;
|
||||
std::cout << "NetOut H-1: " << netOut.composition.getMassFraction("H-1") << std::endl;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
executable(
|
||||
'graphnet_sandbox',
|
||||
'main.cpp',
|
||||
dependencies: [gridfire_dep, composition_dep],
|
||||
dependencies: [gridfire_dep, composition_dep, plugin_dep],
|
||||
)
|
||||
|
||||
69
utils/WRL/format.py
Normal file
69
utils/WRL/format.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def write_cpp_header(df, output_path):
|
||||
"""Writes the DataFrame to a C++ header as a constexpr array of structs."""
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
f.write(f"""// This is an auto generated file, do not edit this file directly
|
||||
// This file was created using the format.py script in GridFire/utils/WRL
|
||||
// This file was created on {datetime.now()}
|
||||
// Rates from this file have been retrived from A. Ravlic, S. Giraud, N. Paar, and R.G.T. Zegers, https://doi.org/10.48550/arXiv.2412.00650
|
||||
// Rates have been culled to cover T9 < 10 & log electron density < 11 for all species up to and including Z=40 (Zirconium)
|
||||
// In order to save space in the binary all data has been stored as either single prescision floating point numbers, uint8_t, or uint16_t\n""")
|
||||
f.write("#pragma once\n\n")
|
||||
f.write("#include <array>\n\n")
|
||||
f.write("#include <cstdint>\n\n")
|
||||
f.write("namespace gridfire::rates::weak {\n\n")
|
||||
|
||||
f.write(" // Represents a single row from the unified weak rate table\n")
|
||||
f.write(" struct RateDataRow {\n")
|
||||
f.write(" uint16_t A;\n")
|
||||
f.write(" uint8_t Z;\n")
|
||||
f.write(" float t9;\n")
|
||||
f.write(" float log_rhoye;\n")
|
||||
f.write(" float mu_e;\n")
|
||||
f.write(" float log_beta_plus;\n")
|
||||
f.write(" float log_electron_capture;\n")
|
||||
f.write(" float log_neutrino_loss_ec;\n")
|
||||
f.write(" float log_beta_minus;\n")
|
||||
f.write(" float log_positron_capture;\n")
|
||||
f.write(" float log_antineutrino_loss_bd;\n")
|
||||
f.write(" };\n\n")
|
||||
|
||||
f.write(" // The complete, pre-processed weak rate table data\n")
|
||||
f.write(f" static constexpr std::array<RateDataRow, {len(df)}> UNIFIED_WEAK_DATA = {{\n")
|
||||
|
||||
for row in tqdm(df.itertuples(), total=len(df)):
|
||||
f.write(" RateDataRow(")
|
||||
f.write(f"{row.A}, {row.Z}, {row.t9}, {row.lrhoYe}, {row.mu_e}, ")
|
||||
f.write(f"{row._6}, {row._7}, {row.nue}, {row._9}, {row._10}, {row.nubar}")
|
||||
f.write("),\n")
|
||||
|
||||
f.write(" };\n\n")
|
||||
f.write("} // namespace gridfire::rates::weak\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Format unified weak rate library into c++ header")
|
||||
parser.add_argument("path", help="path to WRL file", type=str)
|
||||
parser.add_argument("-o", "--output", help="path to save c++ header to", default="weak_rate_library.h", type=str)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"Reading weak rate data from: {args.path}")
|
||||
df = pd.read_csv(args.path, sep=r'\s+', comment='#')
|
||||
df.columns = [
|
||||
"A", "Z", "t9", "lrhoYe", "mu_e", "beta+", "e-",
|
||||
"nue", "beta-", "e+", "nubar", "ID"
|
||||
]
|
||||
|
||||
df = df[(df.t9 < 10) & (df.lrhoYe < 11) & (df.Z <= 40)]
|
||||
print(df)
|
||||
print(f"Found {len(df)} total data rows.")
|
||||
print(f"Generating C++ header file: {args.output}")
|
||||
write_cpp_header(df, args.output)
|
||||
print("Done.")
|
||||
954241
utils/WRL/rate_table_Ravlic_others.txt
Normal file
954241
utils/WRL/rate_table_Ravlic_others.txt
Normal file
File diff suppressed because it is too large
Load Diff
13
utils/WRL/readme.md
Normal file
13
utils/WRL/readme.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Unified Weak Rate Library
|
||||
This library was retrived on August 13th, 2025 from the following URL
|
||||
|
||||
```bash
|
||||
wget https://groups.frib.msu.edu/charge_exchange/weakrate_tables/rate_table_Ravlic_others.txt
|
||||
```
|
||||
|
||||
# Citations
|
||||
- A. Ravlic, S. Giraud, N. Paar, and R.G.T. Zegers, https://doi.org/10.48550/arXiv.2412.00650
|
||||
|
||||
This is version 1.3 of the weak rate library. See
|
||||
[https://www.remcozegers.com/weak-rate-library](https://www.remcozegers.com/weak-rate-library)
|
||||
for details on versions 1.3, 1.2, and 1.1
|
||||
BIN
utils/WRL/test
Executable file
BIN
utils/WRL/test
Executable file
Binary file not shown.
9
utils/WRL/test.cpp
Normal file
9
utils/WRL/test.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "weak_rate_library.h"
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
|
||||
int main() {
|
||||
std::size_t totalBytes = sizeof(gridfire::rates::weak::UNIFIED_WEAK_DATA);
|
||||
std::cout << "Total size in bytes of packed weak reaction data is : " << totalBytes/1.0e6 << " MB" << std::endl;
|
||||
}
|
||||
107
validation/pynucastro/GridFireEquiv/evolve.py
Normal file
107
validation/pynucastro/GridFireEquiv/evolve.py
Normal file
@@ -0,0 +1,107 @@
|
||||
import numpy as np
|
||||
from scipy.integrate import solve_ivp
|
||||
|
||||
import pp_chain_robust as network
|
||||
|
||||
|
||||
T = 1.5e7
|
||||
rho = 1.5e2
|
||||
|
||||
Y0 = np.zeros(network.nnuc)
|
||||
Y0[network.jp] = 0.702583
|
||||
Y0[network.jhe3] = 9.74903e-6
|
||||
Y0[network.jhe4] = 0.068963
|
||||
Y0[network.jc12] = 0.000250029
|
||||
Y0[network.jn14] = 7.85632e-5
|
||||
Y0[network.jo16] = 0.00060151
|
||||
Y0[network.jne20] = 8.10399e-5
|
||||
Y0[network.jmg24] = 2.15159e-5
|
||||
|
||||
t_start = 0.0
|
||||
t_end = 3.14e17
|
||||
t_span = (t_start, t_end)
|
||||
|
||||
sol = solve_ivp(
|
||||
network.rhs,
|
||||
t_span=t_span,
|
||||
y0=Y0,
|
||||
method='Radau',
|
||||
jac=network.jacobian,
|
||||
args=(rho, T),
|
||||
dense_output=True,
|
||||
rtol=1e-8,
|
||||
atol=1e-8
|
||||
)
|
||||
|
||||
|
||||
with open("pynucastro_results.csv", 'w') as f:
|
||||
f.write("t,h1,h2,he3,he4,c12,n14,o16,ne20,mg24\n")
|
||||
for (t,h1,h2,he3,he4,c12,n14,o16,ne20,mg24) in zip(sol.t, sol.y[network.jp, :], sol.y[network.jd, :], sol.y[network.jhe3, :], sol.y[network.jhe4, :], sol.y[network.jc12, :], sol.y[network.jn14, :], sol.y[network.jo16, :], sol.y[network.jne20, :], sol.y[network.jmg24, :]):
|
||||
f.write(f"{t},{h1},{h2},{he3},{he4},{c12},{n14},{o16},{ne20},{mg24}\n")
|
||||
|
||||
from gridfire.engine import GraphEngine, MultiscalePartitioningEngineView, AdaptiveEngineView
|
||||
from gridfire.solver import DirectNetworkSolver
|
||||
from gridfire.type import NetIn
|
||||
|
||||
from fourdst.composition import Composition
|
||||
from fourdst.atomic import species
|
||||
|
||||
symbols : list[str] = ["H-1", "He-3", "He-4", "C-12", "N-14", "O-16", "Ne-20", "Mg-24"]
|
||||
X : list[float] = [0.708, 2.94e-5, 0.276, 0.003, 0.0011, 9.62e-3, 1.62e-3, 5.16e-4]
|
||||
|
||||
|
||||
comp = Composition()
|
||||
comp.registerSymbol(symbols)
|
||||
comp.setMassFraction(symbols, X)
|
||||
comp.finalize(True)
|
||||
|
||||
print(f"Initial H-1 mass fraction {comp.getMassFraction("H-1")}")
|
||||
|
||||
netIn = NetIn()
|
||||
netIn.composition = comp
|
||||
netIn.temperature = 1.5e7
|
||||
netIn.density = 1.6e2
|
||||
netIn.tMax = 3.14e17
|
||||
netIn.dt0 = 1e-12
|
||||
|
||||
baseEngine = GraphEngine(netIn.composition, 2)
|
||||
baseEngine.setUseReverseReactions(False)
|
||||
|
||||
qseEngine = MultiscalePartitioningEngineView(baseEngine)
|
||||
|
||||
adaptiveEngine = AdaptiveEngineView(qseEngine)
|
||||
|
||||
solver = DirectNetworkSolver(adaptiveEngine)
|
||||
|
||||
data = []
|
||||
def callback(context):
|
||||
H1Index = context.engine.getSpeciesIndex(species["H-1"])
|
||||
H2Index = context.engine.getSpeciesIndex(species["H-2"])
|
||||
He3Index = context.engine.getSpeciesIndex(species["He-3"])
|
||||
He4Index = context.engine.getSpeciesIndex(species["He-4"])
|
||||
C12Index = context.engine.getSpeciesIndex(species["C-12"])
|
||||
N14Index = context.engine.getSpeciesIndex(species["N-14"])
|
||||
O16Index = context.engine.getSpeciesIndex(species["O-16"])
|
||||
Ne20Index = context.engine.getSpeciesIndex(species["Mg-24"])
|
||||
Mg24Index = context.engine.getSpeciesIndex(species["Mg-24"])
|
||||
data.append([context.t,
|
||||
context.state[H1Index],
|
||||
context.state[H2Index],
|
||||
context.state[He3Index],
|
||||
context.state[He4Index],
|
||||
context.state[C12Index],
|
||||
context.state[N14Index],
|
||||
context.state[O16Index],
|
||||
context.state[Ne20Index],
|
||||
context.state[Mg24Index]
|
||||
])
|
||||
|
||||
|
||||
solver.set_callback(callback)
|
||||
results = solver.evaluate(netIn)
|
||||
|
||||
with open("gridfire_results.csv", 'w') as f:
|
||||
f.write("t,h1,h2,he3,he4,c12,n14,o16,ne20,mg24\n")
|
||||
for row in data:
|
||||
rowStr = ','.join([str(x) for x in row])
|
||||
f.write(f"{rowStr}\n")
|
||||
@@ -0,0 +1,47 @@
|
||||
import pynucastro as pyna
|
||||
|
||||
from gridfire.engine import GraphEngine, MultiscalePartitioningEngineView, AdaptiveEngineView
|
||||
from gridfire.solver import DirectNetworkSolver
|
||||
from gridfire.type import NetIn
|
||||
|
||||
from fourdst.composition import Composition
|
||||
|
||||
symbols : list[str] = ["H-1", "He-3", "He-4", "C-12", "N-14", "O-16", "Ne-20", "Mg-24"]
|
||||
X : list[float] = [0.708, 2.94e-5, 0.276, 0.003, 0.0011, 9.62e-3, 1.62e-3, 5.16e-4]
|
||||
|
||||
|
||||
comp = Composition()
|
||||
comp.registerSymbol(symbols)
|
||||
comp.setMassFraction(symbols, X)
|
||||
comp.finalize(True)
|
||||
|
||||
print(f"Initial H-1 mass fraction {comp.getMassFraction("H-1")}")
|
||||
|
||||
netIn = NetIn()
|
||||
netIn.composition = comp
|
||||
netIn.temperature = 1.5e7
|
||||
netIn.density = 1.6e2
|
||||
netIn.tMax = 1e-9
|
||||
netIn.dt0 = 1e-12
|
||||
|
||||
baseEngine = GraphEngine(netIn.composition, 2)
|
||||
|
||||
equiv_species = baseEngine.getNetworkSpecies()
|
||||
equiv_species = [x.name().replace("-","").lower() for x in equiv_species]
|
||||
|
||||
equiv_species = [x if x != 'h1' else 'p' for x in equiv_species]
|
||||
equiv_species = [x if x != 'n1' else 'n' for x in equiv_species]
|
||||
|
||||
rl = pyna.ReacLibLibrary()
|
||||
|
||||
# equiv_species = ['p', 'd', 'he3', 'he4', 'c12', 'n14', 'o16', 'ne20', 'mg24']
|
||||
full_lib = rl.linking_nuclei(equiv_species)
|
||||
|
||||
print(f"\nFound {len(full_lib.get_rates())} rates.")
|
||||
|
||||
net = pyna.PythonNetwork(libraries=[full_lib])
|
||||
|
||||
output_filename = "pp_chain_robust.py"
|
||||
net.write_network(output_filename)
|
||||
|
||||
print(f"\nSuccessfully wrote robust PP-chain network to: {output_filename}")
|
||||
16694
validation/pynucastro/GridFireEquiv/pp_chain_robust.py
Normal file
16694
validation/pynucastro/GridFireEquiv/pp_chain_robust.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user