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
|
@@ -16,7 +16,7 @@ import type { BasicProperties } from '../types.js';
|
|
|
16
16
|
* @param rho0 - Initial density guess [kg/m³]
|
|
17
17
|
* @returns Basic thermodynamic properties at the converged density
|
|
18
18
|
*/
|
|
19
|
-
export declare function solveRegion3StateAtPressure(p: number, T: number, rho0: number): BasicProperties;
|
|
19
|
+
export declare function solveRegion3StateAtPressure(p: number, T: number, rho0: number, pressureLow?: number): BasicProperties;
|
|
20
20
|
/**
|
|
21
21
|
* Compute Region 3 basic properties from pressure and temperature.
|
|
22
22
|
*
|
package/dist/core/region3-pt.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as C from '../constants.js';
|
|
2
|
-
import { IF97Error } from '../types.js';
|
|
3
|
-
import { region3ByRhoT } from '../regions/region3.js';
|
|
2
|
+
import { ConvergenceError, IF97Error } from '../types.js';
|
|
3
|
+
import { region3ByRhoT, region3PressureResidual } from '../regions/region3.js';
|
|
4
4
|
import { region3Volume } from '../regions/region3-subregions.js';
|
|
5
|
+
import { saturationPressure, saturationPressurePair } from '../regions/region4.js';
|
|
5
6
|
import { newtonRaphson } from '../solvers/newton-raphson.js';
|
|
7
|
+
import { bracketedNewton } from '../solvers/bracketed-newton.js';
|
|
6
8
|
/**
|
|
7
9
|
* Solve for the Region 3 state at a target pressure and temperature.
|
|
8
10
|
*
|
|
@@ -14,9 +16,8 @@ import { newtonRaphson } from '../solvers/newton-raphson.js';
|
|
|
14
16
|
* @param rho0 - Initial density guess [kg/m³]
|
|
15
17
|
* @returns Basic thermodynamic properties at the converged density
|
|
16
18
|
*/
|
|
17
|
-
export function solveRegion3StateAtPressure(p, T, rho0) {
|
|
18
|
-
//
|
|
19
|
-
// equation evaluation regardless of the order the solver calls them in.
|
|
19
|
+
export function solveRegion3StateAtPressure(p, T, rho0, pressureLow = 0) {
|
|
20
|
+
// Cache full EOS properties for the density derivative and final state.
|
|
20
21
|
let cachedRho = Number.NaN;
|
|
21
22
|
let cachedState = null;
|
|
22
23
|
const stateAt = (rho) => {
|
|
@@ -26,18 +27,33 @@ export function solveRegion3StateAtPressure(p, T, rho0) {
|
|
|
26
27
|
}
|
|
27
28
|
return cachedState;
|
|
28
29
|
};
|
|
29
|
-
const
|
|
30
|
-
if (!Number.isFinite(rhoGuess) || rhoGuess <= 0)
|
|
30
|
+
const residual = (rhoGuess) => {
|
|
31
|
+
if (!Number.isFinite(rhoGuess) || rhoGuess <= 0)
|
|
31
32
|
return Number.NaN;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (!Number.isFinite(rhoGuess) || rhoGuess <= 0)
|
|
33
|
+
return region3PressureResidual(rhoGuess, T, p, pressureLow);
|
|
34
|
+
};
|
|
35
|
+
const derivative = (rhoGuess) => {
|
|
36
|
+
if (!Number.isFinite(rhoGuess) || rhoGuess <= 0)
|
|
36
37
|
return Number.NaN;
|
|
37
|
-
}
|
|
38
38
|
const kappa = stateAt(rhoGuess).isothermalCompressibility;
|
|
39
39
|
return kappa === null ? Number.NaN : 1 / (rhoGuess * kappa);
|
|
40
|
-
}
|
|
40
|
+
};
|
|
41
|
+
let rho;
|
|
42
|
+
try {
|
|
43
|
+
rho = newtonRaphson(residual, rho0, derivative, { tolerance: 1e-12 });
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Subcritical brackets can cross a spinodal and change the requested phase.
|
|
47
|
+
if (!(error instanceof ConvergenceError) || T < C.Tc)
|
|
48
|
+
throw error;
|
|
49
|
+
const lower = rho0 / 2;
|
|
50
|
+
const upper = rho0 * 2;
|
|
51
|
+
if (!(derivative(lower) > 0 && derivative(upper) > 0 && residual(lower) * residual(upper) <= 0))
|
|
52
|
+
throw error;
|
|
53
|
+
rho = bracketedNewton(residual, lower, upper, rho0, {
|
|
54
|
+
derivative, tolerance: 1e-12, residualTolerance: 0,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
41
57
|
return stateAt(rho);
|
|
42
58
|
}
|
|
43
59
|
/**
|
|
@@ -55,10 +71,20 @@ export function solveRegion3PTBasic(p, T) {
|
|
|
55
71
|
if (p === C.Pc && T === C.Tc) {
|
|
56
72
|
return region3ByRhoT(C.RHOc, T);
|
|
57
73
|
}
|
|
58
|
-
const
|
|
74
|
+
const saturation = T < C.Tc ? saturationPressure(T) : null;
|
|
75
|
+
const pressurePair = p === saturation ? saturationPressurePair(T) : null;
|
|
76
|
+
const pressureLow = pressurePair?.[0] === p ? pressurePair[1] : 0;
|
|
77
|
+
const state = solveRegion3StateAtPressure(p, T, 1 / region3Volume(p, T), pressureLow);
|
|
59
78
|
const relErr = Math.abs(state.pressure - p) / p;
|
|
60
|
-
if (relErr > 1e-
|
|
79
|
+
if (relErr > 1e-12) {
|
|
61
80
|
throw new IF97Error(`solveRegion3PTBasic: density solve did not converge — target P=${p} MPa, got P=${state.pressure.toFixed(6)} MPa (relErr=${relErr.toExponential(2)})`);
|
|
62
81
|
}
|
|
63
|
-
|
|
82
|
+
const rho = 1 / state.specificVolume;
|
|
83
|
+
const liquid = saturation !== null && p >= saturation;
|
|
84
|
+
if ((T < C.Tc && (liquid ? rho <= C.RHOc : rho >= C.RHOc)) ||
|
|
85
|
+
![state.cp, state.cv, state.isothermalCompressibility, state.speedOfSound]
|
|
86
|
+
.every((value) => value !== null && Number.isFinite(value) && value > 0)) {
|
|
87
|
+
throw new IF97Error(`Region 3 numerical inconsistency at p=${p} MPa, T=${T} K: cannot construct the requested stable ${T < C.Tc ? liquid ? 'liquid' : 'vapor' : 'single-phase'} EOS branch`);
|
|
88
|
+
}
|
|
89
|
+
return { ...state, pressure: p };
|
|
64
90
|
}
|
|
@@ -8,7 +8,7 @@ function pickNumericAlias(input, shortKey, longKey, label) {
|
|
|
8
8
|
}
|
|
9
9
|
if (shortValue !== undefined &&
|
|
10
10
|
longValue !== undefined &&
|
|
11
|
-
|
|
11
|
+
shortValue !== longValue) {
|
|
12
12
|
throw new IF97Error(`solve input received conflicting values for '${shortKey}' and '${longKey}'`);
|
|
13
13
|
}
|
|
14
14
|
const value = shortValue ?? longValue;
|
|
@@ -17,6 +17,9 @@ function pickNumericAlias(input, shortKey, longKey, label) {
|
|
|
17
17
|
}
|
|
18
18
|
// Normalize public solve() aliases to the canonical short-key form used internally.
|
|
19
19
|
export function normalizeSolveInput(input) {
|
|
20
|
+
if (typeof input !== 'object' || input === null) {
|
|
21
|
+
throw new IF97Error('solve input must be a non-null object');
|
|
22
|
+
}
|
|
20
23
|
const raw = input;
|
|
21
24
|
switch (input.mode) {
|
|
22
25
|
case 'PT':
|
package/dist/core/solver.d.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Main IF97 solve dispatcher.
|
|
3
|
-
* Computes full thermodynamic
|
|
3
|
+
* Computes basic or full thermodynamic states.
|
|
4
4
|
*/
|
|
5
|
-
import type { SteamState, SolveInput } from '../types.js';
|
|
5
|
+
import type { BasicProperties, SteamState, SolveInput } from '../types.js';
|
|
6
6
|
/**
|
|
7
|
-
* Solve for full thermodynamic state given pressure and temperature.
|
|
8
|
-
*
|
|
9
|
-
* @param p - Pressure [MPa]
|
|
10
|
-
* @param T - Temperature [K]
|
|
11
|
-
* @returns Complete steam state with transport properties
|
|
7
|
+
* Solve for full thermodynamic state given pressure [MPa] and temperature [K].
|
|
12
8
|
*/
|
|
13
9
|
export declare function solvePT(p: number, T: number): SteamState;
|
|
14
10
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* and accepts either shorthand or long-form input field names.
|
|
11
|
+
* Compute basic thermodynamic properties from any supported input pair.
|
|
12
|
+
* Accepts either shorthand or long-form input field names, without transport enrichment.
|
|
18
13
|
*/
|
|
14
|
+
export declare function solveBasic(input: SolveInput): BasicProperties;
|
|
15
|
+
/** Compute the full thermodynamic state, including transport properties. */
|
|
19
16
|
export declare function solve(input: SolveInput): SteamState;
|
package/dist/core/solver.js
CHANGED
|
@@ -44,13 +44,13 @@ function enrichState(basic) {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
* Solve for
|
|
47
|
+
* Solve for basic thermodynamic state given pressure and temperature.
|
|
48
48
|
*
|
|
49
49
|
* @param p - Pressure [MPa]
|
|
50
50
|
* @param T - Temperature [K]
|
|
51
|
-
* @returns
|
|
51
|
+
* @returns Basic thermodynamic properties without transport
|
|
52
52
|
*/
|
|
53
|
-
|
|
53
|
+
function solvePTBasic(p, T) {
|
|
54
54
|
assertFiniteNumber('Pressure', p);
|
|
55
55
|
assertFiniteNumber('Temperature', T);
|
|
56
56
|
if (p < C.P_MIN || p > C.P_MAX) {
|
|
@@ -62,7 +62,7 @@ export function solvePT(p, T) {
|
|
|
62
62
|
if (T > C.R5_T_MIN && p > C.R5_P_MAX) {
|
|
63
63
|
throw new OutOfRangeError('Pressure', p, C.P_MIN, C.R5_P_MAX);
|
|
64
64
|
}
|
|
65
|
-
if (
|
|
65
|
+
if (T === C.Tc && p === C.Pc) {
|
|
66
66
|
throw new IF97Error(`solvePT does not support the exact critical point P=${C.Pc} MPa, T=${C.Tc} K because derivative properties become singular`);
|
|
67
67
|
}
|
|
68
68
|
const region = detectRegionPT(p, T);
|
|
@@ -83,25 +83,34 @@ export function solvePT(p, T) {
|
|
|
83
83
|
default:
|
|
84
84
|
throw new IF97Error(`Cannot determine region for P=${p} MPa, T=${T} K`);
|
|
85
85
|
}
|
|
86
|
-
return
|
|
86
|
+
return basic;
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
|
-
*
|
|
90
|
-
* Routes to the correct solver based on input mode, enriches with transport properties,
|
|
91
|
-
* and accepts either shorthand or long-form input field names.
|
|
89
|
+
* Solve for full thermodynamic state given pressure [MPa] and temperature [K].
|
|
92
90
|
*/
|
|
93
|
-
export function
|
|
91
|
+
export function solvePT(p, T) {
|
|
92
|
+
return enrichState(solvePTBasic(p, T));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Compute basic thermodynamic properties from any supported input pair.
|
|
96
|
+
* Accepts either shorthand or long-form input field names, without transport enrichment.
|
|
97
|
+
*/
|
|
98
|
+
export function solveBasic(input) {
|
|
94
99
|
const normalized = normalizeSolveInput(input);
|
|
95
100
|
switch (normalized.mode) {
|
|
96
|
-
case 'PT': return
|
|
97
|
-
case 'PH': return
|
|
98
|
-
case 'PS': return
|
|
99
|
-
case 'HS': return
|
|
100
|
-
case 'Px': return
|
|
101
|
-
case 'Tx': return
|
|
102
|
-
case 'TH': return
|
|
103
|
-
case 'TS': return
|
|
101
|
+
case 'PT': return solvePTBasic(normalized.p, normalized.T);
|
|
102
|
+
case 'PH': return solvePH(normalized.p, normalized.h);
|
|
103
|
+
case 'PS': return solvePS(normalized.p, normalized.s);
|
|
104
|
+
case 'HS': return solveHS(normalized.h, normalized.s);
|
|
105
|
+
case 'Px': return solvePx(normalized.p, normalized.x);
|
|
106
|
+
case 'Tx': return solveTx(normalized.T, normalized.x);
|
|
107
|
+
case 'TH': return solveTH(normalized.T, normalized.h);
|
|
108
|
+
case 'TS': return solveTS(normalized.T, normalized.s);
|
|
104
109
|
default:
|
|
105
110
|
throw new IF97Error(`Unsupported solve mode: ${input.mode ?? 'undefined'}`);
|
|
106
111
|
}
|
|
107
112
|
}
|
|
113
|
+
/** Compute the full thermodynamic state, including transport properties. */
|
|
114
|
+
export function solve(input) {
|
|
115
|
+
return enrichState(solveBasic(input));
|
|
116
|
+
}
|
package/dist/detect.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
+
import type { Region } from './types.js';
|
|
2
|
+
export { detectRegionPT } from './core/region-detector.js';
|
|
3
|
+
export { detectRegionPH, detectRegionPS } from './backward/pressure-property-region.js';
|
|
4
|
+
export { detectRegionHS } from './backward/hs-region.js';
|
|
1
5
|
/**
|
|
2
|
-
*
|
|
6
|
+
* Detect the region only when T and h identify a unique physical state.
|
|
7
|
+
* @returns Region number (1–5) or -1 if no valid state exists
|
|
8
|
+
* @throws {AmbiguousStateError} if multiple physical states match, even in one region
|
|
9
|
+
* @throws {IF97Error} if numerical state construction fails, including near-critical saturation endpoints
|
|
3
10
|
*/
|
|
4
|
-
export
|
|
11
|
+
export declare function detectRegionTH(T: number, h: number): Region | -1;
|
|
12
|
+
/**
|
|
13
|
+
* Detect the region only when T and s identify a unique physical state.
|
|
14
|
+
* @returns Region number (1–5) or -1 if no valid state exists
|
|
15
|
+
* @throws {AmbiguousStateError} if multiple physical states match, even in one region
|
|
16
|
+
* @throws {IF97Error} if numerical state construction fails, including near-critical saturation endpoints
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectRegionTS(T: number, s: number): Region | -1;
|
package/dist/detect.js
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
|
+
/** Public region-detection helper exports. */
|
|
2
|
+
import { uniqueFixedTemperatureState } from './backward/fixed-temperature-candidates.js';
|
|
3
|
+
import { OutOfRangeError } from './types.js';
|
|
4
|
+
export { detectRegionPT } from './core/region-detector.js';
|
|
5
|
+
export { detectRegionPH, detectRegionPS } from './backward/pressure-property-region.js';
|
|
6
|
+
export { detectRegionHS } from './backward/hs-region.js';
|
|
1
7
|
/**
|
|
2
|
-
*
|
|
8
|
+
* Detect the region only when T and h identify a unique physical state.
|
|
9
|
+
* @returns Region number (1–5) or -1 if no valid state exists
|
|
10
|
+
* @throws {AmbiguousStateError} if multiple physical states match, even in one region
|
|
11
|
+
* @throws {IF97Error} if numerical state construction fails, including near-critical saturation endpoints
|
|
3
12
|
*/
|
|
4
|
-
export
|
|
13
|
+
export function detectRegionTH(T, h) {
|
|
14
|
+
try {
|
|
15
|
+
return uniqueFixedTemperatureState(T, h, 'enthalpy')?.region ?? -1;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof OutOfRangeError)
|
|
19
|
+
return -1;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Detect the region only when T and s identify a unique physical state.
|
|
25
|
+
* @returns Region number (1–5) or -1 if no valid state exists
|
|
26
|
+
* @throws {AmbiguousStateError} if multiple physical states match, even in one region
|
|
27
|
+
* @throws {IF97Error} if numerical state construction fails, including near-critical saturation endpoints
|
|
28
|
+
*/
|
|
29
|
+
export function detectRegionTS(T, s) {
|
|
30
|
+
try {
|
|
31
|
+
return uniqueFixedTemperatureState(T, s, 'entropy')?.region ?? -1;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof OutOfRangeError)
|
|
35
|
+
return -1;
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IF97Error, type Region } from './types.js';
|
|
2
|
+
export declare class SaturationEndpointError extends IF97Error {
|
|
3
|
+
}
|
|
4
|
+
export declare class NumericalStateError extends IF97Error {
|
|
5
|
+
}
|
|
6
|
+
export declare class RegionMismatchError extends IF97Error {
|
|
7
|
+
readonly solverName: string;
|
|
8
|
+
readonly actualRegion: Region | -1;
|
|
9
|
+
readonly expectedRegion: Region;
|
|
10
|
+
constructor(solverName: string, actualRegion: Region | -1, expectedRegion: Region);
|
|
11
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IF97Error } from './types.js';
|
|
2
|
+
export class SaturationEndpointError extends IF97Error {
|
|
3
|
+
}
|
|
4
|
+
export class NumericalStateError extends IF97Error {
|
|
5
|
+
}
|
|
6
|
+
export class RegionMismatchError extends IF97Error {
|
|
7
|
+
solverName;
|
|
8
|
+
actualRegion;
|
|
9
|
+
expectedRegion;
|
|
10
|
+
constructor(solverName, actualRegion, expectedRegion) {
|
|
11
|
+
super(`${solverName} produced a PT state in Region ${actualRegion}, not Region ${expectedRegion}`);
|
|
12
|
+
this.solverName = solverName;
|
|
13
|
+
this.actualRegion = actualRegion;
|
|
14
|
+
this.expectedRegion = expectedRegion;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Specific gas constant for water [kJ/(kg·K)].
|
|
2
|
+
* IAPWS-IF97, §2 (Table 1). Fixed value for IF97 internal consistency.
|
|
3
|
+
* Do not replace transport correlations with this value; thermal conductivity
|
|
4
|
+
* critical enhancement intentionally uses `R_IAPWS_2011_THERMAL`. */
|
|
5
|
+
export declare const R = 0.461526;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Specific gas constant for water [kJ/(kg·K)].
|
|
2
|
+
* IAPWS-IF97, §2 (Table 1). Fixed value for IF97 internal consistency.
|
|
3
|
+
* Do not replace transport correlations with this value; thermal conductivity
|
|
4
|
+
* critical enhancement intentionally uses `R_IAPWS_2011_THERMAL`. */
|
|
5
|
+
export const R = 0.461526;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public API exports.
|
|
5
5
|
*/
|
|
6
|
-
import type { SteamState
|
|
7
|
-
export
|
|
8
|
-
export declare function solve(input: SolveInput): SteamState;
|
|
6
|
+
import type { SteamState } from './types.js';
|
|
7
|
+
export { solve, solveBasic, solvePT } from './core/solver.js';
|
|
9
8
|
export declare function solvePH(p: number, h: number): SteamState;
|
|
10
9
|
export declare function solvePS(p: number, s: number): SteamState;
|
|
11
10
|
export declare function solveHS(h: number, s: number): SteamState;
|
|
@@ -13,5 +12,5 @@ export declare function solveTH(T: number, h: number): SteamState;
|
|
|
13
12
|
export declare function solveTS(T: number, s: number): SteamState;
|
|
14
13
|
export declare function solvePx(p: number, x: number): SteamState;
|
|
15
14
|
export declare function solveTx(T: number, x: number): SteamState;
|
|
16
|
-
export type { SteamState, SolveInput } from './types.js';
|
|
17
|
-
export { Region, IF97Error, OutOfRangeError, ConvergenceError } from './types.js';
|
|
15
|
+
export type { BasicProperties, SaturationEndpoints, SteamState, SolveInput } from './types.js';
|
|
16
|
+
export { Region, IF97Error, AmbiguousStateError, OutOfRangeError, ConvergenceError } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,36 +1,25 @@
|
|
|
1
|
-
import { solve as solveAny
|
|
2
|
-
import { normalizePublicState } from './core/public-normalization.js';
|
|
3
|
-
function normalizeSteamState(state) {
|
|
4
|
-
return normalizePublicState(state);
|
|
5
|
-
}
|
|
1
|
+
import { solve as solveAny } from './core/solver.js';
|
|
6
2
|
// Core solvers
|
|
7
|
-
|
|
8
|
-
// keeps full raw precision during iteration and region transitions.
|
|
9
|
-
export function solvePT(p, T) {
|
|
10
|
-
return normalizeSteamState(solvePTInternal(p, T));
|
|
11
|
-
}
|
|
12
|
-
export function solve(input) {
|
|
13
|
-
return normalizeSteamState(solveAny(input));
|
|
14
|
-
}
|
|
3
|
+
export { solve, solveBasic, solvePT } from './core/solver.js';
|
|
15
4
|
export function solvePH(p, h) {
|
|
16
|
-
return
|
|
5
|
+
return solveAny({ mode: 'PH', p, h });
|
|
17
6
|
}
|
|
18
7
|
export function solvePS(p, s) {
|
|
19
|
-
return
|
|
8
|
+
return solveAny({ mode: 'PS', p, s });
|
|
20
9
|
}
|
|
21
10
|
export function solveHS(h, s) {
|
|
22
|
-
return
|
|
11
|
+
return solveAny({ mode: 'HS', h, s });
|
|
23
12
|
}
|
|
24
13
|
export function solveTH(T, h) {
|
|
25
|
-
return
|
|
14
|
+
return solveAny({ mode: 'TH', T, h });
|
|
26
15
|
}
|
|
27
16
|
export function solveTS(T, s) {
|
|
28
|
-
return
|
|
17
|
+
return solveAny({ mode: 'TS', T, s });
|
|
29
18
|
}
|
|
30
19
|
export function solvePx(p, x) {
|
|
31
|
-
return
|
|
20
|
+
return solveAny({ mode: 'Px', p, x });
|
|
32
21
|
}
|
|
33
22
|
export function solveTx(T, x) {
|
|
34
|
-
return
|
|
23
|
+
return solveAny({ mode: 'Tx', T, x });
|
|
35
24
|
}
|
|
36
|
-
export { Region, IF97Error, OutOfRangeError, ConvergenceError } from './types.js';
|
|
25
|
+
export { Region, IF97Error, AmbiguousStateError, OutOfRangeError, ConvergenceError } from './types.js';
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97, Section 5 (Equations for Region 1)
|
|
8
8
|
*/
|
|
9
|
-
import type { BasicProperties } from '../types.js';
|
|
9
|
+
import type { BasicProperties, CoefficientTable } from '../types.js';
|
|
10
|
+
export declare const COEFFICIENTS: CoefficientTable;
|
|
10
11
|
/**
|
|
11
12
|
* Compute Region 1 thermodynamic properties from pressure and temperature.
|
|
12
13
|
*
|
package/dist/regions/region1.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { R } from '../constants.js';
|
|
10
10
|
import { Region } from '../types.js';
|
|
11
11
|
// ─── Coefficient Table (Table 2, IAPWS-IF97) ───────────────────────────────
|
|
12
|
-
const COEFFICIENTS = [
|
|
12
|
+
export const COEFFICIENTS = [
|
|
13
13
|
[0, -2, 0.14632971213167],
|
|
14
14
|
[0, -1, -0.84548187169114],
|
|
15
15
|
[0, 0, -3.756360367204],
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97, Section 6 (Equations for Region 2)
|
|
8
8
|
*/
|
|
9
|
-
import type { BasicProperties } from '../types.js';
|
|
9
|
+
import type { BasicProperties, CoefficientTable } from '../types.js';
|
|
10
|
+
export declare const RESIDUAL_COEFFICIENTS: CoefficientTable;
|
|
10
11
|
/**
|
|
11
12
|
* Compute Region 2 thermodynamic properties from pressure and temperature.
|
|
12
13
|
*
|
package/dist/regions/region2.js
CHANGED
|
@@ -22,7 +22,7 @@ const IDEAL_COEFFICIENTS = [
|
|
|
22
22
|
[3, 0.021268463753307],
|
|
23
23
|
];
|
|
24
24
|
// ─── Residual Part Coefficients (Table 11) ──────────────────────────────────
|
|
25
|
-
const RESIDUAL_COEFFICIENTS = [
|
|
25
|
+
export const RESIDUAL_COEFFICIENTS = [
|
|
26
26
|
[1, 0, -1.7731742473213e-3],
|
|
27
27
|
[1, 1, -0.017834862292358],
|
|
28
28
|
[1, 2, -0.045996013696365],
|
|
@@ -48,7 +48,7 @@ export const R3L = {
|
|
|
48
48
|
};
|
|
49
49
|
export const R3M = {
|
|
50
50
|
pStar: 23, tStar: 650, vStar: 0.0028, piShift: 1, sigShift: 0.997, sigExp: 0.25,
|
|
51
|
-
IJN: [[0, 0, 0.811384363481847], [3, 0, -0.568199310990094e4], [8, 0, -0.178657198172556e11], [20, 2, 0.795537657613427e32], [1, 5, -0.814568209346872e5], [3, 5, -0.659774567602874e8], [4, 5, -0.152861148659302e11], [5, 5, -0.560165667510446e12], [1, 6, 0.458384828593949e6], [6, 6, -0.385754000383848e14], [2, 7, 0.453735800004273e8], [4, 8, 0.939454935735563e12], [14, 8, 0.266572856432938e28], [2, 10, -0.547578313899097e10], [5, 10, 0.200725701112386e15], [3, 12, 0.185007245563239e13], [0, 14, 0.185135446828337e9], [1, 14, -0.170451090076385e12], [1, 18, 0.157890366037614e15], [1, 20, -0.202530509748774e16], [28, 20, 0.368193926183570e60], [2, 22, 0.170215539458936e18], [16, 22, 0.639234909918741e42], [0, 24, -0.821698160721956e15], [5, 24, -0.795260241872306e24], [0, 28, 0.233415869478510e18], [3, 28, -0.600079934586803e23], [4, 28, 0.594584382273384e25], [12, 28, 0.189461279349492e40], [16, 28, -0.810093428842645e46], [1, 32, 0.188813911076809e22], [8, 32, 0.111052244098768e36], [14, 32, 0.291133958602503e46], [0, 36, -0.329421923951460e22], [2, 36, -0.137570282536696e26], [3, 36, 0.181508996303902e28], [4, 36, -0.346865122768353e30], [8, 36, -0.
|
|
51
|
+
IJN: [[0, 0, 0.811384363481847], [3, 0, -0.568199310990094e4], [8, 0, -0.178657198172556e11], [20, 2, 0.795537657613427e32], [1, 5, -0.814568209346872e5], [3, 5, -0.659774567602874e8], [4, 5, -0.152861148659302e11], [5, 5, -0.560165667510446e12], [1, 6, 0.458384828593949e6], [6, 6, -0.385754000383848e14], [2, 7, 0.453735800004273e8], [4, 8, 0.939454935735563e12], [14, 8, 0.266572856432938e28], [2, 10, -0.547578313899097e10], [5, 10, 0.200725701112386e15], [3, 12, 0.185007245563239e13], [0, 14, 0.185135446828337e9], [1, 14, -0.170451090076385e12], [1, 18, 0.157890366037614e15], [1, 20, -0.202530509748774e16], [28, 20, 0.368193926183570e60], [2, 22, 0.170215539458936e18], [16, 22, 0.639234909918741e42], [0, 24, -0.821698160721956e15], [5, 24, -0.795260241872306e24], [0, 28, 0.233415869478510e18], [3, 28, -0.600079934586803e23], [4, 28, 0.594584382273384e25], [12, 28, 0.189461279349492e40], [16, 28, -0.810093428842645e46], [1, 32, 0.188813911076809e22], [8, 32, 0.111052244098768e36], [14, 32, 0.291133958602503e46], [0, 36, -0.329421923951460e22], [2, 36, -0.137570282536696e26], [3, 36, 0.181508996303902e28], [4, 36, -0.346865122768353e30], [8, 36, -0.211961148774260e38], [14, 36, -0.128617899887675e49], [24, 36, 0.479817895699239e65]]
|
|
52
52
|
};
|
|
53
53
|
export const R3N = {
|
|
54
54
|
pStar: 23, tStar: 650, vStar: 0.0031, piShift: 0.976, sigShift: 0.997, transform: 'exp',
|
|
@@ -56,7 +56,7 @@ export const R3N = {
|
|
|
56
56
|
};
|
|
57
57
|
export const R3O = {
|
|
58
58
|
pStar: 23, tStar: 650, vStar: 0.0034, piShift: 0.974, sigShift: 0.996, piExp: 0.5,
|
|
59
|
-
IJN: [[0, -12, 0.128746023979718e-34], [0, -4, -0.735234770382342e-11], [0, -1, 0.289078692149150e-2], [2, -1, 0.244482731907223], [3, -10, 0.141733492030985e-23], [4, -12, -0.354533853059476e-28], [4, -8, -0.594539202901431e-17], [4, -5, -0.585188401782779e-8], [4, -4, 0.201377325411803e-5], [4, -1, 0.138647388209306e1], [5, -4, -0.173959365084772e-4], [5, -3, 0.137680878349369e-2], [6, -8, 0.814897605805513e-14], [7, -12, 0.425596631351839e-25], [8, -10, -0.387449113787755e-17], [8, -8, 0.
|
|
59
|
+
IJN: [[0, -12, 0.128746023979718e-34], [0, -4, -0.735234770382342e-11], [0, -1, 0.289078692149150e-2], [2, -1, 0.244482731907223], [3, -10, 0.141733492030985e-23], [4, -12, -0.354533853059476e-28], [4, -8, -0.594539202901431e-17], [4, -5, -0.585188401782779e-8], [4, -4, 0.201377325411803e-5], [4, -1, 0.138647388209306e1], [5, -4, -0.173959365084772e-4], [5, -3, 0.137680878349369e-2], [6, -8, 0.814897605805513e-14], [7, -12, 0.425596631351839e-25], [8, -10, -0.387449113787755e-17], [8, -8, 0.139814747930240e-12], [8, -4, -0.171849638951521e-2], [10, -12, 0.641890529513296e-21], [10, -8, 0.118960578072018e-10], [14, -12, -0.155282762571611e-17], [14, -8, 0.233907907347507e-7], [20, -12, -0.174093247766213e-12], [20, -10, 0.377682649089149e-8], [24, -12, -0.516720236575302e-10]]
|
|
60
60
|
};
|
|
61
61
|
export const R3P = {
|
|
62
62
|
pStar: 23, tStar: 650, vStar: 0.0041, piShift: 0.972, sigShift: 0.997, piExp: 0.5,
|
|
@@ -88,7 +88,7 @@ export const R3V = {
|
|
|
88
88
|
};
|
|
89
89
|
export const R3W = {
|
|
90
90
|
pStar: 23, tStar: 650, vStar: 0.0039, piShift: 0.959, sigShift: 0.995, transform: 'pow4',
|
|
91
|
-
IJN: [[-12, 8, -0.586219133817016e-7], [-12, 14, -0.894460355005526e11], [-10, -1, 0.531168037519774e-30], [-10, 8, 0.109892402329239], [-8, 6, -0.575368389425212e-1], [-8, 8, 0.228276853990249e5], [-8, 14, -0.158548609655002e19], [-6, -4, 0.329865748576503e-27], [-6, -3, -0.634987981190669e-24], [-6, 2, 0.615762068640611e-8], [-6, 8, -0.961109240985747e8], [-5, -10, -0.406274286652625e-44], [-4, -1, -0.471103725498077e-12], [-4, 3, 0.725937724828145], [-3, -10, 0.187768525763682e-38], [-3, 3, -0.103308436323771e4], [-2, 1, -0.662552816342168e-1], [-2, 2, 0.579514041765710e3], [-1, -8, 0.237416732616644e-26], [-1, -4, 0.271700235739893e-14], [-1, 1, -0.
|
|
91
|
+
IJN: [[-12, 8, -0.586219133817016e-7], [-12, 14, -0.894460355005526e11], [-10, -1, 0.531168037519774e-30], [-10, 8, 0.109892402329239], [-8, 6, -0.575368389425212e-1], [-8, 8, 0.228276853990249e5], [-8, 14, -0.158548609655002e19], [-6, -4, 0.329865748576503e-27], [-6, -3, -0.634987981190669e-24], [-6, 2, 0.615762068640611e-8], [-6, 8, -0.961109240985747e8], [-5, -10, -0.406274286652625e-44], [-4, -1, -0.471103725498077e-12], [-4, 3, 0.725937724828145], [-3, -10, 0.187768525763682e-38], [-3, 3, -0.103308436323771e4], [-2, 1, -0.662552816342168e-1], [-2, 2, 0.579514041765710e3], [-1, -8, 0.237416732616644e-26], [-1, -4, 0.271700235739893e-14], [-1, 1, -0.907886213483600e2], [0, -12, -0.171242509570207e-36], [0, 1, 0.156792067854621e3], [1, -1, 0.923261357901470], [2, -1, -0.597865988422577e1], [2, 2, 0.321988767636389e7], [3, -12, -0.399441390042203e-29], [3, -5, 0.493429086046981e-7], [5, -10, 0.812036983370565e-19], [5, -8, -0.207610284654137e-11], [5, -6, -0.340821291419719e-6], [8, -12, 0.542000573372233e-17], [8, -10, -0.856711586510214e-12], [10, -12, 0.266170454405981e-13], [10, -8, 0.858133791857099e-5]]
|
|
92
92
|
};
|
|
93
93
|
export const R3X = {
|
|
94
94
|
pStar: 23, tStar: 650, vStar: 0.0049, piShift: 0.910, sigShift: 0.988,
|
|
@@ -6,7 +6,7 @@ import { evalSubregion } from './region3-eval.js';
|
|
|
6
6
|
import { REGION3_SUBREGIONS as R3 } from './region3-data.js';
|
|
7
7
|
import { b3ab, b3cd, b3ef, b3gh, b3ij, b3jk, b3mn, b3op, b3qu, b3rx, b3uv, b3wx } from './boundaries.js';
|
|
8
8
|
import { saturationPressure, saturationTemperature } from './region4.js';
|
|
9
|
-
import { Pc } from '../constants.js';
|
|
9
|
+
import { Pc, P_MAX, Tc } from '../constants.js';
|
|
10
10
|
import { IF97Error } from '../types.js';
|
|
11
11
|
// Shared liquid-side C/S saturation threshold from the Region 3 supplementary release.
|
|
12
12
|
const R3_C_S_LIQUID_BOUNDARY_PRESSURE = 19.00881189173929;
|
|
@@ -14,6 +14,9 @@ const R3_C_S_LIQUID_BOUNDARY_PRESSURE = 19.00881189173929;
|
|
|
14
14
|
* Pressure thresholds from IAPWS Supplementary Release on Backward
|
|
15
15
|
* Equations v(P,T) for Region 3, Table 1 (saturation subregion limits). */
|
|
16
16
|
export function region3SatVolume(p, T, x) {
|
|
17
|
+
if (x !== 0 && x !== 1) {
|
|
18
|
+
throw new IF97Error('Region 3 saturation volume requires x = 0 (liquid) or x = 1 (vapor)');
|
|
19
|
+
}
|
|
17
20
|
if (x === 0) {
|
|
18
21
|
if (p < R3_C_S_LIQUID_BOUNDARY_PRESSURE)
|
|
19
22
|
return evalSubregion(R3.C, p, T);
|
|
@@ -35,6 +38,9 @@ export function region3SatVolume(p, T, x) {
|
|
|
35
38
|
* Pressure thresholds from IAPWS Supplementary Release on Backward
|
|
36
39
|
* Equations v(P,T) for Region 3, Figures 2–5. */
|
|
37
40
|
export function region3Volume(p, T) {
|
|
41
|
+
if (!Number.isFinite(p) || !Number.isFinite(T) || p > P_MAX) {
|
|
42
|
+
throw new IF97Error(`Region 3 v(P,T) requires finite p <= ${P_MAX} MPa and finite T`);
|
|
43
|
+
}
|
|
38
44
|
if (p > 40) { // Suppl. Release Fig. 2: subregions A/B
|
|
39
45
|
return T <= b3ab(p) ? evalSubregion(R3.A, p, T) : evalSubregion(R3.B, p, T);
|
|
40
46
|
}
|
|
@@ -97,6 +103,7 @@ export function region3Volume(p, T) {
|
|
|
97
103
|
}
|
|
98
104
|
const Tsat643 = 643.15;
|
|
99
105
|
const Psat643 = saturationPressure(Tsat643);
|
|
106
|
+
const liquid = T <= Tc && p >= saturationPressure(T);
|
|
100
107
|
if (p > Psat643 && p <= 22.5) {
|
|
101
108
|
const tcd = b3cd(p), tqu = b3qu(p), trx = b3rx(p), tjk = b3jk(p);
|
|
102
109
|
if (T <= tcd)
|
|
@@ -123,8 +130,7 @@ export function region3Volume(p, T) {
|
|
|
123
130
|
return evalSubregion(R3.Z, p, T);
|
|
124
131
|
return evalSubregion(R3.X, p, T);
|
|
125
132
|
}
|
|
126
|
-
|
|
127
|
-
if (T > Tsat) {
|
|
133
|
+
if (!liquid) {
|
|
128
134
|
if (p <= 21.90096265)
|
|
129
135
|
return evalSubregion(R3.X, p, T);
|
|
130
136
|
if (T <= twx)
|
|
@@ -142,27 +148,26 @@ export function region3Volume(p, T) {
|
|
|
142
148
|
return evalSubregion(R3.K, p, T);
|
|
143
149
|
}
|
|
144
150
|
if (p > 20.5 && p <= Psat643) {
|
|
145
|
-
const tcd = b3cd(p),
|
|
151
|
+
const tcd = b3cd(p), tjk = b3jk(p);
|
|
146
152
|
if (T <= tcd)
|
|
147
153
|
return evalSubregion(R3.C, p, T);
|
|
148
|
-
if (
|
|
154
|
+
if (liquid)
|
|
149
155
|
return evalSubregion(R3.S, p, T);
|
|
150
156
|
if (T <= tjk)
|
|
151
157
|
return evalSubregion(R3.R, p, T);
|
|
152
158
|
return evalSubregion(R3.K, p, T);
|
|
153
159
|
}
|
|
154
160
|
if (p >= R3_C_S_LIQUID_BOUNDARY_PRESSURE && p <= 20.5) {
|
|
155
|
-
const tcd = b3cd(p)
|
|
156
|
-
if (
|
|
157
|
-
if (T < tcd && T <
|
|
161
|
+
const tcd = b3cd(p);
|
|
162
|
+
if (liquid) {
|
|
163
|
+
if (T < tcd && T < saturationTemperature(p))
|
|
158
164
|
return evalSubregion(R3.C, p, T);
|
|
159
165
|
return evalSubregion(R3.S, p, T);
|
|
160
166
|
}
|
|
161
167
|
return evalSubregion(R3.T, p, T);
|
|
162
168
|
}
|
|
163
169
|
if (p > 16.5291642526) {
|
|
164
|
-
|
|
165
|
-
if (T <= Ts)
|
|
170
|
+
if (liquid)
|
|
166
171
|
return evalSubregion(R3.C, p, T);
|
|
167
172
|
return evalSubregion(R3.T, p, T);
|
|
168
173
|
}
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97, Section 7 (Equations for Region 3)
|
|
8
8
|
*/
|
|
9
|
-
import type { BasicProperties } from '../types.js';
|
|
9
|
+
import type { BasicProperties, CoefficientTable } from '../types.js';
|
|
10
|
+
export declare const COEFFICIENTS: CoefficientTable;
|
|
11
|
+
/** Internal pressure residual: near criticality, rounding pressure before subtraction hides real density error. */
|
|
12
|
+
export declare function region3PressureResidual(rho: number, T: number, pressure: number, pressureLow?: number): number;
|
|
10
13
|
/**
|
|
11
14
|
* Compute Region 3 thermodynamic properties from density and temperature.
|
|
12
15
|
*
|
package/dist/regions/region3.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { R } from '../constants.js';
|
|
10
10
|
import { IF97Error, Region } from '../types.js';
|
|
11
|
+
import { addExtended, divideExtended, multiplyExtended, } from '../solvers/extended-arithmetic.js';
|
|
11
12
|
// ─── Coefficient Table (Table 30, IAPWS-IF97) ──────────────────────────────
|
|
12
|
-
const COEFFICIENTS = [
|
|
13
|
+
export const COEFFICIENTS = [
|
|
13
14
|
// Entry 0 is the coefficient n₁ for the logarithmic term n₁·ln(δ).
|
|
14
15
|
// It shares the [I=0, J=0] shape with entry 1 but is handled separately
|
|
15
16
|
// in the evaluation loop (index 0 = ln term, indices 1+ = polynomial).
|
|
@@ -57,6 +58,35 @@ const COEFFICIENTS = [
|
|
|
57
58
|
// Reduction constants for Region 3
|
|
58
59
|
const RHO_STAR = 322; // ρ* [kg/m³] (critical density)
|
|
59
60
|
const T_STAR = 647.096; // T* [K] (critical temperature)
|
|
61
|
+
function extendedPowers(value, degree) {
|
|
62
|
+
const powers = [[1, 0]];
|
|
63
|
+
for (let i = 1; i <= degree; i += 1) {
|
|
64
|
+
powers.push(multiplyExtended(powers[i - 1], value));
|
|
65
|
+
}
|
|
66
|
+
return powers;
|
|
67
|
+
}
|
|
68
|
+
/** Evaluate rho*R*T*(n1 + sum(n*I*delta^I*tau^J))/1000 without losing its small residual. */
|
|
69
|
+
function pressureExtended(rho, T) {
|
|
70
|
+
const delta = extendedPowers(divideExtended([rho, 0], [RHO_STAR, 0]), 11);
|
|
71
|
+
const tau = extendedPowers(divideExtended([T_STAR, 0], [T, 0]), 26);
|
|
72
|
+
let polynomial = [COEFFICIENTS[0][2], 0];
|
|
73
|
+
for (let idx = 1; idx < COEFFICIENTS.length; idx += 1) {
|
|
74
|
+
const [I, J, N] = COEFFICIENTS[idx];
|
|
75
|
+
if (I === 0)
|
|
76
|
+
continue;
|
|
77
|
+
const coefficient = multiplyExtended([N, 0], [I, 0]);
|
|
78
|
+
const term = multiplyExtended(multiplyExtended(coefficient, delta[I]), tau[J]);
|
|
79
|
+
polynomial = addExtended(polynomial, term);
|
|
80
|
+
}
|
|
81
|
+
const scale = multiplyExtended(multiplyExtended([rho, 0], [R, 0]), [T, 0]);
|
|
82
|
+
return divideExtended(multiplyExtended(scale, polynomial), [1000, 0]);
|
|
83
|
+
}
|
|
84
|
+
/** Internal pressure residual: near criticality, rounding pressure before subtraction hides real density error. */
|
|
85
|
+
export function region3PressureResidual(rho, T, pressure, pressureLow = 0) {
|
|
86
|
+
const evaluated = pressureExtended(rho, T);
|
|
87
|
+
const residual = addExtended(evaluated, [-pressure, -pressureLow]);
|
|
88
|
+
return residual[0] + residual[1];
|
|
89
|
+
}
|
|
60
90
|
/**
|
|
61
91
|
* Compute Region 3 thermodynamic properties from density and temperature.
|
|
62
92
|
*
|
|
@@ -97,7 +127,7 @@ export function region3ByRhoT(rho, T) {
|
|
|
97
127
|
}
|
|
98
128
|
return {
|
|
99
129
|
region: Region.Region3,
|
|
100
|
-
pressure: rho
|
|
130
|
+
pressure: pressureExtended(rho, T)[0],
|
|
101
131
|
temperature: T,
|
|
102
132
|
specificVolume: v,
|
|
103
133
|
internalEnergy: R * T * tau * phi_tau,
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* @throws {OutOfRangeError} if T is outside valid range
|
|
16
16
|
*/
|
|
17
17
|
export declare function saturationPressure(T: number): number;
|
|
18
|
+
/** Internal unrounded target: near criticality, one pressure ULP changes endpoint density. */
|
|
19
|
+
export declare function saturationPressurePair(T: number): readonly [number, number];
|
|
18
20
|
/**
|
|
19
21
|
* Saturation temperature for a given pressure.
|
|
20
22
|
* Equation 31 (pp. 34) of IAPWS-IF97.
|