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.
Files changed (83) hide show
  1. package/CHANGELOG.md +25 -2
  2. package/README.md +69 -246
  3. package/dist/backward/candidate-resolution.d.ts +8 -0
  4. package/dist/backward/candidate-resolution.js +40 -0
  5. package/dist/backward/fixed-temperature-candidates.d.ts +4 -0
  6. package/dist/backward/fixed-temperature-candidates.js +188 -0
  7. package/dist/backward/fixed-temperature-solver.d.ts +3 -3
  8. package/dist/backward/fixed-temperature-solver.js +38 -17
  9. package/dist/backward/fixed-temperature-stationary.d.ts +4 -0
  10. package/dist/backward/fixed-temperature-stationary.js +146 -0
  11. package/dist/backward/hs-region.d.ts +50 -0
  12. package/dist/backward/hs-region.js +695 -0
  13. package/dist/backward/hs-state.d.ts +15 -0
  14. package/dist/backward/hs-state.js +316 -0
  15. package/dist/backward/hs.js +28 -242
  16. package/dist/backward/ph.d.ts +2 -0
  17. package/dist/backward/ph.js +72 -21
  18. package/dist/backward/pressure-property-region.d.ts +13 -0
  19. package/dist/backward/pressure-property-region.js +262 -0
  20. package/dist/backward/ps.d.ts +6 -0
  21. package/dist/backward/ps.js +81 -28
  22. package/dist/backward/solution-validation.d.ts +7 -1
  23. package/dist/backward/solution-validation.js +138 -41
  24. package/dist/backward/th.d.ts +3 -5
  25. package/dist/backward/th.js +10 -71
  26. package/dist/backward/tolerances.d.ts +3 -0
  27. package/dist/backward/tolerances.js +9 -3
  28. package/dist/backward/ts.d.ts +3 -5
  29. package/dist/backward/ts.js +10 -71
  30. package/dist/constants.d.ts +11 -15
  31. package/dist/constants.js +14 -15
  32. package/dist/core/floating-point.d.ts +2 -0
  33. package/dist/core/floating-point.js +7 -0
  34. package/dist/core/formulation-seams.d.ts +27 -0
  35. package/dist/core/formulation-seams.js +289 -0
  36. package/dist/core/input-validation.d.ts +1 -0
  37. package/dist/core/input-validation.js +5 -0
  38. package/dist/core/region-detector.d.ts +3 -40
  39. package/dist/core/region-detector.js +37 -762
  40. package/dist/core/region3-pt.d.ts +1 -1
  41. package/dist/core/region3-pt.js +42 -16
  42. package/dist/core/solve-input-normalization.js +4 -1
  43. package/dist/core/solver.d.ts +7 -10
  44. package/dist/core/solver.js +26 -17
  45. package/dist/detect.d.ts +16 -2
  46. package/dist/detect.js +36 -2
  47. package/dist/errors.d.ts +11 -0
  48. package/dist/errors.js +16 -0
  49. package/dist/gas-constant.d.ts +5 -0
  50. package/dist/gas-constant.js +5 -0
  51. package/dist/index.d.ts +4 -5
  52. package/dist/index.js +10 -21
  53. package/dist/regions/region1.d.ts +2 -1
  54. package/dist/regions/region1.js +1 -1
  55. package/dist/regions/region2.d.ts +2 -1
  56. package/dist/regions/region2.js +1 -1
  57. package/dist/regions/region3-data.js +3 -3
  58. package/dist/regions/region3-subregions.js +15 -10
  59. package/dist/regions/region3.d.ts +4 -1
  60. package/dist/regions/region3.js +32 -2
  61. package/dist/regions/region4.d.ts +2 -0
  62. package/dist/regions/region4.js +39 -12
  63. package/dist/regions/region5.d.ts +2 -1
  64. package/dist/regions/region5.js +2 -2
  65. package/dist/saturation/common.d.ts +2 -8
  66. package/dist/saturation/common.js +64 -36
  67. package/dist/saturation/region4-boundaries.js +13 -13
  68. package/dist/saturation/region4-hs.js +282 -58
  69. package/dist/saturation/two-phase.d.ts +2 -2
  70. package/dist/saturation/two-phase.js +7 -7
  71. package/dist/solvers/bracketed-newton.d.ts +6 -3
  72. package/dist/solvers/bracketed-newton.js +15 -8
  73. package/dist/solvers/extended-arithmetic.d.ts +6 -0
  74. package/dist/solvers/extended-arithmetic.js +38 -0
  75. package/dist/transport/properties.d.ts +4 -2
  76. package/dist/transport/properties.js +14 -4
  77. package/dist/types.d.ts +18 -0
  78. package/dist/types.js +14 -0
  79. package/package.json +4 -4
  80. package/dist/core/public-normalization.d.ts +0 -3
  81. package/dist/core/public-normalization.js +0 -53
  82. /package/dist/{backward → core}/thermodynamic-derivatives.d.ts +0 -0
  83. /package/dist/{backward → core}/thermodynamic-derivatives.js +0 -0
package/CHANGELOG.md CHANGED
@@ -1,12 +1,35 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to this project will be documented in this file.
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, robustness, and performance.
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
- # `iapws-if97`
1
+ # iapws-if97
2
2
 
3
- [![CI](https://github.com/jltonghui/iapws-if97/actions/workflows/ci.yml/badge.svg)](https://github.com/jltonghui/iapws-if97/actions/workflows/ci.yml)
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
- `iapws-if97` calculates industrial water and steam properties in Node.js and TypeScript using the [IAPWS-IF97](https://www.iapws.org/) standard published by the International Association for the Properties of Water and Steam.
7
+ [![CI](https://github.com/jltonghui/iapws-if97/actions/workflows/ci.yml/badge.svg)](https://github.com/jltonghui/iapws-if97/actions/workflows/ci.yml)
8
+ [![npm version](https://img.shields.io/npm/v/iapws-if97.svg)](https://www.npmjs.com/package/iapws-if97)
6
9
 
7
- It includes forward and backward state solvers, saturation solvers, and transport-property helpers.
10
+ [API reference](https://github.com/jltonghui/iapws-if97/blob/main/docs/reference.md) · [References](#references) · [Changelog](CHANGELOG.md)
8
11
 
9
- ## Features
12
+ ![IAPWS-IF97 pressure–temperature map showing Regions 1–5, the saturation curve, and the 100 MPa and 50 MPa pressure limits.](https://raw.githubusercontent.com/jltonghui/iapws-if97/main/assets/pics/if97-regions.svg)
10
13
 
11
- - Covers IF97 Regions 1–5, including high-temperature Region 5
12
- - Forward, backward, and saturation solvers behind a consistent API
13
- - Transport properties: viscosity, thermal conductivity, surface tension, dielectric constant, and ionization constant
14
- - Verified against official IAPWS tables and published engineering references
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
- ## Installation
19
+ ## Start calculating
17
20
 
18
- Requires Node.js `>=20.19.0`. The package publishes ESM, and all documented examples use `import`. CommonJS is not part of the tested API.
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
- ## Quick start
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 { solve, solvePT, solvePx } from 'iapws-if97';
30
+ import { solvePT } from 'iapws-if97';
30
31
 
31
- const a = solvePT(3, 300);
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(a.enthalpy); // kJ/kg
36
- console.log(b.temperature); // K
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
- ## Main API
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
- | Function | Input pair | Units |
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
- All numeric inputs must be finite numbers.
54
-
55
- ### Unified `solve()`
56
-
57
- Use `solve({ mode, ... })` when the input pair is determined at runtime:
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
- ```ts
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
- const state = solve({ mode: 'PT', p: 16, T: 823.15 });
63
- ```
55
+ Use `solve()` when the input pair is chosen at runtime:
64
56
 
65
- Each mode accepts canonical short fields or their long aliases:
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 shortForm: SolveInput = { mode: 'PT', p: 16, T: 823.15 };
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
- You can mix short and long names within one input. If both aliases for the same property are present, their values must match exactly. The exported `SolveInput` type is the source of truth for accepted combinations.
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
- - `quality` is `null` for single-phase states; it is only defined on the saturation line.
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
- ## Units
67
+ Specify quality to calculate saturated liquid, saturated vapor, or wet steam:
132
68
 
133
- - Pressure: `MPa`
134
- - Temperature: `K`
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
- ## Advanced imports
72
+ const wet = solvePx(1, 0.9); // 1 MPa, 90% vapor by mass
152
73
 
153
- The package root is limited to the main solvers, `SteamState`, `SolveInput`, `Region`, and the public error classes. Lower-level helpers are available from explicit subpaths:
74
+ console.log(wet.temperature.toFixed(2)); // 453.04 K
154
75
 
155
- | Subpath | Exports |
156
- | --- | --- |
157
- | `iapws-if97/transport` | `viscosity`, `thermalConductivity`, `surfaceTension`, `dielectricConstant`, `ionizationConstant` |
158
- | `iapws-if97/regions` | `region1`, `region2`, `region3ByRhoT`, `region5` |
159
- | `iapws-if97/saturation` | `saturationPressure`, `saturationTemperature` |
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
- These are low-level mathematical interfaces:
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
- - Region functions return core thermodynamic properties without `density` or transport-property enrichment.
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
- ## Transport correlation limits
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
- Transport correlations have validity ranges independent of the IF97 thermodynamic envelope. The library may return extrapolated values where noted:
180
-
181
- | Property | Implemented behavior |
92
+ | Thermodynamic temperature range | Maximum pressure |
182
93
  | --- | --- |
183
- | Viscosity | Uses the IAPWS 2008 dilute-gas and finite-density terms. The near-critical enhancement is omitted, as permitted for industrial use by the release. |
184
- | Thermal conductivity | Full `SteamState` calculations include the IAPWS 2011 critical enhancement. The two-argument low-level call does not. Values above the release's temperature range are extrapolations. |
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
- ## Thermodynamic validity
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
- The thermodynamic solvers follow the piecewise IF97 industrial range:
99
+ ## Verification and development
218
100
 
219
- - `273.15 K ≤ T ≤ 1073.15 K`: pressure up to `100 MPa`.
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 test:package
105
+ npm run typecheck
241
106
  npm test
107
+ npm run test:package
242
108
  ```
243
109
 
244
- `test:package` performs a clean build and checks that the dry-run npm tarball has no dangling source-map references. Coverage and published-table comparisons are available separately:
245
-
246
- ```bash
247
- npm run test:coverage
248
- npm run test:standards
249
- ```
250
-
251
- ## Integration validation
252
-
253
- ![Mollier h-s diagram generated with iapws-if97](https://raw.githubusercontent.com/jltonghui/iapws-if97/main/assets/pics/mollier-hs-diagram.svg)
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 official website](https://www.iapws.org/)
285
- - [IAPWS R7-97(2012), Industrial Formulation 1997](https://www.iapws.org/relguide/IF97-Rev.html)
286
- - [IAPWS supplementary releases](https://www.iapws.org/release.html) for `T(p,h)`, `T(p,s)`, `p(h,s)`, Region 3 boundary equations, `Tsat(h,s)`, and `v(p,T)`
287
- - [IAPWS SR4-04(2014), Region 3 `p(h,s)` and Region 4 `Tsat(h,s)`](https://iapws.org/documents/release/Supp-phs3-2014)
288
- - [IAPWS R12-08, Viscosity of Ordinary Water Substance](https://www.iapws.org/relguide/viscosity.html)
289
- - [IAPWS R15-11, Thermal Conductivity of Ordinary Water Substance](https://www.iapws.org/relguide/ThCond.html)
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;