iapws-if97 2.2.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -2
- package/README.md +69 -246
- package/dist/backward/candidate-resolution.d.ts +8 -0
- package/dist/backward/candidate-resolution.js +40 -0
- package/dist/backward/fixed-temperature-candidates.d.ts +4 -0
- package/dist/backward/fixed-temperature-candidates.js +188 -0
- package/dist/backward/fixed-temperature-solver.d.ts +3 -3
- package/dist/backward/fixed-temperature-solver.js +38 -17
- package/dist/backward/fixed-temperature-stationary.d.ts +4 -0
- package/dist/backward/fixed-temperature-stationary.js +146 -0
- package/dist/backward/hs-region.d.ts +50 -0
- package/dist/backward/hs-region.js +695 -0
- package/dist/backward/hs-state.d.ts +15 -0
- package/dist/backward/hs-state.js +316 -0
- package/dist/backward/hs.js +28 -242
- package/dist/backward/ph.d.ts +2 -0
- package/dist/backward/ph.js +72 -21
- package/dist/backward/pressure-property-region.d.ts +13 -0
- package/dist/backward/pressure-property-region.js +262 -0
- package/dist/backward/ps.d.ts +6 -0
- package/dist/backward/ps.js +81 -28
- package/dist/backward/solution-validation.d.ts +7 -1
- package/dist/backward/solution-validation.js +138 -41
- package/dist/backward/th.d.ts +3 -5
- package/dist/backward/th.js +10 -71
- package/dist/backward/tolerances.d.ts +3 -0
- package/dist/backward/tolerances.js +9 -3
- package/dist/backward/ts.d.ts +3 -5
- package/dist/backward/ts.js +10 -71
- package/dist/constants.d.ts +11 -15
- package/dist/constants.js +14 -15
- package/dist/core/floating-point.d.ts +2 -0
- package/dist/core/floating-point.js +7 -0
- package/dist/core/formulation-seams.d.ts +27 -0
- package/dist/core/formulation-seams.js +289 -0
- package/dist/core/input-validation.d.ts +1 -0
- package/dist/core/input-validation.js +5 -0
- package/dist/core/region-detector.d.ts +3 -40
- package/dist/core/region-detector.js +37 -762
- package/dist/core/region3-pt.d.ts +1 -1
- package/dist/core/region3-pt.js +42 -16
- package/dist/core/solve-input-normalization.js +4 -1
- package/dist/core/solver.d.ts +7 -10
- package/dist/core/solver.js +26 -17
- package/dist/detect.d.ts +16 -2
- package/dist/detect.js +36 -2
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +16 -0
- package/dist/gas-constant.d.ts +5 -0
- package/dist/gas-constant.js +5 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +10 -21
- package/dist/regions/region1.d.ts +2 -1
- package/dist/regions/region1.js +1 -1
- package/dist/regions/region2.d.ts +2 -1
- package/dist/regions/region2.js +1 -1
- package/dist/regions/region3-data.js +3 -3
- package/dist/regions/region3-subregions.js +15 -10
- package/dist/regions/region3.d.ts +4 -1
- package/dist/regions/region3.js +32 -2
- package/dist/regions/region4.d.ts +2 -0
- package/dist/regions/region4.js +39 -12
- package/dist/regions/region5.d.ts +2 -1
- package/dist/regions/region5.js +2 -2
- package/dist/saturation/common.d.ts +2 -8
- package/dist/saturation/common.js +64 -36
- package/dist/saturation/region4-boundaries.js +13 -13
- package/dist/saturation/region4-hs.js +282 -58
- package/dist/saturation/two-phase.d.ts +2 -2
- package/dist/saturation/two-phase.js +7 -7
- package/dist/solvers/bracketed-newton.d.ts +6 -3
- package/dist/solvers/bracketed-newton.js +15 -8
- package/dist/solvers/extended-arithmetic.d.ts +6 -0
- package/dist/solvers/extended-arithmetic.js +38 -0
- package/dist/transport/properties.d.ts +4 -2
- package/dist/transport/properties.js +14 -4
- package/dist/types.d.ts +18 -0
- package/dist/types.js +14 -0
- package/package.json +4 -4
- package/dist/core/public-normalization.d.ts +0 -3
- package/dist/core/public-normalization.js +0 -53
- /package/dist/{backward → core}/thermodynamic-derivatives.d.ts +0 -0
- /package/dist/{backward → core}/thermodynamic-derivatives.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 2.8.0 (2026-10-20)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add `solveBasic(input)` and exported `BasicProperties` for all eight modes, without density or transport fields.
|
|
8
|
+
- Include liquid and vapor endpoints in Region 4 `saturation` (`SaturationEndpoints`), including at `x = 0` and `x = 1`.
|
|
9
|
+
- Test backward and boundary equations against official IAPWS values at their printed precision, including all 26 Region 3 `v(p,T)` subregions.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Remove decimal snapping and backward property input overwrites. Region 3 PT preserves input pressure after checking equation-of-state (EOS) convergence.
|
|
14
|
+
- Throw `AmbiguousStateError`, an `IF97Error` subclass, when `TH`/`TS` inputs match multiple states. This applies to direct solvers, `solve`, `solveBasic`, and region detectors. Its `candidates` field contains validated basic states in ascending pressure order. Callers that previously received one branch must handle ambiguity.
|
|
15
|
+
- Tighten ordinary backward enthalpy/entropy acceptance to `1e-9 × max(1, |input|)` and Region 3 PT pressure convergence to relative `1e-12`, with separate endpoint and fit-gap tolerances.
|
|
16
|
+
- Shorten the README, move API details to `docs/reference.md`, and redraw the P–T region map.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Correct 11 coefficient transcription errors in Region 1/3 `p(h,s)`, Region 3 `v(p,T)`, HS boundaries, and Region 2a `T(p,h)`/`T(p,s)`. Public `region3Volume` results change; refined solver results can differ in their last floating-point bits.
|
|
21
|
+
- Search all valid `TH`/`TS` branches, including non-monotonic isotherms, subcritical Region 3 vapor, and roots near open endpoints. Preserve multiple candidates near the triple point; low-temperature `TS` can match two liquid states and wet steam.
|
|
22
|
+
- Recover PH/PS and HS boundary roots and resolve region overlaps using `solvePT` boundary ownership. Recompute EOS properties after boundary normalization and revalidate input constraints before accepting candidates or fit-gap states.
|
|
23
|
+
- Preserve saturation input pressure or temperature, endpoint quality, and phase selection at `623.15 K` and near critical conditions. Use extended precision for saturation equations and Region 3 pressure inversion. Throw `IF97Error` when a stable phase or distinct saturation endpoints cannot be constructed.
|
|
24
|
+
- Correct global and pressure/entropy-dependent input limits. Reject out-of-range backward inputs while retaining valid boundary states; explain the triple-point lower bound in saturation errors.
|
|
25
|
+
- Force bisection when two iterations fail to halve the Newton bracket, preserving roots with quantized residuals near the triple point.
|
|
26
|
+
- Compute density as `1 / specificVolume`. Reject non-finite or non-positive viscosity, non-positive thermal-conductivity `cp`, and dielectric-constant inputs at or below `228 K`.
|
|
4
27
|
|
|
5
28
|
## 2.2.0
|
|
6
29
|
|
|
7
30
|
### Fixed
|
|
8
31
|
|
|
9
|
-
- Improved backward-solver accuracy
|
|
32
|
+
- Improved backward-solver accuracy and performance.
|
|
10
33
|
- Fixed saturation-region detection and package validation.
|
|
11
34
|
- Requires Node.js `>=20.19.0`.
|
|
12
35
|
|
package/README.md
CHANGED
|
@@ -1,295 +1,122 @@
|
|
|
1
|
-
#
|
|
1
|
+
# iapws-if97
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Industrial water and steam properties for Node.js and TypeScript.**
|
|
4
|
+
|
|
5
|
+
Turn two known properties into a water or steam state using [IAPWS-IF97](https://iapws.org/technical-guidance/release/IF97-Rev). For steam tables, thermal-cycle calculations, and engineering tools.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
[](https://github.com/jltonghui/iapws-if97/actions/workflows/ci.yml)
|
|
8
|
+
[](https://www.npmjs.com/package/iapws-if97)
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
[API reference](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md) · [References](#references) · [Changelog](CHANGELOG.md)
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+

|
|
10
13
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
14
|
+
- Forward, backward, and saturation solvers for eight input pairs across IF97 Regions 1–5.
|
|
15
|
+
- Saturation results include liquid and vapor endpoints.
|
|
16
|
+
- Viscosity, thermal conductivity, surface tension, dielectric constant, and ionization constant where applicable.
|
|
17
|
+
- ESM with TypeScript declarations and no runtime dependencies.
|
|
15
18
|
|
|
16
|
-
##
|
|
19
|
+
## Start calculating
|
|
17
20
|
|
|
18
|
-
Requires Node.js
|
|
21
|
+
Requires Node.js ≥20.19.0. Use ESM imports.
|
|
19
22
|
|
|
20
23
|
```bash
|
|
21
24
|
npm install iapws-if97
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Save the following as `example.mjs` and run it with `node example.mjs`:
|
|
27
|
+
Save as `example.mjs` and run `node example.mjs`:
|
|
27
28
|
|
|
28
29
|
```js
|
|
29
|
-
import {
|
|
30
|
+
import { solvePT } from 'iapws-if97';
|
|
30
31
|
|
|
31
|
-
const
|
|
32
|
-
const b = solve({ mode: 'PH', p: 3, h: a.enthalpy });
|
|
33
|
-
const c = solvePx(1, 0.5);
|
|
32
|
+
const steam = solvePT(3, 573.15); // 3 MPa, 300 °C
|
|
34
33
|
|
|
35
|
-
console.log(
|
|
36
|
-
console.log(
|
|
37
|
-
console.log(c.quality); // 0.5
|
|
34
|
+
console.log(steam.enthalpy.toFixed(2)); // 2994.35 kJ/kg
|
|
35
|
+
console.log(steam.density.toFixed(3)); // 12.319 kg/m³
|
|
38
36
|
```
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
The result includes pressure, temperature, enthalpy, entropy, density, heat capacities, speed of sound, and applicable transport properties. [All fields and units →](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#solver-return-value)
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
| --- | --- | --- |
|
|
44
|
-
| `solvePT(p, T)` | pressure, temperature | `MPa`, `K` |
|
|
45
|
-
| `solvePH(p, h)` | pressure, enthalpy | `MPa`, `kJ/kg` |
|
|
46
|
-
| `solvePS(p, s)` | pressure, entropy | `MPa`, `kJ/(kg·K)` |
|
|
47
|
-
| `solveHS(h, s)` | enthalpy, entropy | `kJ/kg`, `kJ/(kg·K)` |
|
|
48
|
-
| `solveTH(T, h)` | temperature, enthalpy | `K`, `kJ/kg` |
|
|
49
|
-
| `solveTS(T, s)` | temperature, entropy | `K`, `kJ/(kg·K)` |
|
|
50
|
-
| `solvePx(p, x)` | pressure, vapor quality | `MPa`, dimensionless `[0, 1]` |
|
|
51
|
-
| `solveTx(T, x)` | temperature, vapor quality | `K`, dimensionless `[0, 1]` |
|
|
40
|
+
## Use the properties you have
|
|
52
41
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
42
|
+
| Known properties | Solver |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| Pressure + temperature | `solvePT(p, T)` |
|
|
45
|
+
| Pressure + enthalpy | `solvePH(p, h)` |
|
|
46
|
+
| Pressure + entropy | `solvePS(p, s)` |
|
|
47
|
+
| Enthalpy + entropy | `solveHS(h, s)` |
|
|
48
|
+
| Temperature + enthalpy | `solveTH(T, h)` |
|
|
49
|
+
| Temperature + entropy | `solveTS(T, s)` |
|
|
50
|
+
| Pressure + vapor quality | `solvePx(p, x)` |
|
|
51
|
+
| Temperature + vapor quality | `solveTx(T, x)` |
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
import { solve } from 'iapws-if97';
|
|
53
|
+
Use MPa, K, kJ/kg, and kJ/(kg·K) for pressure, temperature, enthalpy, and entropy. Vapor quality `x` is the vapor mass fraction, from `0` (saturated liquid) to `1` (saturated vapor).
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
```
|
|
55
|
+
Use `solve()` when the input pair is chosen at runtime:
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
| Mode | Short fields | Long aliases |
|
|
68
|
-
| --- | --- | --- |
|
|
69
|
-
| `PT` | `p`, `T` | `pressure`, `temperature` |
|
|
70
|
-
| `PH` | `p`, `h` | `pressure`, `enthalpy` |
|
|
71
|
-
| `PS` | `p`, `s` | `pressure`, `entropy` |
|
|
72
|
-
| `HS` | `h`, `s` | `enthalpy`, `entropy` |
|
|
73
|
-
| `Px` | `p`, `x` | `pressure`, `quality` |
|
|
74
|
-
| `Tx` | `T`, `x` | `temperature`, `quality` |
|
|
75
|
-
| `TH` | `T`, `h` | `temperature`, `enthalpy` |
|
|
76
|
-
| `TS` | `T`, `s` | `temperature`, `entropy` |
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
import type { SolveInput } from 'iapws-if97';
|
|
57
|
+
```js
|
|
80
58
|
import { solve } from 'iapws-if97';
|
|
81
59
|
|
|
82
|
-
const
|
|
83
|
-
const longForm: SolveInput = { mode: 'PT', pressure: 16, temperature: 823.15 };
|
|
84
|
-
|
|
85
|
-
const a = solve(shortForm);
|
|
86
|
-
const b = solve(longForm);
|
|
60
|
+
const state = solve({ mode: 'PH', p: 3, h: 3000 });
|
|
87
61
|
```
|
|
88
62
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
## Solver return value
|
|
92
|
-
|
|
93
|
-
All solvers return a `SteamState` object containing both thermodynamic and transport properties:
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
type SteamState = {
|
|
97
|
-
region: Region;
|
|
98
|
-
pressure: number;
|
|
99
|
-
temperature: number;
|
|
100
|
-
specificVolume: number;
|
|
101
|
-
density: number;
|
|
102
|
-
internalEnergy: number;
|
|
103
|
-
entropy: number;
|
|
104
|
-
enthalpy: number;
|
|
105
|
-
cp: number | null;
|
|
106
|
-
cv: number | null;
|
|
107
|
-
speedOfSound: number | null;
|
|
108
|
-
quality: number | null;
|
|
109
|
-
viscosity: number | null;
|
|
110
|
-
thermalConductivity: number | null;
|
|
111
|
-
surfaceTension: number | null;
|
|
112
|
-
dielectricConstant: number | null;
|
|
113
|
-
ionizationConstant: number | null;
|
|
114
|
-
isobaricExpansion: number | null;
|
|
115
|
-
isothermalCompressibility: number | null;
|
|
116
|
-
};
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
`SteamState` always uses canonical property names.
|
|
120
|
-
|
|
121
|
-
**Notes:**
|
|
63
|
+
Long field names such as `pressure` and `enthalpy` are also accepted. Use [`solveBasic()`](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#thermodynamics-without-transport) when you only need thermodynamics; it skips transport calculations and omits `density`.
|
|
122
64
|
|
|
123
|
-
|
|
124
|
-
- In two-phase mixtures (`0 < x < 1`), `cp`, `cv`, `speedOfSound`, `isobaricExpansion`, `isothermalCompressibility`, `viscosity`, `thermalConductivity`, `dielectricConstant`, and `ionizationConstant` are `null`.
|
|
125
|
-
- Saturation endpoints (`x = 0` or `x = 1`) still expose single-phase transport properties even though they carry Region 4 metadata.
|
|
126
|
-
- `solvePT(p, T)` is a single-phase solver. On the subcritical saturation boundary it resolves to the liquid side.
|
|
127
|
-
- `surfaceTension` is only available for Region 4 saturation states below the critical point; otherwise `null`.
|
|
128
|
-
- `density` is provided directly, so there is no need to invert `specificVolume`.
|
|
129
|
-
- `ionizationConstant` is `null` outside the IAPWS validity range for that correlation.
|
|
65
|
+
## Work with saturation
|
|
130
66
|
|
|
131
|
-
|
|
67
|
+
Specify quality to calculate saturated liquid, saturated vapor, or wet steam:
|
|
132
68
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- Specific volume: `m^3/kg`
|
|
136
|
-
- Density: `kg/m^3`
|
|
137
|
-
- Enthalpy, internal energy: `kJ/kg`
|
|
138
|
-
- Entropy, heat capacities: `kJ/(kg·K)`
|
|
139
|
-
- Speed of sound: `m/s`
|
|
140
|
-
- Quality: dimensionless, `0`–`1` (saturation line only)
|
|
141
|
-
- Viscosity: `Pa·s`
|
|
142
|
-
- Thermal conductivity: `W/(m·K)`
|
|
143
|
-
- Surface tension: `N/m`
|
|
144
|
-
- Dielectric constant: dimensionless
|
|
145
|
-
- Ionization constant (`pKw`): dimensionless
|
|
146
|
-
- Isobaric expansion coefficient: `1/K`
|
|
147
|
-
- Isothermal compressibility: `1/MPa`
|
|
148
|
-
|
|
149
|
-
Any field typed as `number | null` returns `null` when the property is undefined for the given state.
|
|
69
|
+
```js
|
|
70
|
+
import { solvePx } from 'iapws-if97';
|
|
150
71
|
|
|
151
|
-
|
|
72
|
+
const wet = solvePx(1, 0.9); // 1 MPa, 90% vapor by mass
|
|
152
73
|
|
|
153
|
-
|
|
74
|
+
console.log(wet.temperature.toFixed(2)); // 453.04 K
|
|
154
75
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
| `iapws-if97/boundaries` | `boundary23_T_to_P`, `boundary23_P_to_T`, `region3Volume`, `region3SatVolume` |
|
|
161
|
-
| `iapws-if97/detect` | `detectRegionPT`, `detectRegionPH`, `detectRegionPS`, `detectRegionHS`, `detectRegionTH`, `detectRegionTS` |
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
import { viscosity } from 'iapws-if97/transport';
|
|
165
|
-
import { region1 } from 'iapws-if97/regions';
|
|
166
|
-
import { saturationTemperature } from 'iapws-if97/saturation';
|
|
167
|
-
import { detectRegionPT } from 'iapws-if97/detect';
|
|
76
|
+
if (wet.saturation) {
|
|
77
|
+
const { liquid, vapor } = wet.saturation;
|
|
78
|
+
const latentHeat = vapor.enthalpy - liquid.enthalpy;
|
|
79
|
+
console.log(latentHeat.toFixed(2)); // 2014.44 kJ/kg
|
|
80
|
+
}
|
|
168
81
|
```
|
|
169
82
|
|
|
170
|
-
|
|
83
|
+
Every saturation result includes `saturation.liquid` and `saturation.vapor` for phase properties and latent-heat calculations. Use `solveTx(T, x)` when temperature is known instead of pressure.
|
|
171
84
|
|
|
172
|
-
|
|
173
|
-
- Region, boundary, and detection helpers expect callers to respect the corresponding equation domains. Detection helpers return a `Region` value or `-1` when no valid region is found.
|
|
174
|
-
- `thermalConductivity(T, rho)` calculates the base contribution. Pass `cp`, `cv`, `drhodP_T`, and `mu` to include the IAPWS 2011 critical-enhancement term.
|
|
175
|
-
- `surfaceTension(T)` is a saturation-line property. `saturationPressure(T)` and `saturationTemperature(p)` expose the mathematical Region 4 boundary and are more permissive at endpoints than `solveTx` and `solvePx`.
|
|
85
|
+
## Before integrating
|
|
176
86
|
|
|
177
|
-
|
|
87
|
+
- PT selects a single phase. Pressure and temperature alone do not determine wet-steam quality; use `Px` or `Tx` for a mixture.
|
|
88
|
+
- Single-phase `quality` is `null`. Mixtures return `null` for heat capacities, speed of sound, and most transport properties. [Return-value details →](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#solver-return-value)
|
|
89
|
+
- TH and TS throw `AmbiguousStateError` with candidate states when multiple solutions exist. Use pressure or quality to resolve the state. [Errors →](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#errors-and-limits)
|
|
90
|
+
- The exact critical point is unsupported, and near-critical solves can fail. Transport correlations have separate validity ranges. [Numerical limits →](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#saturation-endpoints) · [Transport limits →](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#transport-correlation-limits)
|
|
178
91
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| Property | Implemented behavior |
|
|
92
|
+
| Thermodynamic temperature range | Maximum pressure |
|
|
182
93
|
| --- | --- |
|
|
183
|
-
|
|
|
184
|
-
|
|
|
185
|
-
| Surface tension | Defined for saturation states below the critical point. The low-level helper permits `273.15 K ≤ T ≤ Tc`; values below the triple point `Tt = 273.16 K` are extrapolations. |
|
|
186
|
-
| Dielectric constant | The IAPWS 1997 release is valid through `873 K`. The low-level helper does not enforce that upper bound, so higher-temperature results are extrapolations. |
|
|
187
|
-
| Ionization constant (`pKw`) | Returns `null` outside `273.15 K ≤ T ≤ 1273.15 K`. The release's `1000 MPa` pressure limit describes the correlation, not the state-solver pressure range. |
|
|
188
|
-
|
|
189
|
-
## Saturation endpoints
|
|
190
|
-
|
|
191
|
-
The triple and critical points are `Pt = 0.000611657 MPa`, `Tt = 273.16 K`, `Pc = 22.064 MPa`, and `Tc = 647.096 K`.
|
|
192
|
-
|
|
193
|
-
- Low-level Region 4 helpers accept a wider endpoint range. The saturation state solvers use these stricter bounds:
|
|
194
|
-
- `solvePx(p, x)` accepts `Pt ≤ p < Pc`
|
|
195
|
-
- `solveTx(T, x)` accepts `Tt = 273.16 K ≤ T < Tc`
|
|
196
|
-
- The triple point is supported as a saturation-state boundary:
|
|
197
|
-
- `solvePx(Pt, x)` is valid
|
|
198
|
-
- `solveTx(Tt, x)` is valid
|
|
199
|
-
- `273.15 K` is treated as a low-level extrapolation boundary only.
|
|
200
|
-
- The solvers do not return the exact critical point as a Region 4 state.
|
|
201
|
-
- `solveTH(T, h)` and `solveTS(T, s)` reject inputs within `0.001 K` of the critical temperature.
|
|
202
|
-
|
|
203
|
-
## Errors and limits
|
|
204
|
-
|
|
205
|
-
The library throws typed errors:
|
|
206
|
-
|
|
207
|
-
| Error | Meaning |
|
|
208
|
-
| --- | --- |
|
|
209
|
-
| `OutOfRangeError` | Input is outside the supported IF97 range |
|
|
210
|
-
| `ConvergenceError` | An internal iterative solve failed to converge |
|
|
211
|
-
| `IF97Error` | Base class; root solvers also use it directly for non-numeric or non-finite inputs, conflicting aliases, unsupported modes, and unsupported critical-point states |
|
|
212
|
-
|
|
213
|
-
Numeric inputs to root solvers and transport helpers must be finite. Low-level region, boundary, and detection helpers rely on callers to respect their equation domains. `solvePT(Pc, Tc)`, exact critical Region 4 states, and `solveTH`/`solveTS` inputs within `0.001 K` of `Tc` are rejected because the required derivative properties or inverse solution are singular or ill-conditioned.
|
|
94
|
+
| 273.15–1073.15 K | 100 MPa |
|
|
95
|
+
| Above 1073.15 K, up to 2273.15 K | 50 MPa |
|
|
214
96
|
|
|
215
|
-
|
|
97
|
+
Saturation solvers accept 273.16 ≤ T < 647.096 K or 0.000611657 ≤ p < 22.064 MPa. All numeric inputs must be finite; invalid or unresolved states throw [typed errors](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#errors-and-limits).
|
|
216
98
|
|
|
217
|
-
|
|
99
|
+
## Verification and development
|
|
218
100
|
|
|
219
|
-
-
|
|
220
|
-
- `1073.15 K < T ≤ 2273.15 K` (Region 5): pressure up to `50 MPa`.
|
|
221
|
-
|
|
222
|
-
Transport-property limits are separate; see [Transport correlation limits](#transport-correlation-limits).
|
|
223
|
-
|
|
224
|
-
## Verification
|
|
225
|
-
|
|
226
|
-
The test suite covers:
|
|
227
|
-
|
|
228
|
-
- Official IF97 verification tables (Regions 1–5)
|
|
229
|
-
- Backward-equation round-trip accuracy
|
|
230
|
-
- Temperature-led backward round trips (`TH` and `TS`)
|
|
231
|
-
- High-pressure Region 4 regressions
|
|
232
|
-
- IAPWS R11-24 ionization-constant verification values
|
|
233
|
-
- Coverage thresholds enforced locally
|
|
234
|
-
- ASME and GB/T steam-table comparisons against published values
|
|
235
|
-
|
|
236
|
-
For a clean local verification run:
|
|
101
|
+
Tests cover official IAPWS verification values, backward-solver round trips, region boundaries, and published ASME and GB/T steam tables. CI also checks TypeScript types, package exports, and coverage thresholds. [Verification details and references →](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#verification)
|
|
237
102
|
|
|
238
103
|
```bash
|
|
239
104
|
npm ci
|
|
240
|
-
npm run
|
|
105
|
+
npm run typecheck
|
|
241
106
|
npm test
|
|
107
|
+
npm run test:package
|
|
242
108
|
```
|
|
243
109
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
npm run test:coverage
|
|
248
|
-
npm run test:standards
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## Integration validation
|
|
252
|
-
|
|
253
|
-

|
|
254
|
-
|
|
255
|
-
This Mollier `h-s` diagram was generated with `iapws-if97` as an end-to-end check of the calculation pipeline.
|
|
256
|
-
|
|
257
|
-
The standards tests check the published tables below. Both suites enforce `maxRelativeError < 5e-4` (less than `0.05%`).
|
|
258
|
-
|
|
259
|
-
| Reference | Coverage | Points checked | Worst relative error |
|
|
260
|
-
| --- | --- | ---: | ---: |
|
|
261
|
-
| *ASME International Steam Tables for Industrial Use*, 3rd ed., Table S-2 | Saturation states at 6 pressures | 42 | `0.0315405%` |
|
|
262
|
-
| *GB/T 34060-2017*, Table A.3(续), page 55 | Superheated steam at `10 MPa` and 6 temperatures | 24 | `0.0007020%` |
|
|
263
|
-
|
|
264
|
-
See [`tests/standards-asme`](tests/standards-asme) and [`tests/standards-cn`](tests/standards-cn) for the source values and per-case comparisons.
|
|
265
|
-
|
|
266
|
-
## TypeScript
|
|
267
|
-
|
|
268
|
-
The package ships with generated TypeScript declarations for the root and every public subpath.
|
|
269
|
-
|
|
270
|
-
```ts
|
|
271
|
-
import type { SolveInput, SteamState } from 'iapws-if97';
|
|
272
|
-
import { Region, solve } from 'iapws-if97';
|
|
273
|
-
|
|
274
|
-
const input: SolveInput = { mode: 'PT', p: 3, T: 300 };
|
|
275
|
-
const state: SteamState = solve(input);
|
|
276
|
-
|
|
277
|
-
if (state.region === Region.Region1) {
|
|
278
|
-
console.log('compressed liquid');
|
|
279
|
-
}
|
|
280
|
-
```
|
|
110
|
+
For low-level region equations, saturation curves, transport correlations, or region detection, see [advanced imports](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#advanced-imports).
|
|
281
111
|
|
|
282
112
|
## References
|
|
283
113
|
|
|
284
|
-
- [IAPWS
|
|
285
|
-
- [IAPWS
|
|
286
|
-
- [
|
|
287
|
-
- [
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
- [IAPWS R8-97, Static Dielectric Constant of Ordinary Water Substance](https://www.iapws.org/relguide/dielec.pdf)
|
|
291
|
-
- [IAPWS R1-76(2014), Surface Tension of Ordinary Water Substance](https://www.iapws.org/relguide/Surf-H2O.html)
|
|
292
|
-
- [IAPWS R11-24, Ionization Constant of H2O](https://www.iapws.org/relguide/Ionization.html)
|
|
114
|
+
- [IAPWS R7-97(2012), Industrial Formulation 1997](https://iapws.org/technical-guidance/release/IF97-Rev).
|
|
115
|
+
- [IAPWS supplementary releases](https://iapws.org/technical-guidance/release) for alternative input pairs, region boundaries, and Region 3 specific volume.
|
|
116
|
+
- [R12-08, viscosity](https://iapws.org/technical-guidance/release/viscosity) and [R15-11, thermal conductivity](https://iapws.org/technical-guidance/release/ThCond).
|
|
117
|
+
- [R1-76(2014), surface tension](https://iapws.org/technical-guidance/release/Surf-H2O), [R8-97, dielectric constant](https://iapws.org/technical-guidance/release/Dielec), and [R11-24, ionization constant](https://iapws.org/technical-guidance/release/Ionization).
|
|
118
|
+
|
|
119
|
+
See the [full reference list](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md#references) for release details.
|
|
293
120
|
|
|
294
121
|
## Project origin
|
|
295
122
|
|
|
@@ -299,8 +126,4 @@ if (state.region === Region.Region1) {
|
|
|
299
126
|
|
|
300
127
|
## License
|
|
301
128
|
|
|
302
|
-
MIT
|
|
303
|
-
|
|
304
|
-
## Disclaimer
|
|
305
|
-
|
|
306
|
-
This software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability arising from the use of this software.
|
|
129
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FormulationSeamResolution } from '../core/formulation-seams.js';
|
|
2
|
+
import { type BasicProperties } from '../types.js';
|
|
3
|
+
import { type BackwardConstraint } from './solution-validation.js';
|
|
4
|
+
/** Exhaust nearby roots before applying inverse seam and saturation ownership. */
|
|
5
|
+
export declare function resolveBackwardCandidates(attempts: readonly (() => BasicProperties | null)[], constraints: readonly BackwardConstraint[], options: {
|
|
6
|
+
solverName: string;
|
|
7
|
+
seam?: FormulationSeamResolution;
|
|
8
|
+
}): BasicProperties | null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { NumericalStateError, RegionMismatchError } from '../errors.js';
|
|
2
|
+
import { IF97Error, Region } from '../types.js';
|
|
3
|
+
import { backwardCandidateError, normalizeBackwardState, validateBackwardState, } from './solution-validation.js';
|
|
4
|
+
/** Exhaust nearby roots before applying inverse seam and saturation ownership. */
|
|
5
|
+
export function resolveBackwardCandidates(attempts, constraints, options) {
|
|
6
|
+
const candidates = [];
|
|
7
|
+
let failure = null;
|
|
8
|
+
for (const attempt of attempts) {
|
|
9
|
+
try {
|
|
10
|
+
let state = attempt();
|
|
11
|
+
if (state !== null) {
|
|
12
|
+
let error = backwardCandidateError(state, constraints, options);
|
|
13
|
+
if (error instanceof RegionMismatchError) {
|
|
14
|
+
state = normalizeBackwardState(state, constraints, options.solverName);
|
|
15
|
+
error = backwardCandidateError(state, constraints, options);
|
|
16
|
+
}
|
|
17
|
+
if (error === null)
|
|
18
|
+
candidates.push(state);
|
|
19
|
+
else if (error instanceof NumericalStateError)
|
|
20
|
+
failure ??= error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (!(error instanceof IF97Error))
|
|
25
|
+
throw error;
|
|
26
|
+
if (!(error instanceof RegionMismatchError))
|
|
27
|
+
failure ??= error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const saturated = candidates.find(({ region }) => region === Region.Region4);
|
|
31
|
+
const owned = candidates.find(({ region }) => region === options.seam?.pair.canonical.region);
|
|
32
|
+
if (candidates.length > 0)
|
|
33
|
+
return saturated ?? owned ?? candidates[0];
|
|
34
|
+
if (failure !== null)
|
|
35
|
+
throw failure;
|
|
36
|
+
if (options.seam !== undefined && options.seam.kind === 'gap') {
|
|
37
|
+
return validateBackwardState(options.seam.state, constraints, options);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BasicProperties } from '../types.js';
|
|
2
|
+
import { type FixedTemperatureProperty } from './fixed-temperature-solver.js';
|
|
3
|
+
/** Return the only physical TH/TS state, or null if unresolved; proven envelope violations throw. */
|
|
4
|
+
export declare function uniqueFixedTemperatureState(T: number, target: number, property: FixedTemperatureProperty): BasicProperties | null;
|