1629 Commits
Author SHA1 Message Date
Ray Speth 359d93ebeb [Python] Simplify some pyx->py conversion loose ends 2026-07-10 15:08:48 -04:00
Tim E. Dawson ddb114abdb [SolutionArray] Add unit test for state update bug. 2026-07-08 16:43:46 -04:00
Ingmar Schoegl 42321b6eed [thermo] Make MixtureFugacityTP::cubicSolver more robust 2026-07-08 13:44:32 -04:00
Gaetanosaure b4aeae5325 [thermo] Correct the instrinsic heating expression in PlasmaPhase: the energy deposited by the plasma corresponds to Joules heating, elastic power losses are a fraction of it and were thus counted twice in the previous expression 2026-07-07 15:08:08 -04:00
Gaetanosaure 04d9800b8d [thermo] Add EEDF energy-grid specification options
Add linear, quadratic, and geometric energy-grid options for the Boltzmann
two-term EEDF solver, selectable from the phase YAML `electron-energy-distribution`
node, in addition to the already-present custom grid.

The `Boltzmann-two-term` distribution type now honors a user-supplied
`energy-levels` grid via setCustomGrid instead of silently falling back to the
hard-coded default grid.

Relax test_eedf_solver to verify that the custom grid is honored and that the
resulting EEDF is a finite, positive, monotonically decreasing, normalized
distribution.
2026-07-07 15:08:08 -04:00
Ray Speth f90cd54e2d [Kinetics] Fix derivative calculations with non-unity multipliers
Kinetics derivatives computed using internal finite differencing
(for example, ddM for third-body reactions and pressure derivatives for
P-log and Chebyshev reactions) used an inconsistent multiplier state. This
fixes these calculations to use compute the difference based on the
unperturbed forward rate constants.
2026-07-03 09:54:37 -05:00
Ray Speth e004167a54 [Test] Use pruning to speed up BurnerFlame tests 2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 f3b6b75e1a [1D] Exclude IonFlow from analytic Jacobian; keep regrid tests deterministic
IonFlow overrides the species residual and diffusive-flux physics (ion drift,
electric-field coupling) without supplying matching analytic Jacobian
derivatives, so the inherited Flow1D analytic columns describe a different
residual than IonFlow solves. With the analytic Jacobian now the default, this
broke the stage-two ion-flame solve. Add an analyticJacobianSupported() hook
(false for IonFlow) so "auto" silently uses finite differences and explicit
"analytic" raises for ion flames.

Also pin finite differences in the high-pressure regrid test helper, whose
exact step-count assertions depend on the Jacobian method.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 0616fe8cbd [1D] Raise when explicit analytic Jacobian cannot be used
In explicit jacobian_mode = "analytic", OneDim::evalJacobian now validates each
domain before the finite-difference column loop and raises if the kinetics lacks
composition derivatives or multicomponent transport is active. Internal/transient
conditions (adjoint force-full-update, fewer than 3 points) still fall back
silently.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 e005211701 [1D] Test that 'auto' Jacobian mode falls back without warning
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 a22f1d6118 [1D] Add 'auto' Jacobian mode and make it the default
Introduces a three-valued jacobian_mode. 'auto' (the new default) uses the
analytic Jacobian where supported and silently falls back to finite
differences otherwise; the capability probe no longer warns on fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 68a68089c3 [1D] Detect missing sparse-Jacobian slots in debug builds
accumulateStoichProduct now scans for product entries that the
supplied pattern cannot store and throws instead of silently
dropping them (and leaking into the next column). Compiled out
under NDEBUG.

Aso, merge the three analytic-vs-FD comparison classes into one
TestAnalyticVsFD with compare_modes as a member; solve the comparison
configs with auto=False to avoid masking unexpected failures; fold the
deprecated-alias check into test_solver_stats; and replace GRI 3.0 with
h2o2 (loose refinement) in test_full_solve_matches_fd.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Sonnet 4.6 1ed2aca7d4 [1D] Address code review comments on analytic Jacobian PR
Key changes:
- Extend analytic Jacobian to cover grid points 1 and N-2 (previously 2..N-3);
  boundary residuals have no dependence on neighboring species so those rows are
  safely skipped. Minimum grid size drops from 6 to 3.
- Refactor fluxJacobian to template<bool AtQ> computing only the needed endpoint
  derivative, eliminating the scratch buffer and halving the inner-loop work.
- Remove unused x parameter from computeWdotDerivatives.
- Rename fuseStoichProduct → accumulateStoichProduct; explain template necessity
  (StoichManagerN::derivatives returns Eigen::Map, not SparseMatrix).
- Move factorizeJacobian() body to SteadyStateSystem.cpp, localizing <chrono>.
- Inline the single-use accumulateGridTime lambda in SteadyStateSystem::solve.
- Reorganize Flow1D::hasAnalyticJacobian/evalJacobianAnalytic into the main
  public section rather than a mid-class public: block.
- Fix math-mode formula in radiationPolyFactor docstring.
- Fix Doxygen group comment in SteadyStateSystem.h staging accumulators.
- Remove unused Cython pxd getters (gridSizeStats etc.); add pyi stubs for
  new API (jacobian_mode, global_component_index, eval_jacobian, solver_stats).
- Add analytic-jacobian.md derivation page to Sphinx docs.
- Update release note with mechanism-size scaling explanation.
- Speed up test_radiation by using h2o2.yaml instead of GRI 3.0.
- Update TestAnalyticVsFD claimed-column range to match new j >= 1 condition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 cef9a5b694 [1D] Add Sim1D.solver_stats; deprecate per-metric stat properties
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 7209954ba0 [1D] Address code review: prune dead include, doc notes, strengthen stats test
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 bfcd6277d7 [1D] Add C++ test for OneDim solverStats structure
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 c1c82c8ee4 [1D] Verify end-to-end flame solution with analytic Jacobian
Add TestAnalyticSolve.test_full_solve_matches_fd which solves a GRI-3.0
stoichiometric CH4/air free flame twice — once with the default
finite-difference Jacobian and once with analytic mode — exercising
regridding, time stepping, and workspace reallocation. Asserts flame
speeds agree to within 1e-4 relative tolerance (actual: ~7.6e-7).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 1414adf6e7 [1D] Test analytic Jacobian across flame configurations
Add TestAnalyticConfigMatrix with four tests covering: axisymmetric
counterflow diffusion flame, unstrained burner flame, Soret diffusion
enabled, and two-point control. All pass without new C++ changes,
confirming Tasks 1-7 cover these row/column variants correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 7fa9ad3ec8 [1D] Analytic Jacobian support for radiation and mass-basis fluxes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 c216540ecd [1D] Enable analytic species Jacobian columns in Flow1D (opt-in)
Adds the compare_modes harness and TestAnalyticVsFD, and fixes two bugs
found by the FD oracle:
- The capability probe ran inside evalJacobianAnalytic (after the FD
  column-skip loop), so claimed columns were never skipped and the
  analytic post-pass double-counted them. The probe now runs lazily from
  the const hasAnalyticJacobian()/usingAnalyticJacobian() queries.
- The 1/(rho cp) chain term in the energy row had the wrong sign
  (FD-verified: d(1/(rho cp))/dY_m = (1/(rho cp))(wbar/W_m - cpm/cp),
  giving -B*rcp*(...) for the residual rsd = -u dTdz - B/(rho cp)).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 912389a61e [Kinetics] Add pattern-reusing net production rate derivative fill
Add an overload netProductionRates_ddCi(SparseMatrix&) that fills a
caller-owned sparse matrix and reuses its nonzero pattern across calls.
The pattern of d(wdot_k)/d(c_m) is fixed for a given mechanism and
derivative settings, so it is built once (delegating to the allocating
path) and subsequent calls overwrite the value array in place with no
allocation or symbolic SpGEMM.

The BulkKinetics override fuses the stoichiometry-matrix product directly
into the compressed column storage using an O(K) dense scatter column
(m_rbuf3) rather than a K x K dense buffer, mirroring
calculateCompositionDerivatives() with ddX=false. Result is numerically
identical to the allocating netProductionRates_ddCi() (verified to <1e-12
relative). No new Python API.

Benchmark (gri30, optimize=n library): ~1447 us/call allocating vs
~883 us/call reused = 1.64x on the primitive.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 431d7eaf08 [1D] Add infrastructure for analytic Jacobian columns
Adds a per-domain `jacobian_mode` flag ("finite-difference" or
"analytic"), two virtual hooks (`hasAnalyticJacobian(j,n)` and
`evalJacobianAnalytic(x, jac)`), and the column-skipping logic in
`OneDim::evalJacobian` that calls `evalJacobianAnalytic` after the FD
loop. No domain claims any columns yet, so this is a behavioral no-op.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 5b503cd7eb [1D] Expose steady-state Jacobian evaluation and component indexing to Python
Add `Sim1D.eval_jacobian()` to trigger `evalSSJacobian()` from Python, and
`Domain1D.global_component_index(name, j)` to map a component/point pair to
its index in the global solution vector. Both are needed by the upcoming
analytic Jacobian comparison harness. Includes a test that verifies the
assembled Jacobian matches a manual finite-difference residual perturbation
to within 2% (the tolerance accounts for frozen transport properties in the
solver FD vs full recomputation in sim.eval()).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:54:37 -05:00
Ray SpethandClaude Opus 4.8 4ac73142de [Thermo] Document consistency limitations of PlasmaPhase
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 19:16:45 -04:00
pag1pag 9d0396dc0b [Plasma] Define activity/standard concentration
Define `getActivities` and `getActivityCoefficients`
Redefine `standardConcentration`
2026-07-01 19:16:45 -04:00
pag1pag 4c12188c31 [Plasma] Skip two thermodynamic consistency tests.
#2134 introduced new thermodynamic consistency tests.
Skip them are there are not defined for two-temperature systems, or because the relative error is a bit too big for the acceptable error.
2026-07-01 19:16:45 -04:00
pag1pag 896f01999a [Plasma] Remove setState_* and update tests accordingly 2026-07-01 19:16:45 -04:00
pag1pag d723a27a37 [Plasma] Update tests 2026-07-01 19:16:45 -04:00
Ingmar Schoegl 13a3c79f27 [tpx] Address convergence issue 2026-06-20 20:15:40 -04:00
Ingmar Schoegl c82036c495 [unittest] Test environment variable 2026-06-14 16:34:12 -04:00
Ray SpethandClaude Opus 4.8 7503c44f85 [Test] Add new thermo consistency tests
Add tests checking for consistency with the following identities:

- dG composition <-> T Maxwell relation: s_k = - d(mu_k)/dT at constant P and X
- dG composition <=> P Maxwell relation: v_k = d(mu_k)/dP at constant T and X
- dG pressure coefficiient: V = dG/dP at constant T
- dH pressure coefficient: dH/dP at constant T = V - T*dV/dT at constant P
- composition Hessian symmetry: d(mu_k)/dN_j = d(mu_j)/dN_k

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:34:02 -05:00
Ray SpethandClaude Opus 4.8 154295392b [Thermo] Add Gibbs-Duhem consistency test to thermo_consistency suite
Add a `gibbs_duhem_const_T_P` test to the parametrized ThermoPhase consistency
suite. It perturbs composition at constant T and P and checks the differential
identity sum_k X_k * dmu_k = 0, the complement to the Euler relation
g = sum_k X_k * mu_k that the suite already checked. This is the identity that
was missing: all existing tests held composition fixed and only perturbed T and
P, so a model whose chemical potentials are not consistent partial molar Gibbs
energies of a single G(T, P, N) could pass every check.

The finite-difference step is scaled to the smaller of the two perturbed mole
fractions so that the truncation error is independent of how dilute the species
are; a fixed absolute step gives false positives on dilute aqueous solutes.

Mark the Debye-Huckel B-dot model with per-ion size parameters and the
coverage-dependent surface model as known failures, since both report chemical
potentials that violate Gibbs-Duhem.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:34:02 -05:00
Christopher Neal 9200ac28f0 updates to tests for timestep regridding. 2026-06-10 10:48:55 -04:00
Christopher Neal 8b48ac7312 updates to improve documentation and test coverage 2026-06-10 10:48:55 -04:00
Christopher Neal 937ae06ee1 address broken steady state tests, add options for time step regridding controls, add tests for new options 2026-06-10 10:48:55 -04:00
Ray SpethandGitHub Copilot c9c320a084 [SCons] Prevent duplicated RPATH entries
Co-authored-by: GitHub Copilot (GPT-5.4) <copilot@github.com>
2026-06-10 10:31:50 -04:00
Ray Speth e8836bc477 [SCons] Suppress spurious GTest warnings
Apple Clang (clang-2100.0.123.102) was issuing warnings about
"implicit conversion from 'char8_t' to 'char32_t'".
2026-06-10 10:31:50 -04:00
Ingmar Schoegl d0e97e563a [SolutionArray] Fix slicing issues
Fix bug where m_dataSize was set incorrectly
2026-06-09 07:10:46 -05:00
Ingmar Schoegl f404dd20f6 [SolutionArray] Improve OOB checks for setState
Reorder checks and disallow negative indices (left over after
changing the API from the original size_t to int).
2026-06-09 07:10:46 -05:00
Ingmar Schoegl 80227a9e65 [SolutionArray] Make getState reliable/read-only
Fixes issue #2067 while also making the method const. After this
update, the state of the associated Solution is no longer updated,
which is a clear separation from the alternative setState method.
2026-06-09 07:10:46 -05:00
Ray SpethandClaude Opus 4.8 c6412cb239 [Equil] Fix redistribution of element moles from excluded species
The previous handling of this redistribution (introduced in #2116 / 2219f65)
did not correctly handle polyatomic species.

Partially addresses #268

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 23:41:19 -04:00
Ray SpethandClaude Opus 4.8 f977be8c65 [Equil] Prevent component-basis oscillation in VCS solver
The optimum-basis check at the end of each VCS iteration can disagree with
the basis that vcs_basopt actually selects: the check ranks a noncomponent
against a component by mole number alone, while vcs_basopt additionally
enforces linear independence and uses slightly different size weighting.
When they disagree, the check forces a component recalculation that re-selects
the same basis, which immediately trips the check again. The solver cycles
through its main loop forcing a new basis every iteration and never reaches
the equilibrium check, so it cannot converge.

Fixed by counting consecutive recalculations forced by this check and stopping
forcing once they clearly exceed what a real basis improvement requires. The
convergence criterion is the same for any equivalent basis, so suppressing
an oscillating swap is safe: it affects only conditioning, not the result.

Add a regression test covering a representative spread of the affected
compositions.

Fixes #266.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:23:23 -05:00
Ray SpethandClaude Opus 4.7 9f82790f3e [Equil] Fix component basis reselection in MultiPhaseEquil::computeN
Previously, computeN only reselected the basis when the most-abundant species
per element wasn't a component. It never noticed when a component itself became
depleted. So a radical sitting in the basis at ~8e-10 mol could stay in the basis
and throttle every reaction that must consume it, since the step is bounded by
moles/|Δmoles|. The solver then settles into a limit cycle and never converges,

This is fixed by forcing component reselection when any component drops below a
threshold of 1e-3 * total_moles. This is safe because getComponents is idempotent-optimal;
it re-selects the same species if it's genuinely the best linearly-independent choice.
Otherwise, it swaps in a more abundant species.

Fixes #265

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 10:43:32 -05:00
Ray SpethandClaude Sonnet 4.6 27376a428f [Reactor/Test] Improve coverage for cross-reactor Jacobian calculations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 08:01:16 -05:00
665302b6cb [Reactor] Add accessors for full-network Jacobians
Co-authored-by: Anthony Walker <walkanth@oregonstate.edu>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 08:01:16 -05:00
Ray Speth 7899624b7f [Reactor] Add ExtensibleReactor interface for setting Jacobian elements 2026-05-29 08:01:16 -05:00
Ray SpethandOpenAI Codex 6cd6723b26 [Reactor] Implement cross-reactor Jacobian terms for preconditioners
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-05-29 08:01:16 -05:00
Ray SpethandOpenAI Codex 0131bb3dc7 [Test] Cover corner cases in ThermoPhase HP/UV/SP/SV setters
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-05-18 22:37:29 -04:00
Ray SpethandOpenAI Codex 7ee157920e [Test] Cover corner cases in ChemEquil
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-05-18 22:37:29 -04:00
Ray Speth e1c625e0a3 [Equil] Improve error message when reaching temperature bound 2026-05-18 22:37:29 -04:00