feat(solver): added callback functions to solver in C++ and python

This commit is contained in:
2025-07-31 15:04:57 -04:00
parent 5b74155477
commit 24049b2658
482 changed files with 4318 additions and 1467 deletions

View File

@@ -29,7 +29,7 @@
<tbody>
<tr id="projectrow">
<td id="projectalign">
<div id="projectname">GridFire<span id="projectnumber">&#160;0.0.1a</span>
<div id="projectname">GridFire<span id="projectnumber">&#160;0.6.0</span>
</div>
<div id="projectbrief">General Purpose Nuclear Network</div>
</td>
@@ -228,8 +228,10 @@ Public Member Functions</h2></td></tr>
<tr class="memitem:a818d942efa843959393e4eed3263b7e7 inherit pub_methods_classgridfire_1_1_dynamic_engine" id="r_a818d942efa843959393e4eed3263b7e7"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classgridfire_1_1_dynamic_engine.html#a818d942efa843959393e4eed3263b7e7">generateJacobianMatrix</a> (const std::vector&lt; double &gt; &amp;Y_dynamic, double T9, double rho, const <a class="el" href="namespacegridfire.html#a898dfe22579e649935645cbd6f073178">SparsityPattern</a> &amp;sparsityPattern) const</td></tr>
<tr class="separator:a818d942efa843959393e4eed3263b7e7 inherit pub_methods_classgridfire_1_1_dynamic_engine"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a04317b66ef14d519264bc30ee69f5bf9 inherit pub_methods_classgridfire_1_1_dynamic_engine" id="r_a04317b66ef14d519264bc30ee69f5bf9"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespacegridfire.html#a3b1f70dc7ff5b501809330a97079e4f6">BuildDepthType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classgridfire_1_1_dynamic_engine.html#a04317b66ef14d519264bc30ee69f5bf9">getDepth</a> () const</td></tr>
<tr class="memdesc:a04317b66ef14d519264bc30ee69f5bf9 inherit pub_methods_classgridfire_1_1_dynamic_engine"><td class="mdescLeft">&#160;</td><td class="mdescRight">Get the depth of the network. <br /></td></tr>
<tr class="separator:a04317b66ef14d519264bc30ee69f5bf9 inherit pub_methods_classgridfire_1_1_dynamic_engine"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a4e2c8b896661b7a89beffe0066cb21cf inherit pub_methods_classgridfire_1_1_dynamic_engine" id="r_a4e2c8b896661b7a89beffe0066cb21cf"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classgridfire_1_1_dynamic_engine.html#a4e2c8b896661b7a89beffe0066cb21cf">rebuild</a> (const fourdst::composition::Composition &amp;comp, <a class="el" href="namespacegridfire.html#a3b1f70dc7ff5b501809330a97079e4f6">BuildDepthType</a> depth)</td></tr>
<tr class="memdesc:a4e2c8b896661b7a89beffe0066cb21cf inherit pub_methods_classgridfire_1_1_dynamic_engine"><td class="mdescLeft">&#160;</td><td class="mdescRight">Rebuild the network with a specified depth. <br /></td></tr>
<tr class="separator:a4e2c8b896661b7a89beffe0066cb21cf inherit pub_methods_classgridfire_1_1_dynamic_engine"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="inherit_header pub_methods_classgridfire_1_1_engine"><td colspan="2" onclick="javascript:dynsection.toggleInherit('pub_methods_classgridfire_1_1_engine')"><img src="closed.png" alt="-"/>&#160;Public Member Functions inherited from <a class="el" href="classgridfire_1_1_engine.html">gridfire::Engine</a></td></tr>
<tr class="memitem:a2e7970bed2100699f226f4141d5db037 inherit pub_methods_classgridfire_1_1_engine" id="r_a2e7970bed2100699f226f4141d5db037"><td class="memItemLeft" align="right" valign="top">virtual&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classgridfire_1_1_engine.html#a2e7970bed2100699f226f4141d5db037">~Engine</a> ()=default</td></tr>
@@ -308,14 +310,15 @@ Private Attributes</h2></td></tr>
</table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
<div class="textblock"><p>An engine view that partitions the reaction network into multiple groups based on timescales. </p>
<p>@purpose This class is designed to accelerate the integration of stiff nuclear reaction networks. It identifies species that react on very short timescales ("fast" species) and treats them as being in Quasi-Steady-State Equilibrium (QSE). Their abundances are solved for algebraically, removing their stiff differential equations from the system. The remaining "slow" or "dynamic" species are integrated normally. This significantly improves the stability and performance of the solver.</p>
<p>@how The core logic resides in the <code><a class="el" href="#a7d26945df5395b9317552a3989c42d1c" title="Partitions the network into dynamic and algebraic (QSE) groups based on timescales.">partitionNetwork()</a></code> and <code><a class="el" href="#a4bc879246c6fbd8633b05052858df51d" title="Equilibrates the network by partitioning and solving for QSE abundances.">equilibrateNetwork()</a></code> methods. The partitioning process involves:</p><ol type="1">
<dl class="section user"><dt>Purpose</dt><dd>This class is designed to accelerate the integration of stiff nuclear reaction networks. It identifies species that react on very short timescales ("fast" species) and treats them as being in Quasi-Steady-State Equilibrium (QSE). Their abundances are solved for algebraically, removing their stiff differential equations from the system. The remaining "slow" or "dynamic" species are integrated normally. This significantly improves the stability and performance of the solver.</dd></dl>
<dl class="section user"><dt>How</dt><dd>The core logic resides in the <code><a class="el" href="#a7d26945df5395b9317552a3989c42d1c" title="Partitions the network into dynamic and algebraic (QSE) groups based on timescales.">partitionNetwork()</a></code> and <code><a class="el" href="#a4bc879246c6fbd8633b05052858df51d" title="Equilibrates the network by partitioning and solving for QSE abundances.">equilibrateNetwork()</a></code> methods. The partitioning process involves:<ol type="1">
<li><b>Timescale Analysis:</b> Using <code>getSpeciesDestructionTimescales</code> from the base engine, all species are sorted by their characteristic timescales.</li>
<li><b>Gap Detection:</b> The sorted list of timescales is scanned for large gaps (e.g., several orders of magnitude) to create distinct "timescale pools".</li>
<li><b>Connectivity Analysis:</b> Each pool is analyzed for internal reaction connectivity to form cohesive groups.</li>
<li><b>Flux Validation:</b> Candidate QSE groups are validated by comparing the total reaction flux <em>within</em> the group to the flux <em>leaving</em> the group. A high internal-to-external flux ratio indicates a valid QSE group.</li>
<li><b>QSE Solve:</b> For valid QSE groups, <code>solveQSEAbundances</code> uses a Levenberg-Marquardt nonlinear solver (<code>Eigen::LevenbergMarquardt</code>) to find the equilibrium abundances of the "algebraic" species, holding the "seed" species constant.</li>
</ol>
</dd></dl>
<p>All calculations are cached using <code><a class="el" href="structgridfire_1_1_q_s_e_cache_key.html" title="Key struct for the QSE abundance cache.">QSECacheKey</a></code> to avoid re-partitioning and re-solving for similar thermodynamic conditions.</p>
<dl class="section user"><dt>Usage Example:</dt><dd><div class="fragment"><div class="line"><span class="comment">// 1. Create a base engine (e.g., GraphEngine)</span></div>
<div class="line"><a class="code hl_class" href="classgridfire_1_1_graph_engine.html">gridfire::GraphEngine</a> baseEngine(composition);</div>
@@ -333,7 +336,7 @@ Private Attributes</h2></td></tr>
<div class="line"><span class="keyword">auto</span> Y_initial = multiscaleEngine.mapNetInToMolarAbundanceVector({equilibratedComp, ...});</div>
<div class="line"><span class="keyword">auto</span> derivatives = multiscaleEngine.calculateRHSAndEnergy(Y_initial, T9, rho);</div>
<div class="ttc" id="aclassgridfire_1_1_graph_engine_html"><div class="ttname"><a href="classgridfire_1_1_graph_engine.html">gridfire::GraphEngine</a></div><div class="ttdoc">A reaction network engine that uses a graph-based representation.</div><div class="ttdef"><b>Definition</b> engine_graph.h:100</div></div>
<div class="ttc" id="aclassgridfire_1_1_multiscale_partitioning_engine_view_html"><div class="ttname"><a href="classgridfire_1_1_multiscale_partitioning_engine_view.html">gridfire::MultiscalePartitioningEngineView</a></div><div class="ttdoc">An engine view that partitions the reaction network into multiple groups based on timescales.</div><div class="ttdef"><b>Definition</b> engine_multiscale.h:174</div></div>
<div class="ttc" id="aclassgridfire_1_1_multiscale_partitioning_engine_view_html"><div class="ttname"><a href="classgridfire_1_1_multiscale_partitioning_engine_view.html">gridfire::MultiscalePartitioningEngineView</a></div><div class="ttdoc">An engine view that partitions the reaction network into multiple groups based on timescales.</div><div class="ttdef"><b>Definition</b> engine_multiscale.h:182</div></div>
<div class="ttc" id="astructgridfire_1_1_net_in_html"><div class="ttname"><a href="structgridfire_1_1_net_in.html">gridfire::NetIn</a></div><div class="ttdef"><b>Definition</b> network.h:53</div></div>
</div><!-- fragment --></dd></dl>
<p>&lt;DynamicEngine&gt; </p>
@@ -438,8 +441,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A vector of vectors of species indices, where each inner vector represents a single connected component.</dd></dl>
<p>@purpose To merge timescale pools that are strongly connected by reactions, forming cohesive groups for QSE analysis.</p>
<p>@how For each pool, it builds a reaction connectivity graph using <code>buildConnectivityGraph</code>. It then finds the connected components within that graph using a Breadth-First Search (BFS). The resulting components from all pools are collected and returned. </p>
<dl class="section user"><dt>Purpose</dt><dd>To merge timescale pools that are strongly connected by reactions, forming cohesive groups for QSE analysis.</dd></dl>
<dl class="section user"><dt>How</dt><dd>For each pool, it builds a reaction connectivity graph using <code>buildConnectivityGraph</code>. It then finds the connected components within that graph using a Breadth-First Search (BFS). The resulting components from all pools are collected and returned. </dd></dl>
</div>
</div>
@@ -474,8 +477,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>An unordered map representing the adjacency list of the connectivity graph, where keys are species indices and values are vectors of connected species indices.</dd></dl>
<p>@purpose To represent the reaction pathways among a subset of reactions.</p>
<p>@how It iterates through the specified fast reactions. For each reaction, it creates a two-way edge in the graph between every reactant and every product, signifying that mass can flow between them. </p>
<dl class="section user"><dt>Purpose</dt><dd>To represent the reaction pathways among a subset of reactions.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It iterates through the specified fast reactions. For each reaction, it creates a two-way edge in the graph between every reactant and every product, signifying that mass can flow between them. </dd></dl>
</div>
</div>
@@ -510,8 +513,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>An unordered map representing the adjacency list of the connectivity graph.</dd></dl>
<p>@purpose To find reaction connections within a specific group of species.</p>
<p>@how It iterates through all reactions in the base engine. If a reaction involves at least two distinct species from the input <code>species_pool</code> (one as a reactant and one as a product), it adds edges between all reactants and products from that reaction that are also in the pool. </p>
<dl class="section user"><dt>Purpose</dt><dd>To find reaction connections within a specific group of species.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It iterates through all reactions in the base engine. If a reaction involves at least two distinct species from the input <code>species_pool</code> (one as a reactant and one as a product), it adds edges between all reactants and products from that reaction that are also in the pool. </dd></dl>
</div>
</div>
@@ -563,8 +566,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>Molar flow rate for the reaction (e.g., mol/g/s).</dd></dl>
<p>@purpose To compute the net rate of a single reaction.</p>
<p>@how It first checks the QSE cache. On a hit, it retrieves the cached equilibrium abundances for the algebraic species. It creates a mutable copy of <code>Y_full</code>, overwrites the algebraic species abundances with the cached equilibrium values, and then calls the base engine's <code>calculateMolarReactionFlow</code> with this modified abundance vector.</p>
<dl class="section user"><dt>Purpose</dt><dd>To compute the net rate of a single reaction.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It first checks the QSE cache. On a hit, it retrieves the cached equilibrium abundances for the algebraic species. It creates a mutable copy of <code>Y_full</code>, overwrites the algebraic species abundances with the cached equilibrium values, and then calls the base engine's <code>calculateMolarReactionFlow</code> with this modified abundance vector.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The engine must have a valid QSE cache entry for the given state. </dd></dl>
<dl class="exception"><dt>Exceptions</dt><dd>
<table class="exception">
@@ -619,8 +622,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A <code>std::expected</code> containing <code><a class="el" href="structgridfire_1_1_step_derivatives.html" title="Structure holding derivatives and energy generation for a network step.">StepDerivatives</a>&lt;double&gt;</code> on success, or a <code>StaleEngineError</code> if the engine's QSE cache does not contain a solution for the given state.</dd></dl>
<p>@purpose To compute the time derivatives for the ODE solver. This implementation modifies the derivatives from the base engine to enforce the QSE condition.</p>
<p>@how It first performs a lookup in the QSE abundance cache (<code>m_qse_abundance_cache</code>). If a cache hit occurs, it calls the base engine's <code>calculateRHSAndEnergy</code>. It then manually sets the time derivatives (<code>dydt</code>) of all identified algebraic species to zero, effectively removing their differential equations from the system being solved.</p>
<dl class="section user"><dt>Purpose</dt><dd>To compute the time derivatives for the ODE solver. This implementation modifies the derivatives from the base engine to enforce the QSE condition.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It first performs a lookup in the QSE abundance cache (<code>m_qse_abundance_cache</code>). If a cache hit occurs, it calls the base engine's <code>calculateRHSAndEnergy</code>. It then manually sets the time derivatives (<code>dydt</code>) of all identified algebraic species to zero, effectively removing their differential equations from the system being solved.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The engine must have been updated via <code><a class="el" href="#a6bee75b5a6e508e6eebf83f0d48c50b8" title="Updates the internal state of the engine, performing partitioning and QSE equilibration.">update()</a></code> or <code><a class="el" href="#a4bc879246c6fbd8633b05052858df51d" title="Equilibrates the network by partitioning and solving for QSE abundances.">equilibrateNetwork()</a></code> for the current thermodynamic conditions, so that a valid entry exists in the QSE cache. </dd></dl>
<dl class="section post"><dt>Postcondition</dt><dd>The returned derivatives will have <code>dydt=0</code> for all algebraic species.</dd></dl>
<dl class="exception"><dt>Exceptions</dt><dd>
@@ -682,7 +685,7 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A vector of <code><a class="el" href="structgridfire_1_1_multiscale_partitioning_engine_view_1_1_q_s_e_group.html" title="Struct representing a QSE group.">QSEGroup</a></code> structs, ready for flux validation.</dd></dl>
<p>@how For each input pool, it identifies "bridge" reactions that connect the pool to species outside the pool. The reactants of these bridge reactions that are <em>not</em> in the pool are identified as "seed" species. The original pool members are the "algebraic" species. It then bundles the seed and algebraic species into a <code><a class="el" href="structgridfire_1_1_multiscale_partitioning_engine_view_1_1_q_s_e_group.html" title="Struct representing a QSE group.">QSEGroup</a></code> struct.</p>
<dl class="section user"><dt>How</dt><dd>For each input pool, it identifies "bridge" reactions that connect the pool to species outside the pool. The reactants of these bridge reactions that are <em>not</em> in the pool are identified as "seed" species. The original pool members are the "algebraic" species. It then bundles the seed and algebraic species into a <code><a class="el" href="structgridfire_1_1_multiscale_partitioning_engine_view_1_1_q_s_e_group.html" title="Struct representing a QSE group.">QSEGroup</a></code> struct.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The <code>candidate_pools</code> should be connected components from <code>analyzeTimescalePoolConnectivity</code>. </dd></dl>
<dl class="section post"><dt>Postcondition</dt><dd>A list of candidate <code><a class="el" href="structgridfire_1_1_multiscale_partitioning_engine_view_1_1_q_s_e_group.html" title="Struct representing a QSE group.">QSEGroup</a></code> objects is returned. </dd></dl>
@@ -711,8 +714,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>The equilibrated composition.</dd></dl>
<p>@purpose A convenience overload for <code>equilibrateNetwork</code>.</p>
<p>@how It unpacks the <code>netIn</code> struct into <code>Y</code>, <code>T9</code>, and <code>rho</code> and then calls the primary <code>equilibrateNetwork</code> method. </p>
<dl class="section user"><dt>Purpose</dt><dd>A convenience overload for <code>equilibrateNetwork</code>.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It unpacks the <code>netIn</code> struct into <code>Y</code>, <code>T9</code>, and <code>rho</code> and then calls the primary <code>equilibrateNetwork</code> method. </dd></dl>
</div>
</div>
@@ -750,8 +753,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A new composition object with the equilibrated abundances.</dd></dl>
<p>@purpose A convenience method to run the full QSE analysis and get an equilibrated composition object as a result.</p>
<p>@how It first calls <code><a class="el" href="#a7d26945df5395b9317552a3989c42d1c" title="Partitions the network into dynamic and algebraic (QSE) groups based on timescales.">partitionNetwork()</a></code> with the given state to define the QSE groups. Then, it calls <code><a class="el" href="#a3c5fcb8e3396d74359fd601554c9ffa9" title="Solves for the QSE abundances of the algebraic species in a given state.">solveQSEAbundances()</a></code> to compute the new equilibrium abundances for the algebraic species. Finally, it packs the resulting full abundance vector into a new <code>fourdst::composition::Composition</code> object and returns it.</p>
<dl class="section user"><dt>Purpose</dt><dd>A convenience method to run the full QSE analysis and get an equilibrated composition object as a result.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It first calls <code><a class="el" href="#a7d26945df5395b9317552a3989c42d1c" title="Partitions the network into dynamic and algebraic (QSE) groups based on timescales.">partitionNetwork()</a></code> with the given state to define the QSE groups. Then, it calls <code><a class="el" href="#a3c5fcb8e3396d74359fd601554c9ffa9" title="Solves for the QSE abundances of the algebraic species in a given state.">solveQSEAbundances()</a></code> to compute the new equilibrium abundances for the algebraic species. Finally, it packs the resulting full abundance vector into a new <code>fourdst::composition::Composition</code> object and returns it.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The input state (Y, T9, rho) must be a valid physical state. </dd></dl>
<dl class="section post"><dt>Postcondition</dt><dd>The engine's internal partition is updated. A new composition object is returned. </dd></dl>
@@ -796,8 +799,8 @@ Private Attributes</h2></td></tr>
</table>
</dd>
</dl>
<p>@purpose To visualize the partitioned network graph.</p>
<p>@how This method delegates the DOT file export to the base engine. It does not currently add any partitioning information to the output graph. </p>
<dl class="section user"><dt>Purpose</dt><dd>To visualize the partitioned network graph.</dd></dl>
<dl class="section user"><dt>How</dt><dd>This method delegates the DOT file export to the base engine. It does not currently add any partitioning information to the output graph. </dd></dl>
</div>
</div>
@@ -842,8 +845,8 @@ Private Attributes</h2></td></tr>
</table>
</dd>
</dl>
<p>@purpose To compute the Jacobian matrix required by implicit ODE solvers.</p>
<p>@how It first performs a QSE cache lookup. On a hit, it delegates the full Jacobian calculation to the base engine. While this view could theoretically return a modified, sparser Jacobian reflecting the QSE constraints, the current implementation returns the full Jacobian from the base engine. The solver is expected to handle the algebraic constraints (e.g., via <code>dydt=0</code> from <code>calculateRHSAndEnergy</code>).</p>
<dl class="section user"><dt>Purpose</dt><dd>To compute the Jacobian matrix required by implicit ODE solvers.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It first performs a QSE cache lookup. On a hit, it delegates the full Jacobian calculation to the base engine. While this view could theoretically return a modified, sparser Jacobian reflecting the QSE constraints, the current implementation returns the full Jacobian from the base engine. The solver is expected to handle the algebraic constraints (e.g., via <code>dydt=0</code> from <code>calculateRHSAndEnergy</code>).</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The engine must have a valid QSE cache entry for the given state. </dd></dl>
<dl class="section post"><dt>Postcondition</dt><dd>The base engine's internal Jacobian is updated.</dd></dl>
<dl class="exception"><dt>Exceptions</dt><dd>
@@ -881,8 +884,8 @@ Private Attributes</h2></td></tr>
</div><div class="memdoc">
<p>Generates the stoichiometry matrix for the network. </p>
<p>@purpose To prepare the stoichiometry matrix for later queries.</p>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#abe76a46784b1ebc8ad67a9eec40d369a" title="Generates the stoichiometry matrix for the network.">generateStoichiometryMatrix()</a></code>. The stoichiometry is based on the full, unpartitioned network. </p>
<dl class="section user"><dt>Purpose</dt><dd>To prepare the stoichiometry matrix for later queries.</dd></dl>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#abe76a46784b1ebc8ad67a9eec40d369a" title="Generates the stoichiometry matrix for the network.">generateStoichiometryMatrix()</a></code>. The stoichiometry is based on the full, unpartitioned network. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#aeae6d84ef74d88fd2cdf07b82e98a16f">gridfire::DynamicEngine</a>.</p>
@@ -943,8 +946,8 @@ Private Attributes</h2></td></tr>
<p>Gets the dynamic species in the network. </p>
<dl class="section return"><dt>Returns</dt><dd>A const reference to the vector of species identified as "dynamic" or "slow".</dd></dl>
<p>@purpose To allow external queries of the partitioning results.</p>
<p>@how It returns a const reference to the <code>m_dynamic_species</code> member vector.</p>
<dl class="section user"><dt>Purpose</dt><dd>To allow external queries of the partitioning results.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It returns a const reference to the <code>m_dynamic_species</code> member vector.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd><code><a class="el" href="#a7d26945df5395b9317552a3989c42d1c" title="Partitions the network into dynamic and algebraic (QSE) groups based on timescales.">partitionNetwork()</a></code> must have been called. </dd></dl>
</div>
@@ -974,8 +977,8 @@ Private Attributes</h2></td></tr>
<p>Gets the fast species in the network. </p>
<dl class="section return"><dt>Returns</dt><dd>A vector of species identified as "fast" or "algebraic" by the partitioning.</dd></dl>
<p>@purpose To allow external queries of the partitioning results.</p>
<p>@how It returns a copy of the <code>m_algebraic_species</code> member vector.</p>
<dl class="section user"><dt>Purpose</dt><dd>To allow external queries of the partitioning results.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It returns a copy of the <code>m_algebraic_species</code> member vector.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd><code><a class="el" href="#a7d26945df5395b9317552a3989c42d1c" title="Partitions the network into dynamic and algebraic (QSE) groups based on timescales.">partitionNetwork()</a></code> must have been called. </dd></dl>
</div>
@@ -1016,8 +1019,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>Value of the Jacobian matrix at (i_full, j_full).</dd></dl>
<p>@purpose To provide Jacobian entries to an implicit solver.</p>
<p>@how This method directly delegates to the base engine's <code>getJacobianMatrixEntry</code>. It does not currently modify the Jacobian to reflect the QSE algebraic constraints, as these are handled by setting <code>dY/dt = 0</code> in <code>calculateRHSAndEnergy</code>.</p>
<dl class="section user"><dt>Purpose</dt><dd>To provide Jacobian entries to an implicit solver.</dd></dl>
<dl class="section user"><dt>How</dt><dd>This method directly delegates to the base engine's <code>getJacobianMatrixEntry</code>. It does not currently modify the Jacobian to reflect the QSE algebraic constraints, as these are handled by setting <code>dY/dt = 0</code> in <code>calculateRHSAndEnergy</code>.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd><code><a class="el" href="#acdf5ad8765290ea2b78170235aea391d" title="Generates the Jacobian matrix for the current state.">generateJacobianMatrix()</a></code> must have been called for the current state. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#a05d15ff35a6bc06a2fa7eda19838bd07">gridfire::DynamicEngine</a>.</p>
@@ -1109,7 +1112,7 @@ Private Attributes</h2></td></tr>
<p>Gets the current electron screening model. </p>
<dl class="section return"><dt>Returns</dt><dd>The currently active screening model type.</dd></dl>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#a7bfb4e6fec2f337a1dea69e3d4f1fc82" title="Gets the current electron screening model.">getScreeningModel()</a></code>. </p>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#a7bfb4e6fec2f337a1dea69e3d4f1fc82" title="Gets the current electron screening model.">getScreeningModel()</a></code>. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#a7a203f8e0f3a6744ddc912dfbcfdbcc0">gridfire::DynamicEngine</a>.</p>
@@ -1157,8 +1160,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A <code>std::expected</code> containing a map from <code>Species</code> to their characteristic destruction timescales (s) on success, or a <code>StaleEngineError</code> on failure.</dd></dl>
<p>@purpose To get the timescale for species destruction, which is used as the primary metric for network partitioning.</p>
<p>@how It delegates the calculation to the base engine. For any species identified as algebraic (in QSE), it manually sets their timescale to 0.0.</p>
<dl class="section user"><dt>Purpose</dt><dd>To get the timescale for species destruction, which is used as the primary metric for network partitioning.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It delegates the calculation to the base engine. For any species identified as algebraic (in QSE), it manually sets their timescale to 0.0.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The engine must have a valid QSE cache entry for the given state. </dd></dl>
<dl class="exception"><dt>Exceptions</dt><dd>
<table class="exception">
@@ -1202,7 +1205,7 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>The index of the species in the base engine's network.</dd></dl>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#a91d32b7197fcb27ee697d5bfde960f3f" title="Gets the index of a species in the full network.">getSpeciesIndex()</a></code>. </p>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#a91d32b7197fcb27ee697d5bfde960f3f" title="Gets the index of a species in the full network.">getSpeciesIndex()</a></code>. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#ad3d56a8b9161b9cc7f4da51f6bf7e8c9">gridfire::DynamicEngine</a>.</p>
@@ -1250,8 +1253,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A <code>std::expected</code> containing a map from <code>Species</code> to their characteristic timescales (s) on success, or a <code>StaleEngineError</code> on failure.</dd></dl>
<p>@purpose To get the characteristic timescale <code>Y / (dY/dt)</code> for each species.</p>
<p>@how It delegates the calculation to the base engine. For any species identified as algebraic (in QSE), it manually sets their timescale to 0.0 to signify that they equilibrate instantaneously on the timescale of the solver.</p>
<dl class="section user"><dt>Purpose</dt><dd>To get the characteristic timescale <code>Y / (dY/dt)</code> for each species.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It delegates the calculation to the base engine. For any species identified as algebraic (in QSE), it manually sets their timescale to 0.0 to signify that they equilibrate instantaneously on the timescale of the solver.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The engine must have a valid QSE cache entry for the given state. </dd></dl>
<dl class="exception"><dt>Exceptions</dt><dd>
<table class="exception">
@@ -1300,8 +1303,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>Stoichiometric coefficient for the species in the reaction.</dd></dl>
<p>@purpose To query the stoichiometric relationship between a species and a reaction.</p>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#a510b920dea726aef859ac1f6d051807e" title="Gets an entry from the stoichiometry matrix.">getStoichiometryMatrixEntry()</a></code>.</p>
<dl class="section user"><dt>Purpose</dt><dd>To query the stoichiometric relationship between a species and a reaction.</dd></dl>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#a510b920dea726aef859ac1f6d051807e" title="Gets an entry from the stoichiometry matrix.">getStoichiometryMatrixEntry()</a></code>.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd><code><a class="el" href="#abe76a46784b1ebc8ad67a9eec40d369a" title="Generates the stoichiometry matrix for the network.">generateStoichiometryMatrix()</a></code> must have been called. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#afa108dd5227dbb1045e90d7b3bd8b84f">gridfire::DynamicEngine</a>.</p>
@@ -1356,8 +1359,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>The index of the pool with the largest (slowest) mean destruction timescale.</dd></dl>
<p>@purpose To identify the core set of dynamic species that will not be part of any QSE group.</p>
<p>@how It calculates the geometric mean of the destruction timescales for all species in each pool and returns the index of the pool with the maximum mean timescale. </p>
<dl class="section user"><dt>Purpose</dt><dd>To identify the core set of dynamic species that will not be part of any QSE group.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It calculates the geometric mean of the destruction timescales for all species in each pool and returns the index of the pool with the maximum mean timescale. </dd></dl>
</div>
</div>
@@ -1392,8 +1395,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd><code>true</code> if the engine is stale, <code>false</code> otherwise.</dd></dl>
<p>@purpose To determine if <code><a class="el" href="#a6bee75b5a6e508e6eebf83f0d48c50b8" title="Updates the internal state of the engine, performing partitioning and QSE equilibration.">update()</a></code> needs to be called.</p>
<p>@how It creates a <code><a class="el" href="structgridfire_1_1_q_s_e_cache_key.html" title="Key struct for the QSE abundance cache.">QSECacheKey</a></code> from the <code>netIn</code> data and checks for its existence in the <code>m_qse_abundance_cache</code>. A cache miss indicates the engine is stale because it does not have a valid QSE partition for the current conditions. It also queries the base engine's <code><a class="el" href="#ae7847959fc5af2b83f5446dd73567b46" title="Checks if the engine&#39;s internal state is stale relative to the provided conditions.">isStale()</a></code> method. </p>
<dl class="section user"><dt>Purpose</dt><dd>To determine if <code><a class="el" href="#a6bee75b5a6e508e6eebf83f0d48c50b8" title="Updates the internal state of the engine, performing partitioning and QSE equilibration.">update()</a></code> needs to be called.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It creates a <code><a class="el" href="structgridfire_1_1_q_s_e_cache_key.html" title="Key struct for the QSE abundance cache.">QSECacheKey</a></code> from the <code>netIn</code> data and checks for its existence in the <code>m_qse_abundance_cache</code>. A cache miss indicates the engine is stale because it does not have a valid QSE partition for the current conditions. It also queries the base engine's <code><a class="el" href="#ae7847959fc5af2b83f5446dd73567b46" title="Checks if the engine&#39;s internal state is stale relative to the provided conditions.">isStale()</a></code> method. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#a942e65ced17ca602482cc42e469d6398">gridfire::DynamicEngine</a>.</p>
@@ -1430,7 +1433,7 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A vector of molar abundances corresponding to the species order in the base engine.</dd></dl>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#aada497e8df74a295fdf5df7d7cdf64e0" title="Maps a NetIn struct to a molar abundance vector for the full network.">mapNetInToMolarAbundanceVector()</a></code>. </p>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#aada497e8df74a295fdf5df7d7cdf64e0" title="Maps a NetIn struct to a molar abundance vector for the full network.">mapNetInToMolarAbundanceVector()</a></code>. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#a55f1b7e5ebe2840e1d7c54665ca5411a">gridfire::DynamicEngine</a>.</p>
@@ -1478,8 +1481,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A vector of vectors of species indices, where each inner vector represents a timescale pool.</dd></dl>
<p>@purpose To group species into "pools" based on their destruction timescales.</p>
<p>@how It retrieves all species destruction timescales from the base engine, sorts them, and then iterates through the sorted list, creating a new pool whenever it detects a gap between consecutive timescales that is larger than a predefined threshold (e.g., a factor of 100). </p>
<dl class="section user"><dt>Purpose</dt><dd>To group species into "pools" based on their destruction timescales.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It retrieves all species destruction timescales from the base engine, sorts them, and then iterates through the sorted list, creating a new pool whenever it detects a gap between consecutive timescales that is larger than a predefined threshold (e.g., a factor of 100). </dd></dl>
</div>
</div>
@@ -1505,8 +1508,8 @@ Private Attributes</h2></td></tr>
</table>
</dd>
</dl>
<p>@purpose A convenience overload for <code>partitionNetwork</code>.</p>
<p>@how It unpacks the <code>netIn</code> struct into <code>Y</code>, <code>T9</code>, and <code>rho</code> and then calls the primary <code>partitionNetwork</code> method. </p>
<dl class="section user"><dt>Purpose</dt><dd>A convenience overload for <code>partitionNetwork</code>.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It unpacks the <code>netIn</code> struct into <code>Y</code>, <code>T9</code>, and <code>rho</code> and then calls the primary <code>partitionNetwork</code> method. </dd></dl>
</div>
</div>
@@ -1543,7 +1546,7 @@ Private Attributes</h2></td></tr>
</table>
</dd>
</dl>
<p>@purpose To perform the core partitioning logic that identifies which species are "fast" (and can be treated algebraically) and which are "slow" (and must be integrated dynamically).</p>
<dl class="section user"><dt>Purpose</dt><dd>To perform the core partitioning logic that identifies which species are "fast" (and can be treated algebraically) and which are "slow" (and must be integrated dynamically).</dd></dl>
<p>@how</p><ol type="1">
<li><b><code>partitionByTimescale</code></b>: Gets species destruction timescales from the base engine, sorts them, and looks for large gaps to create timescale "pools".</li>
<li><b><code>identifyMeanSlowestPool</code></b>: The pool with the slowest average timescale is designated as the core set of dynamic species.</li>
@@ -1587,8 +1590,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A <code><a class="el" href="structgridfire_1_1_priming_report.html" title="Captures the result of a network priming operation.">PrimingReport</a></code> struct containing information about the priming process.</dd></dl>
<p>@purpose To prepare the network for ignition or specific pathway studies.</p>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#a05730ced13ac5331060ca011f0da6235" title="Primes the engine with a specific species.">primeEngine()</a></code>. The multiscale view does not currently interact with the priming process. </p>
<dl class="section user"><dt>Purpose</dt><dd>To prepare the network for ignition or specific pathway studies.</dd></dl>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#a05730ced13ac5331060ca011f0da6235" title="Primes the engine with a specific species.">primeEngine()</a></code>. The multiscale view does not currently interact with the priming process. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#a21c34f59c080a853fafa38a25175124e">gridfire::DynamicEngine</a>.</p>
@@ -1624,8 +1627,8 @@ Private Attributes</h2></td></tr>
</table>
</dd>
</dl>
<p>@purpose To modify the reaction network.</p>
<p>@how This operation is not supported by the <code><a class="el" href="classgridfire_1_1_multiscale_partitioning_engine_view.html" title="An engine view that partitions the reaction network into multiple groups based on timescales.">MultiscalePartitioningEngineView</a></code> as it would invalidate the partitioning logic. It logs a critical error and throws an exception. <a class="el" href="classgridfire_1_1_network.html">Network</a> modifications should be done on the base engine before it is wrapped by this view.</p>
<dl class="section user"><dt>Purpose</dt><dd>To modify the reaction network.</dd></dl>
<dl class="section user"><dt>How</dt><dd>This operation is not supported by the <code><a class="el" href="classgridfire_1_1_multiscale_partitioning_engine_view.html" title="An engine view that partitions the reaction network into multiple groups based on timescales.">MultiscalePartitioningEngineView</a></code> as it would invalidate the partitioning logic. It logs a critical error and throws an exception. <a class="el" href="classgridfire_1_1_network.html">Network</a> modifications should be done on the base engine before it is wrapped by this view.</dd></dl>
<dl class="exception"><dt>Exceptions</dt><dd>
<table class="exception">
<tr><td class="paramname"><a class="el" href="classgridfire_1_1exceptions_1_1_unable_to_set_network_reactions_error.html">exceptions::UnableToSetNetworkReactionsError</a></td><td>Always. </td></tr>
@@ -1667,7 +1670,7 @@ Private Attributes</h2></td></tr>
</table>
</dd>
</dl>
<p>@how This method delegates directly to the base engine's <code><a class="el" href="#a1a0c0a0ade632eb10f0eecab828a059f" title="Sets the electron screening model.">setScreeningModel()</a></code>. </p>
<dl class="section user"><dt>How</dt><dd>This method delegates directly to the base engine's <code><a class="el" href="#a1a0c0a0ade632eb10f0eecab828a059f" title="Sets the electron screening model.">setScreeningModel()</a></code>. </dd></dl>
<p>Implements <a class="el" href="classgridfire_1_1_dynamic_engine.html#a3fb44b6f55563a2f590f31916528f2bd">gridfire::DynamicEngine</a>.</p>
@@ -1715,8 +1718,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A vector of molar abundances for the algebraic species.</dd></dl>
<p>@purpose To find the equilibrium abundances of the algebraic species that satisfy the QSE conditions.</p>
<p>@how It uses the Levenberg-Marquardt algorithm via Eigen's <code>LevenbergMarquardt</code> class. The problem is defined by the <code><a class="el" href="structgridfire_1_1_multiscale_partitioning_engine_view_1_1_eigen_functor.html" title="Functor for solving QSE abundances using Eigen&#39;s nonlinear optimization.">EigenFunctor</a></code> which computes the residuals and Jacobian for the QSE equations.</p>
<dl class="section user"><dt>Purpose</dt><dd>To find the equilibrium abundances of the algebraic species that satisfy the QSE conditions.</dd></dl>
<dl class="section user"><dt>How</dt><dd>It uses the Levenberg-Marquardt algorithm via Eigen's <code>LevenbergMarquardt</code> class. The problem is defined by the <code><a class="el" href="structgridfire_1_1_multiscale_partitioning_engine_view_1_1_eigen_functor.html" title="Functor for solving QSE abundances using Eigen&#39;s nonlinear optimization.">EigenFunctor</a></code> which computes the residuals and Jacobian for the QSE equations.</dd></dl>
<dl class="section pre"><dt>Precondition</dt><dd>The input state (Y_full, T9, rho) must be a valid physical state. </dd></dl>
<dl class="section post"><dt>Postcondition</dt><dd>The algebraic species in the QSE cache are updated with the new equilibrium abundances. </dd></dl>
@@ -1753,7 +1756,7 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>The new composition after QSE species have been brought to equilibrium.</dd></dl>
<p>@purpose This is the main entry point for preparing the multiscale engine for use. It triggers the network partitioning and solves for the initial QSE abundances, caching the result.</p>
<dl class="section user"><dt>Purpose</dt><dd>This is the main entry point for preparing the multiscale engine for use. It triggers the network partitioning and solves for the initial QSE abundances, caching the result.</dd></dl>
<p>@how</p><ol type="1">
<li>It first checks the QSE cache. If a valid entry already exists for the input state, it returns the input composition, as no work is needed.</li>
<li>If the cache misses, it calls <code><a class="el" href="#a4bc879246c6fbd8633b05052858df51d" title="Equilibrates the network by partitioning and solving for QSE abundances.">equilibrateNetwork()</a></code>.</li>
@@ -1817,8 +1820,8 @@ Private Attributes</h2></td></tr>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A vector of validated QSE groups that meet the flux criteria.</dd></dl>
<p>@purpose To ensure that a candidate QSE group is truly in equilibrium by checking that the reaction fluxes <em>within</em> the group are much larger than the fluxes <em>leaving</em> the group.</p>
<p>@how For each candidate group, it calculates the sum of all internal reaction fluxes and the sum of all external (bridge) reaction fluxes. If the ratio of internal to external flux exceeds a configurable threshold, the group is considered valid and is added to the returned vector. </p>
<dl class="section user"><dt>Purpose</dt><dd>To ensure that a candidate QSE group is truly in equilibrium by checking that the reaction fluxes <em>within</em> the group are much larger than the fluxes <em>leaving</em> the group.</dd></dl>
<dl class="section user"><dt>How</dt><dd>For each candidate group, it calculates the sum of all internal reaction fluxes and the sum of all external (bridge) reaction fluxes. If the ratio of internal to external flux exceeds a configurable threshold, the group is considered valid and is added to the returned vector. </dd></dl>
</div>
</div>
@@ -2060,7 +2063,7 @@ Private Attributes</h2></td></tr>
</div><div class="memdoc">
<p>Cache for QSE abundances based on T9, rho, and Y. </p>
<p>@purpose This is the core of the caching mechanism. It stores the results of QSE solves to avoid re-computation. The key is a <code><a class="el" href="structgridfire_1_1_q_s_e_cache_key.html" title="Key struct for the QSE abundance cache.">QSECacheKey</a></code> which hashes the thermodynamic state, and the value is the vector of solved molar abundances for the algebraic species. </p>
<dl class="section user"><dt>Purpose</dt><dd>This is the core of the caching mechanism. It stores the results of QSE solves to avoid re-computation. The key is a <code><a class="el" href="structgridfire_1_1_q_s_e_cache_key.html" title="Key struct for the QSE abundance cache.">QSECacheKey</a></code> which hashes the thermodynamic state, and the value is the vector of solved molar abundances for the algebraic species. </dd></dl>
</div>
</div>