1const _R: f64 = 0.461526;
2
3const REGION_1_COEFFS: [[f64; 3]; 34] = [
4 [0.0, -2.0, 0.14632971213167],
5 [0.0, -1.0, -0.84548187169114],
6 [0.0, 0.0, -0.37563603672040e1],
7 [0.0, 1.0, 0.33855169168385e1],
8 [0.0, 2.0, -0.95791963387872],
9 [0.0, 3.0, 0.15772038513228],
10 [0.0, 4.0, -0.16616417199501e-1],
11 [0.0, 5.0, 0.81214629983568e-3],
12 [1.0, -9.0, 0.28319080123804e-3],
13 [1.0, -7.0, -0.60706301565874e-3],
14 [1.0, -1.0, -0.18990068218419e-1],
15 [1.0, 0.0, -0.32529748770505e-1],
16 [1.0, 1.0, -0.21841717175414e-1],
17 [1.0, 3.0, -0.52838357969930e-4],
18 [2.0, -3.0, -0.47184321073267e-3],
19 [2.0, 0.0, -0.30001780793026e-3],
20 [2.0, 1.0, 0.47661393906987e-4],
21 [2.0, 3.0, -0.44141845330846e-5],
22 [2.0, 17.0, -0.72694996297594e-15],
23 [3.0, -4.0, -0.31679644845054e-4],
24 [3.0, 0.0, -0.28270797985312e-5],
25 [3.0, 6.0, -0.85205128120103e-9],
26 [4.0, -5.0, -0.22425281908000e-5],
27 [4.0, -2.0, -0.65171222895601e-6],
28 [4.0, 10.0, -0.14341729937924e-12],
29 [5.0, -8.0, -0.40516996860117e-6],
30 [8.0, -11.0, -0.12734301741641e-8],
31 [8.0, -6.0, -0.17424871230634e-9],
32 [21.0, -29.0, -0.68762131295531e-18],
33 [23.0, -31.0, 0.14478307828521e-19],
34 [29.0, -38.0, 0.26335781662795e-22],
35 [30.0, -39.0, -0.11947622640071e-22],
36 [31.0, -40.0, 0.18228094581404e-23],
37 [32.0, -41.0, -0.93537087292458e-25],
38];
39
40const REGION_1_BACK_COEFFS_PH: [[f64; 3]; 20] = [
41 [0.0, 0.0, -0.23872489924521e+3],
42 [0.0, 1.0, 0.40421188637945e+3],
43 [0.0, 2.0, 0.11349746881718e+3],
44 [0.0, 6.0, -0.58457616048039e+1],
45 [0.0, 22.0, -0.15285482413140e-3],
46 [0.0, 32.0, -0.10866707695377e-5],
47 [1.0, 0.0, -0.13391744872602e+2],
48 [1.0, 1.0, 0.43211039183559e+2],
49 [1.0, 2.0, -0.54010067170506e+2],
50 [1.0, 3.0, 0.30535892203916e+2],
51 [1.0, 4.0, -0.65964749423638e+1],
52 [1.0, 10.0, 0.93965400878363e-2],
53 [1.0, 32.0, 0.11573647505340e-6],
54 [2.0, 10.0, -0.25858641282073e-4],
55 [2.0, 32.0, -0.40644363084799e-8],
56 [3.0, 10.0, 0.66456186191635e-7],
57 [3.0, 32.0, 0.80670734103027e-10],
58 [4.0, 32.0, -0.93477771213947e-12],
59 [5.0, 32.0, 0.58265442020601e-14],
60 [6.0, 32.0, -0.15020185953503e-16]
61
62];
63const REGION_1_BACK_COEFFS_PS: [[f64; 3]; 20] = [
64 [0.0, 0.0, 0.17478268058307e+03],
65 [0.0, 1.0, 0.34806930892873e+02],
66 [0.0, 2.0, 0.65292584978455e+01],
67 [0.0, 3.0, 0.33039981775489],
68 [0.0, 11.0, -0.19281382923196e-06],
69 [0.0, 31.0, -0.24909197244573e-22],
70 [1.0, 0.0, -0.26107636489332],
71 [1.0, 1.0, 0.22592965981586],
72 [1.0, 2.0, -0.64256463395226e-01],
73 [1.0, 3.0, 0.78876289270526e-02],
74 [1.0, 12.0, 0.35672110607366e-09],
75 [1.0, 31.0, 0.17332496994895e-23],
76 [2.0, 0.0, 0.56608900654837e-03],
77 [2.0, 1.0, -0.32635483139717e-03],
78 [2.0, 2.0, 0.44778286690632e-04],
79 [2.0, 9.0, -0.51322156908507e-09],
80 [2.0, 31.0, -0.42522657042207e-25],
81 [3.0, 10.0, 0.26400441360689e-12],
82 [3.0, 32.0, 0.78124600459723e-28],
83 [4.0, 32.0, -0.30732199903668e-30]
84];
85
86
87const REGION_2_COEFFS_RES: [[f64; 3]; 43] = [
90 [1.0, 0.0, -0.0017731742473213],
91 [1.0, 1.0, -0.017834862292358],
92 [1.0, 2.0, -0.045996013696365],
93 [1.0, 3.0, -0.057581259083432],
94 [1.0, 6.0, -0.05032527872793],
95 [2.0, 1.0, -0.000033032641670203],
96 [2.0, 2.0, -0.00018948987516315],
97 [2.0, 4.0, -0.0039392777243355],
98 [2.0, 7.0, -0.043797295650573],
99 [2.0, 36.0, -0.000026674547914087],
100 [3.0, 0.0, 2.0481737692309E-08],
101 [3.0, 1.0, 4.3870667284435E-07],
102 [3.0, 3.0, -0.00003227767723857],
103 [3.0, 6.0, -0.0015033924542148],
104 [3.0, 35.0, -0.040668253562649],
105 [4.0, 1.0, -7.8847309559367E-10],
106 [4.0, 2.0, 1.2790717852285E-08],
107 [4.0, 3.0, 4.8225372718507E-07],
108 [5.0, 7.0, 2.2922076337661E-06],
109 [6.0, 3.0, -1.6714766451061E-11],
110 [6.0, 16.0, -0.0021171472321355],
111 [6.0, 35.0, -23.895741934104],
112 [7.0, 0.0, -5.905956432427E-18],
113 [7.0, 11.0, -1.2621808899101E-06],
114 [7.0, 25.0, -0.038946842435739],
115 [8.0, 8.0, 1.1256211360459E-11],
116 [8.0, 36.0, -8.2311340897998],
117 [9.0, 13.0, 1.9809712802088E-08],
118 [10.0, 4.0, 1.0406965210174E-19],
119 [10.0, 10.0, -1.0234747095929E-13],
120 [10.0, 14.0, -1.0018179379511E-09],
121 [16.0, 29.0, -8.0882908646985E-11],
122 [16.0, 50.0, 0.10693031879409],
123 [18.0, 57.0, -0.33662250574171],
124 [20.0, 20.0, 8.9185845355421E-25],
125 [20.0, 35.0, 3.0629316876232E-13],
126 [20.0, 48.0, -4.2002467698208E-06],
127 [21.0, 21.0, -5.9056029685639E-26],
128 [22.0, 53.0, 3.7826947613457E-06],
129 [23.0, 39.0, -1.2768608934681E-15],
130 [24.0, 26.0, 7.3087610595061E-29],
131 [24.0, 40.0, 5.5414715350778E-17],
132 [24.0, 58.0, -9.436970724121E-07],
133];
134
135const REGION_2_COEFFS_IDEAL: [[f64; 2]; 9] = [
136 [0.0, -0.96927686500217e1],
137 [1.0, 0.10086655968018e2],
138 [-5.0, -0.56087911283020e-2],
139 [-4.0, 0.71452738081455e-1],
140 [-3.0, -0.40710498223928],
141 [-2.0, 0.14240819171444e1],
142 [-1.0, -0.43839511319450e1],
143 [2.0, -0.28408632460772],
144 [3.0, 0.21268463753307e-1],
145];
146
147const REGION_4_SATURATION_COEFFS: [f64; 10] = [
148 0.11670521452767e4,
149 -0.72421316703206e6,
150 -0.17073846940092e2,
151 0.12020824702470e5,
152 -0.32325550322333e7,
153 0.14915108613530e2,
154 -0.48232657361591e4,
155 0.40511340542057e6,
156 -0.23855557567849,
157 0.65017534844798e3,
158];
159
160const REGION_3_COEFFS: [[f64; 3]; 40] = [
164 [0.0, 0.0, 0.10658070028513e1],
165 [0.0, 0.0, -0.15732845290239e2],
166 [0.0, 1.0, 0.20944396974307e2],
167 [0.0, 2.0, -0.76867707878716e1],
168 [0.0, 7.0, 0.26185947787954e1],
169 [0.0, 10.0, -0.28080781148620e1],
170 [0.0, 12.0, 0.12053369696517e1],
171 [0.0, 23.0, -0.84566812812502e-2],
172 [1.0, 2.0, -0.12654315477714e1],
173 [1.0, 6.0, -0.11524407806681e1],
174 [1.0, 15.0, 0.88521043984318],
175 [1.0, 17.0, -0.64207765181607],
176 [2.0, 0.0, 0.38493460186671],
177 [2.0, 2.0, -0.85214708824206],
178 [2.0, 6.0, 0.48972281541877e1],
179 [2.0, 7.0, -0.30502617256965e1],
180 [2.0, 22.0, 0.39420536879154e-1],
181 [2.0, 26.0, 0.12558408424308],
182 [3.0, 0.0, -0.27999329698710],
183 [3.0, 2.0, 0.13899799569460e1],
184 [3.0, 4.0, -0.20189915023570e1],
185 [3.0, 16.0, -0.82147637173963e-2],
186 [3.0, 26.0, -0.47596035734923],
187 [4.0, 0.0, 0.43984074473500e-1],
188 [4.0, 2.0, -0.44476435428739],
189 [4.0, 4.0, 0.90572070719733],
190 [4.0, 26.0, 0.70522450087967],
191 [5.0, 1.0, 0.10770512626332],
192 [5.0, 3.0, -0.32913623258954],
193 [5.0, 26.0, -0.50871062041158],
194 [6.0, 0.0, -0.22175400873096e-1],
195 [6.0, 2.0, 0.94260751665092e-1],
196 [6.0, 26.0, 0.16436278447961],
197 [7.0, 2.0, -0.13503372241348e-1],
198 [8.0, 26.0, -0.14834345352472e-1],
199 [9.0, 2.0, 0.57922953628084e-3],
200 [9.0, 26.0, 0.32308904703711e-2],
201 [10.0, 0.0, 0.80964802996215e-4],
202 [10.0, 1.0, -0.16557679795037e-3],
203 [11.0, 26.0, -0.44923899061815e-4],
204];
205
206pub enum Region {
207 Region1,
208 Region2,
209 Region3,
210 Region4,
211 Region5,
212}
213
214#[derive(Debug)]
215pub enum IAPWSError {
216 OutOfBounds(f64, f64),
217 NotImplemented()
218}
219
220pub fn region(t: f64, p: f64) -> Result<Region,IAPWSError> {
238 if t < 273.15 || t > 2273.15{
239 return Err(IAPWSError::OutOfBounds(t, p));
240 }
241 if p > 100e6 || p < 0.0{
242 return Err(IAPWSError::OutOfBounds(t, p));
243 }
244
245 if t <= 623.15 {
246 if p > p_sat(t){
247 return Ok(Region::Region1);
248 }else if p < p_sat(t) {
249 return Ok(Region::Region2);
250 }
251 return Ok(Region::Region4);
252 }
253
254 if t <= 863.15 {
255 if p > p_boundary_2_3(t){
256 return Ok(Region::Region3);
257 }else if p < p_boundary_2_3(t) {
258 return Ok(Region::Region2);
259 }
260 return Ok(Region::Region4);
261 }
262
263 if t < 1073.15 {
264 return Ok(Region::Region2);
265 }
266
267 if t >= 1073.15 {
268 if p > 50e6 {
269 return Err(IAPWSError::OutOfBounds(t, p));
270 }
271 return Ok(Region::Region5);
272 }
273
274
275 Err(IAPWSError::OutOfBounds(t, p))
276}
277
278pub fn h_tp(t: f64, p: f64) -> Result<f64, IAPWSError> {
291 let region = region(t, p)?;
292 return match region {
293 Region::Region1 => Ok(h_tp_1(t, p)),
294 Region::Region2 => Ok(h_tp_2(t, p)),
295 _ => Err(IAPWSError::NotImplemented())
296 }
297}
298
299pub fn u_tp(t: f64, p: f64) -> Result<f64, IAPWSError> {
312 let region = region(t, p)?;
313 return match region {
314 Region::Region1 => Ok(u_tp_1(t, p)),
315 Region::Region2 => Ok(u_tp_2(t, p)),
316 _ => Err(IAPWSError::NotImplemented())
317 }
318}
319
320fn gamma_1(t: f64, p: f64) -> f64 {
326 let tau = tau_1(t);
327 let pi = pi_1(p);
328 let mut sum = 0.0;
329 for i in 0..REGION_1_COEFFS.len() {
330 let ii = REGION_1_COEFFS[i][0] as i32;
331 let ji = REGION_1_COEFFS[i][1] as i32;
332 let ni = REGION_1_COEFFS[i][2];
333 sum += ni * (7.1 - pi).powi(ii) * (tau - 1.222).powi(ji);
334 }
335 sum
336}
337
338fn gamma_pi_1(t: f64, p: f64) -> f64 {
342 let tau = tau_1(t);
343 let pi = pi_1(p);
344 let mut sum = 0.0;
345 for i in 0..REGION_1_COEFFS.len() {
346 let ii = REGION_1_COEFFS[i][0] as i32;
347 let ji = REGION_1_COEFFS[i][1] as i32;
348 let ni = REGION_1_COEFFS[i][2];
349 sum += -ni * f64::from(ii) * (7.1 - pi).powi(ii - 1) * (tau - 1.222).powi(ji);
350 }
351 sum
352}
353
354fn gamma_pi_pi_1(t: f64, p: f64) -> f64 {
358 let tau = tau_1(t);
359 let pi = pi_1(p);
360 let mut sum = 0.0;
361 for i in 0..REGION_1_COEFFS.len() {
362 let ii = REGION_1_COEFFS[i][0] as i32;
363 let ji = REGION_1_COEFFS[i][1] as i32;
364 let ni = REGION_1_COEFFS[i][2];
365 sum += ni * f64::from(ii*(ii-1)) * (7.1 - pi).powi(ii - 2) * (tau - 1.222).powi(ji);
366 }
367 sum
368}
369
370fn gamma_tau_1(t: f64, p: f64) -> f64 {
374 let tau = tau_1(t);
375 let pi = pi_1(p);
376 let mut sum = 0.0;
377 for i in 0..REGION_1_COEFFS.len() {
378 let ii = REGION_1_COEFFS[i][0] as i32;
379 let ji = REGION_1_COEFFS[i][1] as i32;
380 let ni = REGION_1_COEFFS[i][2];
381 sum += ni * f64::from(ji) * (7.1 - pi).powi(ii) * (tau - 1.222).powi(ji - 1);
382 }
383 sum
384}
385
386fn gamma_tau_tau_1(t: f64, p: f64) -> f64 {
390 let tau = tau_1(t);
391 let pi = pi_1(p);
392 let mut sum = 0.0;
393 for i in 0..REGION_1_COEFFS.len() {
394 let ii = REGION_1_COEFFS[i][0] as i32;
395 let ji = REGION_1_COEFFS[i][1] as i32;
396 let ni = REGION_1_COEFFS[i][2];
397 sum += ni * f64::from(ji * (ji-1)) * (7.1 - pi).powi(ii) * (tau - 1.222).powi(ji - 2);
398 }
399 sum
400}
401
402fn gamma_pi_tau_1(t: f64, p: f64) -> f64 {
406 let tau = tau_1(t);
407 let pi = pi_1(p);
408 let mut sum = 0.0;
409 for i in 0..REGION_1_COEFFS.len() {
410 let ii = REGION_1_COEFFS[i][0] as i32;
411 let ji = REGION_1_COEFFS[i][1] as i32;
412 let ni = REGION_1_COEFFS[i][2];
413 sum += -ni * f64::from(ii * ji) * (7.1 - pi).powi(ii - 1) * (tau - 1.222).powi(ji - 1);
414 }
415 sum
416}
417
418fn tau_1(t: f64) -> f64 {
422 1386.0 / t
423}
424
425fn pi_1(p: f64) -> f64 {
429 p / (16.53e6)
430
431}
432
433pub fn h_tp_1(t: f64, p: f64) -> f64 {
437 _R * t * tau_1(t) * gamma_tau_1(t, p)
438}
439
440pub fn v_tp_1(t: f64, p: f64) -> f64 {
444 ((_R * 1000.0) * t / p) * pi_1(p) * gamma_pi_1(t, p)
446}
447
448pub fn u_tp_1(t: f64, p: f64) -> f64 {
452 _R * t * (tau_1(t) * gamma_tau_1(t, p) - pi_1(p) * gamma_pi_1(t,p))
453}
454
455pub fn s_tp_1(t: f64, p: f64) -> f64 {
459 _R * (tau_1(t) * gamma_tau_1(t, p) - gamma_1(t,p))
460}
461
462pub fn cp_tp_1(t: f64, p: f64) -> f64 {
466 let tau = tau_1(t);
467 _R * (-tau.powi(2) * gamma_tau_tau_1(t, p))
468}
469
470pub fn cv_tp_1(t: f64, p: f64) -> f64 {
474 let tau = tau_1(t);
475 let corr = (gamma_pi_1(t, p) - tau * gamma_pi_tau_1(t, p)).powi(2)/gamma_pi_pi_1(t, p);
476 _R * (-tau.powi(2) * gamma_tau_tau_1(t, p) + corr)
477}
478
479pub fn w_tp_1(t: f64, p: f64) -> f64 {
483 let tau = tau_1(t);
484 let gamma_pi = gamma_pi_1(t, p);
485 let gamma_pi_tau = gamma_pi_tau_1(t, p);
486 let gamma_pi_pi = gamma_pi_pi_1(t, p);
487 let gamma_tau_tau = gamma_tau_tau_1(t, p);
488 let term = (gamma_pi - tau * gamma_pi_tau).powi(2)/(tau.powi(2) * gamma_tau_tau);
489
490 let square = (_R * 1000.0) * t * (gamma_pi.powi(2)/(term - gamma_pi_pi));
492 square.sqrt()
493}
494
495fn theta_1_back(t: f64) -> f64 {
498 t
499}
500
501fn eta_1_back(h: f64) -> f64 {
504 h / 2500.0
505}
506
507fn pi_1_back(p: f64) -> f64{
510 p / 1e6
511}
512
513fn sigma_1_back(s: f64) -> f64{
516 s
517}
518
519pub fn t_ps_1(p: f64, s: f64) -> f64 {
523 let sig = sigma_1_back(s);
524 let pi = pi_1_back(p);
525 let mut sum = 0.0;
526 for i in 0..REGION_1_BACK_COEFFS_PS.len() {
527 let ii = REGION_1_BACK_COEFFS_PS[i][0] as i32;
528 let ji = REGION_1_BACK_COEFFS_PS[i][1] as i32;
529 let ni = REGION_1_BACK_COEFFS_PS[i][2];
530 sum += ni * pi.powi(ii) * (sig + 2.0).powi(ji);
531 }
532 sum
533}
534
535pub fn t_ph_1(p: f64, h: f64) -> f64 {
539 let eta = eta_1_back(h);
540 let pi = pi_1_back(p);
541 let mut sum = 0.0;
542 for i in 0..REGION_1_BACK_COEFFS_PH.len() {
543 let ii = REGION_1_BACK_COEFFS_PH[i][0] as i32;
544 let ji = REGION_1_BACK_COEFFS_PH[i][1] as i32;
545 let ni = REGION_1_BACK_COEFFS_PH[i][2];
546 sum += ni * pi.powi(ii) * (eta + 1.0).powi(ji);
547 }
548 sum
549}
550
551fn t_boundary_2_3(p: f64) -> f64 {
555 let pi = p / 1e6;
556 let theta_star = 1.0;
557 let n3 = 0.10192970039326e-2;
558 let n4 = 0.57254459862746e3;
559 let n5 = 0.13918839778870e2;
560 let theta = n4 + ((pi - n5)/n3).sqrt();
561 theta * theta_star
562}
563fn p_boundary_2_3(t: f64) -> f64 {
564 let p_star = 1e6;
565 let theta = t / 1.0;
566 let n1 = 0.34805185628969e3;
567 let n2 = -0.11671859879975e1;
568 let n3 = 0.10192970039326e-2;
569 p_star * (n1 + n2 * theta + n3 * theta*theta)
570
571 }
572
573fn tau_2(t: f64) -> f64 {
577 540.0 / t
578}
579
580fn pi_2(p: f64) -> f64 {
584 p / 1e6
585}
586
587fn gamma_2_ideal(t: f64, p: f64) -> f64 {
591 let pi = pi_2(p);
592 let mut sum: f64 = 0.0;
593 let tau = tau_2(t);
594 for i in 0..REGION_2_COEFFS_IDEAL.len() {
595 let ji = REGION_2_COEFFS_IDEAL[i][0];
596 let ni = REGION_2_COEFFS_IDEAL[i][1];
597 sum += ni * tau.powf(ji);
598 }
599 pi.ln() + sum
600}
601
602fn gamma_2_res(t: f64, p: f64) -> f64 {
606 let pi = pi_2(p);
607 let mut sum: f64 = 0.0;
608 let tau = tau_2(t);
609 for i in 0..REGION_2_COEFFS_RES.len() {
610 let ii = REGION_2_COEFFS_RES[i][0] as i32;
611 let ji = REGION_2_COEFFS_RES[i][1] as i32;
612 let ni = REGION_2_COEFFS_RES[i][2];
613 sum += ni * pi.powi(ii) * (tau - 0.5).powi(ji);
614 }
615 sum
616}
617
618fn gamma_tau_2_ideal(t: f64, _: f64) -> f64 {
622 let mut sum: f64 = 0.0;
623 let tau = tau_2(t);
624 for i in 0..REGION_2_COEFFS_IDEAL.len() {
625 let ji = REGION_2_COEFFS_IDEAL[i][0] as i32;
626 let ni = REGION_2_COEFFS_IDEAL[i][1];
627 sum += ni * f64::from(ji) * tau.powi(ji - 1);
628 }
629 sum
630}
631
632fn gamma_tau_tau_2_ideal(t: f64, _: f64) -> f64 {
636 let mut sum: f64 = 0.0;
637 let tau = tau_2(t);
638 for i in 0..REGION_2_COEFFS_IDEAL.len() {
639 let ji = REGION_2_COEFFS_IDEAL[i][0] as i32;
640 let ni = REGION_2_COEFFS_IDEAL[i][1];
641 sum += ni * f64::from(ji * (ji - 1)) * tau.powi(ji - 2);
642 }
643 sum
644}
645
646fn gamma_pi_2_ideal(_: f64, p: f64) -> f64 {
650 1.0 / pi_2(p)
651}
652
653fn gamma_tau_2_res(t: f64, p: f64) -> f64 {
657 let mut sum: f64 = 0.0;
658 let tau = tau_2(t);
659 let pi = pi_2(p);
660 for i in 0..REGION_2_COEFFS_RES.len() {
661 let ii = REGION_2_COEFFS_RES[i][0] as i32;
662 let ji = REGION_2_COEFFS_RES[i][1] as i32;
663 let ni = REGION_2_COEFFS_RES[i][2];
664 sum += ni * pi.powi(ii) * f64::from(ji) * (tau - 0.5).powi(ji - 1);
665 }
666 sum
667}
668
669fn gamma_tau_tau_2_res(t: f64, p: f64) -> f64 {
673 let mut sum: f64 = 0.0;
674 let tau = tau_2(t);
675 let pi = pi_2(p);
676 for i in 0..REGION_2_COEFFS_RES.len() {
677 let ii = REGION_2_COEFFS_RES[i][0] as i32;
678 let ji = REGION_2_COEFFS_RES[i][1] as i32;
679 let ni = REGION_2_COEFFS_RES[i][2];
680 sum += ni * pi.powi(ii) * f64::from(ji * (ji - 1)) * (tau - 0.5).powi(ji - 2);
681 }
682 sum
683}
684
685fn gamma_pi_2_res(t: f64, p: f64) -> f64 {
689 let mut sum: f64 = 0.0;
690 let tau = tau_2(t);
691 let pi = pi_2(p);
692 for i in 0..REGION_2_COEFFS_RES.len() {
693 let ii = REGION_2_COEFFS_RES[i][0] as i32;
694 let ji = REGION_2_COEFFS_RES[i][1] as i32;
695 let ni = REGION_2_COEFFS_RES[i][2];
696 sum += ni * pi.powi(ii - 1) * f64::from(ii) * (tau - 0.5).powi(ji);
697 }
698 sum
699}
700
701fn gamma_pi_pi_2_res(t: f64, p: f64) -> f64 {
705 let mut sum: f64 = 0.0;
706 let tau = tau_2(t);
707 let pi = pi_2(p);
708 for i in 0..REGION_2_COEFFS_RES.len() {
709 let ii = REGION_2_COEFFS_RES[i][0] as i32;
710 let ji = REGION_2_COEFFS_RES[i][1] as i32;
711 let ni = REGION_2_COEFFS_RES[i][2];
712 sum += ni * pi.powi(ii - 2) * f64::from(ii * (ii - 1)) * (tau - 0.5).powi(ji);
713 }
714 sum
715}
716
717fn gamma_pi_tau_2_res(t: f64, p: f64) -> f64 {
721 let mut sum: f64 = 0.0;
722 let tau = tau_2(t);
723 let pi = pi_2(p);
724 for i in 0..REGION_2_COEFFS_RES.len() {
725 let ii = REGION_2_COEFFS_RES[i][0] as i32;
726 let ji = REGION_2_COEFFS_RES[i][1] as i32;
727 let ni = REGION_2_COEFFS_RES[i][2];
728 sum += ni * pi.powi(ii - 1) * f64::from(ii * ji) * (tau - 0.5).powi(ji - 1);
729 }
730 sum
731}
732
733pub fn v_tp_2(t: f64, p: f64) -> f64 {
737 ((_R * 1000.0) * t / p) * pi_2(p) * (gamma_pi_2_ideal(t, p) + gamma_pi_2_res(t, p))
738}
739
740pub fn h_tp_2(t: f64, p: f64) -> f64 {
744 _R * t * tau_2(t) * (gamma_tau_2_ideal(t, p) + gamma_tau_2_res(t, p))
745}
746
747pub fn u_tp_2(t: f64, p: f64) -> f64 {
751 let tau = tau_2(t);
752 let pi = pi_2(p);
753 let tau_term = gamma_tau_2_ideal(t, p) + gamma_tau_2_res(t, p);
754 let pi_term = gamma_pi_2_ideal(t, p) + gamma_pi_2_res(t, p);
755 _R * t * (tau * tau_term - pi * pi_term)
756}
757
758pub fn s_tp_2(t: f64, p: f64) -> f64 {
762 let tau = tau_2(t);
763 let tau_term = gamma_tau_2_ideal(t, p) + gamma_tau_2_res(t, p);
764 let pi_term = gamma_2_ideal(t, p) + gamma_2_res(t, p);
765 _R * (tau * tau_term - pi_term)
766}
767
768pub fn cp_tp_2(t: f64, p: f64) -> f64 {
772 let tau = tau_2(t);
773 - _R * tau.powi(2) * (gamma_tau_tau_2_ideal(t, p) + gamma_tau_tau_2_res(t, p))
774}
775
776pub fn cv_tp_2(t: f64, p: f64) -> f64 {
780 let tau = tau_2(t);
781 let pi = pi_2(p);
782 let num = (1.0 + pi*gamma_pi_2_res(t, p) - tau * pi * gamma_pi_tau_2_res(t,p)).powi(2);
783 let den = 1.0 - pi.powi(2) * gamma_pi_pi_2_res(t,p);
784 cp_tp_2(t, p) - _R * num/ den
785}
786
787pub fn w_tp_2(t: f64, p: f64) -> f64 {
791 let tau = tau_2(t);
792 let pi = pi_2(p);
793 let num = 1.0 + 2.0*pi*gamma_pi_2_res(t, p) + pi.powi(2) * gamma_pi_2_res(t,p).powi(2);
794 let subnum = (1.0 + pi * gamma_pi_2_res(t, p) - tau * pi * gamma_pi_tau_2_res(t, p)).powi(2);
795 let subden = tau.powi(2)*(gamma_tau_tau_2_ideal(t, p) + gamma_tau_tau_2_res(t, p));
796 let den = 1.0 - pi.powi(2) * gamma_pi_pi_2_res(t,p) + subnum / subden;
797 ((_R * 1000.0 * t) * num / den).sqrt()
798}
799
800pub fn p_sat(t: f64) -> f64 {
805 let n1 = REGION_4_SATURATION_COEFFS[0];
806 let n2 = REGION_4_SATURATION_COEFFS[1];
807 let n3 = REGION_4_SATURATION_COEFFS[2];
808 let n4 = REGION_4_SATURATION_COEFFS[3];
809 let n5 = REGION_4_SATURATION_COEFFS[4];
810 let n6 = REGION_4_SATURATION_COEFFS[5];
811 let n7 = REGION_4_SATURATION_COEFFS[6];
812 let n8 = REGION_4_SATURATION_COEFFS[7];
813 let n9 = REGION_4_SATURATION_COEFFS[8];
814 let n10 = REGION_4_SATURATION_COEFFS[9];
815
816 let theta = t + n9 / (t - n10);
817
818 let coef_a = theta * theta + n1 * theta + n2;
819 let coef_b = n3 * theta * theta + n4 * theta + n5;
820 let coef_c = n6 * theta * theta + n7 * theta + n8;
821 (2.0 * coef_c / (-coef_b + (coef_b * coef_b - 4.0 * coef_a * coef_c).sqrt())).powi(4) * 1e6
822}
823
824pub fn t_sat(p: f64) -> f64 {
827 let n1 = REGION_4_SATURATION_COEFFS[0];
828 let n2 = REGION_4_SATURATION_COEFFS[1];
829 let n3 = REGION_4_SATURATION_COEFFS[2];
830 let n4 = REGION_4_SATURATION_COEFFS[3];
831 let n5 = REGION_4_SATURATION_COEFFS[4];
832 let n6 = REGION_4_SATURATION_COEFFS[5];
833 let n7 = REGION_4_SATURATION_COEFFS[6];
834 let n8 = REGION_4_SATURATION_COEFFS[7];
835 let n9 = REGION_4_SATURATION_COEFFS[8];
836 let n10 = REGION_4_SATURATION_COEFFS[9];
837
838 let beta = (p / 1e6).powf(0.25);
839
840 let coef_e = beta * beta + n3 * beta + n6;
841 let coef_f = n1 * beta * beta + n4 * beta + n7;
842 let coef_g = n2 * beta * beta + n5 * beta + n8;
843
844 let coef_d = 2.0 * coef_g / (-coef_f - (coef_f * coef_f - 4.0 * coef_e * coef_g).sqrt());
845
846 (n10 + coef_d - ((n10 + coef_d).powi(2) - 4.0 * (n9 + n10 * coef_d)).sqrt()) / 2.0
847}
848
849#[cfg(test)]
850mod tests {
851 use super::*;
852
853 fn is_close(x: f64, y: f64, tol: f64) -> bool {
854 (x - y).abs() < tol
855 }
856
857 #[test]
858 fn canary() {}
859
860 #[test]
861 fn region_1_enthalpy() {
862 let h1 = h_tp_1(300.0, 3e6);
863
864 assert!(is_close(h1 / 1000.0, 0.115331273, 1e-9));
865
866 let h1 = h_tp_1(300.0, 80e6);
867 assert!(is_close(h1 / 1000.0, 0.184142828, 1e-9));
868
869 let h1 = h_tp_1(500.0, 3e6);
870 assert!(is_close(h1 / 1000.0, 0.975542239, 1e-9));
871 }
872
873 #[test]
874 fn region_1_internal_energy() {
875 let u1 = u_tp_1(300.0, 3e6);
876
877 assert!(is_close(u1 / 1000.0, 0.112324818, 1e-9));
878
879 let u1 = u_tp_1(300.0, 80e6);
880 assert!(is_close(u1 / 1000.0, 0.106448356, 1e-9));
881
882 let u1 = u_tp_1(500.0, 3e6);
883 assert!(is_close(u1 / 1000.0, 0.971934985, 1e-9));
884 }
885
886 #[test]
887 fn region_1_entropy() {
888 let s1 = s_tp_1(300.0, 3e6);
889 assert!(is_close(s1 , 0.392294792, 1e-9));
890
891 let s1 = s_tp_1(300.0, 80e6);
892 assert!(is_close(s1 , 0.368563852, 1e-9));
893
894 let s1 = s_tp_1(500.0, 3e6);
895 assert!(is_close(s1 , 0.258041912e1, 1e-9));
896 }
897
898 #[test]
899 fn region_1_cp() {
900 let cp1 = cp_tp_1(300.0, 3e6);
901 println!("{}", cp1);
902 assert!(is_close(cp1/10.0 , 0.417301218, 1e-9));
903
904 let cp1 = cp_tp_1(300.0, 80e6);
905 assert!(is_close(cp1/10.0 , 0.401008987, 1e-9));
906
907 let cp1 = cp_tp_1(500.0, 3e6);
908 assert!(is_close(cp1/10.0 , 0.465580682, 1e-9));
909 }
910
911 #[test]
912 fn region_1_sound_velocity() {
913 let w1 = w_tp_1(300.0, 3e6);
914 assert!(is_close(w1/10000.0 , 0.150773921 , 1e-9));
915
916 let w1 = w_tp_1(300.0, 80e6);
917 assert!(is_close(w1/10000.0 , 0.163469054, 1e-9));
918
919 let w1 = w_tp_1(500.0, 3e6);
920 assert!(is_close(w1/10000.0 , 0.124071337, 1e-9));
921 }
922
923 #[test]
924 fn region_1_specific_volume() {
925 let v1 = v_tp_1(300.0, 3e6);
926 assert!(is_close(v1 * 100.0, 0.100215168, 1e-9));
927
928 let v1 = v_tp_1(300.0, 80e6);
929 assert!(is_close(v1 * 1000.0 , 0.971180894, 1e-9));
930
931 let v1 = v_tp_1(500.0, 3e6);
932 assert!(is_close(v1 * 100.0, 0.120241800, 1e-9));
933 }
934
935 #[test]
936 fn region_1_backwards_t_ph() {
937 let t = t_ph_1( 3e6, 500.0);
938 assert!(is_close(t / 1000.0, 0.391798509, 1e-9));
939
940 let t = t_ph_1( 80e6, 500.0);
941 assert!(is_close(t / 1000.0, 0.378108626, 1e-9));
942
943 let t = t_ph_1( 80e6, 1500.0);
944 assert!(is_close(t / 1000.0, 0.611041229, 1e-9));
945
946 }
947
948 #[test]
949 fn region_1_backwards_t_ps() {
950 let t = t_ps_1( 3e6, 0.5);
951 assert!(is_close(t / 1000.0, 0.307842258, 1e-9));
952
953 let t = t_ps_1( 80e6, 0.5);
954 assert!(is_close(t / 1000.0, 0.309979785, 1e-9));
955
956 let t = t_ps_1( 80e6, 3.0);
957 assert!(is_close(t / 1000.0, 0.565899909, 1e-9));
958
959 }
960
961 #[test]
962 fn region_2_specific_volume() {
963 let v = v_tp_2(300.0, 0.0035e6);
964 assert!(is_close(v / 100.0, 0.394913866, 1e-9));
965
966 let v = v_tp_2(700.0, 0.0035e6);
967 assert!(is_close(v / 100.0, 0.923015898 , 1e-9));
968
969 let v = v_tp_2(700.0, 30e6);
970 assert!(is_close(v / 0.01, 0.542946619, 1e-9));
971 }
972
973 #[test]
974 fn region_2_enthalpy() {
975 let h = h_tp_2(300.0, 0.0035e6);
976 assert!(is_close(h / 10000.0, 0.254991145, 1e-9));
977
978 let h = h_tp_2(700.0, 0.0035e6);
979 assert!(is_close(h / 10000.0, 0.333568375, 1e-9));
980
981 let h = h_tp_2(700.0, 30e6);
982 assert!(is_close(h / 10000.0, 0.263149474, 1e-9));
983 }
984
985 #[test]
986 fn region_2_internal_energy() {
987 let u = u_tp_2(300.0, 0.0035e6);
988 assert!(is_close(u / 10000.0, 0.241169160, 1e-9));
989
990 let u = u_tp_2(700.0, 0.0035e6);
991 assert!(is_close(u / 10000.0, 0.301262819, 1e-9));
992
993 let u = u_tp_2(700.0, 30e6);
994 assert!(is_close(u / 10000.0, 0.246861076, 1e-9));
995 }
996
997 #[test]
998 fn region_2_entropy() {
999 let s = s_tp_2(300.0, 0.0035e6);
1000 println!("{}", s);
1001 assert!(is_close(s / 10.0, 0.852238967, 1e-9));
1002
1003 let s = s_tp_2(700.0, 0.0035e6);
1004 assert!(is_close(s / 100.0, 0.101749996, 1e-9));
1005
1006 let s = s_tp_2(700.0, 30e6);
1007 assert!(is_close(s / 10.0, 0.517540298, 1e-9));
1008 }
1009
1010 #[test]
1011 fn region_2_cp() {
1012 let cp = cp_tp_2(300.0, 0.0035e6);
1013 assert!(is_close(cp / 10.0, 0.191300162, 1e-9));
1014
1015 let cp = cp_tp_2(700.0, 0.0035e6);
1016 assert!(is_close(cp / 10.0, 0.208141274 , 1e-9));
1017
1018 let cp = cp_tp_2(700.0, 30e6);
1019 assert!(is_close(cp / 100.0, 0.103505092, 1e-9));
1020 }
1021
1022 #[test]
1023 fn region_2_sound_velocity() {
1024 let w = w_tp_2(300.0, 0.0035e6);
1025 assert!(is_close(w / 1000.0, 0.427920172, 1e-9));
1026
1027 let w = w_tp_2(700.0, 0.0035e6);
1028 assert!(is_close(w / 1000.0, 0.644289068, 1e-9));
1029
1030 let w = w_tp_2(700.0, 30e6);
1031 assert!(is_close(w / 1000.0, 0.480386523, 1e-9));
1032 }
1033
1034 #[test]
1035 fn region_2_3_auxiliary_boundary() {
1036 let p = p_boundary_2_3(623.15);
1037 assert!(is_close(p / 1e8, 0.165291643, 1e-9));
1038
1039 let t = t_boundary_2_3(0.165291643e8);
1040 assert!(is_close(t / 1e3, 0.623150000, 1e-9));
1041
1042 }
1043
1044
1045 #[test]
1048 fn region_4_saturation_pressure() {
1049 let ps = p_sat(300.0);
1050 assert!(is_close(ps / 10000.0, 0.353658941, 1e-9));
1051
1052 let ps = p_sat(500.0);
1053 assert!(is_close(ps / 1e7, 0.263889776, 1e-9));
1054
1055 let ps = p_sat(600.0);
1056 assert!(is_close(ps / 1e8, 0.123443146, 1e-9));
1057 }
1058
1059 #[test]
1060 fn region_4_saturation_temperature() {
1061 let ts = t_sat(0.1e6);
1062 assert!(is_close(ts / 1000.0, 0.372755919, 1e-9));
1063
1064 let ts = t_sat(1e6);
1065 assert!(is_close(ts / 1000.0, 0.453035632, 1e-9));
1066
1067 let ts = t_sat(10e6);
1068 assert!(is_close(ts / 1000.0, 0.584149488, 1e-9));
1069 }
1070}