Regression & ThermoML¶
Differentiable parameter estimation (Levenberg-Marquardt and gradient descent), UNIFAC-to-binary prediction, the bundled ThermoML parameter bank, and the NIST ThermoML archive reader.
Regression¶
regression
¶
Differentiable parameter estimation for activity-coefficient models.
Because every equilibrium output is differentiable with respect to the
activity-model parameters (see fugacio.thermo.gammaphi,
fugacio.thermo.lle), fitting a model to data is plain gradient-based
optimisation: no finite-difference parameter sweeps, no black-box derivatives.
This module supplies:
- two self-contained optimisers,
levenberg_marquardtfor nonlinear least squares (exact Gauss-Newton Hessian, adaptive damping) and a simplegradient_descent, that operate on an arbitrary parameter pytree; - residual builders that turn experimental data into a residual vector:
bubble_pressure_residuals(isothermal/isobaric P-x-y VLE),activity_residuals(measuredln gamma), andlle_residuals(mutual-solubility / tie-line data); and - convenience fitters (
fit_nrtl_binary,fit_uniquac_binary) that wire a model factory to the optimiser and return a ready model object.
A "model factory" is any theta -> ActivityModel mapping; the optimiser fits
theta (the differentiable leaves you choose to expose), so you control which
parameters are free and which are fixed.
Functions:
| Name | Description |
|---|---|
levenberg_marquardt |
Minimise |
gradient_descent |
Minimise a scalar |
bubble_pressure_residuals |
Residuals of predicted vs. measured bubble pressure (and optionally vapour). |
activity_residuals |
Residuals of predicted vs. measured log activity coefficients. |
lle_residuals |
Isoactivity residuals at measured liquid-liquid tie-line ends. |
fit_nrtl_binary |
Fit binary NRTL |
unifac_ln_gamma_grid |
Sample (modified) UNIFAC |
predict_nrtl_from_unifac |
Predict binary NRTL |
predict_uniquac_from_unifac |
Predict binary UNIQUAC |
fit_uniquac_binary |
Fit binary UNIQUAC |
levenberg_marquardt
¶
levenberg_marquardt(
residual: ResidualFn,
theta0: Any,
*,
max_iter: int = 100,
lambda0: float = 0.01,
factor: float = 5.0,
tol: float = 1e-12,
) -> tuple[Any, Array]
Minimise 0.5 * sum(residual(theta)**2) by Levenberg-Marquardt.
A trust-region blend of Gauss-Newton and gradient descent: each step solves
(J^T J + lambda diag(J^T J)) delta = -J^T r with the exact Jacobian J
(via jax.jacobian), shrinking lambda after an accepted step and
growing it after a rejected one. Operates on any parameter pytree theta0.
Returns:
| Type | Description |
|---|---|
Any
|
|
Array
|
half-sum-of-squares cost. |
gradient_descent
¶
gradient_descent(
objective: Callable[[Any], Array],
theta0: Any,
*,
learning_rate: float = 0.01,
max_iter: int = 500,
) -> tuple[Any, Array]
Minimise a scalar objective(theta) by fixed-step gradient descent.
A dependency-free fallback for objectives that are not least-squares; returns
(theta, objective(theta)).
bubble_pressure_residuals
¶
bubble_pressure_residuals(
make_model: ModelFactory,
t: Array,
x: Array,
p_exp: Array,
tc: Array,
pc: Array,
omega: Array,
*,
y_exp: Array | None = None,
p_scale: ArrayLike | None = None,
y_weight: float = 1.0,
**opts: Any,
) -> ResidualFn
Residuals of predicted vs. measured bubble pressure (and optionally vapour).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
make_model
|
ModelFactory
|
|
required |
t
|
Array
|
Temperatures (K), shape |
required |
x
|
Array
|
Liquid compositions, shape |
required |
p_exp
|
Array
|
Measured bubble pressures (Pa), shape |
required |
tc
|
Array
|
Component critical temperatures (K). |
required |
pc
|
Array
|
Component critical pressures (Pa). |
required |
omega
|
Array
|
Component acentric factors. |
required |
y_exp
|
Array | None
|
Optional measured vapour compositions, shape |
None
|
p_scale
|
ArrayLike | None
|
Pressure normaliser (defaults to |
None
|
y_weight
|
float
|
Relative weight on the vapour-composition residuals. |
1.0
|
**opts
|
Any
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
ResidualFn
|
|
activity_residuals
¶
activity_residuals(
make_model: ModelFactory,
t: Array,
x: Array,
ln_gamma_exp: Array,
) -> ResidualFn
Residuals of predicted vs. measured log activity coefficients.
t is shape (m,), x and ln_gamma_exp are shape (m, n).
lle_residuals
¶
Isoactivity residuals at measured liquid-liquid tie-line ends.
A consistent model makes each experimental conjugate pair iso-active:
x_i^I gamma_i^I = x_i^II gamma_i^II. t is (m,); the compositions
are (m, n).
fit_nrtl_binary
¶
fit_nrtl_binary(
t: Array,
x: Array,
p_exp: Array,
tc: Array,
pc: Array,
omega: Array,
*,
alpha: float = 0.3,
y_exp: Array | None = None,
b0: tuple[float, float] = (0.0, 0.0),
max_iter: int = 80,
**opts: Any,
) -> tuple[NRTL, Array]
Fit binary NRTL b parameters (fixed alpha) to bubble-point data.
The free parameters are the two 1/T interaction coefficients
b12, b21 (Kelvin); a = 0 and the non-randomness alpha are held
fixed. Returns (fitted NRTL, final cost).
unifac_ln_gamma_grid
¶
unifac_ln_gamma_grid(
components: list[str],
t: ArrayLike,
*,
points: int = 11,
dortmund: bool = False,
x_min: float = 0.02,
) -> tuple[Array, Array, Array]
Sample (modified) UNIFAC ln gamma on a binary composition/temperature grid.
This turns a predictive group-contribution model into pseudo-data for fitting a correlative NRTL/UNIQUAC model, the standard way to obtain binary interaction parameters for a pair that has no measured VLE.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
components
|
list[str]
|
Exactly two component names with UNIFAC group assignments. |
required |
t
|
ArrayLike
|
Temperature(s) (K); a scalar or 1-D array. The grid is the outer product of the temperatures with the composition samples. |
required |
points
|
int
|
Number of liquid compositions sampled in |
11
|
dortmund
|
bool
|
Use modified UNIFAC (Dortmund) instead of classic UNIFAC. |
False
|
x_min
|
float
|
Smallest mole fraction sampled (kept away from the pure limits). |
0.02
|
Returns:
| Type | Description |
|---|---|
Array
|
|
Array
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
if |
predict_nrtl_from_unifac
¶
predict_nrtl_from_unifac(
components: list[str],
t: ArrayLike,
*,
alpha: float = 0.3,
dortmund: bool = False,
points: int = 11,
x_min: float = 0.02,
b0: tuple[float, float] = (0.0, 0.0),
max_iter: int = 120,
) -> tuple[NRTL, Array]
Predict binary NRTL b parameters by fitting to UNIFAC activity coefficients.
UNIFAC supplies ln gamma over a composition (and temperature) grid; the two
NRTL 1/T coefficients b12, b21 (with a = 0 and fixed alpha)
are fitted to it by levenberg_marquardt. Use it to bootstrap a
correlative model for a pair without measured data.
Returns:
| Type | Description |
|---|---|
tuple[NRTL, Array]
|
|
predict_uniquac_from_unifac
¶
predict_uniquac_from_unifac(
components: list[str],
t: ArrayLike,
*,
r: Array | None = None,
q: Array | None = None,
dortmund: bool = False,
points: int = 11,
x_min: float = 0.02,
b0: tuple[float, float] = (0.0, 0.0),
max_iter: int = 120,
) -> tuple[UNIQUAC, Array]
Predict binary UNIQUAC b parameters by fitting to UNIFAC activity coefficients.
Like predict_nrtl_from_unifac, but for UNIQUAC. The surface/volume
parameters r, q default to the curated values
(fugacio.thermo.data.uniquac_rq); the free parameters are the 1/T
coefficients of tau = exp(b/T).
Returns:
| Type | Description |
|---|---|
tuple[UNIQUAC, Array]
|
|
fit_uniquac_binary
¶
fit_uniquac_binary(
t: Array,
x: Array,
p_exp: Array,
tc: Array,
pc: Array,
omega: Array,
r: Array,
q: Array,
*,
y_exp: Array | None = None,
b0: tuple[float, float] = (0.0, 0.0),
max_iter: int = 80,
**opts: Any,
) -> tuple[UNIQUAC, Array]
Fit binary UNIQUAC b parameters (with given r, q) to bubble-point data.
Free parameters are the 1/T coefficients of ln tau = a + b/T with
a = 0. Returns (fitted UNIQUAC, final cost).
Parameter bank¶
parameter_bank
¶
Batch regression of ThermoML datasets into a reusable binary-parameter bank.
This is the bridge between the ThermoML reader (fugacio.thermo.thermoml)
and the differentiable fitters (fugacio.thermo.regression): point it at
parsed documents (or the bundled samples) and it fits a binary activity model to
every isothermal P-x VLE table it can understand, recording the fitted
parameters together with their provenance: source dataset, temperature range,
point count, and the scaled root-mean-square pressure residual. The collected
FittedBinary records form a ParameterBank that hands back
ready-to-use NRTL models with the
component ordering you ask for.
A bank fitted to the bundled samples ships with the package
(parameter_bank.json, regenerated by scripts/gen_parameter_bank.py); load
it with ParameterBank.load_bundled. Components are matched to the
Fugacio database by CAS number, never by name, so document-local naming
quirks ("water (H2O)") cannot mis-assign a dataset.
Classes:
| Name | Description |
|---|---|
FittedBinary |
A fitted binary interaction record with its provenance. |
ParameterBank |
A lookup table of fitted binary parameters, keyed by component pair. |
Functions:
| Name | Description |
|---|---|
fit_vle_dataset |
Fit binary NRTL |
fit_bundled_samples |
Fit every binary P-x VLE dataset among the bundled ThermoML samples. |
FittedBinary
dataclass
¶
FittedBinary(
components: tuple[str, str],
model: str,
alpha: float,
b12: float,
b21: float,
t_min: float,
t_max: float,
n_points: int,
rmse: float,
source: str,
evidence: str = "unspecified",
)
A fitted binary interaction record with its provenance.
Attributes:
| Name | Type | Description |
|---|---|---|
components |
tuple[str, str]
|
Database names |
model |
str
|
Activity-model family (currently always |
alpha |
float
|
The fixed NRTL non-randomness parameter used in the fit. |
b12, |
b21
|
Fitted |
t_min, |
t_max
|
Temperature range of the underlying data (K). |
n_points |
int
|
Number of data rows fitted. |
rmse |
float
|
Root-mean-square residual of |
source |
str
|
Provenance string (sample name or document citation). |
Methods:
| Name | Description |
|---|---|
nrtl |
The fitted model as a ready-to-evaluate two-component NRTL. |
ParameterBank
¶
ParameterBank(entries: list[FittedBinary])
A lookup table of fitted binary parameters, keyed by component pair.
Pairs are stored orientation-free: get and nrtl accept the
components in either order and return parameters oriented as requested
(swapping b12/b21 when needed).
Methods:
| Name | Description |
|---|---|
get |
The record for a pair, reoriented so |
nrtl |
A ready NRTL model for the pair, in the requested component order. |
to_json |
Serialize the bank (sorted, human-diffable). |
from_json |
Inverse of |
load_bundled |
The bank fitted to the bundled ThermoML samples (ships with the package). |
Attributes:
| Name | Type | Description |
|---|---|---|
entries |
list[FittedBinary]
|
All records, sorted by component pair for stable iteration. |
entries
property
¶
entries: list[FittedBinary]
All records, sorted by component pair for stable iteration.
get
¶
get(
component_1: str, component_2: str
) -> FittedBinary | None
The record for a pair, reoriented so component_1 is component 1.
nrtl
¶
A ready NRTL model for the pair, in the requested component order.
Raises:
| Type | Description |
|---|---|
KeyError
|
if the bank has no record for the pair. |
load_bundled
classmethod
¶
load_bundled() -> ParameterBank
The bank fitted to the bundled ThermoML samples (ships with the package).
fit_vle_dataset
¶
fit_vle_dataset(
data: ThermoMLData,
dataset: Dataset,
*,
alpha: float = 0.3,
source: str = "",
max_iter: int = 80,
) -> FittedBinary
Fit binary NRTL b parameters to one parsed P-x VLE dataset.
The dataset must be binary with a temperature column, a composition column for its first component, and a pressure column (the layout of every bundled VLE sample and of archive isothermal P-x tables).
Returns:
| Type | Description |
|---|---|
FittedBinary
|
The |
FittedBinary
|
dataset's first component. |
Raises:
| Type | Description |
|---|---|
ValueError
|
if the dataset is not a binary P-x table. |
KeyError
|
if a compound cannot be matched to the component database. |
fit_bundled_samples
¶
fit_bundled_samples(
names: list[str] | None = None, *, alpha: float = 0.3
) -> list[FittedBinary]
Fit every binary P-x VLE dataset among the bundled ThermoML samples.
Non-VLE samples (pure-component tables, missing columns) are skipped, so the driver can be pointed at the whole sample directory. This is the batch regression behind the bundled parameter bank.
ThermoML reader¶
thermoml
¶
Reader for the NIST ThermoML archive XML format.
ThermoML <https://www.nist.gov/mml/acmd/trc/thermoml>_ is the IUPAC/NIST XML
standard for thermophysical and thermochemical property data; the public
ThermoML Archive
<https://www.nist.gov/mml/acmd/trc/thermoml/thermoml-archive>_ holds tens of
thousands of experimental datasets. This module turns those files into tidy,
typed tables you can feed straight into fugacio.thermo.regression, so a
model can be fitted to real measurements, and predictions graded against them.
The parser is dependency-free (standard-library
xml.etree.ElementTree only):
- XML namespaces are stripped, so files declaring the ThermoML namespace (or none) parse identically;
- compounds, mixtures, variables, properties, and the numeric value rows are read by their local element names, matching the published schema without binding to a specific version;
- each
Datasetexposes its columns as aligned numeric rows plus convenience accessors (Dataset.temperature,Dataset.pressure,Dataset.mole_fraction) with pressure unit conversion to pascal.
Synthetic schema-faithful datasets ship for tests and examples; see
list_samples / load_sample. The separate measured corpus and strict
normalization workflow live in fugacio.thermo.experimental.
Classes:
| Name | Description |
|---|---|
Compound |
A chemical compound declared in a ThermoML document. |
Uncertainty |
A reported uncertainty, in the associated column's original units. |
Column |
One variable or property column of a |
Dataset |
A |
ThermoMLData |
A parsed ThermoML document: its compounds, datasets, and citation. |
Functions:
| Name | Description |
|---|---|
convert_values |
Convert supported measurement units, rejecting unknown or incompatible units. |
loads |
Parse a ThermoML document from an in-memory string or bytes. |
read_thermoml |
Parse a ThermoML document from a path or open file object. |
list_samples |
Names (without extension) of the bundled ThermoML sample datasets. |
sample_path |
Filesystem path of a bundled sample (with or without the |
load_sample |
Parse a bundled ThermoML sample by name (see |
Compound
dataclass
¶
Compound(
org_num: int,
name: str | None = None,
formula: str | None = None,
cas: str | None = None,
inchikey: str | None = None,
inchi: str | None = None,
)
A chemical compound declared in a ThermoML document.
Attributes:
| Name | Type | Description |
|---|---|---|
org_num |
int
|
The document-local organization number used to reference this compound from mixtures and composition variables. |
name |
str | None
|
Common name, if given. |
formula |
str | None
|
Molecular formula, if given. |
cas |
str | None
|
CAS registry number, if present. |
inchikey |
str | None
|
Standard InChIKey, if present. |
Uncertainty
dataclass
¶
Uncertainty(
standard: float | None = None,
expanded: float | None = None,
coverage_factor: float | None = None,
confidence_percent: float | None = None,
assessment: str | None = None,
)
A reported uncertainty, in the associated column's original units.
Expanded uncertainty is converted to standard uncertainty only when the source explicitly supplies a coverage factor. Confidence alone isn't a coverage factor. Missing uncertainty remains unknown.
Attributes:
| Name | Type | Description |
|---|---|---|
standard_value |
float | None
|
Standard uncertainty, or None when it cannot be recovered. |
Column
dataclass
¶
Column(
number: int,
role: str,
kind: str,
label: str,
component: int | None = None,
phase: str | None = None,
presentation: str = "Direct value, X",
method: str | None = None,
)
One variable or property column of a Dataset table.
Attributes:
| Name | Type | Description |
|---|---|---|
number |
int
|
The |
role |
str
|
|
kind |
str
|
The ThermoML type element local name, e.g. |
label |
str
|
Human-readable label including units, e.g. |
component |
int | None
|
For composition columns, the |
Dataset
dataclass
¶
Dataset(
components: tuple[int, ...],
columns: tuple[Column, ...],
rows: tuple[tuple[float, ...], ...],
phase: str | None = None,
number: int | None = None,
phases: tuple[str, ...] = (),
uncertainties: tuple[
tuple[Uncertainty | None, ...], ...
] = (),
issues: tuple[str, ...] = (),
)
A PureOrMixtureData block: a table of measurements for one mixture.
The rows are aligned with columns; a missing cell is float('nan').
Attributes:
| Name | Type | Description |
|---|---|---|
components |
tuple[int, ...]
|
|
columns |
tuple[Column, ...]
|
The variable and property columns, in document order. |
rows |
tuple[tuple[float, ...], ...]
|
Numeric rows aligned with |
phase |
str | None
|
The reported phase string, if any (e.g. |
number |
int | None
|
The |
Methods:
| Name | Description |
|---|---|
values |
All values of one column, in row order. |
find_column |
First column matching the given filters (any combination). |
select_column |
Select exactly one column; reject missing and ambiguous measurements. |
values_in |
Read a direct measurement in a supported unit, without guessing its basis. |
standard_uncertainties |
Standard uncertainties in a requested unit; unknown values remain None. |
validate |
Reject incomplete, nonfinite, or unsupported measurement tables. |
temperature |
Temperatures in kelvin (raises if the dataset has no temperature column). |
pressure |
Pressures converted to |
mole_fraction |
Mole fractions of |
to_dict |
The table as |
find_column
¶
find_column(
*,
kind: str | None = None,
quantity: str | None = None,
component: int | None = None,
phase: str | None = None,
role: str | None = None,
) -> Column | None
First column matching the given filters (any combination).
select_column
¶
Select exactly one column; reject missing and ambiguous measurements.
values_in
¶
Read a direct measurement in a supported unit, without guessing its basis.
standard_uncertainties
¶
Standard uncertainties in a requested unit; unknown values remain None.
temperature
¶
Temperatures in kelvin (raises if the dataset has no temperature column).
pressure
¶
Pressures converted to unit (default pascal).
Accepts pressure stored either as a controlled variable (ePressure) or
as a measured property (e.g. a vapour-pressure column).
mole_fraction
¶
Mole fractions of component (by org_num).
ThermoMLData
dataclass
¶
ThermoMLData(
compounds: tuple[Compound, ...],
datasets: tuple[Dataset, ...],
citation: str | None = None,
doi: str | None = None,
authors: tuple[str, ...] = (),
source_type: str | None = None,
sha256: str = "",
)
A parsed ThermoML document: its compounds, datasets, and citation.
Methods:
| Name | Description |
|---|---|
compound |
The compound with the given |
component_names |
Best-effort names of a dataset's components (falls back to |
convert_values
¶
Convert supported measurement units, rejecting unknown or incompatible units.
Supported dimensions are pressure, temperature, molar energy, mass density, molar volume, and dimensionless composition. No unit is inferred when absent.
loads
¶
loads(text: str | bytes) -> ThermoMLData
Parse a ThermoML document from an in-memory string or bytes.
read_thermoml
¶
list_samples
¶
Names (without extension) of the bundled ThermoML sample datasets.
sample_path
¶
Filesystem path of a bundled sample (with or without the .xml suffix).
load_sample
¶
load_sample(name: str) -> ThermoMLData
Parse a bundled ThermoML sample by name (see list_samples).
Measured corpus¶
experimental
¶
Reproducible, phase-aware measurements from the vendored NIST ThermoML corpus.
Raw archive bytes and their SHA-256 hashes are retained. Complementary tables are joined by identical independent conditions, never by row position. The normalizer accepts binary VLE, excess enthalpy, and cloud-point temperatures; it rejects other layouts instead of inventing a composition or uncertainty. Cloud points aren't conjugate tie lines and aren't accepted by the VLE fitter.
Classes:
| Name | Description |
|---|---|
Measurement |
One published value in SI units, preserving phase, role, and uncertainty. |
Observation |
One experimental condition with its joined measurements and source IDs. |
Functions:
| Name | Description |
|---|---|
normalize_document |
Normalize explicitly selected tables using CAS/InChIKey identity evidence. |
corpus_manifest |
Read source citations, checksums, identity mappings, and explicit exclusions. |
load_corpus |
Verify all raw checksums and reconstruct the measured corpus offline. |
grouped_split |
Split by explicit source DOI, temperature (K), or source/dataset ID. |
Measurement
dataclass
¶
Measurement(
quantity: str,
value: float,
unit: str,
phase: str | None,
component: str | None,
role: str,
uncertainty: Uncertainty | None = None,
)
One published value in SI units, preserving phase, role, and uncertainty.
Observation
dataclass
¶
Observation(
id: str,
source: str,
source_sha256: str,
dataset_ids: tuple[int, ...],
components: tuple[str, str],
cas: tuple[str, str],
kind: str,
measurements: tuple[Measurement, ...],
)
One experimental condition with its joined measurements and source IDs.
Compositions use components order. dataset_ids includes every table
contributing to the condition, allowing splits that keep joined data together.
Methods:
| Name | Description |
|---|---|
measurement |
Select exactly one quantity, optionally within a phase. |
composition |
Binary composition, completing only the explicitly binary complement. |
to_dict |
Serializable record with explicit SI units and retained uncertainties. |
Attributes:
| Name | Type | Description |
|---|---|---|
temperature |
float
|
Temperature in kelvin. |
pressure |
float
|
Pressure in pascals; unavailable pressure raises rather than defaulting. |
pressure
property
¶
pressure: float
Pressure in pascals; unavailable pressure raises rather than defaulting.
measurement
¶
measurement(
quantity: str, phase: str | None = None
) -> Measurement
Select exactly one quantity, optionally within a phase.
composition
¶
Binary composition, completing only the explicitly binary complement.
normalize_document
¶
normalize_document(
data: ThermoMLData,
identities: dict[str, dict[str, str]],
selected: tuple[int, ...],
excluded_rows: dict[str, dict[str, str]] | None = None,
) -> tuple[Observation, ...]
Normalize explicitly selected tables using CAS/InChIKey identity evidence.
Unknown identifiers, conflicting identifiers, ambiguous joins, nonfinite cells, transformed properties, and incomplete conditions raise ValueError. A DOI and raw-file checksum are required for measured evidence.
corpus_manifest
¶
Read source citations, checksums, identity mappings, and explicit exclusions.
load_corpus
¶
load_corpus() -> tuple[Observation, ...]
Verify all raw checksums and reconstruct the measured corpus offline.
grouped_split
¶
grouped_split(
observations: tuple[Observation, ...],
*,
by: str,
holdout: tuple[str, ...],
) -> tuple[
tuple[Observation, ...], tuple[Observation, ...]
]
Split by explicit source DOI, temperature (K), or source/dataset ID.
Temperature keys use format(T, '.12g'). Dataset keys use DOI#number;
selecting any joined table holds out the whole observation. No random row
splitting is offered. Both partitions must be nonempty; missing keys raise.
Measured regression and validation¶
measured_regression
¶
Multi-temperature, multi-property NRTL regression with held-out validation.
The fitted convention is tau_ij = a_ij + b_ij/T with fixed alpha. Saturation
pressures use the same Peng-Robinson reference as GammaPhiPackage. Ideal vapor,
no Poynting correction, and no saturation fugacity correction are explicit model
assumptions. Excess enthalpy is the Gibbs-Helmholtz derivative of that same NRTL
model. Optimization runs on the host; residuals and Jacobians use JAX.
Classes:
| Name | Description |
|---|---|
FitWeights |
Declared residual scales when standard measurement uncertainty is unknown. |
FitDiagnostics |
Optimizer status and local parameter identifiability at the final iterate. |
MeasuredFit |
Portable NRTL fit with exact training IDs, source hashes, and validity bounds. |
ValidationLimits |
Explicit holdout RMSE acceptance limits, fixed before evaluating predictions. |
Functions:
| Name | Description |
|---|---|
fit_measured_nrtl |
Fit four NRTL coefficients across temperatures and/or VLE and enthalpy. |
validate_fit |
Evaluate unseen observations and report physical errors by property. |
FitWeights
dataclass
¶
FitWeights(
pressure_relative: float = 0.02,
vapor_fraction: float = 0.02,
excess_enthalpy: float = 100.0,
)
Declared residual scales when standard measurement uncertainty is unknown.
These are modeling weights, not claims about experimental uncertainty. Temperature/composition uncertainty isn't silently reinterpreted as pressure uncertainty. Covariance is conditional on treating measured inputs as exact.
FitDiagnostics
dataclass
¶
FitDiagnostics(
converged: bool,
reason: str,
iterations: int,
weighted_rmse: float,
gradient_norm: float,
jacobian_rank: int,
condition_number: float | None,
degrees_of_freedom: int,
covariance: tuple[tuple[float, ...], ...] | None,
standard_errors: tuple[float, ...] | None,
uncertainty_note: str,
)
Optimizer status and local parameter identifiability at the final iterate.
MeasuredFit
dataclass
¶
MeasuredFit(
components: tuple[str, str],
alpha: float,
reference_temperature: float,
theta: tuple[float, ...],
training_ids: tuple[str, ...],
sources: tuple[tuple[str, str], ...],
temperature_range: tuple[float, float],
pressure_range: tuple[float, float],
composition_range: tuple[float, float],
diagnostics: FitDiagnostics,
weights: FitWeights,
)
Portable NRTL fit with exact training IDs, source hashes, and validity bounds.
theta is (tau12_ref, tau21_ref, b12/Tref, b21/Tref). Local covariance
and standard errors refer to this centered coordinate system. A successful
fit is still unqualified until independent holdout validation passes.
Methods:
| Name | Description |
|---|---|
model |
Build a differentiable model, preserving requested component order. |
to_dict |
Versioned, strict-JSON fit artifact. |
save |
Save coefficients and complete evidence without replacing the sample bank. |
load |
Read and validate a versioned fit artifact. |
from_dict |
Validate an inline artifact without mutating the caller's document. |
model
¶
Build a differentiable model, preserving requested component order.
save
¶
Save coefficients and complete evidence without replacing the sample bank.
load
classmethod
¶
load(path: str | Path) -> MeasuredFit
Read and validate a versioned fit artifact.
from_dict
classmethod
¶
from_dict(value: dict[str, Any]) -> MeasuredFit
Validate an inline artifact without mutating the caller's document.
ValidationLimits
dataclass
¶
ValidationLimits(
pressure_relative_rmse: float = 0.05,
vapor_fraction_rmse: float = 0.05,
excess_enthalpy_rmse: float = 150.0,
)
Explicit holdout RMSE acceptance limits, fixed before evaluating predictions.
fit_measured_nrtl
¶
fit_measured_nrtl(
observations: tuple[Observation, ...],
*,
alpha: float = 0.3,
weights: FitWeights = DEFAULT_WEIGHTS,
max_iter: int = 150,
initial: tuple[float, float, float, float] = (
0.5,
0.5,
1.0,
1.0,
),
) -> MeasuredFit
Fit four NRTL coefficients across temperatures and/or VLE and enthalpy.
Uses damped Gauss-Newton with exact autodiff Jacobians. Rank deficiency is a failed fit even if the objective is stationary; covariance is then unknown. The returned status must be checked before using coefficients in a package.
validate_fit
¶
validate_fit(
fit: MeasuredFit,
holdout: tuple[Observation, ...],
*,
limits: ValidationLimits = DEFAULT_LIMITS,
) -> dict[str, Any]
Evaluate unseen observations and report physical errors by property.
Training/holdout ID overlap raises. Passing a limit qualifies only these properties, systems, and conditions, never an entire model family.
Qualification matrix¶
qualification
¶
Executable measured-data qualification matrix with visible coverage gaps.
The matrix evaluates the current curated NRTL bank against every selected measured system. Missing parameters are unsupported, and failed tolerances are unqualified. Neither is relabeled as a passing test. A separate independent publication holdout qualifies the reproducible ethanol-water fit.
Functions:
| Name | Description |
|---|---|
qualify_ethanol_water |
Fit the 2011 publication and hold out all unambiguous 2012 measurements. |
measured_matrix |
Evaluate current curated NRTL predictions for all corpus systems and properties. |
qualify_ethanol_water
¶
qualify_ethanol_water() -> tuple[
MeasuredFit, dict[str, Any]
]
Fit the 2011 publication and hold out all unambiguous 2012 measurements.
measured_matrix
¶
Evaluate current curated NRTL predictions for all corpus systems and properties.
VLE limits are 5% pressure RMSE and 0.05 vapor mole-fraction RMSE; enthalpy limit is 150 J/mol. Cloud-point compositions are compared with the nearest nontrivial binodal branch, with 0.05 mole-fraction RMSE. Cloud-point tests don't infer unreported conjugate compositions from the measured data.