Files
GridFire/src/network/include/gridfire/reaction/reaction.h

270 lines
11 KiB
C
Raw Normal View History

#pragma once
#include <string_view>
#include "fourdst/composition/atomicSpecies.h"
#include "fourdst/logging/logging.h"
#include "quill/Logger.h"
#include <unordered_map>
#include <vector>
#include <memory>
#include <unordered_set>
#include <cstdint>
#include "cppad/cppad.hpp"
namespace gridfire::reaction {
/**
* @struct REACLIBRateCoefficientSet
* @brief Holds the seven fitting parameters for a single REACLIB rate set.
* @details The thermonuclear reaction rate for a single set is calculated as:
* rate = exp(a0 + a1/T9 + a2/T9^(-1/3) + a3*T9^(1/3) + a4*T9 + a5*T9^(5/3) + a6*ln(T9))
* where T9 is the temperature in billions of Kelvin. The total rate for a
* reaction is the sum of the rates from all its sets.
*/
struct REACLIBRateCoefficientSet {
const double a0;
const double a1;
const double a2;
const double a3;
const double a4;
const double a5;
const double a6;
friend std::ostream& operator<<(std::ostream& os, const REACLIBRateCoefficientSet& r) {
os << "[" << r.a0 << ", " << r.a1 << ", " << r.a2 << ", "
<< r.a3 << ", " << r.a4 << ", " << r.a5 << ", " << r.a6 << "]";
return os;
}
};
class Reaction {
public:
Reaction(
const std::string_view id,
const double qValue,
const std::vector<fourdst::atomic::Species>& reactants,
const std::vector<fourdst::atomic::Species>& products,
const bool reverse = false
);
virtual ~Reaction() = default;
virtual std::unique_ptr<Reaction> clone() const = 0;
virtual double calculate_rate(double T9) const = 0;
virtual CppAD::AD<double> calculate_rate(const CppAD::AD<double> T9) const = 0;
virtual std::string_view peName() const { return ""; }
[[nodiscard]] bool contains(const fourdst::atomic::Species& species) const;
[[nodiscard]] bool contains_reactant(const fourdst::atomic::Species& species) const;
[[nodiscard]] bool contains_product(const fourdst::atomic::Species& species) const;
std::unordered_set<fourdst::atomic::Species> all_species() const;
std::unordered_set<fourdst::atomic::Species> reactant_species() const;
std::unordered_set<fourdst::atomic::Species> product_species() const;
size_t num_species() const;
int stoichiometry(const fourdst::atomic::Species& species) const;
std::unordered_map<fourdst::atomic::Species, int> stoichiometry() const;
std::string_view id() const { return m_id; }
double qValue() const { return m_qValue; }
const std::vector<fourdst::atomic::Species>& reactants() const { return m_reactants; }
const std::vector<fourdst::atomic::Species>& products() const { return m_products; }
bool is_reverse() const { return m_reverse; }
double excess_energy() const;
bool operator==(const Reaction& other) const { return m_id == other.m_id; }
bool operator!=(const Reaction& other) const { return !(*this == other); }
[[nodiscard]] uint64_t hash(uint64_t seed) const;
protected:
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
std::string m_id;
double m_qValue = 0.0; ///< Q-value of the reaction
std::vector<fourdst::atomic::Species> m_reactants; ///< Reactants of the reaction
std::vector<fourdst::atomic::Species> m_products; ///< Products of the reaction
bool m_reverse = false;
};
class ReactionSet {
public:
explicit ReactionSet(std::vector<std::unique_ptr<Reaction>> reactions);
ReactionSet(const ReactionSet& other);
ReactionSet& operator=(const ReactionSet& other);
virtual ~ReactionSet() = default;
virtual void add_reaction(std::unique_ptr<Reaction> reaction);
virtual void remove_reaction(const std::unique_ptr<Reaction>& reaction);
bool contains(const std::string_view& id) const;
bool contains(const Reaction& reaction) const;
size_t size() const { return m_reactions.size(); }
void sort(double T9=1.0);
bool contains_species(const fourdst::atomic::Species& species) const;
bool contains_reactant(const fourdst::atomic::Species& species) const;
bool contains_product(const fourdst::atomic::Species& species) const;
[[nodiscard]] const Reaction& operator[](size_t index) const;
[[nodiscard]] const Reaction& operator[](const std::string_view& id) const;
bool operator==(const ReactionSet& other) const;
bool operator!=(const ReactionSet& other) const;
[[nodiscard]] uint64_t hash(uint64_t seed = 0) const;
auto begin() { return m_reactions.begin(); }
auto begin() const { return m_reactions.cbegin(); }
auto end() { return m_reactions.end(); }
auto end() const { return m_reactions.cend(); }
protected:
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
std::vector<std::unique_ptr<Reaction>> m_reactions;
std::string m_id;
std::unordered_map<std::string, Reaction*> m_reactionNameMap; ///< Maps reaction IDs to Reaction objects for quick lookup
};
/**
* @struct REACLIBReaction
* @brief Represents a single nuclear reaction from the JINA REACLIB database.
* @details This struct is designed to be constructed at compile time (constexpr) from
* the data parsed by the Python generation script. It stores all necessary
* information to identify a reaction and calculate its rate.
*/
class REACLIBReaction final : public Reaction {
public:
/**
* @brief Constructs a REACLIBReaction object at compile time.
* @param id A unique string identifier generated by the Python script.
* @param peName
* @param chapter The REACLIB chapter number, defining the reaction structure.
* @param reactants A vector of strings with the names of the reactant species.
* @param products A vector of strings with the names of the product species.
* @param qValue The Q-value of the reaction in MeV.
* @param label The source label for the rate data (e.g., "wc12w", "st08").
* @param sets A vector of RateFitSet, containing the fitting coefficients for the rate.
* @param reverse A boolean indicating if the reaction is reversed (default is false).
*/
REACLIBReaction(
const std::string_view id,
const std::string_view peName,
const int chapter,
const std::vector<fourdst::atomic::Species> &reactants,
const std::vector<fourdst::atomic::Species> &products,
const double qValue,
const std::string_view label,
const REACLIBRateCoefficientSet &sets,
const bool reverse = false);
[[nodiscard]] std::unique_ptr<Reaction> clone() const override;
[[nodiscard]] double calculate_rate(const double T9) const override;
[[nodiscard]] CppAD::AD<double> calculate_rate(const CppAD::AD<double> T9) const override;
template <typename GeneralScalarType>
[[nodiscard]] GeneralScalarType calculate_rate(const GeneralScalarType T9) const {
const GeneralScalarType T913 = CppAD::pow(T9, 1.0/3.0);
const GeneralScalarType rateExponent = m_rateCoefficients.a0 +
m_rateCoefficients.a1 / T9 +
m_rateCoefficients.a2 / T913 +
m_rateCoefficients.a3 * T913 +
m_rateCoefficients.a4 * T9 +
m_rateCoefficients.a5 * CppAD::pow(T9, 5.0/3.0) +
m_rateCoefficients.a6 * CppAD::log(T9);
return CppAD::exp(rateExponent);
}
[[nodiscard]] std::string_view peName() const override { return m_peName; }
[[nodiscard]] int chapter() const { return m_chapter; }
[[nodiscard]] std::string_view sourceLabel() const { return m_sourceLabel; }
[[nodiscard]] const REACLIBRateCoefficientSet& rateCoefficients() const { return m_rateCoefficients; }
friend std::ostream& operator<<(std::ostream& os, const REACLIBReaction& reaction);
private:
std::string m_peName; ///< Name of the reaction in (projectile, ejectile) notation (e.g. p(p, g)d)
int m_chapter; ///< Chapter number from the REACLIB database, defining the reaction structure.
std::string m_sourceLabel; ///< Source label for the rate data, indicating the origin of the rate coefficients (e.g., "wc12w", "st08").
REACLIBRateCoefficientSet m_rateCoefficients;
};
class REACLIBReactionSet final : public ReactionSet {
public:
explicit REACLIBReactionSet(std::vector<REACLIBReaction>);
std::unordered_set<std::string> peNames() const;
friend std::ostream& operator<<(std::ostream& os, const REACLIBReactionSet& set);
};
class REACLIBLogicalReaction final : public Reaction {
public:
explicit REACLIBLogicalReaction(const std::vector<REACLIBReaction> &reactions);
explicit REACLIBLogicalReaction(const REACLIBReaction &reaction);
void add_reaction(const REACLIBReaction& reaction);
[[nodiscard]] std::unique_ptr<Reaction> clone() const override;
[[nodiscard]] std::string_view peName() const override { return m_id; };
[[nodiscard]] size_t size() const { return m_rates.size(); }
[[nodiscard]] std::vector<std::string> sources() const { return m_sources; }
[[nodiscard]] double calculate_rate(const double T9) const override;
[[nodiscard]] CppAD::AD<double> calculate_rate(const CppAD::AD<double> T9) const override;
template <typename T>
[[nodiscard]] T calculate_rate(const T T9) const {
T sum = static_cast<T>(0.0);
const T T913 = CppAD::pow(T9, 1.0/3.0);
const T T953 = CppAD::pow(T9, 5.0/3.0);
const T logT9 = CppAD::log(T9);
// ReSharper disable once CppUseStructuredBinding
for (const auto& rate : m_rates) {
const T exponent = rate.a0 +
rate.a1 / T9 +
rate.a2 / T913 +
rate.a3 * T913 +
rate.a4 * T9 +
rate.a5 * T953 +
rate.a6 * logT9;
sum += CppAD::exp(exponent);
}
return sum;
}
[[nodiscard]] int chapter() const { return m_chapter; }
auto begin() { return m_rates.begin(); }
auto begin() const { return m_rates.cbegin(); }
auto end() { return m_rates.end(); }
auto end() const { return m_rates.cend(); }
private:
int m_chapter;
std::vector<std::string> m_sources;
std::vector<REACLIBRateCoefficientSet> m_rates;
};
class REACLIBLogicalReactionSet final : public ReactionSet {
public:
REACLIBLogicalReactionSet() = delete;
explicit REACLIBLogicalReactionSet(const REACLIBReactionSet& reactionSet);
[[nodiscard]] std::unordered_set<std::string> peNames() const;
private:
std::unordered_set<std::string> m_peNames;
};
}