GridFire 0.0.1a General Purpose Nuclear Network

Loading...
Searching...
No Matches
priming.cpp
Go to the documentation of this file.
1#include "gridfire/engine/procedures/priming.h"
2#include "gridfire/engine/views/engine_priming.h"
3#include "gridfire/engine/procedures/construction.h"
4#include "gridfire/solver/solver.h"
5
6#include "gridfire/engine/engine_abstract.h"
7#include "gridfire/network.h"
8
9#include "fourdst/logging/logging.h"
10#include "quill/Logger.h"
11#include "quill/LogMacros.h"
12
13 namespace gridfire {
14 using fourdst::composition::Composition;
15 using fourdst::atomic::Species;
16
17 const reaction::Reaction* findDominantCreationChannel (
18 const DynamicEngine& engine,
19 const Species& species,
20 const std::vector<double>& Y,
21 const double T9,
22 const double rho
23 ) {
24 const reaction::Reaction* dominateReaction = nullptr;
25 double maxFlow = -1.0;
26 for (const auto& reaction : engine.getNetworkReactions()) {
27 if (reaction.contains(species) && reaction.stoichiometry(species) > 0) {
28 const double flow = engine.calculateMolarReactionFlow(reaction, Y, T9, rho);
29 if (flow > maxFlow) {
30 maxFlow = flow;
31 dominateReaction = &reaction;
32 }
33 }
34 }
35 return dominateReaction;
36 }
37
38
39 PrimingReport primeNetwork(const NetIn& netIn, DynamicEngine& engine) {
40 auto logger = LogManager::getInstance().getLogger("log");
41
42 std::vector<Species> speciesToPrime;
43 for (const auto &entry: netIn.composition | std::views::values) {
44 if (entry.mass_fraction() == 0.0) {
45 speciesToPrime.push_back(entry.isotope());
46 }
47 }
48 LOG_DEBUG(logger, "Priming {} species in the network.", speciesToPrime.size());
49
50 PrimingReport report;
51 if (speciesToPrime.empty()) {
52 report.primedComposition = netIn.composition;
53 report.success = true;
54 report.status = PrimingReportStatus::NO_SPECIES_TO_PRIME;
55 return report;
56 }
57
58 const double T9 = netIn.temperature / 1e9;
59 const double rho = netIn.density;
60 const auto initialReactionSet = engine.getNetworkReactions();
61
62 report.status = PrimingReportStatus::FULL_SUCCESS;
63 report.success = true;
64
65 // --- 1: pack composition into internal map ---
66 std::unordered_map<Species, double> currentMassFractions;
67 for (const auto& entry : netIn.composition | std::views::values) {
68 currentMassFractions[entry.isotope()] = entry.mass_fraction();
69 }
70 for (const auto& entry : speciesToPrime) {
71 currentMassFractions[entry] = 0.0; // Initialize priming species with 0 mass fraction
72 }
73
74 std::unordered_map<Species, double> totalMassFractionChanges;
75
76 engine.rebuild(netIn.composition, NetworkBuildDepth::Full);
77
78 for (const auto& primingSpecies : speciesToPrime) {
79 LOG_TRACE_L3(logger, "Priming species: {}", primingSpecies.name());
80
81 // Create a temporary composition from the current internal state for the primer
82 Composition tempComp;
83 for(const auto& [sp, mf] : currentMassFractions) {
84 tempComp.registerSymbol(std::string(sp.name()));
85 if (mf < 0.0 && std::abs(mf) < 1e-16) {
86 tempComp.setMassFraction(sp, 0.0); // Avoid negative mass fractions
87 } else {
88 tempComp.setMassFraction(sp, mf);
89 }
90 }
91 tempComp.finalize(true); // Finalize with normalization
92
93 NetIn tempNetIn = netIn;
94 tempNetIn.composition = tempComp;
95
96 NetworkPrimingEngineView primer(primingSpecies, engine);
97
98 if (primer.getNetworkReactions().size() == 0) {
99 LOG_ERROR(logger, "No priming reactions found for species {}.", primingSpecies.name());
100 report.success = false;
101 report.status = PrimingReportStatus::FAILED_TO_FIND_PRIMING_REACTIONS;
102 continue;
103 }
104
105 const auto Y = primer.mapNetInToMolarAbundanceVector(tempNetIn);
106 const double destructionRateConstant = calculateDestructionRateConstant(primer, primingSpecies, Y, T9, rho);
107
108 double equilibriumMassFraction = 0.0;
109
110 if (destructionRateConstant > 1e-99) {
111 const double creationRate = calculateCreationRate(primer, primingSpecies, Y, T9, rho);
112 equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
113 if (std::isnan(equilibriumMassFraction)) {
114 LOG_WARNING(logger, "Equilibrium mass fraction for {} is NaN. Setting to 0.0. This is likely not an issue. It probably originates from all reactions leading to creation and destruction being frozen out. In that case 0.0 should be a good approximation. Hint: This happens often when the network temperature is very the low. ", primingSpecies.name());
115 equilibriumMassFraction = 0.0;
116 }
117 LOG_TRACE_L3(logger, "Found equilibrium for {}: X_eq = {:.4e}", primingSpecies.name(), equilibriumMassFraction);
118
119 const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho);
120
121 if (dominantChannel) {
122 LOG_TRACE_L3(logger, "Dominant creation channel for {}: {}", primingSpecies.name(), dominantChannel->peName());
123
124 double totalReactantMass = 0.0;
125 for (const auto& reactant : dominantChannel->reactants()) {
126 totalReactantMass += reactant.mass();
127 }
128
129 double scalingFactor = 1.0;
130 for (const auto& reactant : dominantChannel->reactants()) {
131 const double massToSubtract = equilibriumMassFraction * (reactant.mass() / totalReactantMass);
132 double availableMass = 0.0;
133 if (currentMassFractions.contains(reactant)) {
134 availableMass = currentMassFractions.at(reactant);
135 }
136 if (massToSubtract > availableMass && availableMass > 0) {
137 scalingFactor = std::min(scalingFactor, availableMass / massToSubtract);
138 }
139 }
140
141 if (scalingFactor < 1.0) {
142 LOG_WARNING(logger, "Priming for {} was limited by reactant availability. Scaling transfer by {:.4e}", primingSpecies.name(), scalingFactor);
143 equilibriumMassFraction *= scalingFactor;
144 }
145
146 // Update the internal mass fraction map and accumulate total changes
147 totalMassFractionChanges[primingSpecies] += equilibriumMassFraction;
148 currentMassFractions[primingSpecies] += equilibriumMassFraction;
149
150 for (const auto& reactant : dominantChannel->reactants()) {
151 const double massToSubtract = equilibriumMassFraction * (reactant.mass() / totalReactantMass);
152 totalMassFractionChanges[reactant] -= massToSubtract;
153 currentMassFractions[reactant] -= massToSubtract;
154 }
155 } else {
156 LOG_ERROR(logger, "Failed to find dominant creation channel for {}.", primingSpecies.name());
157 report.status = PrimingReportStatus::FAILED_TO_FIND_CREATION_CHANNEL;
158 totalMassFractionChanges[primingSpecies] += 1e-40;
159 currentMassFractions[primingSpecies] += 1e-40;
160 }
161 } else {
162 LOG_WARNING(logger, "No destruction channel found for {}. Using fallback abundance.", primingSpecies.name());
163 totalMassFractionChanges[primingSpecies] += 1e-40;
164 currentMassFractions[primingSpecies] += 1e-40;
165 report.status = PrimingReportStatus::BASE_NETWORK_TOO_SHALLOW;
166 }
167 }
168
169 // --- Final Composition Construction ---
170 std::vector<std::string> final_symbols;
171 std::vector<double> final_mass_fractions;
172 for(const auto& [species, mass_fraction] : currentMassFractions) {
173 final_symbols.push_back(std::string(species.name()));
174 if (mass_fraction < 0.0 && std::abs(mass_fraction) < 1e-16) {
175 final_mass_fractions.push_back(0.0); // Avoid negative mass fractions
176 } else {
177 final_mass_fractions.push_back(mass_fraction);
178 }
179 }
180
181 // Create the final composition object from the pre-normalized mass fractions
182 Composition primedComposition(final_symbols, final_mass_fractions, true);
183
184 report.primedComposition = primedComposition;
185 for (const auto& [species, change] : totalMassFractionChanges) {
186 report.massFractionChanges.emplace_back(species, change);
187 }
188
189 engine.setNetworkReactions(initialReactionSet);
190 return report;
191 }
192
193 double calculateDestructionRateConstant(
194 const DynamicEngine& engine,
195 const fourdst::atomic::Species& species,
196 const std::vector<double>& Y,
197 const double T9,
198 const double rho
199 ) {
200 const int speciesIndex = engine.getSpeciesIndex(species);
201 std::vector<double> Y_scaled(Y.begin(), Y.end());
202 Y_scaled[speciesIndex] = 1.0; // Set the abundance of the species to 1.0 for rate constant calculation
203 double destructionRateConstant = 0.0;
204 for (const auto& reaction: engine.getNetworkReactions()) {
205 if (reaction.contains_reactant(species)) {
206 const int stoichiometry = reaction.stoichiometry(species);
207 destructionRateConstant += std::abs(stoichiometry) * engine.calculateMolarReactionFlow(reaction, Y_scaled, T9, rho);
208 }
209 }
210 return destructionRateConstant;
211 }
212
213 double calculateCreationRate(
214 const DynamicEngine& engine,
215 const fourdst::atomic::Species& species,
216 const std::vector<double>& Y,
217 const double T9,
218 const double rho
219 ) {
220 double creationRate = 0.0;
221 for (const auto& reaction: engine.getNetworkReactions()) {
222 const int stoichiometry = reaction.stoichiometry(species);
223 if (stoichiometry > 0) {
224 creationRate += stoichiometry * engine.calculateMolarReactionFlow(reaction, Y, T9, rho);
225 }
226 }
227 return creationRate;
228 }
229}
gridfire::DefinedEngineView::mapNetInToMolarAbundanceVector
std::vector< double > mapNetInToMolarAbundanceVector(const NetIn &netIn) const override
Definition engine_defined.cpp:201
gridfire::DefinedEngineView::getNetworkReactions
const reaction::LogicalReactionSet & getNetworkReactions() const override
Gets the set of active logical reactions in the network.
Definition engine_defined.cpp:108
gridfire::DynamicEngine
Abstract class for engines supporting Jacobian and stoichiometry operations.
Definition engine_abstract.h:130
gridfire::DynamicEngine::rebuild
virtual void rebuild(const fourdst::composition::Composition &comp, BuildDepthType depth)
Definition engine_abstract.h:309
gridfire::DynamicEngine::calculateMolarReactionFlow
virtual double calculateMolarReactionFlow(const reaction::Reaction &reaction, const std::vector< double > &Y, double T9, double rho) const =0
Calculate the molar reaction flow for a given reaction.
gridfire::DynamicEngine::getNetworkReactions
virtual const reaction::LogicalReactionSet & getNetworkReactions() const =0
Get the set of logical reactions in the network.
gridfire::DynamicEngine::getSpeciesIndex
virtual int getSpeciesIndex(const fourdst::atomic::Species &species) const =0
gridfire::DynamicEngine::setNetworkReactions
virtual void setNetworkReactions(const reaction::LogicalReactionSet &reactions)=0
gridfire::NetworkPrimingEngineView
Provides a view of a DynamicEngine filtered to reactions involving a specified priming species.
Definition engine_priming.h:30
gridfire::reaction::Reaction
Represents a single nuclear reaction from a specific data source.
Definition reaction.h:72
gridfire::reaction::Reaction::reactants
const std::vector< fourdst::atomic::Species > & reactants() const
Gets the vector of reactant species.
Definition reaction.h:216
gridfire::reaction::Reaction::peName
virtual std::string_view peName() const
Gets the reaction name in (projectile, ejectile) notation.
Definition reaction.h:122
gridfire::reaction::TemplatedReactionSet::size
size_t size() const
Gets the number of reactions in the set.
Definition reaction.h:459
construction.h
engine_abstract.h
Abstract interfaces for reaction network engines in GridFire.
engine_priming.h
gridfire::reaction
Definition reaction.h:25
gridfire
Definition engine_abstract.h:31
gridfire::NetworkBuildDepth::Full
@ Full
Definition building.h:22
gridfire::calculateCreationRate
double calculateCreationRate(const DynamicEngine &engine, const fourdst::atomic::Species &species, const std::vector< double > &Y, double T9, double rho)
Computes the creation rate for a specific species.
Definition priming.cpp:213
gridfire::PrimingReportStatus::FAILED_TO_FIND_PRIMING_REACTIONS
@ FAILED_TO_FIND_PRIMING_REACTIONS
Definition reporting.h:37
gridfire::PrimingReportStatus::FULL_SUCCESS
@ FULL_SUCCESS
Definition reporting.h:32
gridfire::PrimingReportStatus::NO_SPECIES_TO_PRIME
@ NO_SPECIES_TO_PRIME
Definition reporting.h:33
gridfire::PrimingReportStatus::FAILED_TO_FIND_CREATION_CHANNEL
@ FAILED_TO_FIND_CREATION_CHANNEL
Definition reporting.h:36
gridfire::PrimingReportStatus::BASE_NETWORK_TOO_SHALLOW
@ BASE_NETWORK_TOO_SHALLOW
Definition reporting.h:38
gridfire::calculateDestructionRateConstant
double calculateDestructionRateConstant(const DynamicEngine &engine, const fourdst::atomic::Species &species, const std::vector< double > &Y, double T9, double rho)
Computes the destruction rate constant for a specific species.
Definition priming.cpp:193
gridfire::primeNetwork
PrimingReport primeNetwork(const NetIn &, DynamicEngine &engine)
Primes absent species in the network to their equilibrium abundances.
Definition priming.cpp:39
gridfire::findDominantCreationChannel
const reaction::Reaction * findDominantCreationChannel(const DynamicEngine &engine, const Species &species, const std::vector< double > &Y, const double T9, const double rho)
Definition priming.cpp:17
network.h
priming.h
solver.h
gridfire::NetIn
Definition network.h:53
gridfire::NetIn::density
double density
Density in g/cm^3.
Definition network.h:58
gridfire::NetIn::composition
fourdst::composition::Composition composition
Composition of the network.
Definition network.h:54
gridfire::NetIn::temperature
double temperature
Temperature in Kelvin.
Definition network.h:57
gridfire::PrimingReport
Captures the result of a network priming operation.
Definition reporting.h:67
gridfire::PrimingReport::primedComposition
fourdst::composition::Composition primedComposition
Definition reporting.h:69
gridfire::PrimingReport::massFractionChanges
std::vector< std::pair< fourdst::atomic::Species, double > > massFractionChanges
Definition reporting.h:74
gridfire::PrimingReport::status
PrimingReportStatus status
Definition reporting.h:78
gridfire::PrimingReport::success
bool success
Definition reporting.h:76