/* *********************************************************************** // // Copyright (C) 2025 -- The 4D-STAR Collaboration // File Authors: Aaron Dotter, Emily Boudreaux // Last Modified: March 21, 2025 // // 4DSSE is free software; you can use it and/or modify // it under the terms and restrictions the GNU General Library Public // License version 3 (GPLv3) as published by the Free Software Foundation. // // 4DSSE is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with this software; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // *********************************************************************** */ #include "gridfire/network.h" #include #include "gridfire/approx8.h" #include "quill/LogMacros.h" #include "gridfire/reaclib.h" #include "gridfire/reactions.h" namespace gridfire { Network::Network(const NetworkFormat format) : m_config(fourdst::config::Config::getInstance()), m_logManager(fourdst::logging::LogManager::getInstance()), m_logger(m_logManager.getLogger("log")), m_format(format), m_constants(fourdst::constant::Constants::getInstance()){ if (format == NetworkFormat::UNKNOWN) { LOG_ERROR(m_logger, "nuclearNetwork::Network::Network() called with UNKNOWN format"); throw std::runtime_error("nuclearNetwork::Network::Network() called with UNKNOWN format"); } } NetworkFormat Network::getFormat() const { return m_format; } NetworkFormat Network::setFormat(const NetworkFormat format) { const NetworkFormat oldFormat = m_format; m_format = format; return oldFormat; } NetOut Network::evaluate(const NetIn &netIn) { NetOut netOut; switch (m_format) { case APPROX8: { approx8::Approx8Network network; netOut = network.evaluate(netIn); break; } case UNKNOWN: { LOG_ERROR(m_logger, "Network format {} is not implemented.", FormatStringLookup.at(m_format)); throw std::runtime_error("Network format not implemented."); } default: { LOG_ERROR(m_logger, "Unknown network format."); throw std::runtime_error("Unknown network format."); } } return netOut; } LogicalReaction::LogicalReaction(const std::vector &reactions) { if (reactions.empty()) { LOG_ERROR(m_logger, "Empty reaction set provided to LogicalReaction constructor."); throw std::runtime_error("Empty reaction set provided to LogicalReaction constructor."); } const auto& first_reaction = reactions.front(); m_peID = first_reaction.peName(); m_reactants = first_reaction.reactants(); m_products = first_reaction.products(); m_qValue = first_reaction.qValue(); m_reverse = first_reaction.is_reverse(); m_chapter = first_reaction.chapter(); m_rates.reserve(reactions.size()); for (const auto& reaction : reactions) { m_rates.push_back(reaction.rateFits()); if (std::abs(reaction.qValue() - m_qValue) > 1e-6) { LOG_ERROR(m_logger, "Inconsistent Q-values in reactions {}. All reactions must have the same Q-value.", m_peID); throw std::runtime_error("Inconsistent Q-values in reactions. All reactions must have the same Q-value."); } } } LogicalReaction::LogicalReaction(const reaclib::REACLIBReaction &first_reaction) { m_peID = first_reaction.peName(); m_reactants = first_reaction.reactants(); m_products = first_reaction.products(); m_qValue = first_reaction.qValue(); m_reverse = first_reaction.is_reverse(); m_chapter = first_reaction.chapter(); m_rates.reserve(1); m_rates.push_back(first_reaction.rateFits()); } void LogicalReaction::add_reaction(const reaclib::REACLIBReaction &reaction) { if (std::abs(reaction.qValue() - m_qValue > 1e-6)) { LOG_ERROR(m_logger, "Inconsistent Q-values in reactions {}. All reactions must have the same Q-value.", m_peID); throw std::runtime_error("Inconsistent Q-values in reactions. All reactions must have the same Q-value."); } m_rates.push_back(reaction.rateFits()); } auto LogicalReaction::begin() { return m_rates.begin(); } auto LogicalReaction::begin() const { return m_rates.cbegin(); } auto LogicalReaction::end() { return m_rates.end(); } auto LogicalReaction::end() const { return m_rates.cend(); } LogicalReactionSet::LogicalReactionSet(const std::vector &reactions) { if (reactions.empty()) { LOG_ERROR(m_logger, "Empty reaction set provided to LogicalReactionSet constructor."); throw std::runtime_error("Empty reaction set provided to LogicalReactionSet constructor."); } for (const auto& reaction : reactions) { m_reactions.push_back(reaction); } m_reactionNameMap.reserve(m_reactions.size()); for (const auto& reaction : m_reactions) { if (m_reactionNameMap.contains(reaction.id())) { LOG_ERROR(m_logger, "Duplicate reaction ID '{}' found in LogicalReactionSet.", reaction.id()); throw std::runtime_error("Duplicate reaction ID found in LogicalReactionSet: " + std::string(reaction.id())); } m_reactionNameMap[reaction.id()] = reaction; } } LogicalReactionSet::LogicalReactionSet(const std::vector &reactions) { std::vector uniquePeNames; for (const auto& reaction: reactions) { if (uniquePeNames.empty()) { uniquePeNames.emplace_back(reaction.peName()); } else if (std::ranges::find(uniquePeNames, reaction.peName()) == uniquePeNames.end()) { uniquePeNames.emplace_back(reaction.peName()); } } for (const auto& peName : uniquePeNames) { std::vector reactionsForPe; for (const auto& reaction : reactions) { if (reaction.peName() == peName) { reactionsForPe.push_back(reaction); } } m_reactions.emplace_back(reactionsForPe); } m_reactionNameMap.reserve(m_reactions.size()); for (const auto& reaction : m_reactions) { if (m_reactionNameMap.contains(reaction.id())) { LOG_ERROR(m_logger, "Duplicate reaction ID '{}' found in LogicalReactionSet.", reaction.id()); throw std::runtime_error("Duplicate reaction ID found in LogicalReactionSet: " + std::string(reaction.id())); } m_reactionNameMap[reaction.id()] = reaction; } } LogicalReactionSet::LogicalReactionSet(const reaclib::REACLIBReactionSet &reactionSet) { LogicalReactionSet(reactionSet.get_reactions()); } void LogicalReactionSet::add_reaction(const LogicalReaction& reaction) { if (m_reactionNameMap.contains(reaction.id())) { LOG_WARNING(m_logger, "Reaction {} already exists in the set. Not adding again.", reaction.id()); std::cerr << "Warning: Reaction " << reaction.id() << " already exists in the set. Not adding again." << std::endl; return; } m_reactions.push_back(reaction); m_reactionNameMap[reaction.id()] = reaction; } void LogicalReactionSet::add_reaction(const reaclib::REACLIBReaction& reaction) { if (m_reactionNameMap.contains(reaction.id())) { m_reactionNameMap[reaction.id()].add_reaction(reaction); } else { const LogicalReaction logicalReaction(reaction); m_reactions.push_back(logicalReaction); m_reactionNameMap[reaction.id()] = logicalReaction; } } bool LogicalReactionSet::contains(const std::string_view &id) const { for (const auto& reaction : m_reactions) { if (reaction.id() == id) { return true; } } return false; } bool LogicalReactionSet::contains(const LogicalReaction &reactions) const { for (const auto& reaction : m_reactions) { if (reaction.id() == reactions.id()) { return true; } } return false; } bool LogicalReactionSet::contains_species(const fourdst::atomic::Species &species) const { return contains_reactant(species) || contains_product(species); } bool LogicalReactionSet::contains_reactant(const fourdst::atomic::Species &species) const { for (const auto& reaction : m_reactions) { if (std::ranges::find(reaction.reactants(), species) != reaction.reactants().end()) { return true; } } return false; } bool LogicalReactionSet::contains_product(const fourdst::atomic::Species &species) const { for (const auto& reaction : m_reactions) { if (std::ranges::find(reaction.products(), species) != reaction.products().end()) { return true; } } return false; } const LogicalReaction & LogicalReactionSet::operator[](size_t index) const { return m_reactions.at(index); } const LogicalReaction & LogicalReactionSet::operator[](const std::string_view &id) const { return m_reactionNameMap.at(id); } auto LogicalReactionSet::begin() { return m_reactions.begin(); } auto LogicalReactionSet::begin() const { return m_reactions.cbegin(); } auto LogicalReactionSet::end() { return m_reactions.end(); } auto LogicalReactionSet::end() const { return m_reactions.cend(); } LogicalReactionSet build_reaclib_nuclear_network(const fourdst::composition::Composition &composition) { using namespace reaclib; REACLIBReactionSet reactions; auto logger = fourdst::logging::LogManager::getInstance().getLogger("log"); if (!s_initialized) { LOG_INFO(logger, "REACLIB reactions not initialized. Calling initializeAllReaclibReactions()..."); initializeAllReaclibReactions(); } for (const auto &reaction: s_all_reaclib_reactions | std::views::values) { bool gotReaction = true; const auto& reactants = reaction.reactants(); for (const auto& reactant : reactants) { if (!composition.contains(reactant)) { gotReaction = false; break; // If any reactant is not in the composition, skip this reaction } } if (gotReaction) { LOG_INFO(logger, "Adding reaction {} to REACLIB reaction set.", reaction.peName()); reactions.add_reaction(reaction); } } reactions.sort(); return LogicalReactionSet(reactions); } LogicalReactionSet build_reaclib_nuclear_network(const fourdst::composition::Composition &composition, const double culling, const double T9) { using namespace reaclib; LogicalReactionSet allReactions = build_reaclib_nuclear_network(composition); LogicalReactionSet reactions; for (const auto& reaction : allReactions) { if (reaction.calculate_rate(T9) >= culling) { reactions.add_reaction(reaction); } } return reactions; } }