2025-07-14 14:50:49 -04:00
# include "gridfire/engine/procedures/construction.h"
2025-10-07 15:16:03 -04:00
# include "gridfire/reaction/weak/weak_interpolator.h"
# include "gridfire/reaction/weak/weak.h"
# include "gridfire/reaction/weak/weak_types.h"
2025-07-14 14:50:49 -04:00
# include <ranges>
# include <stdexcept>
2025-10-07 15:16:03 -04:00
# include <memory>
2025-07-14 14:50:49 -04:00
# include "gridfire/reaction/reaction.h"
# include "gridfire/reaction/reaclib.h"
# include "fourdst/composition/composition.h"
# include "fourdst/logging/logging.h"
# include "quill/Logger.h"
# include "quill/LogMacros.h"
namespace gridfire {
using reaction : : ReactionSet ;
using reaction : : Reaction ;
using fourdst : : composition : : Composition ;
using fourdst : : atomic : : Species ;
2025-10-07 15:16:03 -04:00
ReactionSet build_nuclear_network (
const Composition & composition ,
const rates : : weak : : WeakRateInterpolator & weak_interpolator ,
BuildDepthType maxLayers ,
bool reverse_reaclib ) {
2025-07-14 14:50:49 -04:00
int depth ;
if ( std : : holds_alternative < NetworkBuildDepth > ( maxLayers ) ) {
depth = static_cast < int > ( std : : get < NetworkBuildDepth > ( maxLayers ) ) ;
} else {
depth = std : : get < int > ( maxLayers ) ;
}
auto logger = fourdst : : logging : : LogManager : : getInstance ( ) . getLogger ( " log " ) ;
if ( depth = = 0 ) {
LOG_ERROR ( logger , " Network build depth is set to 0. No reactions will be collected. " ) ;
throw std : : logic_error ( " Network build depth is set to 0. No reactions will be collected. " ) ;
}
2025-10-07 15:16:03 -04:00
// --- Step 1: Create a single master pool that owns all possible reactions ---
ReactionSet master_reaction_pool ;
// Clone all relevant REACLIB reactions into the master pool
const auto & allReaclibReactions = reaclib : : get_all_reaclib_reactions ( ) ;
for ( const auto & reaction : allReaclibReactions ) {
if ( reaction - > is_reverse ( ) = = reverse_reaclib ) {
master_reaction_pool . add_reaction ( reaction - > clone ( ) ) ;
2025-07-14 14:50:49 -04:00
}
}
2025-10-07 15:16:03 -04:00
for ( const auto & parent_species : weak_interpolator . available_isotopes ( ) ) {
master_reaction_pool . add_reaction (
std : : make_unique < rates : : weak : : WeakReaction > (
parent_species ,
rates : : weak : : WeakReactionType : : BETA_PLUS_DECAY ,
weak_interpolator
)
) ;
master_reaction_pool . add_reaction (
std : : make_unique < rates : : weak : : WeakReaction > (
parent_species ,
rates : : weak : : WeakReactionType : : BETA_MINUS_DECAY ,
weak_interpolator
)
) ;
master_reaction_pool . add_reaction (
std : : make_unique < rates : : weak : : WeakReaction > (
parent_species ,
rates : : weak : : WeakReactionType : : ELECTRON_CAPTURE ,
weak_interpolator
)
) ;
master_reaction_pool . add_reaction (
std : : make_unique < rates : : weak : : WeakReaction > (
parent_species ,
rates : : weak : : WeakReactionType : : POSITRON_CAPTURE ,
weak_interpolator
)
) ;
}
// --- Step 2: Use non-owning raw pointers for the fast build algorithm ---
std : : vector < Reaction * > remainingReactions ;
remainingReactions . reserve ( master_reaction_pool . size ( ) ) ;
for ( const auto & reaction : master_reaction_pool ) {
remainingReactions . push_back ( reaction . get ( ) ) ;
}
2025-07-14 14:50:49 -04:00
if ( depth = = static_cast < int > ( NetworkBuildDepth : : Full ) ) {
2025-10-07 15:16:03 -04:00
LOG_INFO ( logger , " Building full nuclear network with a total of {} reactions. " , remainingReactions . size ( ) ) ;
return master_reaction_pool ; // No need to build layer by layer if we want the full network
2025-07-14 14:50:49 -04:00
}
2025-10-07 15:16:03 -04:00
// --- Step 3: Execute the layered network build using observing pointers ---
2025-07-14 14:50:49 -04:00
std : : unordered_set < Species > availableSpecies ;
2025-10-07 15:16:03 -04:00
for ( const auto & entry : composition | std : : views : : values ) {
2025-07-14 14:50:49 -04:00
if ( entry . mass_fraction ( ) > 0.0 ) {
availableSpecies . insert ( entry . isotope ( ) ) ;
}
}
2025-10-07 15:16:03 -04:00
std : : vector < Reaction * > collectedReactionPtrs ;
2025-07-14 14:50:49 -04:00
LOG_INFO ( logger , " Starting network construction with {} available species. " , availableSpecies . size ( ) ) ;
2025-10-07 15:16:03 -04:00
2025-07-14 14:50:49 -04:00
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 ( ) ) ;
2025-08-14 13:33:46 -04:00
std : : vector < Reaction * > reactionsForNextPass ;
2025-07-14 14:50:49 -04:00
std : : unordered_set < Species > newProductsThisLayer ;
bool newReactionsAdded = false ;
reactionsForNextPass . reserve ( remainingReactions . size ( ) ) ;
2025-10-07 15:16:03 -04:00
for ( Reaction * reaction : remainingReactions ) {
2025-07-14 14:50:49 -04:00
bool allReactantsAvailable = true ;
2025-08-14 13:33:46 -04:00
for ( const auto & reactant : reaction - > reactants ( ) ) {
2025-07-14 14:50:49 -04:00
if ( ! availableSpecies . contains ( reactant ) ) {
allReactantsAvailable = false ;
break ;
}
}
if ( allReactantsAvailable ) {
2025-10-07 15:16:03 -04:00
collectedReactionPtrs . push_back ( reaction ) ;
2025-07-14 14:50:49 -04:00
newReactionsAdded = true ;
2025-08-14 13:33:46 -04:00
for ( const auto & product : reaction - > products ( ) ) {
2025-07-14 14:50:49 -04:00
newProductsThisLayer . insert ( product ) ;
}
} else {
reactionsForNextPass . push_back ( reaction ) ;
}
}
if ( ! newReactionsAdded ) {
2025-10-07 15:16:03 -04:00
LOG_INFO ( logger , " No new reactions added in layer {}. Stopping network construction. " , layer ) ;
2025-07-14 14:50:49 -04:00
break ;
}
2025-10-07 15:16:03 -04:00
LOG_TRACE_L1 ( logger , " Layer {}: Collected {} new reactions. New products this layer: {} " , collectedReactionPtrs . size ( ) - collectedReactionPtrs . size ( ) , newProductsThisLayer . size ( ) ) ;
2025-07-14 14:50:49 -04:00
availableSpecies . insert ( newProductsThisLayer . begin ( ) , newProductsThisLayer . end ( ) ) ;
remainingReactions = std : : move ( reactionsForNextPass ) ;
}
2025-10-07 15:16:03 -04:00
// --- Step 4: Construct the final ReactionSet by moving ownership ---
LOG_INFO ( logger , " Network construction completed. Assembling final set of {} reactions. " , collectedReactionPtrs . size ( ) ) ;
ReactionSet finalReactionSet ;
std : : unordered_set < Reaction * > collectedPtrSet ( collectedReactionPtrs . begin ( ) , collectedReactionPtrs . end ( ) ) ;
for ( auto & reaction_ptr : master_reaction_pool ) {
if ( reaction_ptr & & collectedPtrSet . contains ( reaction_ptr . get ( ) ) ) {
finalReactionSet . add_reaction ( std : : move ( reaction_ptr ) ) ;
}
}
return finalReactionSet ;
2025-07-14 14:50:49 -04:00
}
2025-10-07 15:16:03 -04:00
2025-07-14 14:50:49 -04:00
}