iapws-if97 2.2.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -2
- package/README.md +69 -246
- package/dist/backward/candidate-resolution.d.ts +8 -0
- package/dist/backward/candidate-resolution.js +40 -0
- package/dist/backward/fixed-temperature-candidates.d.ts +4 -0
- package/dist/backward/fixed-temperature-candidates.js +188 -0
- package/dist/backward/fixed-temperature-solver.d.ts +3 -3
- package/dist/backward/fixed-temperature-solver.js +38 -17
- package/dist/backward/fixed-temperature-stationary.d.ts +4 -0
- package/dist/backward/fixed-temperature-stationary.js +146 -0
- package/dist/backward/hs-region.d.ts +50 -0
- package/dist/backward/hs-region.js +695 -0
- package/dist/backward/hs-state.d.ts +15 -0
- package/dist/backward/hs-state.js +316 -0
- package/dist/backward/hs.js +28 -242
- package/dist/backward/ph.d.ts +2 -0
- package/dist/backward/ph.js +72 -21
- package/dist/backward/pressure-property-region.d.ts +13 -0
- package/dist/backward/pressure-property-region.js +262 -0
- package/dist/backward/ps.d.ts +6 -0
- package/dist/backward/ps.js +81 -28
- package/dist/backward/solution-validation.d.ts +7 -1
- package/dist/backward/solution-validation.js +138 -41
- package/dist/backward/th.d.ts +3 -5
- package/dist/backward/th.js +10 -71
- package/dist/backward/tolerances.d.ts +3 -0
- package/dist/backward/tolerances.js +9 -3
- package/dist/backward/ts.d.ts +3 -5
- package/dist/backward/ts.js +10 -71
- package/dist/constants.d.ts +11 -15
- package/dist/constants.js +14 -15
- package/dist/core/floating-point.d.ts +2 -0
- package/dist/core/floating-point.js +7 -0
- package/dist/core/formulation-seams.d.ts +27 -0
- package/dist/core/formulation-seams.js +289 -0
- package/dist/core/input-validation.d.ts +1 -0
- package/dist/core/input-validation.js +5 -0
- package/dist/core/region-detector.d.ts +3 -40
- package/dist/core/region-detector.js +37 -762
- package/dist/core/region3-pt.d.ts +1 -1
- package/dist/core/region3-pt.js +42 -16
- package/dist/core/solve-input-normalization.js +4 -1
- package/dist/core/solver.d.ts +7 -10
- package/dist/core/solver.js +26 -17
- package/dist/detect.d.ts +16 -2
- package/dist/detect.js +36 -2
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +16 -0
- package/dist/gas-constant.d.ts +5 -0
- package/dist/gas-constant.js +5 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +10 -21
- package/dist/regions/region1.d.ts +2 -1
- package/dist/regions/region1.js +1 -1
- package/dist/regions/region2.d.ts +2 -1
- package/dist/regions/region2.js +1 -1
- package/dist/regions/region3-data.js +3 -3
- package/dist/regions/region3-subregions.js +15 -10
- package/dist/regions/region3.d.ts +4 -1
- package/dist/regions/region3.js +32 -2
- package/dist/regions/region4.d.ts +2 -0
- package/dist/regions/region4.js +39 -12
- package/dist/regions/region5.d.ts +2 -1
- package/dist/regions/region5.js +2 -2
- package/dist/saturation/common.d.ts +2 -8
- package/dist/saturation/common.js +64 -36
- package/dist/saturation/region4-boundaries.js +13 -13
- package/dist/saturation/region4-hs.js +282 -58
- package/dist/saturation/two-phase.d.ts +2 -2
- package/dist/saturation/two-phase.js +7 -7
- package/dist/solvers/bracketed-newton.d.ts +6 -3
- package/dist/solvers/bracketed-newton.js +15 -8
- package/dist/solvers/extended-arithmetic.d.ts +6 -0
- package/dist/solvers/extended-arithmetic.js +38 -0
- package/dist/transport/properties.d.ts +4 -2
- package/dist/transport/properties.js +14 -4
- package/dist/types.d.ts +18 -0
- package/dist/types.js +14 -0
- package/package.json +4 -4
- package/dist/core/public-normalization.d.ts +0 -3
- package/dist/core/public-normalization.js +0 -53
- /package/dist/{backward → core}/thermodynamic-derivatives.d.ts +0 -0
- /package/dist/{backward → core}/thermodynamic-derivatives.js +0 -0
package/dist/regions/region4.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97, Section 8 (Equations for Region 4)
|
|
8
8
|
*/
|
|
9
|
-
import { Tc, Pc, P_MIN } from '../constants.js';
|
|
9
|
+
import { Tc, Pc, Tt, Pt, T_MIN, P_MIN } from '../constants.js';
|
|
10
10
|
import { OutOfRangeError } from '../types.js';
|
|
11
|
+
import { addExtended, divideExtended, multiplyExtended, sqrtExtended, subtractExtended, } from '../solvers/extended-arithmetic.js';
|
|
11
12
|
import { normalizeRegion4Pressure, normalizeRegion4Temperature, } from '../saturation/region4-boundaries.js';
|
|
12
13
|
// ─── Saturation Line Coefficients (Table 34, IAPWS-IF97) ───────────────────
|
|
13
14
|
const n = [
|
|
@@ -32,14 +33,30 @@ const n = [
|
|
|
32
33
|
* @throws {OutOfRangeError} if T is outside valid range
|
|
33
34
|
*/
|
|
34
35
|
export function saturationPressure(T) {
|
|
36
|
+
const pressure = saturationPressurePair(T)[0];
|
|
37
|
+
if (T === T_MIN)
|
|
38
|
+
return P_MIN;
|
|
39
|
+
// The fitted equation reaches the rounded triple-point pressure just below Tt.
|
|
40
|
+
if (T <= Tt && pressure >= Pt)
|
|
41
|
+
return Pt;
|
|
42
|
+
if (T === Tc)
|
|
43
|
+
return Pc;
|
|
44
|
+
return normalizeRegion4Pressure(pressure);
|
|
45
|
+
}
|
|
46
|
+
/** Internal unrounded target: near criticality, one pressure ULP changes endpoint density. */
|
|
47
|
+
export function saturationPressurePair(T) {
|
|
35
48
|
if (T < 273.15 || T > Tc) {
|
|
36
49
|
throw new OutOfRangeError('Temperature', T, 273.15, Tc);
|
|
37
50
|
}
|
|
38
|
-
const theta = T
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
51
|
+
const theta = addExtended([T, 0], divideExtended([n[9], 0], subtractExtended([T, 0], [n[10], 0])));
|
|
52
|
+
const thetaSquared = multiplyExtended(theta, theta);
|
|
53
|
+
const A = addExtended(addExtended(thetaSquared, multiplyExtended([n[1], 0], theta)), [n[2], 0]);
|
|
54
|
+
const B = addExtended(addExtended(multiplyExtended([n[3], 0], thetaSquared), multiplyExtended([n[4], 0], theta)), [n[5], 0]);
|
|
55
|
+
const C = addExtended(addExtended(multiplyExtended([n[6], 0], thetaSquared), multiplyExtended([n[7], 0], theta)), [n[8], 0]);
|
|
56
|
+
const discriminant = subtractExtended(multiplyExtended(B, B), multiplyExtended(multiplyExtended([4, 0], A), C));
|
|
57
|
+
const root = divideExtended(multiplyExtended([2, 0], C), addExtended([-B[0], -B[1]], sqrtExtended(discriminant)));
|
|
58
|
+
const squared = multiplyExtended(root, root);
|
|
59
|
+
return multiplyExtended(squared, squared);
|
|
43
60
|
}
|
|
44
61
|
/**
|
|
45
62
|
* Saturation temperature for a given pressure.
|
|
@@ -55,10 +72,20 @@ export function saturationTemperature(p) {
|
|
|
55
72
|
if (p < P_MIN || p > Pc) {
|
|
56
73
|
throw new OutOfRangeError('Pressure', p, P_MIN, Pc);
|
|
57
74
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
if (p === P_MIN)
|
|
76
|
+
return T_MIN;
|
|
77
|
+
if (p === Pt)
|
|
78
|
+
return Tt;
|
|
79
|
+
if (p === Pc)
|
|
80
|
+
return Tc;
|
|
81
|
+
const beta = sqrtExtended(sqrtExtended([p, 0]));
|
|
82
|
+
const betaSquared = multiplyExtended(beta, beta);
|
|
83
|
+
const E = addExtended(addExtended(betaSquared, multiplyExtended([n[3], 0], beta)), [n[6], 0]);
|
|
84
|
+
const F = addExtended(addExtended(multiplyExtended([n[1], 0], betaSquared), multiplyExtended([n[4], 0], beta)), [n[7], 0]);
|
|
85
|
+
const G = addExtended(addExtended(multiplyExtended([n[2], 0], betaSquared), multiplyExtended([n[5], 0], beta)), [n[8], 0]);
|
|
86
|
+
const discriminant = subtractExtended(multiplyExtended(F, F), multiplyExtended(multiplyExtended([4, 0], E), G));
|
|
87
|
+
const D = divideExtended(multiplyExtended([2, 0], G), subtractExtended([-F[0], -F[1]], sqrtExtended(discriminant)));
|
|
88
|
+
const difference = subtractExtended([n[10], 0], D);
|
|
89
|
+
const temperature = divideExtended(subtractExtended(addExtended([n[10], 0], D), sqrtExtended(subtractExtended(multiplyExtended(difference, difference), [4 * n[9], 0]))), [2, 0]);
|
|
90
|
+
return p >= Pt && temperature[0] < Tt ? Tt : normalizeRegion4Temperature(temperature[0]);
|
|
64
91
|
}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97, Section 9 (Equations for Region 5)
|
|
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 5 thermodynamic properties from pressure and temperature.
|
|
12
13
|
*
|
package/dist/regions/region5.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reference: IAPWS-IF97, Section 9 (Equations for Region 5)
|
|
8
8
|
*/
|
|
9
|
-
import { R } from '../
|
|
9
|
+
import { R } from '../gas-constant.js';
|
|
10
10
|
import { Region } from '../types.js';
|
|
11
11
|
// ─── Ideal Part Coefficients (Table 37) ─────────────────────────────────────
|
|
12
12
|
const IDEAL_COEFFICIENTS = [
|
|
@@ -18,7 +18,7 @@ const IDEAL_COEFFICIENTS = [
|
|
|
18
18
|
[2, -0.32961626538917],
|
|
19
19
|
];
|
|
20
20
|
// ─── Residual Part Coefficients (Table 38) ──────────────────────────────────
|
|
21
|
-
const RESIDUAL_COEFFICIENTS = [
|
|
21
|
+
export const RESIDUAL_COEFFICIENTS = [
|
|
22
22
|
[1, 1, 1.5736404855259e-3],
|
|
23
23
|
[1, 2, 9.0153761673944e-4],
|
|
24
24
|
[1, 3, -5.0270077677648e-3],
|
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
* two-phase boundary, and provides helpers for quality interpolation
|
|
6
6
|
* and two-phase mixing.
|
|
7
7
|
*/
|
|
8
|
-
import type { BasicProperties } from '../types.js';
|
|
9
|
-
|
|
10
|
-
export interface SaturationEndpoints {
|
|
11
|
-
pressure: number;
|
|
12
|
-
temperature: number;
|
|
13
|
-
liquid: BasicProperties;
|
|
14
|
-
vapor: BasicProperties;
|
|
15
|
-
}
|
|
8
|
+
import type { BasicProperties, SaturationEndpoints } from '../types.js';
|
|
9
|
+
export type { SaturationEndpoints } from '../types.js';
|
|
16
10
|
export declare function rawQualityFromSaturationProperty(liquidValue: number, vaporValue: number, mixtureValue: number): number;
|
|
17
11
|
/**
|
|
18
12
|
* Compute saturated liquid and vapour properties at a given pressure.
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { IF97Error, Region } from '../types.js';
|
|
2
|
-
import {
|
|
2
|
+
import { SaturationEndpointError } from '../errors.js';
|
|
3
|
+
import { Pc, Pt, P_MIN, R2_T_MIN, RHOc, T_MIN, Tc, Tt } from '../constants.js';
|
|
3
4
|
import { region1 } from '../regions/region1.js';
|
|
4
5
|
import { region2 } from '../regions/region2.js';
|
|
5
6
|
import { region3ByRhoT } from '../regions/region3.js';
|
|
6
|
-
import { saturationPressure, saturationTemperature } from '../regions/region4.js';
|
|
7
|
+
import { saturationPressure, saturationPressurePair, saturationTemperature } from '../regions/region4.js';
|
|
7
8
|
import { region3SatVolume } from '../regions/region3-subregions.js';
|
|
8
9
|
import { solveRegion3StateAtPressure } from '../core/region3-pt.js';
|
|
10
|
+
import { nextPositiveFloat } from '../core/floating-point.js';
|
|
9
11
|
import { normalizeRegion4Pressure, normalizeRegion4Temperature, } from './region4-boundaries.js';
|
|
12
|
+
const REGION12_SATURATION_PRESSURE = saturationPressure(R2_T_MIN);
|
|
10
13
|
/** Tag a single-phase state as Region 4 with the given vapour quality. */
|
|
11
|
-
function withRegion4Metadata(state, quality) {
|
|
12
|
-
return { ...state, region: Region.Region4, quality };
|
|
14
|
+
function withRegion4Metadata(state, quality, saturation) {
|
|
15
|
+
return { ...state, region: Region.Region4, quality, saturation };
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* Solve for the Region 3 saturation endpoint state.
|
|
@@ -18,8 +21,8 @@ function withRegion4Metadata(state, quality) {
|
|
|
18
21
|
* @param T - Saturation temperature [K]
|
|
19
22
|
* @param x - Phase indicator: 0 = liquid, 1 = vapour
|
|
20
23
|
*/
|
|
21
|
-
function solveR3Endpoint(p, T, x) {
|
|
22
|
-
return solveRegion3StateAtPressure(p, T, 1 / region3SatVolume(p, T, x));
|
|
24
|
+
function solveR3Endpoint(p, T, x, pressureLow) {
|
|
25
|
+
return solveRegion3StateAtPressure(p, T, 1 / region3SatVolume(p, T, x), pressureLow);
|
|
23
26
|
}
|
|
24
27
|
/** Clamp vapour quality to [0, 1], snapping near-zero/one values to the boundary. */
|
|
25
28
|
function clampQuality(x) {
|
|
@@ -44,6 +47,48 @@ export function rawQualityFromSaturationProperty(liquidValue, vaporValue, mixtur
|
|
|
44
47
|
}
|
|
45
48
|
return (mixtureValue - liquidValue) / span;
|
|
46
49
|
}
|
|
50
|
+
function buildSaturationEndpoints(pressure, temperature) {
|
|
51
|
+
// Both caller coordinates must use the same native saturation EOS pair.
|
|
52
|
+
const pressurePair = saturationPressurePair(temperature);
|
|
53
|
+
const eosPressure = temperature === T_MIN ? P_MIN
|
|
54
|
+
: temperature <= Tt && pressurePair[0] >= Pt ? Pt : normalizeRegion4Pressure(pressurePair[0]);
|
|
55
|
+
const pressureLow = eosPressure === pressurePair[0] ? pressurePair[1] : 0;
|
|
56
|
+
let liquid;
|
|
57
|
+
let vapor;
|
|
58
|
+
if (pressure === Pc && temperature === Tc) {
|
|
59
|
+
liquid = vapor = region3ByRhoT(RHOc, temperature);
|
|
60
|
+
}
|
|
61
|
+
else if (pressure > REGION12_SATURATION_PRESSURE) {
|
|
62
|
+
// Inverse-temperature rounding must not change formula ownership at 623.15 K.
|
|
63
|
+
const inconsistency = `Region 4 numerical inconsistency at p=${pressure} MPa, T=${temperature} K: cannot construct distinct stable liquid and vapor EOS endpoints`;
|
|
64
|
+
try {
|
|
65
|
+
liquid = solveR3Endpoint(eosPressure, temperature, 0, pressureLow);
|
|
66
|
+
vapor = solveR3Endpoint(eosPressure, temperature, 1, pressureLow);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (!(error instanceof IF97Error))
|
|
70
|
+
throw error;
|
|
71
|
+
throw new SaturationEndpointError(`${inconsistency}: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
if (!(1 / liquid.specificVolume > RHOc && 1 / vapor.specificVolume < RHOc &&
|
|
74
|
+
vapor.specificVolume > liquid.specificVolume && vapor.enthalpy > liquid.enthalpy &&
|
|
75
|
+
vapor.entropy > liquid.entropy && [liquid, vapor].every((state) => Number.isFinite(state.pressure) && Math.abs(state.pressure - pressure) / pressure <= 1e-6 &&
|
|
76
|
+
[state.cp, state.cv, state.isothermalCompressibility, state.speedOfSound]
|
|
77
|
+
.every((value) => value !== null && Number.isFinite(value) && value > 0)))) {
|
|
78
|
+
throw new SaturationEndpointError(inconsistency);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
liquid = region1(eosPressure, temperature);
|
|
83
|
+
vapor = region2(eosPressure, temperature);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
pressure,
|
|
87
|
+
temperature,
|
|
88
|
+
liquid: { ...liquid, pressure, temperature },
|
|
89
|
+
vapor: { ...vapor, pressure, temperature },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
47
92
|
/**
|
|
48
93
|
* Compute saturated liquid and vapour properties at a given pressure.
|
|
49
94
|
*
|
|
@@ -54,25 +99,15 @@ export function rawQualityFromSaturationProperty(liquidValue, vaporValue, mixtur
|
|
|
54
99
|
*/
|
|
55
100
|
export function saturationEndpointsAtPressure(p) {
|
|
56
101
|
const pressure = normalizeRegion4Pressure(p);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
pressure,
|
|
65
|
-
temperature,
|
|
66
|
-
liquid: solveR3Endpoint(pressure, temperature, 0),
|
|
67
|
-
vapor: solveR3Endpoint(pressure, temperature, 1),
|
|
68
|
-
};
|
|
102
|
+
let temperature = pressure === REGION12_SATURATION_PRESSURE
|
|
103
|
+
? R2_T_MIN
|
|
104
|
+
: normalizeRegion4Temperature(saturationTemperature(pressure));
|
|
105
|
+
if ((pressure > REGION12_SATURATION_PRESSURE && temperature <= R2_T_MIN) ||
|
|
106
|
+
(pressure < REGION12_SATURATION_PRESSURE && temperature >= R2_T_MIN)) {
|
|
107
|
+
// Keep a rounded derived temperature on the pressure's formula side.
|
|
108
|
+
temperature = nextPositiveFloat(R2_T_MIN, pressure > REGION12_SATURATION_PRESSURE ? 1 : -1);
|
|
69
109
|
}
|
|
70
|
-
return
|
|
71
|
-
pressure,
|
|
72
|
-
temperature,
|
|
73
|
-
liquid: region1(pressure, temperature),
|
|
74
|
-
vapor: region2(pressure, temperature),
|
|
75
|
-
};
|
|
110
|
+
return buildSaturationEndpoints(pressure, temperature);
|
|
76
111
|
}
|
|
77
112
|
/**
|
|
78
113
|
* Compute saturated liquid and vapour properties at a given temperature.
|
|
@@ -80,16 +115,8 @@ export function saturationEndpointsAtPressure(p) {
|
|
|
80
115
|
*/
|
|
81
116
|
export function saturationEndpointsAtTemperature(T) {
|
|
82
117
|
const temperature = normalizeRegion4Temperature(T);
|
|
83
|
-
const pressure =
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
pressure,
|
|
87
|
-
temperature,
|
|
88
|
-
liquid: region1(pressure, temperature),
|
|
89
|
-
vapor: region2(pressure, temperature),
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
return saturationEndpointsAtPressure(pressure);
|
|
118
|
+
const pressure = saturationPressure(temperature);
|
|
119
|
+
return buildSaturationEndpoints(pressure, temperature);
|
|
93
120
|
}
|
|
94
121
|
/**
|
|
95
122
|
* Compute vapour quality from any extensive saturation property.
|
|
@@ -123,10 +150,10 @@ export function mixSaturationState(endpoints, qualityInput) {
|
|
|
123
150
|
}
|
|
124
151
|
const { liquid, vapor, pressure, temperature } = endpoints;
|
|
125
152
|
if (quality === 0) {
|
|
126
|
-
return withRegion4Metadata(liquid, 0);
|
|
153
|
+
return withRegion4Metadata(liquid, 0, endpoints);
|
|
127
154
|
}
|
|
128
155
|
if (quality === 1) {
|
|
129
|
-
return withRegion4Metadata(vapor, 1);
|
|
156
|
+
return withRegion4Metadata(vapor, 1, endpoints);
|
|
130
157
|
}
|
|
131
158
|
return {
|
|
132
159
|
region: Region.Region4,
|
|
@@ -140,6 +167,7 @@ export function mixSaturationState(endpoints, qualityInput) {
|
|
|
140
167
|
cv: null,
|
|
141
168
|
speedOfSound: null,
|
|
142
169
|
quality,
|
|
170
|
+
saturation: endpoints,
|
|
143
171
|
isobaricExpansion: null,
|
|
144
172
|
isothermalCompressibility: null,
|
|
145
173
|
};
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import * as C from '../constants.js';
|
|
2
2
|
import { IF97Error, OutOfRangeError } from '../types.js';
|
|
3
3
|
export function normalizeRegion4Pressure(p) {
|
|
4
|
-
if (
|
|
4
|
+
if (p < C.P_MIN && C.P_MIN - p <= C.REGION4_PRESSURE_TOLERANCE * C.P_MIN)
|
|
5
5
|
return C.P_MIN;
|
|
6
|
-
if (
|
|
7
|
-
return C.Pt;
|
|
8
|
-
if (Math.abs(p - C.Pc) <= C.REGION4_PRESSURE_TOLERANCE)
|
|
6
|
+
if (p > C.Pc && p - C.Pc <= C.REGION4_PRESSURE_TOLERANCE * C.Pc)
|
|
9
7
|
return C.Pc;
|
|
10
8
|
return p;
|
|
11
9
|
}
|
|
12
10
|
export function normalizeRegion4Temperature(T) {
|
|
13
|
-
if (
|
|
11
|
+
if (T < C.T_MIN && C.T_MIN - T <= C.REGION4_TEMPERATURE_TOLERANCE)
|
|
14
12
|
return C.T_MIN;
|
|
15
|
-
if (
|
|
16
|
-
return C.Tt;
|
|
17
|
-
if (Math.abs(T - C.Tc) <= C.REGION4_TEMPERATURE_TOLERANCE)
|
|
13
|
+
if (T > C.Tc && T - C.Tc <= C.REGION4_TEMPERATURE_TOLERANCE)
|
|
18
14
|
return C.Tc;
|
|
19
15
|
return T;
|
|
20
16
|
}
|
|
@@ -31,7 +27,7 @@ function criticalPointMessage(solverName) {
|
|
|
31
27
|
return `${solverName} does not support the critical point P=${C.Pc} MPa, T=${C.Tc} K as a Region 4 saturation state`;
|
|
32
28
|
}
|
|
33
29
|
export function assertRegion4PressureStateInput(p, solverName) {
|
|
34
|
-
const pressure = normalizeRegion4Pressure(p);
|
|
30
|
+
const pressure = p < C.Pt && C.Pt - p <= 8 * Number.EPSILON * C.Pt ? C.Pt : normalizeRegion4Pressure(p);
|
|
35
31
|
if (pressure < C.Pt || pressure > C.Pc) {
|
|
36
32
|
throw new OutOfRangeError('Pressure', p, C.Pt, C.Pc);
|
|
37
33
|
}
|
|
@@ -41,9 +37,13 @@ export function assertRegion4PressureStateInput(p, solverName) {
|
|
|
41
37
|
return pressure;
|
|
42
38
|
}
|
|
43
39
|
export function assertRegion4TemperatureStateInput(T, solverName) {
|
|
44
|
-
const temperature = normalizeRegion4Temperature(T);
|
|
40
|
+
const temperature = T < C.Tt && C.Tt - T <= 8 * Number.EPSILON * C.Tt ? C.Tt : normalizeRegion4Temperature(T);
|
|
45
41
|
if (temperature < C.Tt || temperature > C.Tc) {
|
|
46
|
-
|
|
42
|
+
const error = new OutOfRangeError('Temperature', T, C.Tt, C.Tc);
|
|
43
|
+
if (temperature < C.Tt) {
|
|
44
|
+
error.message += `; ${solverName} saturation states start at the triple point (${C.Tt} K). 0 °C = 273.15 K is 0.01 K lower; low-level saturationPressure accepts 273.15 K.`;
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
47
|
}
|
|
48
48
|
if (temperature === C.Tc) {
|
|
49
49
|
throw new IF97Error(criticalPointMessage(solverName));
|
|
@@ -62,12 +62,12 @@ function isCriticalRegion4Entropy(s) {
|
|
|
62
62
|
return Math.abs(s - C.R3_S_CRT) <= C.REGION4_CRITICAL_HS_TOLERANCE;
|
|
63
63
|
}
|
|
64
64
|
export function assertCriticalRegion4PHInput(p, h, solverName) {
|
|
65
|
-
if (
|
|
65
|
+
if (p === C.Pc && isCriticalRegion4Enthalpy(h)) {
|
|
66
66
|
throw new IF97Error(criticalPointMessage(solverName));
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
export function assertCriticalRegion4PSInput(p, s, solverName) {
|
|
70
|
-
if (
|
|
70
|
+
if (p === C.Pc && isCriticalRegion4Entropy(s)) {
|
|
71
71
|
throw new IF97Error(criticalPointMessage(solverName));
|
|
72
72
|
}
|
|
73
73
|
}
|