iapws-if97 2.1.5 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/README.md +78 -215
  3. package/dist/backward/candidate-resolution.d.ts +8 -0
  4. package/dist/backward/candidate-resolution.js +40 -0
  5. package/dist/backward/fixed-temperature-candidates.d.ts +4 -0
  6. package/dist/backward/fixed-temperature-candidates.js +188 -0
  7. package/dist/backward/fixed-temperature-solver.d.ts +6 -6
  8. package/dist/backward/fixed-temperature-solver.js +56 -9
  9. package/dist/backward/fixed-temperature-stationary.d.ts +4 -0
  10. package/dist/backward/fixed-temperature-stationary.js +146 -0
  11. package/dist/backward/hs-region.d.ts +50 -0
  12. package/dist/backward/hs-region.js +695 -0
  13. package/dist/backward/hs-state.d.ts +15 -0
  14. package/dist/backward/hs-state.js +316 -0
  15. package/dist/backward/hs.d.ts +1 -2
  16. package/dist/backward/hs.js +28 -232
  17. package/dist/backward/ph.d.ts +8 -3
  18. package/dist/backward/ph.js +102 -54
  19. package/dist/backward/pressure-property-region.d.ts +13 -0
  20. package/dist/backward/pressure-property-region.js +262 -0
  21. package/dist/backward/ps.d.ts +6 -1
  22. package/dist/backward/ps.js +103 -38
  23. package/dist/backward/solution-validation.d.ts +7 -2
  24. package/dist/backward/solution-validation.js +162 -37
  25. package/dist/backward/th.d.ts +3 -6
  26. package/dist/backward/th.js +10 -73
  27. package/dist/backward/tolerances.d.ts +3 -1
  28. package/dist/backward/tolerances.js +9 -4
  29. package/dist/backward/ts.d.ts +3 -6
  30. package/dist/backward/ts.js +10 -73
  31. package/dist/boundaries.d.ts +0 -1
  32. package/dist/boundaries.js +0 -1
  33. package/dist/constants.d.ts +11 -24
  34. package/dist/constants.js +17 -28
  35. package/dist/core/floating-point.d.ts +2 -0
  36. package/dist/core/floating-point.js +7 -0
  37. package/dist/core/formulation-seams.d.ts +27 -0
  38. package/dist/core/formulation-seams.js +289 -0
  39. package/dist/core/input-validation.d.ts +1 -1
  40. package/dist/core/input-validation.js +5 -1
  41. package/dist/core/region-detector.d.ts +3 -41
  42. package/dist/core/region-detector.js +39 -597
  43. package/dist/core/region3-pt.d.ts +12 -1
  44. package/dist/core/region3-pt.js +68 -13
  45. package/dist/core/solve-input-normalization.d.ts +0 -1
  46. package/dist/core/solve-input-normalization.js +4 -2
  47. package/dist/core/solver.d.ts +7 -11
  48. package/dist/core/solver.js +26 -18
  49. package/dist/core/thermodynamic-derivatives.d.ts +17 -0
  50. package/dist/core/thermodynamic-derivatives.js +27 -0
  51. package/dist/detect.d.ts +16 -3
  52. package/dist/detect.js +36 -3
  53. package/dist/errors.d.ts +11 -0
  54. package/dist/errors.js +16 -0
  55. package/dist/gas-constant.d.ts +5 -0
  56. package/dist/gas-constant.js +5 -0
  57. package/dist/index.d.ts +4 -6
  58. package/dist/index.js +10 -22
  59. package/dist/regions/boundaries.d.ts +0 -1
  60. package/dist/regions/boundaries.js +0 -1
  61. package/dist/regions/region1.d.ts +2 -2
  62. package/dist/regions/region1.js +1 -2
  63. package/dist/regions/region2.d.ts +2 -2
  64. package/dist/regions/region2.js +1 -2
  65. package/dist/regions/region3-data.d.ts +0 -1
  66. package/dist/regions/region3-data.js +3 -4
  67. package/dist/regions/region3-eval.d.ts +0 -1
  68. package/dist/regions/region3-eval.js +0 -1
  69. package/dist/regions/region3-subregions.d.ts +0 -1
  70. package/dist/regions/region3-subregions.js +15 -11
  71. package/dist/regions/region3.d.ts +4 -2
  72. package/dist/regions/region3.js +32 -3
  73. package/dist/regions/region4.d.ts +2 -1
  74. package/dist/regions/region4.js +39 -13
  75. package/dist/regions/region5.d.ts +2 -2
  76. package/dist/regions/region5.js +2 -3
  77. package/dist/regions.d.ts +0 -1
  78. package/dist/regions.js +0 -1
  79. package/dist/saturation/common.d.ts +2 -9
  80. package/dist/saturation/common.js +66 -45
  81. package/dist/saturation/region4-boundaries.d.ts +0 -5
  82. package/dist/saturation/region4-boundaries.js +17 -18
  83. package/dist/saturation/region4-hs.d.ts +2 -1
  84. package/dist/saturation/region4-hs.js +499 -106
  85. package/dist/saturation/two-phase.d.ts +2 -3
  86. package/dist/saturation/two-phase.js +7 -8
  87. package/dist/saturation.d.ts +0 -1
  88. package/dist/saturation.js +0 -1
  89. package/dist/solvers/bracketed-newton.d.ts +10 -6
  90. package/dist/solvers/bracketed-newton.js +19 -13
  91. package/dist/solvers/damped-newton-2d.d.ts +12 -0
  92. package/dist/solvers/damped-newton-2d.js +68 -0
  93. package/dist/solvers/extended-arithmetic.d.ts +6 -0
  94. package/dist/solvers/extended-arithmetic.js +38 -0
  95. package/dist/solvers/newton-raphson.d.ts +0 -1
  96. package/dist/solvers/newton-raphson.js +0 -1
  97. package/dist/transport/properties.d.ts +4 -3
  98. package/dist/transport/properties.js +14 -5
  99. package/dist/transport.d.ts +0 -1
  100. package/dist/transport.js +0 -1
  101. package/dist/types.d.ts +18 -1
  102. package/dist/types.js +14 -1
  103. package/package.json +18 -10
  104. package/dist/backward/objective-normalization.d.ts +0 -7
  105. package/dist/backward/objective-normalization.js +0 -8
  106. package/dist/core/public-normalization.d.ts +0 -4
  107. package/dist/core/public-normalization.js +0 -54
  108. package/dist/solvers/nelder-mead.d.ts +0 -17
  109. package/dist/solvers/nelder-mead.js +0 -116
@@ -0,0 +1,289 @@
1
+ import * as C from '../constants.js';
2
+ import { boundary23_T_to_P } from '../regions/boundaries.js';
3
+ import { region1 } from '../regions/region1.js';
4
+ import { region2 } from '../regions/region2.js';
5
+ import { region5 } from '../regions/region5.js';
6
+ import { saturationPressure } from '../regions/region4.js';
7
+ import { bracketedNewton } from '../solvers/bracketed-newton.js';
8
+ import { gibbsPropertyDerivatives } from './thermodynamic-derivatives.js';
9
+ import { solveRegion3PTBasic } from './region3-pt.js';
10
+ import { detectRegionPT, nativeB23TemperatureBracket } from './region-detector.js';
11
+ import { nextPositiveFloat } from './floating-point.js';
12
+ function pairAt(seam, p, T) {
13
+ const r3 = () => solveRegion3PTBasic(p, T);
14
+ const lower = seam === '13' ? region1(p, T) : seam === '23' ? r3() : region2(p, T);
15
+ const upper = seam === '13' ? r3() : seam === '23' ? region2(p, T) : region5(p, T);
16
+ return {
17
+ seam, pressure: p, temperature: T,
18
+ lower, upper, canonical: lower,
19
+ };
20
+ }
21
+ export function formulationSeamAtPressure(p, seam) {
22
+ if (!Number.isFinite(p) || p < C.P_MIN || p > C.P_MAX)
23
+ return null;
24
+ if (seam === '25')
25
+ return p <= C.R5_P_MAX ? pairAt(seam, p, C.R2_T_MAX) : null;
26
+ if (p <= C.B23_P_MIN)
27
+ return null;
28
+ if (seam === '13')
29
+ return p > saturationPressure(C.R2_T_MIN) ? pairAt(seam, p, C.R2_T_MIN) : null;
30
+ const [T] = nativeB23TemperatureBracket(p);
31
+ return T <= C.R2_T_MIN || (T < C.Tc && p >= saturationPressure(T)) ? null : pairAt(seam, p, T);
32
+ }
33
+ /** B13/B25 cannot be crossed while retaining an independently supplied temperature. */
34
+ export function formulationSeamAtTemperature(T) {
35
+ if (!Number.isFinite(T) || T <= C.R2_T_MIN || T >= C.B23_T_MAX)
36
+ return null;
37
+ const p = boundary23_T_to_P(T);
38
+ return p > C.B23_P_MIN && p <= C.P_MAX &&
39
+ (T >= C.Tc || p < saturationPressure(T)) ? pairAt('23', p, T) : null;
40
+ }
41
+ export function findPressureSeam(p, target, property) {
42
+ if (!Number.isFinite(p) || !Number.isFinite(target) || p < C.P_MIN || p > C.P_MAX)
43
+ return null;
44
+ for (const seam of ['13', '23', '25']) {
45
+ if (seam === '25' ? p > C.R5_P_MAX : p <= C.B23_P_MIN)
46
+ continue;
47
+ let reference;
48
+ if (seam === '13') {
49
+ if (p <= saturationPressure(C.R2_T_MIN))
50
+ continue;
51
+ reference = region1(p, C.R2_T_MIN);
52
+ }
53
+ else if (seam === '23') {
54
+ const [T] = nativeB23TemperatureBracket(p);
55
+ if (T < C.Tc && p >= saturationPressure(T))
56
+ continue;
57
+ reference = region2(p, T);
58
+ }
59
+ else {
60
+ reference = region2(p, C.R2_T_MAX);
61
+ }
62
+ // IF97 Table 43 consistency limits only prefilter; acceptance uses the actual EOS span.
63
+ if (Math.abs(reference[property] - target) > (property === 'enthalpy' ? 0.2 : 0.0002))
64
+ continue;
65
+ const pair = formulationSeamAtPressure(p, seam);
66
+ const match = pair === null ? null : matchFixedSeam(pair, property, target);
67
+ if (match !== null)
68
+ return match;
69
+ }
70
+ return null;
71
+ }
72
+ function numericalAllowance(value) {
73
+ return 128 * Number.EPSILON * Math.max(1, Math.abs(value));
74
+ }
75
+ function resolution(pair, kind, hsReconstruction = false) {
76
+ return {
77
+ pair, kind, state: pair.canonical,
78
+ budgets: {
79
+ enthalpy: Math.abs(pair.upper.enthalpy - pair.lower.enthalpy) +
80
+ (hsReconstruction ? 1e-9 : numericalAllowance(pair.canonical.enthalpy)),
81
+ entropy: Math.abs(pair.upper.entropy - pair.lower.entropy) +
82
+ (hsReconstruction ? 1e-12 : numericalAllowance(pair.canonical.entropy)),
83
+ },
84
+ };
85
+ }
86
+ export function matchFixedSeam(pair, property, target, coordinate = 'pressure') {
87
+ if (coordinate === 'temperature' && pair.seam !== '23')
88
+ return null;
89
+ if (pair.seam === '23' && pair.pressure === C.P_MAX) {
90
+ const corner = region2(C.P_MAX, C.B23_T_MAX);
91
+ // The exact PT corner is R2, above the native quadratic's last R3 float.
92
+ if (target === corner[property])
93
+ return resolution({ ...pair, canonical: corner }, 'canonical');
94
+ }
95
+ const lower = pair.lower[property];
96
+ const upper = pair.upper[property];
97
+ if (!Number.isFinite(target) || target < Math.min(lower, upper) || target > Math.max(lower, upper))
98
+ return null;
99
+ if (target === pair.canonical[property])
100
+ return resolution(pair, 'canonical');
101
+ const interior = coordinate === 'temperature'
102
+ ? region2(nextPositiveFloat(pair.pressure, -1), pair.temperature)
103
+ : pair.seam === '13' ? solveRegion3PTBasic(pair.pressure, nextPositiveFloat(pair.temperature, 1))
104
+ : pair.seam === '23' ? region2(pair.pressure, nextPositiveFloat(pair.temperature, 1))
105
+ : region5(pair.pressure, nextPositiveFloat(pair.temperature, 1));
106
+ // EOS rounding can put the first admissible float inside the endpoint's gap.
107
+ if (coordinate === 'pressure' && detectRegionPT(interior.pressure, interior.temperature) === interior.region &&
108
+ Math.abs(interior[property] - target) <= (property === 'enthalpy' ? 1e-9 : 1e-12)) {
109
+ return resolution({ ...pair, canonical: interior }, 'canonical');
110
+ }
111
+ if (coordinate === 'temperature') {
112
+ if (target !== upper && interior[property] === target)
113
+ return null;
114
+ const first = gibbsPropertyDerivatives(pair.lower);
115
+ const second = gibbsPropertyDerivatives(pair.upper);
116
+ const derivative = property === 'enthalpy' ? 'dhDp' : 'dsDp';
117
+ if (first[derivative] >= 0 || second[derivative] >= 0)
118
+ return null;
119
+ }
120
+ return resolution(pair, upper > lower ? 'gap' : 'overlap');
121
+ }
122
+ function tangent(pair, state) {
123
+ const derivatives = gibbsPropertyDerivatives(state);
124
+ if (pair.seam !== '23')
125
+ return [derivatives.dhDp, derivatives.dsDp];
126
+ // Derivative of the native quadratic B23 pressure boundary.
127
+ const dpDT = -1.1671859879975 + 2 * 0.0010192970039326 * pair.temperature;
128
+ return [
129
+ derivatives.dhDT + derivatives.dhDp * dpDT,
130
+ derivatives.dsDT + derivatives.dsDp * dpDT,
131
+ ];
132
+ }
133
+ let hsDomains;
134
+ function b23LowerTemperature() {
135
+ let lower = C.R2_T_MIN;
136
+ let upper = C.Tc;
137
+ while (true) {
138
+ const middle = (lower + upper) / 2;
139
+ if (middle === lower || middle === upper)
140
+ return upper;
141
+ if (boundary23_T_to_P(middle) < saturationPressure(middle))
142
+ upper = middle;
143
+ else
144
+ lower = middle;
145
+ }
146
+ }
147
+ function pairAtParameter(seam, parameter) {
148
+ return seam === '23'
149
+ ? pairAt(seam, boundary23_T_to_P(parameter), parameter)
150
+ : pairAt(seam, parameter, seam === '13' ? C.R2_T_MIN : C.R2_T_MAX);
151
+ }
152
+ function hsSeamDomains() {
153
+ if (hsDomains !== undefined)
154
+ return hsDomains;
155
+ hsDomains = ['13', '23', '25'].map((seam) => {
156
+ const lower = seam === '25' ? C.P_MIN : seam === '13'
157
+ ? nextPositiveFloat(saturationPressure(C.R2_T_MIN), 1) : b23LowerTemperature();
158
+ const upper = seam === '25' ? C.R5_P_MAX : seam === '13'
159
+ ? C.P_MAX : nativeB23TemperatureBracket(C.P_MAX)[0];
160
+ const nodes = [lower, upper];
161
+ {
162
+ // Partition both equations at their folds before inverting either property.
163
+ for (const side of ['lower', 'upper']) {
164
+ for (const propertyIndex of [0, 1]) {
165
+ let previous = lower;
166
+ const first = pairAtParameter(seam, previous);
167
+ let previousDerivative = tangent(first, first[side])[propertyIndex];
168
+ for (let i = 1; i <= 16; i++) {
169
+ const current = lower + (upper - lower) * i / 16;
170
+ const pair = pairAtParameter(seam, current);
171
+ const currentDerivative = tangent(pair, pair[side])[propertyIndex];
172
+ if (previousDerivative * currentDerivative < 0) {
173
+ nodes.push(bracketedNewton((q) => {
174
+ const at = pairAtParameter(seam, q);
175
+ return tangent(at, at[side])[propertyIndex];
176
+ }, previous, current, undefined, { tolerance: 1e-13 }));
177
+ }
178
+ previous = current;
179
+ previousDerivative = currentDerivative;
180
+ }
181
+ }
182
+ }
183
+ }
184
+ nodes.sort((a, b) => a - b);
185
+ const states = nodes.flatMap((q) => {
186
+ const pair = pairAtParameter(seam, q);
187
+ return [pair.lower, pair.upper];
188
+ });
189
+ return {
190
+ seam, nodes,
191
+ minimumEntropy: Math.min(...states.map((state) => state.entropy)),
192
+ maximumEntropy: Math.max(...states.map((state) => state.entropy)),
193
+ minimumEnthalpy: Math.min(...states.map((state) => state.enthalpy)),
194
+ maximumEnthalpy: Math.max(...states.map((state) => state.enthalpy)),
195
+ };
196
+ });
197
+ return hsDomains;
198
+ }
199
+ /** Locate both constraints on one bounded ribbon between independently fitted EOS. */
200
+ export function findHSSeam(h, s) {
201
+ if (!Number.isFinite(h) || !Number.isFinite(s))
202
+ return null;
203
+ const corner = region2(C.P_MAX, C.B23_T_MAX);
204
+ if (h === corner.enthalpy && s === corner.entropy) {
205
+ return resolution({ ...formulationSeamAtPressure(C.P_MAX, '23'), canonical: corner }, 'canonical');
206
+ }
207
+ for (const domain of hsSeamDomains()) {
208
+ const entropyNoise = numericalAllowance(s);
209
+ const enthalpyNoise = numericalAllowance(h);
210
+ if (h < domain.minimumEnthalpy - enthalpyNoise || h > domain.maximumEnthalpy + enthalpyNoise)
211
+ continue;
212
+ if (s < domain.minimumEntropy - entropyNoise || s > domain.maximumEntropy + entropyNoise)
213
+ continue;
214
+ const cache = new Map();
215
+ const at = (q) => {
216
+ let pair = cache.get(q);
217
+ if (pair === undefined) {
218
+ pair = pairAtParameter(domain.seam, q);
219
+ cache.set(q, pair);
220
+ }
221
+ return pair;
222
+ };
223
+ const bounds = [...domain.nodes];
224
+ for (let i = 1; i < domain.nodes.length; i++) {
225
+ const lower = domain.nodes[i - 1];
226
+ const upper = domain.nodes[i];
227
+ for (const side of ['lower', 'upper']) {
228
+ const first = at(lower)[side].entropy - s;
229
+ const last = at(upper)[side].entropy - s;
230
+ if (first * last < 0) {
231
+ bounds.push(bracketedNewton((q) => at(q)[side].entropy - s, lower, upper, undefined, {
232
+ derivative: (q) => { const pair = at(q); return tangent(pair, pair[side])[1]; },
233
+ tolerance: 1e-13,
234
+ }));
235
+ }
236
+ }
237
+ }
238
+ bounds.sort((a, b) => a - b);
239
+ const hScale = Math.max(1, Math.abs(h));
240
+ const sScale = Math.max(1, Math.abs(s));
241
+ const crossResidual = (q) => {
242
+ const pair = at(q);
243
+ const dh = (pair.upper.enthalpy - pair.lower.enthalpy) / hScale;
244
+ const ds = (pair.upper.entropy - pair.lower.entropy) / sScale;
245
+ const length = Math.hypot(dh, ds);
246
+ return length === 0 ? (pair.lower.entropy - s) / sScale
247
+ : ((h - pair.lower.enthalpy) / hScale * ds - (s - pair.lower.entropy) / sScale * dh) / length;
248
+ };
249
+ const matchAt = (q) => {
250
+ const pair = at(q);
251
+ const dh = pair.upper.enthalpy - pair.lower.enthalpy;
252
+ const ds = pair.upper.entropy - pair.lower.entropy;
253
+ const scaledH = dh / hScale;
254
+ const scaledS = ds / sScale;
255
+ const squareLength = scaledH * scaledH + scaledS * scaledS;
256
+ const fraction = squareLength === 0 ? 0 : Math.max(0, Math.min(1, (((h - pair.lower.enthalpy) / hScale) * scaledH +
257
+ ((s - pair.lower.entropy) / sScale) * scaledS) / squareLength));
258
+ // Region 3 density inversion introduces cancellation beyond machine-noise in h/s.
259
+ if (Math.abs(pair.lower.enthalpy + fraction * dh - h) > 1e-9 ||
260
+ Math.abs(pair.lower.entropy + fraction * ds - s) > 1e-12)
261
+ return null;
262
+ if (Math.abs(pair.canonical.enthalpy - h) <= numericalAllowance(h) &&
263
+ Math.abs(pair.canonical.entropy - s) <= numericalAllowance(s))
264
+ return resolution(pair, 'canonical');
265
+ const direction = tangent(pair, pair.lower);
266
+ return resolution(pair, direction[0] * ds - direction[1] * dh > 0 ? 'gap' : 'overlap', true);
267
+ };
268
+ for (let i = 0; i < bounds.length; i++) {
269
+ const exact = matchAt(bounds[i]);
270
+ if (exact !== null)
271
+ return exact;
272
+ if (i === 0 || bounds[i] === bounds[i - 1])
273
+ continue;
274
+ const lower = bounds[i - 1];
275
+ const upper = bounds[i];
276
+ const middle = at((lower + upper) / 2);
277
+ if (s < Math.min(middle.lower.entropy, middle.upper.entropy) - entropyNoise ||
278
+ s > Math.max(middle.lower.entropy, middle.upper.entropy) + entropyNoise)
279
+ continue;
280
+ if (crossResidual(lower) * crossResidual(upper) >= 0)
281
+ continue;
282
+ const root = bracketedNewton(crossResidual, lower, upper, undefined, { tolerance: 4 * Number.EPSILON });
283
+ const match = matchAt(root);
284
+ if (match !== null)
285
+ return match;
286
+ }
287
+ }
288
+ return null;
289
+ }
@@ -1,2 +1,2 @@
1
1
  export declare function assertFiniteNumber(parameter: string, value: unknown): asserts value is number;
2
- //# sourceMappingURL=input-validation.d.ts.map
2
+ export declare function withinClosedLowerBound(value: number, boundary: number, property: 'enthalpy' | 'entropy'): boolean;
@@ -4,4 +4,8 @@ export function assertFiniteNumber(parameter, value) {
4
4
  throw new IF97Error(`${parameter} must be a finite number`);
5
5
  }
6
6
  }
7
- //# sourceMappingURL=input-validation.js.map
7
+ // shortcut: EOS cancellation floors are empirical; remeasure if the EOS evaluation changes.
8
+ export function withinClosedLowerBound(value, boundary, property) {
9
+ const floor = property === 'enthalpy' ? 1e-12 : 1e-14;
10
+ return value >= boundary - Math.max(floor, 8 * Number.EPSILON * Math.max(1, Math.abs(boundary)));
11
+ }
@@ -4,44 +4,6 @@ import { Region } from '../types.js';
4
4
  * @returns Region number (1–5) or -1 if out of range
5
5
  */
6
6
  export declare function detectRegionPT(p: number, T: number): Region | -1;
7
- /**
8
- * Detect region for P-H inputs.
9
- */
10
- export declare function detectRegionPH(p: number, h: number): Region | -1;
11
- /**
12
- * Detect region for P-S inputs.
13
- */
14
- export declare function detectRegionPS(p: number, s: number): Region | -1;
15
- /**
16
- * Detect the IAPWS-IF97 region for given T and H.
17
- *
18
- * Uses explicit enthalpy comparisons (including saturation-boundary proximity
19
- * checks via `isClose`) rather than the generic helper, because enthalpy is
20
- * not monotonic across regions at some temperatures.
21
- *
22
- * @param T - Temperature [K]
23
- * @param h - Specific enthalpy [kJ/kg]
24
- * @returns Region number (1–5) or -1 if out of range
25
- */
26
- export declare function detectRegionTH(T: number, h: number): Region | -1;
27
- /**
28
- * Detect the IAPWS-IF97 region for given T and S.
29
- *
30
- * Delegates to the generic temperature-property detector since entropy
31
- * is monotonic across regions at fixed temperature.
32
- *
33
- * @param T - Temperature [K]
34
- * @param s - Specific entropy [kJ/(kg·K)]
35
- * @returns Region number (1–5) or -1 if out of range
36
- */
37
- export declare function detectRegionTS(T: number, s: number): Region | -1;
38
- /**
39
- * Detect the IAPWS-IF97 region for given H and S.
40
- * Implements the zone-based detection from the IAPWS supplementary release.
41
- *
42
- * @param h - Specific enthalpy [kJ/kg]
43
- * @param s - Specific entropy [kJ/(kg·K)]
44
- * @returns Region number (1–5) or -1 if out of range
45
- */
46
- export declare function detectRegionHS(h: number, s: number): Region | -1;
47
- //# sourceMappingURL=region-detector.d.ts.map
7
+ export declare function nativeSaturationTemperatureBracket(p: number): readonly [number, number];
8
+ /** Invert the native B23 boundary; rounded Eq. (6) cannot determine PT ownership. */
9
+ export declare function nativeB23TemperatureBracket(p: number): readonly [number, number];