GridFire 0.0.1a
General Purpose Nuclear Network
Loading...
Searching...
No Matches
solver.cpp
Go to the documentation of this file.
3#include "gridfire/network.h"
4
6
7#include "fourdst/composition/atomicSpecies.h"
8#include "fourdst/composition/composition.h"
9#include "fourdst/config/config.h"
10
11#include "Eigen/Dense"
12#include "unsupported/Eigen/NonLinearOptimization"
13
14#include <boost/numeric/odeint.hpp>
15
16#include <vector>
17#include <unordered_map>
18#include <string>
19#include <stdexcept>
20#include <iomanip>
21
22#include "quill/LogMacros.h"
23
24namespace gridfire::solver {
25
27 // --- Use the policy to decide whether to update the view ---
28 if (shouldUpdateView(netIn)) {
29 LOG_DEBUG(m_logger, "Solver update policy triggered, network view updating...");
30 m_engine.update(netIn);
31 LOG_DEBUG(m_logger, "Network view updated!");
32
35 }
36 m_engine.generateJacobianMatrix(netIn.MolarAbundance(), netIn.temperature / 1e9, netIn.density);
37 using state_type = boost::numeric::ublas::vector<double>;
38 using namespace boost::numeric::odeint;
39
40 NetOut postIgnition = initializeNetworkWithShortIgnition(netIn);
41
42 constexpr double abundance_floor = 1.0e-30;
43 std::vector<double>Y_sanitized_initial;
44 Y_sanitized_initial.reserve(m_engine.getNetworkSpecies().size());
45
46 LOG_DEBUG(m_logger, "Sanitizing initial abundances with a floor of {:0.3E}...", abundance_floor);
47 for (const auto& species : m_engine.getNetworkSpecies()) {
48 double molar_abundance = 0.0;
49 if (postIgnition.composition.contains(species)) {
50 molar_abundance = postIgnition.composition.getMolarAbundance(std::string(species.name()));
51 }
52
53 if (molar_abundance < abundance_floor) {
54 molar_abundance = abundance_floor;
55 }
56 Y_sanitized_initial.push_back(molar_abundance);
57 }
58 const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
59 const double rho = netIn.density; // Density in g/cm^3
60
61 const auto indices = packSpeciesTypeIndexVectors(Y_sanitized_initial, T9, rho);
62 Eigen::VectorXd Y_QSE;
63 try {
64 Y_QSE = calculateSteadyStateAbundances(Y_sanitized_initial, T9, rho, indices);
65 LOG_DEBUG(m_logger, "QSE Abundances: {}", [*this](const dynamicQSESpeciesIndices& indices, const Eigen::VectorXd& Y_QSE) -> std::string {
66 std::stringstream ss;
67 ss << std::scientific << std::setprecision(5);
68 for (size_t i = 0; i < indices.QSESpeciesIndices.size(); ++i) {
69 ss << std::string(m_engine.getNetworkSpecies()[indices.QSESpeciesIndices[i]].name()) + ": ";
70 ss << Y_QSE(i);
71 if (i < indices.QSESpeciesIndices.size() - 2) {
72 ss << ", ";
73 } else if (i == indices.QSESpeciesIndices.size() - 2) {
74 ss << ", and ";
75 }
76
77 }
78 return ss.str();
79 }(indices, Y_QSE));
80 } catch (const std::runtime_error& e) {
81 LOG_ERROR(m_logger, "Failed to calculate steady state abundances. Aborting QSE evaluation.");
82 m_logger->flush_log();
83 throw std::runtime_error("Failed to calculate steady state abundances: " + std::string(e.what()));
84 }
85
86 state_type YDynamic_ublas(indices.dynamicSpeciesIndices.size() + 1);
87 for (size_t i = 0; i < indices.dynamicSpeciesIndices.size(); ++i) {
88 YDynamic_ublas(i) = Y_sanitized_initial[indices.dynamicSpeciesIndices[i]];
89 }
90 YDynamic_ublas(indices.dynamicSpeciesIndices.size()) = 0.0; // Placeholder for specific energy rate
91
92 const RHSFunctor rhs_functor(m_engine, indices.dynamicSpeciesIndices, indices.QSESpeciesIndices, Y_QSE, T9, rho);
93 const auto stepper = make_controlled<runge_kutta_dopri5<state_type>>(1.0e-8, 1.0e-8);
94
95 size_t stepCount = integrate_adaptive(
96 stepper,
97 rhs_functor,
98 YDynamic_ublas,
99 0.0, // Start time
100 netIn.tMax,
101 netIn.dt0
102 );
103
104 std::vector<double> YFinal = Y_sanitized_initial;
105 for (size_t i = 0; i <indices.dynamicSpeciesIndices.size(); ++i) {
106 YFinal[indices.dynamicSpeciesIndices[i]] = YDynamic_ublas(i);
107 }
108 for (size_t i = 0; i < indices.QSESpeciesIndices.size(); ++i) {
109 YFinal[indices.QSESpeciesIndices[i]] = Y_QSE(i);
110 }
111
112 const double finalSpecificEnergyRate = YDynamic_ublas(indices.dynamicSpeciesIndices.size());
113
114 // --- Marshal output variables ---
115 std::vector<std::string> speciesNames(m_engine.getNetworkSpecies().size());
116 std::vector<double> finalMassFractions(m_engine.getNetworkSpecies().size());
117 double massFractionSum = 0.0;
118
119 for (size_t i = 0; i < speciesNames.size(); ++i) {
120 const auto& species = m_engine.getNetworkSpecies()[i];
121 speciesNames[i] = species.name();
122 finalMassFractions[i] = YFinal[i] * species.mass(); // Convert from molar abundance to mass fraction
123 massFractionSum += finalMassFractions[i];
124 }
125 for (auto& mf : finalMassFractions) {
126 mf /= massFractionSum; // Normalize to get mass fractions
127 }
128
129 fourdst::composition::Composition outputComposition(speciesNames, finalMassFractions);
130 NetOut netOut;
131 netOut.composition = outputComposition;
132 netOut.energy = finalSpecificEnergyRate; // Specific energy rate
133 netOut.num_steps = stepCount;
134 return netOut;
135 }
136
138 const std::vector<double>& Y,
139 const double T9,
140 const double rho
141 ) const {
142 constexpr double timescaleCutoff = 1.0e-5;
143 constexpr double abundanceCutoff = 1.0e-15;
144
145 LOG_INFO(m_logger, "Partitioning species using T9={:0.2f} and ρ={:0.2e}", T9, rho);
146 LOG_INFO(m_logger, "Timescale Cutoff: {:.1e} s, Abundance Cutoff: {:.1e}", timescaleCutoff, abundanceCutoff);
147
148 std::vector<size_t>dynamicSpeciesIndices; // Slow species that are not in QSE
149 std::vector<size_t>QSESpeciesIndices; // Fast species that are in QSE
150
151 std::unordered_map<fourdst::atomic::Species, double> speciesTimescale = m_engine.getSpeciesTimescales(Y, T9, rho);
152
153 for (size_t i = 0; i < m_engine.getNetworkSpecies().size(); ++i) {
154 const auto& species = m_engine.getNetworkSpecies()[i];
155 const double network_timescale = speciesTimescale.at(species);
156 const double abundance = Y[i];
157
158 double decay_timescale = std::numeric_limits<double>::infinity();
159 const double half_life = species.halfLife();
160 if (half_life > 0 && !std::isinf(half_life)) {
161 constexpr double LN2 = 0.69314718056;
162 decay_timescale = half_life / LN2;
163 }
164
165 const double final_timescale = std::min(network_timescale, decay_timescale);
166
167 if (std::isinf(final_timescale) || abundance < abundanceCutoff || final_timescale <= timescaleCutoff) {
168 QSESpeciesIndices.push_back(i);
169 } else {
170 dynamicSpeciesIndices.push_back(i);
171 }
172 }
173 LOG_INFO(m_logger, "Partitioning complete. Dynamical species: {}, QSE species: {}.", dynamicSpeciesIndices.size(), QSESpeciesIndices.size());
174 LOG_INFO(m_logger, "Dynamic species: {}", [dynamicSpeciesIndices](const DynamicEngine& engine_wrapper) -> std::string {
175 std::string result;
176 int count = 0;
177 for (const auto& i : dynamicSpeciesIndices) {
178 result += std::string(engine_wrapper.getNetworkSpecies()[i].name());
179 if (count < dynamicSpeciesIndices.size() - 2) {
180 result += ", ";
181 } else if (count == dynamicSpeciesIndices.size() - 2) {
182 result += " and ";
183 }
184 count++;
185 }
186 return result;
187 }(m_engine));
188 LOG_INFO(m_logger, "QSE species: {}", [QSESpeciesIndices](const DynamicEngine& engine_wrapper) -> std::string {
189 std::string result;
190 int count = 0;
191 for (const auto& i : QSESpeciesIndices) {
192 result += std::string(engine_wrapper.getNetworkSpecies()[i].name());
193 if (count < QSESpeciesIndices.size() - 2) {
194 result += ", ";
195 } else if (count == QSESpeciesIndices.size() - 2) {
196 result += " and ";
197 }
198 count++;
199 }
200 return result;
201 }(m_engine));
202 return {dynamicSpeciesIndices, QSESpeciesIndices};
203 }
204
206 const std::vector<double> &Y,
207 const double T9,
208 const double rho,
209 const dynamicQSESpeciesIndices &indices
210 ) const {
211 LOG_TRACE_L1(m_logger, "Calculating steady state abundances for QSE species...");
212
213 if (indices.QSESpeciesIndices.empty()) {
214 LOG_DEBUG(m_logger, "No QSE species to solve for.");
215 return Eigen::VectorXd(0);
216 }
217 // Use the EigenFunctor with Eigen's nonlinear solver
218 EigenFunctor<double> functor(
219 m_engine,
220 Y,
221 indices.dynamicSpeciesIndices,
222 indices.QSESpeciesIndices,
223 T9,
224 rho
225 );
226
227 Eigen::VectorXd v_qse_log_initial(indices.QSESpeciesIndices.size());
228 for (size_t i = 0; i < indices.QSESpeciesIndices.size(); ++i) {
229 v_qse_log_initial(i) = std::log(std::max(Y[indices.QSESpeciesIndices[i]], 1e-99));
230 }
231
232 const static std::unordered_map<Eigen::LevenbergMarquardtSpace::Status, const char*> statusMessages = {
233 {Eigen::LevenbergMarquardtSpace::NotStarted, "Not started"},
234 {Eigen::LevenbergMarquardtSpace::Running, "Running"},
235 {Eigen::LevenbergMarquardtSpace::ImproperInputParameters, "Improper input parameters"},
236 {Eigen::LevenbergMarquardtSpace::RelativeReductionTooSmall, "Relative reduction too small"},
237 {Eigen::LevenbergMarquardtSpace::RelativeErrorTooSmall, "Relative error too small"},
238 {Eigen::LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall, "Relative error and reduction too small"},
239 {Eigen::LevenbergMarquardtSpace::CosinusTooSmall, "Cosine too small"},
240 {Eigen::LevenbergMarquardtSpace::TooManyFunctionEvaluation, "Too many function evaluations"},
241 {Eigen::LevenbergMarquardtSpace::FtolTooSmall, "Function tolerance too small"},
242 {Eigen::LevenbergMarquardtSpace::XtolTooSmall, "X tolerance too small"},
243 {Eigen::LevenbergMarquardtSpace::GtolTooSmall, "Gradient tolerance too small"},
244 {Eigen::LevenbergMarquardtSpace::UserAsked, "User asked to stop"}
245 };
246
247 Eigen::LevenbergMarquardt lm(functor);
248 const Eigen::LevenbergMarquardtSpace::Status info = lm.minimize(v_qse_log_initial);
249
250 if (info <= 0 || info >= 4) {
251 LOG_ERROR(m_logger, "QSE species minimization failed with status: {} ({})",
252 static_cast<int>(info), statusMessages.at(info));
253 throw std::runtime_error(
254 "QSE species minimization failed with status: " + std::to_string(static_cast<int>(info)) +
255 " (" + std::string(statusMessages.at(info)) + ")"
256 );
257 }
258 LOG_DEBUG(m_logger, "QSE species minimization completed successfully with status: {} ({})",
259 static_cast<int>(info), statusMessages.at(info));
260 return v_qse_log_initial.array().exp();
261
262 }
263
265 const auto ignitionTemperature = m_config.get<double>(
266 "gridfire:solver:QSE:ignition:temperature",
267 2e8
268 ); // 0.2 GK
269 const auto ignitionDensity = m_config.get<double>(
270 "gridfire:solver:QSE:ignition:density",
271 1e6
272 ); // 1e6 g/cm^3
273 const auto ignitionTime = m_config.get<double>(
274 "gridfire:solver:QSE:ignition:tMax",
275 1e-7
276 ); // 0.1 μs
277 const auto ignitionStepSize = m_config.get<double>(
278 "gridfire:solver:QSE:ignition:dt0",
279 1e-15
280 ); // 1e-15 seconds
281
282 LOG_INFO(
283 m_logger,
284 "Igniting network with T={:<5.3E}, ρ={:<5.3E}, tMax={:<5.3E}, dt0={:<5.3E}...",
285 ignitionTemperature,
286 ignitionDensity,
287 ignitionTime,
288 ignitionStepSize
289 );
290
291 NetIn preIgnition = netIn;
292 preIgnition.temperature = ignitionTemperature;
293 preIgnition.density = ignitionDensity;
294 preIgnition.tMax = ignitionTime;
295 preIgnition.dt0 = ignitionStepSize;
296
297 const auto prevScreeningModel = m_engine.getScreeningModel();
298 LOG_DEBUG(m_logger, "Setting screening model to BARE for high temperature and density ignition.");
299 m_engine.setScreeningModel(screening::ScreeningType::BARE);
300 DirectNetworkSolver ignitionSolver(m_engine);
301 NetOut postIgnition = ignitionSolver.evaluate(preIgnition);
302 LOG_INFO(m_logger, "Network ignition completed in {} steps.", postIgnition.num_steps);
303 m_engine.setScreeningModel(prevScreeningModel);
304 LOG_DEBUG(m_logger, "Restoring previous screening model: {}", static_cast<int>(prevScreeningModel));
305 return postIgnition;
306 }
307
308 bool QSENetworkSolver::shouldUpdateView(const NetIn &conditions) const {
309 // Policy 1: If the view has never been initialized, we must update.
310 if (!m_isViewInitialized) {
311 return true;
312 }
313
314 // Policy 2: Check for significant relative change in temperature.
315 // Reaction rates are exponentially sensitive to temperature, so we use a tight threshold.
316 const double temp_threshold = m_config.get<double>("gridfire:solver:policy:temp_threshold", 0.05); // 5%
317 const double temp_relative_change = std::abs(conditions.temperature - m_lastSeenConditions.temperature) / m_lastSeenConditions.temperature;
318 if (temp_relative_change > temp_threshold) {
319 LOG_DEBUG(m_logger, "Temperature changed by {:.1f}%, triggering view update.", temp_relative_change * 100);
320 return true;
321 }
322
323 // Policy 3: Check for significant relative change in density.
324 const double rho_threshold = m_config.get<double>("gridfire:solver:policy:rho_threshold", 0.10); // 10%
325 const double rho_relative_change = std::abs(conditions.density - m_lastSeenConditions.density) / m_lastSeenConditions.density;
326 if (rho_relative_change > rho_threshold) {
327 LOG_DEBUG(m_logger, "Density changed by {:.1f}%, triggering view update.", rho_relative_change * 100);
328 return true;
329 }
330
331 // Policy 4: Check for fuel depletion.
332 // If a primary fuel source changes significantly, the network structure may change.
333 const double fuel_threshold = m_config.get<double>("gridfire:solver:policy:fuel_threshold", 0.15); // 15%
334
335 // Example: Check hydrogen abundance
336 const double h1_old = m_lastSeenConditions.composition.getMassFraction("H-1");
337 const double h1_new = conditions.composition.getMassFraction("H-1");
338 if (h1_old > 1e-12) { // Avoid division by zero
339 const double h1_relative_change = std::abs(h1_new - h1_old) / h1_old;
340 if (h1_relative_change > fuel_threshold) {
341 LOG_DEBUG(m_logger, "H-1 mass fraction changed by {:.1f}%, triggering view update.", h1_relative_change * 100);
342 return true;
343 }
344 }
345
346 // If none of the above conditions are met, the current view is still good enough.
347 return false;
348 }
349
351 const boost::numeric::ublas::vector<double> &YDynamic,
352 boost::numeric::ublas::vector<double> &dYdtDynamic,
353 double t
354 ) const {
355 // --- Populate the slow / dynamic species vector ---
356 std::vector<double> YFull(m_engine.getNetworkSpecies().size());
357 for (size_t i = 0; i < m_dynamicSpeciesIndices.size(); ++i) {
358 YFull[m_dynamicSpeciesIndices[i]] = YDynamic(i);
359 }
360
361 // --- Populate the QSE species vector ---
362 for (size_t i = 0; i < m_QSESpeciesIndices.size(); ++i) {
363 YFull[m_QSESpeciesIndices[i]] = m_Y_QSE(i);
364 }
365
366 auto [full_dYdt, specificEnergyRate] = m_engine.calculateRHSAndEnergy(YFull, m_T9, m_rho);
367
368 dYdtDynamic.resize(m_dynamicSpeciesIndices.size() + 1);
369 for (size_t i = 0; i < m_dynamicSpeciesIndices.size(); ++i) {
370 dYdtDynamic(i) = full_dYdt[m_dynamicSpeciesIndices[i]];
371 }
372 dYdtDynamic[m_dynamicSpeciesIndices.size()] = specificEnergyRate;
373 }
374
376 namespace ublas = boost::numeric::ublas;
377 namespace odeint = boost::numeric::odeint;
378 using fourdst::composition::Composition;
379
380
381 const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
382 const unsigned long numSpecies = m_engine.getNetworkSpecies().size();
383
384 const auto absTol = m_config.get<double>("gridfire:solver:DirectNetworkSolver:absTol", 1.0e-8);
385 const auto relTol = m_config.get<double>("gridfire:solver:DirectNetworkSolver:relTol", 1.0e-8);
386
387 size_t stepCount = 0;
388
389 RHSFunctor rhsFunctor(m_engine, T9, netIn.density);
390 JacobianFunctor jacobianFunctor(m_engine, T9, netIn.density);
391
392 ublas::vector<double> Y(numSpecies + 1);
393
394 for (size_t i = 0; i < numSpecies; ++i) {
395 const auto& species = m_engine.getNetworkSpecies()[i];
396 try {
397 Y(i) = netIn.composition.getMolarAbundance(std::string(species.name()));
398 } catch (const std::runtime_error) {
399 LOG_DEBUG(m_logger, "Species '{}' not found in composition. Setting abundance to 0.0.", species.name());
400 Y(i) = 0.0;
401 }
402 }
403 Y(numSpecies) = 0.0;
404
405 const auto stepper = odeint::make_controlled<odeint::rosenbrock4<double>>(absTol, relTol);
406 stepCount = odeint::integrate_adaptive(
407 stepper,
408 std::make_pair(rhsFunctor, jacobianFunctor),
409 Y,
410 0.0,
411 netIn.tMax,
412 netIn.dt0
413 );
414
415 std::vector<double> finalMassFractions(numSpecies);
416 for (size_t i = 0; i < numSpecies; ++i) {
417 const double molarMass = m_engine.getNetworkSpecies()[i].mass();
418 finalMassFractions[i] = Y(i) * molarMass; // Convert from molar abundance to mass fraction
419 if (finalMassFractions[i] < MIN_ABUNDANCE_THRESHOLD) {
420 finalMassFractions[i] = 0.0;
421 }
422 }
423
424 std::vector<std::string> speciesNames;
425 speciesNames.reserve(numSpecies);
426 for (const auto& species : m_engine.getNetworkSpecies()) {
427 speciesNames.push_back(std::string(species.name()));
428 }
429
430 Composition outputComposition(speciesNames);
431 outputComposition.setMassFraction(speciesNames, finalMassFractions);
432 outputComposition.finalize(true);
433
434 NetOut netOut;
435 netOut.composition = std::move(outputComposition);
436 netOut.energy = Y(numSpecies); // Specific energy rate
437 netOut.num_steps = stepCount;
438
439 return netOut;
440 }
441
443 const boost::numeric::ublas::vector<double> &Y,
444 boost::numeric::ublas::vector<double> &dYdt,
445 double t
446 ) const {
447 const std::vector<double> y(Y.begin(), m_numSpecies + Y.begin());
448
449 // std::string timescales = utils::formatNuclearTimescaleLogString(
450 // m_engine,
451 // y,
452 // m_T9,
453 // m_rho
454 // );
455 // LOG_TRACE_L2(m_logger, "{}", timescales);
456
457 auto [dydt, eps] = m_engine.calculateRHSAndEnergy(y, m_T9, m_rho);
458 dYdt.resize(m_numSpecies + 1);
459 std::ranges::copy(dydt, dYdt.begin());
460 dYdt(m_numSpecies) = eps;
461 }
462
464 const boost::numeric::ublas::vector<double> &Y,
465 boost::numeric::ublas::matrix<double> &J,
466 double t,
467 boost::numeric::ublas::vector<double> &dfdt
468 ) const {
469 J.resize(m_numSpecies+1, m_numSpecies+1);
470 J.clear();
471 for (int i = 0; i < m_numSpecies; ++i) {
472 for (int j = 0; j < m_numSpecies; ++j) {
473 J(i, j) = m_engine.getJacobianMatrixEntry(i, j);
474 }
475 }
476 }
477}
Abstract class for engines supporting Jacobian and stoichiometry operations.
virtual const std::vector< fourdst::atomic::Species > & getNetworkSpecies() const =0
Get the list of species in the network.
A network solver that directly integrates the reaction network ODEs.
Definition solver.h:386
quill::Logger * m_logger
Logger instance.
Definition solver.h:491
fourdst::config::Config & m_config
Configuration instance.
Definition solver.h:492
NetOut evaluate(const NetIn &netIn) override
Evaluates the network for a given timestep using direct integration.
Definition solver.cpp:375
Eigen::VectorXd calculateSteadyStateAbundances(const std::vector< double > &Y, const double T9, const double rho, const dynamicQSESpeciesIndices &indices) const
Calculates the steady-state abundances of the QSE species.
Definition solver.cpp:205
bool shouldUpdateView(const NetIn &conditions) const
Determines whether the adaptive engine view should be updated.
Definition solver.cpp:308
NetIn m_lastSeenConditions
The last seen input conditions.
Definition solver.h:373
quill::Logger * m_logger
Logger instance.
Definition solver.h:369
NetOut evaluate(const NetIn &netIn) override
Evaluates the network for a given timestep using the QSE approach.
Definition solver.cpp:26
dynamicQSESpeciesIndices packSpeciesTypeIndexVectors(const std::vector< double > &Y, const double T9, const double rho) const
Packs the species indices into vectors based on their type (dynamic or QSE).
Definition solver.cpp:137
fourdst::config::Config & m_config
Configuration instance.
Definition solver.h:370
bool m_isViewInitialized
Flag indicating whether the adaptive engine view has been initialized.
Definition solver.h:372
NetOut initializeNetworkWithShortIgnition(const NetIn &netIn) const
Initializes the network with a short ignition phase.
Definition solver.cpp:264
@ BARE
No screening applied. The screening factor is always 1.0.
static constexpr double MIN_ABUNDANCE_THRESHOLD
Minimum abundance threshold below which species are ignored.
double density
Density in g/cm^3.
Definition network.h:58
double tMax
Maximum time.
Definition network.h:55
fourdst::composition::Composition composition
Composition of the network.
Definition network.h:54
std::vector< double > MolarAbundance() const
Definition network.cpp:30
double dt0
Initial time step.
Definition network.h:56
double temperature
Temperature in Kelvin.
Definition network.h:57
fourdst::composition::Composition composition
Composition of the network after evaluation.
Definition network.h:66
double energy
Energy in ergs after evaluation.
Definition network.h:68
int num_steps
Number of steps taken in the evaluation.
Definition network.h:67
Functor for calculating the Jacobian matrix.
Definition solver.h:452
const size_t m_numSpecies
The number of species in the network.
Definition solver.h:456
DynamicEngine & m_engine
The engine used to evaluate the network.
Definition solver.h:453
void operator()(const boost::numeric::ublas::vector< double > &Y, boost::numeric::ublas::matrix< double > &J, double t, boost::numeric::ublas::vector< double > &dfdt) const
Calculates the Jacobian matrix.
Definition solver.cpp:463
Functor for calculating the right-hand side of the ODEs.
Definition solver.h:409
DynamicEngine & m_engine
The engine used to evaluate the network.
Definition solver.h:410
const double m_T9
Temperature in units of 10^9 K.
Definition solver.h:411
void operator()(const boost::numeric::ublas::vector< double > &Y, boost::numeric::ublas::vector< double > &dYdt, double t) const
Calculates the time derivatives of the species abundances.
Definition solver.cpp:442
const double m_rho
Density in g/cm^3.
Definition solver.h:412
const size_t m_numSpecies
The number of species in the network.
Definition solver.h:413
Functor for calculating the residual and Jacobian for the QSE species using Eigen.
Definition solver.h:309
Functor for calculating the right-hand side of the ODEs for the dynamic species.
Definition solver.h:201
const Eigen::VectorXd & m_Y_QSE
Steady-state abundances of the QSE species.
Definition solver.h:205
DynamicEngine & m_engine
The engine used to evaluate the network.
Definition solver.h:202
const double m_T9
Temperature in units of 10^9 K.
Definition solver.h:206
const std::vector< size_t > & m_dynamicSpeciesIndices
Indices of the dynamic species.
Definition solver.h:203
const std::vector< size_t > & m_QSESpeciesIndices
Indices of the QSE species.
Definition solver.h:204
const double m_rho
Density in g/cm^3.
Definition solver.h:207
void operator()(const boost::numeric::ublas::vector< double > &YDynamic, boost::numeric::ublas::vector< double > &dYdtDynamic, double t) const
Calculates the time derivatives of the dynamic species.
Definition solver.cpp:350
Structure to hold indices of dynamic and QSE species.
Definition solver.h:27
std::vector< size_t > QSESpeciesIndices
Indices of fast species that are in QSE.
Definition solver.h:29
std::vector< size_t > dynamicSpeciesIndices
Indices of slow species that are not in QSE.
Definition solver.h:28