iapws-if97 2.1.2 → 2.2.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 +12 -0
- package/README.md +134 -94
- package/dist/backward/fixed-temperature-solver.d.ts +6 -6
- package/dist/backward/fixed-temperature-solver.js +34 -8
- package/dist/backward/hs.d.ts +1 -2
- package/dist/backward/hs.js +67 -46
- package/dist/backward/ph.d.ts +8 -5
- package/dist/backward/ph.js +43 -46
- package/dist/backward/ps.d.ts +0 -1
- package/dist/backward/ps.js +30 -18
- package/dist/backward/solution-validation.d.ts +0 -1
- package/dist/backward/solution-validation.js +33 -5
- package/dist/backward/th.d.ts +0 -1
- package/dist/backward/th.js +4 -6
- package/dist/backward/thermodynamic-derivatives.d.ts +17 -0
- package/dist/backward/thermodynamic-derivatives.js +27 -0
- package/dist/backward/tolerances.d.ts +0 -1
- package/dist/backward/tolerances.js +0 -1
- package/dist/backward/ts.d.ts +0 -1
- package/dist/backward/ts.js +4 -6
- package/dist/boundaries.d.ts +0 -1
- package/dist/boundaries.js +0 -1
- package/dist/constants.d.ts +0 -9
- package/dist/constants.js +3 -13
- package/dist/core/input-validation.d.ts +0 -1
- package/dist/core/input-validation.js +0 -1
- package/dist/core/public-normalization.d.ts +0 -1
- package/dist/core/public-normalization.js +0 -1
- package/dist/core/region-detector.d.ts +0 -1
- package/dist/core/region-detector.js +234 -67
- package/dist/core/region3-pt.d.ts +12 -1
- package/dist/core/region3-pt.js +38 -9
- package/dist/core/solve-input-normalization.d.ts +0 -1
- package/dist/core/solve-input-normalization.js +0 -1
- package/dist/core/solver.d.ts +0 -1
- package/dist/core/solver.js +0 -1
- package/dist/detect.d.ts +0 -1
- package/dist/detect.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/regions/boundaries.d.ts +0 -1
- package/dist/regions/boundaries.js +0 -1
- package/dist/regions/region1.d.ts +0 -1
- package/dist/regions/region1.js +0 -1
- package/dist/regions/region2.d.ts +0 -1
- package/dist/regions/region2.js +0 -1
- package/dist/regions/region3-data.d.ts +0 -1
- package/dist/regions/region3-data.js +0 -1
- package/dist/regions/region3-eval.d.ts +0 -1
- package/dist/regions/region3-eval.js +0 -1
- package/dist/regions/region3-subregions.d.ts +0 -1
- package/dist/regions/region3-subregions.js +0 -1
- package/dist/regions/region3.d.ts +0 -1
- package/dist/regions/region3.js +0 -1
- package/dist/regions/region4.d.ts +0 -1
- package/dist/regions/region4.js +0 -1
- package/dist/regions/region5.d.ts +0 -1
- package/dist/regions/region5.js +0 -1
- package/dist/regions.d.ts +0 -1
- package/dist/regions.js +0 -1
- package/dist/saturation/common.d.ts +0 -1
- package/dist/saturation/common.js +6 -13
- package/dist/saturation/region4-boundaries.d.ts +0 -5
- package/dist/saturation/region4-boundaries.js +4 -5
- package/dist/saturation/region4-hs.d.ts +2 -1
- package/dist/saturation/region4-hs.js +277 -108
- package/dist/saturation/two-phase.d.ts +0 -1
- package/dist/saturation/two-phase.js +0 -1
- package/dist/saturation.d.ts +0 -1
- package/dist/saturation.js +0 -1
- package/dist/solvers/bracketed-newton.d.ts +5 -4
- package/dist/solvers/bracketed-newton.js +5 -6
- package/dist/solvers/damped-newton-2d.d.ts +12 -0
- package/dist/solvers/damped-newton-2d.js +68 -0
- package/dist/solvers/newton-raphson.d.ts +0 -1
- package/dist/solvers/newton-raphson.js +0 -1
- package/dist/transport/properties.d.ts +0 -1
- package/dist/transport/properties.js +0 -1
- package/dist/transport.d.ts +0 -1
- package/dist/transport.js +0 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -1
- package/package.json +19 -10
- package/dist/backward/fixed-temperature-solver.d.ts.map +0 -1
- package/dist/backward/fixed-temperature-solver.js.map +0 -1
- package/dist/backward/hs.d.ts.map +0 -1
- package/dist/backward/hs.js.map +0 -1
- package/dist/backward/objective-normalization.d.ts +0 -7
- package/dist/backward/objective-normalization.d.ts.map +0 -1
- package/dist/backward/objective-normalization.js +0 -8
- package/dist/backward/objective-normalization.js.map +0 -1
- package/dist/backward/ph.d.ts.map +0 -1
- package/dist/backward/ph.js.map +0 -1
- package/dist/backward/ps.d.ts.map +0 -1
- package/dist/backward/ps.js.map +0 -1
- package/dist/backward/solution-validation.d.ts.map +0 -1
- package/dist/backward/solution-validation.js.map +0 -1
- package/dist/backward/th.d.ts.map +0 -1
- package/dist/backward/th.js.map +0 -1
- package/dist/backward/tolerances.d.ts.map +0 -1
- package/dist/backward/tolerances.js.map +0 -1
- package/dist/backward/ts.d.ts.map +0 -1
- package/dist/backward/ts.js.map +0 -1
- package/dist/boundaries.d.ts.map +0 -1
- package/dist/boundaries.js.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/core/input-validation.d.ts.map +0 -1
- package/dist/core/input-validation.js.map +0 -1
- package/dist/core/public-normalization.d.ts.map +0 -1
- package/dist/core/public-normalization.js.map +0 -1
- package/dist/core/region-detector.d.ts.map +0 -1
- package/dist/core/region-detector.js.map +0 -1
- package/dist/core/region3-pt.d.ts.map +0 -1
- package/dist/core/region3-pt.js.map +0 -1
- package/dist/core/solve-input-normalization.d.ts.map +0 -1
- package/dist/core/solve-input-normalization.js.map +0 -1
- package/dist/core/solver.d.ts.map +0 -1
- package/dist/core/solver.js.map +0 -1
- package/dist/detect.d.ts.map +0 -1
- package/dist/detect.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/regions/boundaries.d.ts.map +0 -1
- package/dist/regions/boundaries.js.map +0 -1
- package/dist/regions/region1.d.ts.map +0 -1
- package/dist/regions/region1.js.map +0 -1
- package/dist/regions/region2.d.ts.map +0 -1
- package/dist/regions/region2.js.map +0 -1
- package/dist/regions/region3-data.d.ts.map +0 -1
- package/dist/regions/region3-data.js.map +0 -1
- package/dist/regions/region3-eval.d.ts.map +0 -1
- package/dist/regions/region3-eval.js.map +0 -1
- package/dist/regions/region3-subregions.d.ts.map +0 -1
- package/dist/regions/region3-subregions.js.map +0 -1
- package/dist/regions/region3.d.ts.map +0 -1
- package/dist/regions/region3.js.map +0 -1
- package/dist/regions/region4.d.ts.map +0 -1
- package/dist/regions/region4.js.map +0 -1
- package/dist/regions/region5.d.ts.map +0 -1
- package/dist/regions/region5.js.map +0 -1
- package/dist/regions.d.ts.map +0 -1
- package/dist/regions.js.map +0 -1
- package/dist/saturation/common.d.ts.map +0 -1
- package/dist/saturation/common.js.map +0 -1
- package/dist/saturation/region4-boundaries.d.ts.map +0 -1
- package/dist/saturation/region4-boundaries.js.map +0 -1
- package/dist/saturation/region4-hs.d.ts.map +0 -1
- package/dist/saturation/region4-hs.js.map +0 -1
- package/dist/saturation/two-phase.d.ts.map +0 -1
- package/dist/saturation/two-phase.js.map +0 -1
- package/dist/saturation.d.ts.map +0 -1
- package/dist/saturation.js.map +0 -1
- package/dist/solvers/bracketed-newton.d.ts.map +0 -1
- package/dist/solvers/bracketed-newton.js.map +0 -1
- package/dist/solvers/nelder-mead.d.ts +0 -17
- package/dist/solvers/nelder-mead.d.ts.map +0 -1
- package/dist/solvers/nelder-mead.js +0 -116
- package/dist/solvers/nelder-mead.js.map +0 -1
- package/dist/solvers/newton-raphson.d.ts.map +0 -1
- package/dist/solvers/newton-raphson.js.map +0 -1
- package/dist/transport/properties.d.ts.map +0 -1
- package/dist/transport/properties.js.map +0 -1
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 2.2.0
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Improved backward-solver accuracy, robustness, and performance.
|
|
10
|
+
- Fixed saturation-region detection and package validation.
|
|
11
|
+
- Requires Node.js `>=20.19.0`.
|
|
12
|
+
|
|
13
|
+
## 2.1.5
|
|
14
|
+
|
|
15
|
+
- fix some issues
|
|
16
|
+
|
|
5
17
|
## 2.1.2
|
|
6
18
|
|
|
7
19
|
- fix some issues
|
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# `iapws-if97`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/jltonghui/iapws-if97/actions/workflows/ci.yml)
|
|
4
4
|
|
|
5
|
-
|
|
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.
|
|
6
|
+
|
|
7
|
+
It includes forward and backward state solvers, saturation solvers, and transport-property helpers.
|
|
6
8
|
|
|
7
9
|
## Features
|
|
8
10
|
|
|
@@ -11,21 +13,19 @@ This library provides forward and backward state solvers, saturation solvers, an
|
|
|
11
13
|
- Transport properties: viscosity, thermal conductivity, surface tension, dielectric constant, and ionization constant
|
|
12
14
|
- Verified against official IAPWS tables and published engineering references
|
|
13
15
|
|
|
14
|
-
## Project Origin
|
|
15
|
-
|
|
16
|
-
> `iapws-if97` is the core calculation engine behind the WeChat Mini Program "汽水计算器" (`wxid: wx7201fd1713b524e5`). Since its launch in 2019, it has served nearly 20,000 users. With the help of AI, this edition has been updated to incorporate `R11-24 (2024)`. I am open-sourcing it in the hope that it will help others with similar engineering needs.
|
|
17
|
-
|
|
18
|
-
<p align="right">-- Retired Thermodynamic Engineer, Shuping</p>
|
|
19
|
-
|
|
20
16
|
## Installation
|
|
21
17
|
|
|
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.
|
|
19
|
+
|
|
22
20
|
```bash
|
|
23
21
|
npm install iapws-if97
|
|
24
22
|
```
|
|
25
23
|
|
|
26
|
-
## Quick
|
|
24
|
+
## Quick start
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
Save the following as `example.mjs` and run it with `node example.mjs`:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
29
|
import { solve, solvePT, solvePx } from 'iapws-if97';
|
|
30
30
|
|
|
31
31
|
const a = solvePT(3, 300);
|
|
@@ -39,15 +39,20 @@ console.log(c.quality); // 0.5
|
|
|
39
39
|
|
|
40
40
|
## Main API
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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]` |
|
|
52
|
+
|
|
53
|
+
All numeric inputs must be finite numbers.
|
|
54
|
+
|
|
55
|
+
### Unified `solve()`
|
|
51
56
|
|
|
52
57
|
Use `solve({ mode, ... })` when the input pair is determined at runtime:
|
|
53
58
|
|
|
@@ -57,30 +62,33 @@ import { solve } from 'iapws-if97';
|
|
|
57
62
|
const state = solve({ mode: 'PT', p: 16, T: 823.15 });
|
|
58
63
|
```
|
|
59
64
|
|
|
60
|
-
|
|
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` |
|
|
61
77
|
|
|
62
78
|
```ts
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
79
|
+
import type { SolveInput } from 'iapws-if97';
|
|
80
|
+
import { solve } from 'iapws-if97';
|
|
66
81
|
|
|
67
|
-
|
|
82
|
+
const shortForm: SolveInput = { mode: 'PT', p: 16, T: 823.15 };
|
|
83
|
+
const longForm: SolveInput = { mode: 'PT', pressure: 16, temperature: 823.15 };
|
|
68
84
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
| { mode: 'PT'; p: number; T: number }
|
|
72
|
-
| { mode: 'PH'; p: number; h: number }
|
|
73
|
-
| { mode: 'PS'; p: number; s: number }
|
|
74
|
-
| { mode: 'HS'; h: number; s: number }
|
|
75
|
-
| { mode: 'Px'; p: number; x: number }
|
|
76
|
-
| { mode: 'Tx'; T: number; x: number }
|
|
77
|
-
| { mode: 'TH'; T: number; h: number }
|
|
78
|
-
| { mode: 'TS'; T: number; s: number };
|
|
85
|
+
const a = solve(shortForm);
|
|
86
|
+
const b = solve(longForm);
|
|
79
87
|
```
|
|
80
88
|
|
|
81
|
-
You can
|
|
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.
|
|
82
90
|
|
|
83
|
-
## Solver
|
|
91
|
+
## Solver return value
|
|
84
92
|
|
|
85
93
|
All solvers return a `SteamState` object containing both thermodynamic and transport properties:
|
|
86
94
|
|
|
@@ -108,16 +116,16 @@ type SteamState = {
|
|
|
108
116
|
};
|
|
109
117
|
```
|
|
110
118
|
|
|
111
|
-
`SteamState` always uses canonical property names.
|
|
119
|
+
`SteamState` always uses canonical property names.
|
|
112
120
|
|
|
113
121
|
**Notes:**
|
|
114
122
|
|
|
115
|
-
- `quality` is `null` for single-phase states
|
|
123
|
+
- `quality` is `null` for single-phase states; it is only defined on the saturation line.
|
|
116
124
|
- In two-phase mixtures (`0 < x < 1`), `cp`, `cv`, `speedOfSound`, `isobaricExpansion`, `isothermalCompressibility`, `viscosity`, `thermalConductivity`, `dielectricConstant`, and `ionizationConstant` are `null`.
|
|
117
125
|
- Saturation endpoints (`x = 0` or `x = 1`) still expose single-phase transport properties even though they carry Region 4 metadata.
|
|
118
126
|
- `solvePT(p, T)` is a single-phase solver. On the subcritical saturation boundary it resolves to the liquid side.
|
|
119
127
|
- `surfaceTension` is only available for Region 4 saturation states below the critical point; otherwise `null`.
|
|
120
|
-
- `density` is provided directly
|
|
128
|
+
- `density` is provided directly, so there is no need to invert `specificVolume`.
|
|
121
129
|
- `ionizationConstant` is `null` outside the IAPWS validity range for that correlation.
|
|
122
130
|
|
|
123
131
|
## Units
|
|
@@ -140,19 +148,59 @@ type SteamState = {
|
|
|
140
148
|
|
|
141
149
|
Any field typed as `number | null` returns `null` when the property is undefined for the given state.
|
|
142
150
|
|
|
143
|
-
##
|
|
151
|
+
## Advanced imports
|
|
152
|
+
|
|
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:
|
|
154
|
+
|
|
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';
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
These are low-level mathematical interfaces:
|
|
171
|
+
|
|
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`.
|
|
144
176
|
|
|
145
|
-
|
|
177
|
+
## Transport correlation limits
|
|
178
|
+
|
|
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 |
|
|
182
|
+
| --- | --- |
|
|
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:
|
|
146
194
|
- `solvePx(p, x)` accepts `Pt ≤ p < Pc`
|
|
147
195
|
- `solveTx(T, x)` accepts `Tt = 273.16 K ≤ T < Tc`
|
|
148
|
-
- The
|
|
196
|
+
- The triple point is supported as a saturation-state boundary:
|
|
149
197
|
- `solvePx(Pt, x)` is valid
|
|
150
198
|
- `solveTx(Tt, x)` is valid
|
|
151
199
|
- `273.15 K` is treated as a low-level extrapolation boundary only.
|
|
152
|
-
- The exact critical point
|
|
153
|
-
- `solveTH(T, h)` and `solveTS(T, s)`
|
|
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.
|
|
154
202
|
|
|
155
|
-
## Errors and
|
|
203
|
+
## Errors and limits
|
|
156
204
|
|
|
157
205
|
The library throws typed errors:
|
|
158
206
|
|
|
@@ -160,14 +208,18 @@ The library throws typed errors:
|
|
|
160
208
|
| --- | --- |
|
|
161
209
|
| `OutOfRangeError` | Input is outside the supported IF97 range |
|
|
162
210
|
| `ConvergenceError` | An internal iterative solve failed to converge |
|
|
163
|
-
| `IF97Error` | Base class for
|
|
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 |
|
|
164
212
|
|
|
165
|
-
|
|
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.
|
|
166
214
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
215
|
+
## Thermodynamic validity
|
|
216
|
+
|
|
217
|
+
The thermodynamic solvers follow the piecewise IF97 industrial range:
|
|
218
|
+
|
|
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).
|
|
171
223
|
|
|
172
224
|
## Verification
|
|
173
225
|
|
|
@@ -181,60 +233,39 @@ The test suite covers:
|
|
|
181
233
|
- Coverage thresholds enforced locally
|
|
182
234
|
- ASME and GB/T steam-table comparisons against published values
|
|
183
235
|
|
|
184
|
-
|
|
236
|
+
For a clean local verification run:
|
|
185
237
|
|
|
186
238
|
```bash
|
|
187
|
-
npm
|
|
239
|
+
npm ci
|
|
240
|
+
npm run test:package
|
|
188
241
|
npm test
|
|
242
|
+
```
|
|
243
|
+
|
|
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
|
|
189
247
|
npm run test:coverage
|
|
190
248
|
npm run test:standards
|
|
191
249
|
```
|
|
192
250
|
|
|
193
|
-
## Integration
|
|
251
|
+
## Integration validation
|
|
194
252
|
|
|
195
253
|

|
|
196
254
|
|
|
197
|
-
This Mollier `h-s` diagram was generated with `iapws-if97` as
|
|
198
|
-
|
|
199
|
-
### ASME Validation Snapshot
|
|
200
|
-
|
|
201
|
-
Compares saturation states against *ASME International Steam Tables for Industrial Use*, 3rd ed., Table S-2 ("Properties of Saturated Water and Steam — Pressure").
|
|
202
|
-
Each case checks 7 values: saturation temperature, liquid/vapor specific volume, enthalpy, and entropy.
|
|
203
|
-
The snapshot below reflects the current `tests/standards-asme` regression run.
|
|
204
|
-
|
|
205
|
-
| ASME case | Pressure (MPa) | Points checked | Max relative error |
|
|
206
|
-
| --- | ---: | ---: | ---: |
|
|
207
|
-
| Table S-2 @ 0.01 MPa | 0.01 | 7 | 0.0257993% |
|
|
208
|
-
| Table S-2 @ 0.10 MPa | 0.10 | 7 | 0.0141744% |
|
|
209
|
-
| Table S-2 @ 1.00 MPa | 1.00 | 7 | 0.0207405% |
|
|
210
|
-
| Table S-2 @ 5.0 MPa | 5.0 | 7 | 0.0315405% |
|
|
211
|
-
| Table S-2 @ 10.0 MPa | 10.0 | 7 | 0.0261599% |
|
|
212
|
-
| Table S-2 @ 20.0 MPa | 20.0 | 7 | 0.0173004% |
|
|
213
|
-
| Overall worst case | - | 42 | 0.0315405% |
|
|
255
|
+
This Mollier `h-s` diagram was generated with `iapws-if97` as an end-to-end check of the calculation pipeline.
|
|
214
256
|
|
|
215
|
-
The
|
|
257
|
+
The standards tests check the published tables below. Both suites enforce `maxRelativeError < 5e-4` (less than `0.05%`).
|
|
216
258
|
|
|
217
|
-
|
|
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%` |
|
|
218
263
|
|
|
219
|
-
|
|
220
|
-
Each case checks 4 values at `10 MPa`: specific volume, enthalpy, entropy, and speed of sound.
|
|
221
|
-
The snapshot below reflects the current `tests/standards-cn` regression run.
|
|
222
|
-
|
|
223
|
-
| GB/T case | Pressure (MPa) | Temperature (°C) | Points checked | Max relative error |
|
|
224
|
-
| --- | ---: | ---: | ---: | ---: |
|
|
225
|
-
| Table A.3 @ 10 MPa, 350 C | 10 | 350 | 4 | 0.0007020% |
|
|
226
|
-
| Table A.3 @ 10 MPa, 400 C | 10 | 400 | 4 | 0.0004650% |
|
|
227
|
-
| Table A.3 @ 10 MPa, 500 C | 10 | 500 | 4 | 0.0006808% |
|
|
228
|
-
| Table A.3 @ 10 MPa, 600 C | 10 | 600 | 4 | 0.0005630% |
|
|
229
|
-
| Table A.3 @ 10 MPa, 700 C | 10 | 700 | 4 | 0.0004072% |
|
|
230
|
-
| Table A.3 @ 10 MPa, 800 C | 10 | 800 | 4 | 0.0004146% |
|
|
231
|
-
| Overall worst case | - | - | 24 | 0.0007020% |
|
|
232
|
-
|
|
233
|
-
The current GB/T regression threshold is `maxRelativeError < 5e-4` (less than `0.05%`).
|
|
264
|
+
See [`tests/standards-asme`](tests/standards-asme) and [`tests/standards-cn`](tests/standards-cn) for the source values and per-case comparisons.
|
|
234
265
|
|
|
235
266
|
## TypeScript
|
|
236
267
|
|
|
237
|
-
The package ships with
|
|
268
|
+
The package ships with generated TypeScript declarations for the root and every public subpath.
|
|
238
269
|
|
|
239
270
|
```ts
|
|
240
271
|
import type { SolveInput, SteamState } from 'iapws-if97';
|
|
@@ -251,11 +282,20 @@ if (state.region === Region.Region1) {
|
|
|
251
282
|
## References
|
|
252
283
|
|
|
253
284
|
- [IAPWS official website](https://www.iapws.org/)
|
|
254
|
-
- IAPWS R7-97(2012),
|
|
255
|
-
- IAPWS supplementary releases for
|
|
256
|
-
- IAPWS
|
|
257
|
-
- IAPWS
|
|
258
|
-
- IAPWS
|
|
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)
|
|
293
|
+
|
|
294
|
+
## Project origin
|
|
295
|
+
|
|
296
|
+
> `iapws-if97` began as the calculation engine behind the WeChat Mini Program "汽水计算器" (`wxid: wx7201fd1713b524e5`). Since its 2019 launch, it has served more than 20,000 users. AI-assisted review helped bring this open-source edition up to date with IAPWS `R11-24 (2024)`. I am sharing the engine so it can reach engineers far beyond the original program.
|
|
297
|
+
|
|
298
|
+
<p align="right">Shuping, retired thermodynamic engineer</p>
|
|
259
299
|
|
|
260
300
|
## License
|
|
261
301
|
|
|
@@ -5,21 +5,21 @@
|
|
|
5
5
|
* (enthalpy or entropy) using a bracketed Newton method.
|
|
6
6
|
*/
|
|
7
7
|
import type { BasicProperties } from '../types.js';
|
|
8
|
-
|
|
8
|
+
/** Property being inverted against pressure at fixed temperature. */
|
|
9
|
+
export type FixedTemperatureProperty = 'enthalpy' | 'entropy';
|
|
9
10
|
/**
|
|
10
11
|
* Solve for pressure at fixed temperature by matching a target property value.
|
|
11
12
|
*
|
|
12
13
|
* Evaluates the region equation at the bracket endpoints first (short-circuit
|
|
13
|
-
* if either already matches), then runs a bracketed Newton iteration
|
|
14
|
+
* if either already matches), then runs a bracketed Newton iteration driven by
|
|
15
|
+
* the analytic pressure derivative.
|
|
14
16
|
*
|
|
15
17
|
* @param evaluator - Region-specific equation returning BasicProperties from (p, T)
|
|
16
18
|
* @param T - Fixed temperature [K]
|
|
17
19
|
* @param target - Target property value (enthalpy or entropy)
|
|
18
20
|
* @param lower - Lower pressure bracket [MPa]
|
|
19
21
|
* @param upper - Upper pressure bracket [MPa]
|
|
20
|
-
* @param
|
|
22
|
+
* @param property - Which property `target` represents
|
|
21
23
|
* @param solverName - Label used in error messages
|
|
22
24
|
*/
|
|
23
|
-
export declare function solveFixedTemperaturePressure(evaluator: (p: number, T: number) => BasicProperties, T: number, target: number, lower: number, upper: number,
|
|
24
|
-
export {};
|
|
25
|
-
//# sourceMappingURL=fixed-temperature-solver.d.ts.map
|
|
25
|
+
export declare function solveFixedTemperaturePressure(evaluator: (p: number, T: number) => BasicProperties, T: number, target: number, lower: number, upper: number, property: FixedTemperatureProperty, solverName: string): BasicProperties;
|
|
@@ -1,31 +1,57 @@
|
|
|
1
1
|
import { IF97Error } from '../types.js';
|
|
2
2
|
import { bracketedNewton } from '../solvers/bracketed-newton.js';
|
|
3
|
+
import { gibbsPropertyDerivatives } from './thermodynamic-derivatives.js';
|
|
4
|
+
function propertyValue(state, property) {
|
|
5
|
+
return property === 'enthalpy' ? state.enthalpy : state.entropy;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* (∂h/∂p)_T = 1000·v(1 − Tα) or (∂s/∂p)_T = −1000·v·α, both per MPa.
|
|
9
|
+
*
|
|
10
|
+
* These are Maxwell-relation identities, so they hold for the Helmholtz-based
|
|
11
|
+
* Region 3 states as well as the Gibbs-based regions. Returns NaN when a state
|
|
12
|
+
* carries no cp/α, which makes the caller fall back to a bisection step.
|
|
13
|
+
*/
|
|
14
|
+
function pressureDerivative(state, property) {
|
|
15
|
+
const derivatives = gibbsPropertyDerivatives(state);
|
|
16
|
+
return property === 'enthalpy' ? derivatives.dhDp : derivatives.dsDp;
|
|
17
|
+
}
|
|
3
18
|
/**
|
|
4
19
|
* Solve for pressure at fixed temperature by matching a target property value.
|
|
5
20
|
*
|
|
6
21
|
* Evaluates the region equation at the bracket endpoints first (short-circuit
|
|
7
|
-
* if either already matches), then runs a bracketed Newton iteration
|
|
22
|
+
* if either already matches), then runs a bracketed Newton iteration driven by
|
|
23
|
+
* the analytic pressure derivative.
|
|
8
24
|
*
|
|
9
25
|
* @param evaluator - Region-specific equation returning BasicProperties from (p, T)
|
|
10
26
|
* @param T - Fixed temperature [K]
|
|
11
27
|
* @param target - Target property value (enthalpy or entropy)
|
|
12
28
|
* @param lower - Lower pressure bracket [MPa]
|
|
13
29
|
* @param upper - Upper pressure bracket [MPa]
|
|
14
|
-
* @param
|
|
30
|
+
* @param property - Which property `target` represents
|
|
15
31
|
* @param solverName - Label used in error messages
|
|
16
32
|
*/
|
|
17
|
-
export function solveFixedTemperaturePressure(evaluator, T, target, lower, upper,
|
|
33
|
+
export function solveFixedTemperaturePressure(evaluator, T, target, lower, upper, property, solverName) {
|
|
34
|
+
// Keyed by p, so the residual and its derivative at the same point share one
|
|
35
|
+
// equation evaluation regardless of the order the solver calls them in.
|
|
36
|
+
let cachedPressure = Number.NaN;
|
|
37
|
+
let cachedState = null;
|
|
38
|
+
const stateAt = (p) => {
|
|
39
|
+
if (p !== cachedPressure || cachedState === null) {
|
|
40
|
+
cachedPressure = p;
|
|
41
|
+
cachedState = evaluator(p, T);
|
|
42
|
+
}
|
|
43
|
+
return cachedState;
|
|
44
|
+
};
|
|
18
45
|
const lowerState = evaluator(lower, T);
|
|
19
46
|
const upperState = evaluator(upper, T);
|
|
20
|
-
if (Math.abs(
|
|
47
|
+
if (Math.abs(propertyValue(lowerState, property) - target) <= 1e-9)
|
|
21
48
|
return lowerState;
|
|
22
|
-
if (Math.abs(
|
|
49
|
+
if (Math.abs(propertyValue(upperState, property) - target) <= 1e-9)
|
|
23
50
|
return upperState;
|
|
24
|
-
const pressure = bracketedNewton((p) =>
|
|
25
|
-
const state =
|
|
51
|
+
const pressure = bracketedNewton((p) => propertyValue(stateAt(p), property) - target, lower, upper, (lower + upper) / 2, { derivative: (p) => pressureDerivative(stateAt(p), property) });
|
|
52
|
+
const state = stateAt(pressure);
|
|
26
53
|
if (!Number.isFinite(state.pressure)) {
|
|
27
54
|
throw new IF97Error(`${solverName} failed to recover a valid pressure`);
|
|
28
55
|
}
|
|
29
56
|
return state;
|
|
30
57
|
}
|
|
31
|
-
//# sourceMappingURL=fixed-temperature-solver.js.map
|
package/dist/backward/hs.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* IAPWS-IF97 Backward Equations: H-S -> P, T
|
|
3
3
|
*
|
|
4
4
|
* Given specific enthalpy and entropy, compute pressure and temperature.
|
|
5
|
-
* Uses backward P(h,s) equations for initial
|
|
5
|
+
* Uses backward P(h,s) equations for initial guesses + damped Newton refinement.
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97 Supplementary Release on Backward Equations p(h,s)
|
|
8
8
|
*/
|
|
@@ -13,4 +13,3 @@ import type { BasicProperties } from '../types.js';
|
|
|
13
13
|
* @param s - Specific entropy [kJ/(kg·K)]
|
|
14
14
|
*/
|
|
15
15
|
export declare function solveHS(h: number, s: number): BasicProperties;
|
|
16
|
-
//# sourceMappingURL=hs.d.ts.map
|
package/dist/backward/hs.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* IAPWS-IF97 Backward Equations: H-S -> P, T
|
|
3
3
|
*
|
|
4
4
|
* Given specific enthalpy and entropy, compute pressure and temperature.
|
|
5
|
-
* Uses backward P(h,s) equations for initial
|
|
5
|
+
* Uses backward P(h,s) equations for initial guesses + damped Newton refinement.
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97 Supplementary Release on Backward Equations p(h,s)
|
|
8
8
|
*/
|
|
@@ -14,12 +14,10 @@ import { region3ByRhoT } from '../regions/region3.js';
|
|
|
14
14
|
import { region5 } from '../regions/region5.js';
|
|
15
15
|
import { assertFiniteNumber } from '../core/input-validation.js';
|
|
16
16
|
import { detectRegionHS } from '../core/region-detector.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { solvePH } from './ph.js';
|
|
17
|
+
import { dampedNewton2D } from '../solvers/damped-newton-2d.js';
|
|
18
|
+
import { r1BackwardT, r2BackwardT, r3BackwardPHInitial } from './ph.js';
|
|
20
19
|
import { validateBackwardState } from './solution-validation.js';
|
|
21
|
-
import {
|
|
22
|
-
import { backwardConstraintTolerance } from './tolerances.js';
|
|
20
|
+
import { gibbsPropertyDerivatives, helmholtzPropertyDerivatives, } from './thermodynamic-derivatives.js';
|
|
23
21
|
import { tryRegion4HSState, } from '../saturation/region4-hs.js';
|
|
24
22
|
import { assertCriticalRegion4HSInput, } from '../saturation/region4-boundaries.js';
|
|
25
23
|
// ─── Backward Polynomial Evaluator ─────────────────────────────────────────
|
|
@@ -159,21 +157,52 @@ function r3Phs(h, s) {
|
|
|
159
157
|
return r3aPhs(h, s);
|
|
160
158
|
return r3bPhs(h, s);
|
|
161
159
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
160
|
+
function solveGibbsHS(h, s, initial, stateAt) {
|
|
161
|
+
const hScale = Math.max(1, Math.abs(h));
|
|
162
|
+
const sScale = Math.max(1, Math.abs(s));
|
|
163
|
+
const [p, T] = dampedNewton2D(([candidateP, candidateT]) => {
|
|
164
|
+
const state = stateAt(candidateP, candidateT);
|
|
165
|
+
const derivatives = gibbsPropertyDerivatives(state);
|
|
166
|
+
return {
|
|
167
|
+
residual: [
|
|
168
|
+
(state.enthalpy - h) / hScale,
|
|
169
|
+
(state.entropy - s) / sScale,
|
|
170
|
+
],
|
|
171
|
+
jacobian: [
|
|
172
|
+
[derivatives.dhDp / hScale, derivatives.dhDT / hScale],
|
|
173
|
+
[derivatives.dsDp / sScale, derivatives.dsDT / sScale],
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
}, initial, {
|
|
177
|
+
isValid: ([candidateP, candidateT]) => candidateP > 0 && candidateT > 0,
|
|
178
|
+
});
|
|
179
|
+
return stateAt(p, T);
|
|
180
|
+
}
|
|
181
|
+
function solveRegion3HS(h, s, rho0, T0) {
|
|
182
|
+
const hScale = Math.max(1, Math.abs(h));
|
|
183
|
+
const sScale = Math.max(1, Math.abs(s));
|
|
184
|
+
const [rho, T] = dampedNewton2D(([candidateRho, candidateT]) => {
|
|
185
|
+
const state = region3ByRhoT(candidateRho, candidateT);
|
|
186
|
+
const derivatives = helmholtzPropertyDerivatives(state, candidateRho);
|
|
187
|
+
return {
|
|
188
|
+
residual: [
|
|
189
|
+
(state.enthalpy - h) / hScale,
|
|
190
|
+
(state.entropy - s) / sScale,
|
|
191
|
+
],
|
|
192
|
+
jacobian: [
|
|
193
|
+
[derivatives.dhDrho / hScale, derivatives.dhDT / hScale],
|
|
194
|
+
[derivatives.dsDrho / sScale, derivatives.dsDT / sScale],
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
}, [rho0, T0], {
|
|
198
|
+
// Tighter than the 1e-10 default and load-bearing: near the 100 MPa ceiling
|
|
199
|
+
// Region 3 is nearly incompressible, so a residual the default would accept
|
|
200
|
+
// still lands p far enough outside [P_MIN, P_MAX] to fail envelope
|
|
201
|
+
// validation. Covered by the p=100 MPa cases in newton-regressions.test.ts.
|
|
202
|
+
tolerance: 1e-12,
|
|
203
|
+
isValid: ([candidateRho, candidateT]) => candidateRho > 0 && candidateT > 0,
|
|
204
|
+
});
|
|
205
|
+
return region3ByRhoT(rho, T);
|
|
177
206
|
}
|
|
178
207
|
// ─── Main HS Solver ─────────────────────────────────────────────────────────
|
|
179
208
|
/**
|
|
@@ -191,53 +220,46 @@ export function solveHS(h, s) {
|
|
|
191
220
|
throw new OutOfRangeError('Entropy', s, C.S_MIN, C.S_MAX);
|
|
192
221
|
}
|
|
193
222
|
assertCriticalRegion4HSInput(h, s, 'solveHS');
|
|
194
|
-
const region4State = tryRegion4HSState(h, s);
|
|
195
|
-
if (region4State !== null) {
|
|
196
|
-
return validateBackwardState(region4State, [
|
|
197
|
-
{ label: 'enthalpy', expected: h },
|
|
198
|
-
{ label: 'entropy', expected: s },
|
|
199
|
-
], { solverName: 'solveHS', expectedRegion: Region.Region4 });
|
|
200
|
-
}
|
|
201
223
|
const region = detectRegionHS(h, s);
|
|
202
224
|
switch (region) {
|
|
203
225
|
case Region.Region1: {
|
|
204
226
|
const P0 = r1Phs(h, s);
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
return validateBackwardState(region1(sol.x[0], sol.x[1]), [
|
|
227
|
+
const state = solveGibbsHS(h, s, [P0, r1BackwardT(P0, h)], region1);
|
|
228
|
+
return validateBackwardState(state, [
|
|
208
229
|
{ label: 'enthalpy', expected: h },
|
|
209
230
|
{ label: 'entropy', expected: s },
|
|
210
231
|
], { solverName: 'solveHS', expectedRegion: Region.Region1 });
|
|
211
232
|
}
|
|
212
233
|
case Region.Region2: {
|
|
213
234
|
const P0 = r2Phs(h, s);
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
Math.abs(region2(pair[0], pair[1]).entropy - s), [P0, T0]);
|
|
217
|
-
return validateBackwardState(region2(sol.x[0], sol.x[1]), [
|
|
235
|
+
const state = solveGibbsHS(h, s, [P0, r2BackwardT(P0, h)], region2);
|
|
236
|
+
return validateBackwardState(state, [
|
|
218
237
|
{ label: 'enthalpy', expected: h },
|
|
219
238
|
{ label: 'entropy', expected: s },
|
|
220
239
|
], { solverName: 'solveHS', expectedRegion: Region.Region2 });
|
|
221
240
|
}
|
|
222
241
|
case Region.Region3: {
|
|
223
242
|
const P0 = r3Phs(h, s);
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
const sol = nelderMead((pair) => Math.abs(region3ByRhoT(pair[0], pair[1]).enthalpy - h) +
|
|
228
|
-
Math.abs(region3ByRhoT(pair[0], pair[1]).entropy - s), [rho0, T0]);
|
|
229
|
-
return validateBackwardState(region3ByRhoT(sol.x[0], sol.x[1]), [
|
|
243
|
+
const initial = r3BackwardPHInitial(P0, h);
|
|
244
|
+
const state = solveRegion3HS(h, s, initial.rho, initial.T);
|
|
245
|
+
return validateBackwardState(state, [
|
|
230
246
|
{ label: 'enthalpy', expected: h },
|
|
231
247
|
{ label: 'entropy', expected: s },
|
|
232
248
|
], { solverName: 'solveHS', expectedRegion: Region.Region3 });
|
|
233
249
|
}
|
|
234
250
|
case Region.Region4: {
|
|
235
|
-
|
|
251
|
+
const state = tryRegion4HSState(h, s);
|
|
252
|
+
if (state === null) {
|
|
253
|
+
throw new IF97Error('solveHS identified Region 4 but failed to construct a valid saturation state');
|
|
254
|
+
}
|
|
255
|
+
return validateBackwardState(state, [
|
|
256
|
+
{ label: 'enthalpy', expected: h },
|
|
257
|
+
{ label: 'entropy', expected: s },
|
|
258
|
+
], { solverName: 'solveHS', expectedRegion: Region.Region4 });
|
|
236
259
|
}
|
|
237
260
|
case Region.Region5: {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
return validateBackwardState(region5(sol.x[0], sol.x[1]), [
|
|
261
|
+
const state = solveGibbsHS(h, s, [1, 1400], region5);
|
|
262
|
+
return validateBackwardState(state, [
|
|
241
263
|
{ label: 'enthalpy', expected: h },
|
|
242
264
|
{ label: 'entropy', expected: s },
|
|
243
265
|
], { solverName: 'solveHS', expectedRegion: Region.Region5 });
|
|
@@ -246,4 +268,3 @@ export function solveHS(h, s) {
|
|
|
246
268
|
throw new IF97Error(`Cannot determine region for h=${h} kJ/kg, s=${s} kJ/(kg·K)`);
|
|
247
269
|
}
|
|
248
270
|
}
|
|
249
|
-
//# sourceMappingURL=hs.js.map
|