1use crate::gsw_internal_const::{DB2PA, GSW_PU, GSW_SFAC};
6use crate::gsw_sp_coefficients::*;
7use crate::gsw_specvol_coefficients::{V005, V006};
8use crate::{Error, Result};
9
10const G0: f64 = 2.641_463_563_366_498e-1;
11const G1: f64 = 2.007_883_247_811_176e-4;
12const G2: f64 = -4.107_694_432_853_053e-6;
13const G3: f64 = 8.401_670_882_091_225e-8;
14const G4: f64 = -1.711_392_021_989_21e-9;
15const G5: f64 = 3.374_193_893_377_38e-11;
16const G6: f64 = -5.923_731_174_730_784e-13;
17const G7: f64 = 8.057_771_569_962_299e-15;
18const G8: f64 = -7.054_313_817_447_962e-17;
19const G9: f64 = 2.859_992_717_347_235e-19;
20
21#[inline]
22pub(crate) fn non_dimensional_p(p: f64) -> f64 {
54 if cfg!(feature = "compat") {
55 p * 1e-4
56 } else {
57 p / GSW_PU
58 }
59}
60
61pub fn specvol_sso_0(p: f64) -> f64 {
74 const VXX0: f64 = if cfg!(feature = "compat") {
75 9.726_613_854_843_87e-4
76 } else {
77 9.726_613_854_843_871e-4
78 };
79
80 const VXX1: f64 = if cfg!(feature = "compat") {
81 -4.505_913_211_160_929e-5
82 } else {
83 -4.505_913_211_160_931e-5
84 };
85
86 const VXX2: f64 = if cfg!(feature = "compat") {
87 7.130_728_965_927_127e-6
88 } else {
89 7.130_728_965_927_128e-6
90 };
91
92 const VXX3: f64 = if cfg!(feature = "compat") {
93 -6.657_179_479_768_312e-7
94 } else {
95 -6.657_179_479_768_313e-7
96 };
97 const VXX4: f64 = if cfg!(feature = "compat") {
98 -2.994_054_447_232_88e-8
99 } else {
100 -2.994_054_447_232_877_6e-8
101 };
102
103 let p = non_dimensional_p(p);
104 VXX0 + p * (VXX1 + p * (VXX2 + p * (VXX3 + p * (VXX4 + p * (V005 + V006 * p)))))
105}
106
107#[cfg(test)]
108mod test_specvol_sso_0 {
109 use super::specvol_sso_0;
110 use crate::gsw_internal_const::GSW_SSO;
111 use crate::volume::specvol;
112
113 #[test]
115 fn specvol_vs_specvol_sso_0() {
116 let p_to_test: [f64; 5] = [0., 10., 100., 1_000., 5_000.];
117 for p in p_to_test.iter().cloned() {
118 let specvol = specvol(GSW_SSO, 0., p).unwrap();
119 let specvol_sso_0 = specvol_sso_0(p);
120 assert!((specvol - specvol_sso_0).abs() < f64::EPSILON);
121 }
122 }
123}
124
125pub(crate) fn enthalpy_sso_0(p: f64) -> f64 {
126 const H006: f64 = -2.107_876_881_00e-9;
127 const H007: f64 = 2.801_929_132_90e-10;
128
129 let z = p * 1.0e-4;
130
131 let dynamic_enthalpy_sso_0_p = z
132 * (9.726_613_854_843_87e-4
133 + z * (-2.252_956_605_630_465e-5
134 + z * (2.376_909_655_387_404e-6
135 + z * (-1.664_294_869_986_011e-7
136 + z * (-5.988_108_894_465_758e-9 + z * (H006 + H007 * z))))));
137
138 dynamic_enthalpy_sso_0_p * DB2PA * 1.0e4
139}
140
141pub(crate) fn hill_ratio_at_sp2(t: f64) -> f64 {
142 let sp2 = 2.0;
143
144 let t68: f64 = crate::conversions::t68_from_t90(t);
145 let ft68: f64 = (t68 - 15.0) / (1.0 + K * (t68 - 15.0));
146
147 let rtx0: f64 = G0
150 + t68
151 * (G1
152 + t68
153 * (G2
154 + t68
155 * (G3
156 + t68
157 * (G4
158 + t68
159 * (G5
160 + t68
161 * (G6
162 + t68 * (G7 + t68 * (G8 + t68 * G9))))))));
163
164 let dsp_drtx: f64 = A1
165 + (2.0 * A2 + (3.0 * A3 + (4.0 * A4 + 5.0 * A5 * rtx0) * rtx0) * rtx0) * rtx0
166 + ft68 * (B1 + (2.0 * B2 + (3.0 * B3 + (4.0 * B4 + 5.0 * B5 * rtx0) * rtx0) * rtx0) * rtx0);
167
168 let sp_est: f64 = A0
172 + (A1 + (A2 + (A3 + (A4 + A5 * rtx0) * rtx0) * rtx0) * rtx0) * rtx0
173 + ft68 * (B0 + (B1 + (B2 + (B3 + (B4 + B5 * rtx0) * rtx0) * rtx0) * rtx0) * rtx0);
174 let rtx: f64 = rtx0 - (sp_est - sp2) / dsp_drtx;
175 let rtxm: f64 = 0.5 * (rtx + rtx0);
176 let dsp_drtx: f64 = A1
177 + (2.0 * A2 + (3.0 * A3 + (4.0 * A4 + 5.0 * A5 * rtxm) * rtxm) * rtxm) * rtxm
178 + ft68 * (B1 + (2.0 * B2 + (3.0 * B3 + (4.0 * B4 + 5.0 * B5 * rtxm) * rtxm) * rtxm) * rtxm);
179 let rtx: f64 = rtx0 - (sp_est - sp2) / dsp_drtx;
180
181 let x: f64 = 400.0 * rtx * rtx;
186 let sqrty: f64 = 10.0 * rtx;
187 let part1: f64 = 1.0 + x * (1.5 + x);
188 let part2: f64 = 1.0 + sqrty * (1.0 + sqrty * (1.0 + sqrty));
189 let sp_hill_raw_at_sp2: f64 = sp2 - A0 / part1 - B0 * ft68 / part2;
190
191 2.0 / sp_hill_raw_at_sp2
192}
193
194#[cfg(test)]
195mod test_hill_ratio_at_sp2 {
196 use super::hill_ratio_at_sp2;
197
198 #[test]
199 fn example_values() {
203 let ratio = hill_ratio_at_sp2(0.);
204 assert!((ratio - 0.999_834_364_412_733_2).abs() <= f64::EPSILON);
205
206 let ratio = hill_ratio_at_sp2(10.);
207 assert!((ratio - 0.999_958_676_175_969_7).abs() <= f64::EPSILON);
208
209 let ratio = hill_ratio_at_sp2(25.);
210 assert!((ratio - 1.000_076_483_096_847_2).abs() <= f64::EPSILON);
211
212 let ratio = hill_ratio_at_sp2(30.);
213 assert!((ratio - 1.000_104_961_868_661_5).abs() <= f64::EPSILON,);
214
215 let ratio = hill_ratio_at_sp2(40.);
216 assert!((ratio - 1.000_151_589_022_029_8).abs() <= f64::EPSILON);
217
218 let ratio = hill_ratio_at_sp2(50.);
219 assert!((ratio - 1.000_188_151_345_468_5).abs() <= f64::EPSILON);
220 }
221}
222
223#[allow(dead_code, clippy::excessive_precision, clippy::manual_range_contains)]
224pub(crate) fn gibbs(ns: u8, nt: u8, np: u8, sa: f64, t: f64, p: f64) -> Result<f64> {
229 if sa.is_nan() | t.is_nan() | p.is_nan() {
231 return Ok(f64::NAN);
232 }
233
234 let sa: f64 = if sa < 0.0 {
235 if cfg!(feature = "compat") {
236 0.0
237 } else if cfg!(feature = "invalidasnan") {
238 return Ok(f64::NAN);
239 } else {
240 return Err(Error::NegativeSalinity);
241 }
242 } else {
243 sa
244 };
245
246 if (sa > 120.0) | (t < -12.0) | (t > 80.0) | (p > 12_000.0) {
247 if cfg!(feature = "invalidasnan") {
248 return Ok(f64::NAN);
249 } else {
250 return Err(Error::Undefined);
251 }
252 }
253
254 let x2 = GSW_SFAC * sa;
255 let x = libm::sqrt(x2);
256 let y = t * 0.025;
257 let z = non_dimensional_p(p);
259
260 if (ns == 0) & (nt == 0) & (np == 0) {
261 let g03 = 101.342_743_139_674
262 + z * (100_015.695_367_145
263 + z * (-2_544.576_542_036_3
264 + z * (284.517_778_446_287
265 + z * (-33.314_675_425_361_1
266 + (4.202_631_088_030_84 - 0.546_428_511_471_039 * z) * z))))
267 + y * (5.905_783_479_094_02
268 + z * (-270.983_805_184_062
269 + z * (776.153_611_613_101
270 + z * (-196.512_550_881_22
271 + (28.979_652_629_417_5 - 2.132_900_835_183_27 * z) * z)))
272 + y * (-12_357.785_933_039
273 + z * (1_455.036_454_046_8
274 + z * (-756.558_385_769_359
275 + z * (273.479_662_323_528
276 + z * (-55.560_406_381_721_8 + 4.344_206_719_171_97 * z))))
277 + y * (736.741_204_151_612
278 + z * (-672.507_783_145_07
279 + z * (499.360_390_819_152
280 + z * (-239.545_330_654_412
281 + (48.801_251_859_387_2 - 1.663_071_062_089_05 * z) * z)))
282 + y * (-148.185_936_433_658
283 + z * (397.968_445_406_972
284 + z * (-301.815_380_621_876
285 + (152.196_371_733_841 - 26.374_837_723_280_2 * z) * z))
286 + y * (58.025_912_584_257_1
287 + z * (-194.618_310_617_595
288 + z * (120.520_654_902_025
289 + z * (-55.272_305_234_015_2
290 + 6.481_906_680_772_21 * z)))
291 + y * (-18.984_384_651_417_2
292 + y * (3.050_816_464_879_67 - 9.631_081_193_930_62 * z)
293 + z * (63.511_393_664_178_5
294 + z * (-22.289_731_714_045_9
295 + 8.170_605_418_181_12 * z))))))));
296
297 let mut g08 = x2
298 * (1_416.276_484_841_97
299 + z * (-3_310.491_540_448_39
300 + z * (384.794_152_978_599
301 + z * (-96.532_432_010_745_8
302 + (15.840_817_276_682_4 - 2.624_801_565_909_92 * z) * z)))
303 + x * (-2_432.146_623_817_94
304 + x * (2_025.801_156_036_97
305 + y * (543.835_333_000_098
306 + y * (-68.557_250_920_449_1
307 + y * (49.366_769_485_625_4
308 + y * (-17.139_757_741_978_8 + 2.496_970_095_695_08 * y)))
309 - 22.668_355_851_282_9 * z)
310 + x * (-1_091.668_410_429_67 - 196.028_306_689_776 * y
311 + x * (374.601_237_877_84 - 48.589_106_902_540_9 * x
312 + 36.757_162_299_580_5 * y)
313 + 36.028_419_561_108_6 * z)
314 + z * (-54.791_913_353_288_7
315 + (-4.081_939_789_122_61 - 30.175_511_197_116_1 * z) * z))
316 + z * (199.459_603_073_901
317 + z * (-52.294_090_928_133_5
318 + (68.044_494_272_645_9 - 3.412_519_324_412_82 * z) * z))
319 + y * (-493.407_510_141_682
320 + z * (-175.292_041_186_547
321 + (83.192_392_780_181_9 - 29.483_064_349_429 * z) * z)
322 + y * (-43.066_467_597_804_2
323 + z * (383.058_066_002_476
324 + z * (-54.191_726_251_711_2 + 25.639_848_738_991_4 * z))
325 + y * (-10.022_737_086_187_5 - 460.319_931_801_257 * z
326 + y * (0.875_600_661_808_945 + 234.565_187_611_355 * z)))))
327 + y * (168.072_408_311_545
328 + z * (729.116_529_735_046
329 + z * (-343.956_902_961_561
330 + z * (124.687_671_116_248
331 + z * (-31.656_964_386_073 + 7.046_588_033_154_49 * z))))
332 + y * (880.031_352_997_204
333 + y * (-225.267_649_263_401
334 + y * (91.426_044_775_125_9
335 + y * (-21.660_324_087_531_1 + 2.130_169_708_471_83 * y)
336 + z * (-297.728_741_987_187
337 + (74.726_141_138_756 - 36.487_291_900_158_8 * z) * z))
338 + z * (694.244_814_133_268
339 + z * (-204.889_641_964_903
340 + (113.561_697_840_594 - 11.128_273_432_641_3 * z) * z)))
341 + z * (-860.764_303_783_977
342 + z * (337.409_530_269_367
343 + z * (-178.314_556_207_638
344 + (44.204_035_830_8 - 7.920_015_472_116_82 * z) * z))))));
345
346 if x > 0.0 {
347 g08 += x2 * (5_812.814_566_267_32 + 851.226_734_946_706 * y) * libm::log(x);
348 }
349
350 Ok(g03 + g08)
351 } else if (ns == 1) & (nt == 0) & (np == 0) {
352 let mut g08 = 8_645.367_535_951_26
353 + z * (-6_620.983_080_896_78
354 + z * (769.588_305_957_198
355 + z * (-193.064_864_021_491_6
356 + (31.681_634_553_364_8 - 5.249_603_131_819_84 * z) * z)))
357 + x * (-7_296.439_871_453_82
358 + x * (8_103.204_624_147_88
359 + y * (2_175.341_332_000_392
360 + y * (-274.229_003_681_796_4
361 + y * (197.467_077_942_501_6
362 + y * (-68.559_030_967_915_2 + 9.987_880_382_780_32 * y)))
363 - 90.673_423_405_131_6 * z)
364 + x * (-5_458.342_052_148_35 - 980.141_533_448_88 * y
365 + x * (2_247.607_427_267_04 - 340.123_748_317_786_3 * x
366 + 220.542_973_797_483 * y)
367 + 180.142_097_805_543 * z)
368 + z * (-219.167_653_413_154_8
369 + (-16.327_759_156_490_44 - 120.702_044_788_464_4 * z) * z))
370 + z * (598.378_809_221_703
371 + z * (-156.882_272_784_400_5
372 + (204.133_482_817_937_7 - 10.237_557_973_238_46 * z) * z))
373 + y * (-1_480.222_530_425_046
374 + z * (-525.876_123_559_641
375 + (249.577_178_340_545_71 - 88.449_193_048_287 * z) * z)
376 + y * (-129.199_402_793_412_6
377 + z * (1_149.174_198_007_428
378 + z * (-162.575_178_755_133_6 + 76.919_546_216_974_2 * z))
379 + y * (-30.068_211_258_562_5 - 1_380.959_795_403_770_8 * z
380 + y * (2.626_801_985_426_835 + 703.695_562_834_065 * z)))))
381 + y * (1_187.371_551_569_795_9
382 + z * (1_458.233_059_470_092
383 + z * (-687.913_805_923_122
384 + z * (249.375_342_232_496
385 + z * (-63.313_928_772_146 + 14.093_176_066_308_98 * z))))
386 + y * (1_760.062_705_994_408
387 + y * (-450.535_298_526_802
388 + y * (182.852_089_550_251_8
389 + y * (-43.320_648_175_062_2 + 4.260_339_416_943_66 * y)
390 + z * (-595.457_483_974_374
391 + (149.452_282_277_512 - 72.974_583_800_317_6 * z) * z))
392 + z * (1_388.489_628_266_536
393 + z * (-409.779_283_929_806
394 + (227.123_395_681_188 - 22.256_546_865_282_6 * z) * z)))
395 + z * (-1_721.528_607_567_954
396 + z * (674.819_060_538_734
397 + z * (-356.629_112_415_276
398 + (88.408_071_661_6 - 15.840_030_944_233_64 * z) * z)))));
399
400 if x > 0.0 {
401 g08 += (11_625.629_132_534_64 + 1_702.453_469_893_412 * y) * libm::log(x);
402 }
403 if x == 0.0 {
404 g08 = f64::NAN;
405 }
406
407 Ok(0.5 * GSW_SFAC * g08)
408 } else if (ns == 0) & (nt == 1) & (np == 0) {
409 let g03 = 5.905_783_479_094_02
410 + z * (-270.983_805_184_062
411 + z * (776.153_611_613_101
412 + z * (-196.512_550_881_22
413 + (28.979_652_629_417_5 - 2.132_900_835_183_27 * z) * z)))
414 + y * (-24_715.571_866_078
415 + z * (2_910.072_908_093_6
416 + z * (-1_513.116_771_538_718
417 + z * (546.959_324_647_056
418 + z * (-111.120_812_763_443_6 + 8.688_413_438_343_94 * z))))
419 + y * (2_210.223_612_454_836_3
420 + z * (-2_017.523_349_435_21
421 + z * (1_498.081_172_457_456
422 + z * (-718.635_991_963_235_9
423 + (146.403_755_578_161_6 - 4.989_213_186_267_150_5 * z) * z)))
424 + y * (-592.743_745_734_632
425 + z * (1_591.873_781_627_888
426 + z * (-1_207.261_522_487_504
427 + (608.785_486_935_364 - 105.499_350_893_120_8 * z) * z))
428 + y * (290.129_562_921_285_47
429 + z * (-973.091_553_087_975
430 + z * (602.603_274_510_125
431 + z * (-276.361_526_170_076 + 32.409_533_403_861_05 * z)))
432 + y * (-113.906_307_908_503_21
433 + y * (21.355_715_254_157_69 - 67.417_568_357_514_34 * z)
434 + z * (381.068_361_985_070_96
435 + z * (-133.738_390_284_275_4
436 + 49.023_632_509_086_724 * z)))))));
437
438 let mut g08 = x2
439 * (168.072_408_311_545
440 + z * (729.116_529_735_046
441 + z * (-343.956_902_961_561
442 + z * (124.687_671_116_248
443 + z * (-31.656_964_386_073 + 7.046_588_033_154_49 * z))))
444 + x * (-493.407_510_141_682
445 + x * (543.835_333_000_098
446 + x * (-196.028_306_689_776 + 36.757_162_299_580_5 * x)
447 + y * (-137.114_501_840_898_2
448 + y * (148.100_308_456_876_18
449 + y * (-68.559_030_967_915_2 + 12.484_850_478_475_4 * y)))
450 - 22.668_355_851_282_9 * z)
451 + z * (-175.292_041_186_547
452 + (83.192_392_780_181_9 - 29.483_064_349_429 * z) * z)
453 + y * (-86.132_935_195_608_4
454 + z * (766.116_132_004_952
455 + z * (-108.383_452_503_422_4 + 51.279_697_477_982_8 * z))
456 + y * (-30.068_211_258_562_5 - 1_380.959_795_403_770_8 * z
457 + y * (3.502_402_647_235_78 + 938.260_750_445_42 * z))))
458 + y * (1_760.062_705_994_408
459 + y * (-675.802_947_790_203
460 + y * (365.704_179_100_503_6
461 + y * (-108.301_620_437_655_52 + 12.781_018_250_830_98 * y)
462 + z * (-1_190.914_967_948_748
463 + (298.904_564_555_024 - 145.949_167_600_635_2 * z) * z))
464 + z * (2_082.734_442_399_804_3
465 + z * (-614.668_925_894_709
466 + (340.685_093_521_782 - 33.384_820_297_923_9 * z) * z)))
467 + z * (-1_721.528_607_567_954
468 + z * (674.819_060_538_734
469 + z * (-356.629_112_415_276
470 + (88.408_071_661_6 - 15.840_030_944_233_64 * z) * z)))));
471
472 if x > 0.0 {
473 g08 += 851.226_734_946_706 * x2 * libm::log(x);
474 }
475
476 Ok((g03 + g08) * 0.025)
477 } else if (ns == 0) & (nt == 0) & (np == 1) {
478 let g03 = 100_015.695_367_145
479 + z * (-5_089.153_084_072_6
480 + z * (853.553_335_338_861_1
481 + z * (-133.258_701_701_444_4
482 + (21.013_155_440_154_2 - 3.278_571_068_826_234 * z) * z)))
483 + y * (-270.983_805_184_062
484 + z * (1_552.307_223_226_202
485 + z * (-589.537_652_643_66
486 + (115.918_610_517_67 - 10.664_504_175_916_349 * z) * z))
487 + y * (1_455.036_454_046_8
488 + z * (-1_513.116_771_538_718
489 + z * (820.438_986_970_584
490 + z * (-222.241_625_526_887_2 + 21.721_033_595_859_85 * z)))
491 + y * (-672.507_783_145_07
492 + z * (998.720_781_638_304
493 + z * (-718.635_991_963_235_9
494 + (195.205_007_437_548_8 - 8.315_355_310_445_25 * z) * z))
495 + y * (397.968_445_406_972
496 + z * (-603.630_761_243_752
497 + (456.589_115_201_523 - 105.499_350_893_120_8 * z) * z)
498 + y * (-194.618_310_617_595
499 + y * (63.511_393_664_178_5 - 9.631_081_193_930_62 * y
500 + z * (-44.579_463_428_091_8
501 + 24.511_816_254_543_362 * z))
502 + z * (241.041_309_804_05
503 + z * (-165.816_915_702_045_6
504 + 25.927_626_723_088_84 * z)))))));
505
506 let g08 = x2
507 * (-3_310.491_540_448_39
508 + z * (769.588_305_957_198
509 + z * (-289.597_296_032_237_4
510 + (63.363_269_106_729_6 - 13.124_007_829_549_6 * z) * z))
511 + x * (199.459_603_073_901
512 + x * (-54.791_913_353_288_7 + 36.028_419_561_108_6 * x
513 - 22.668_355_851_282_9 * y
514 + (-8.163_879_578_245_22 - 90.526_533_591_348_31 * z) * z)
515 + z * (-104.588_181_856_267
516 + (204.133_482_817_937_7 - 13.650_077_297_651_28 * z) * z)
517 + y * (-175.292_041_186_547
518 + (166.384_785_560_363_8 - 88.449_193_048_287 * z) * z
519 + y * (383.058_066_002_476
520 + y * (-460.319_931_801_257 + 234.565_187_611_355 * y)
521 + z * (-108.383_452_503_422_4 + 76.919_546_216_974_2 * z))))
522 + y * (729.116_529_735_046
523 + z * (-687.913_805_923_122
524 + z * (374.063_013_348_744
525 + z * (-126.627_857_544_292 + 35.232_940_165_772_45 * z)))
526 + y * (-860.764_303_783_977
527 + y * (694.244_814_133_268
528 + y * (-297.728_741_987_187
529 + (149.452_282_277_512 - 109.461_875_700_476_41 * z) * z)
530 + z * (-409.779_283_929_806
531 + (340.685_093_521_782 - 44.513_093_730_565_2 * z) * z))
532 + z * (674.819_060_538_734
533 + z * (-534.943_668_622_914
534 + (176.816_143_323_2 - 39.600_077_360_584_095 * z) * z)))));
535 Ok((g03 + g08) * 1e-8)
536 } else if (ns == 1) & (nt == 1) & (np == 0) {
538 let mut g08 = 1_187.371_551_569_795_9
539 + z * (1_458.233_059_470_092
540 + z * (-687.913_805_923_122
541 + z * (249.375_342_232_496
542 + z * (-63.313_928_772_146 + 14.093_176_066_308_98 * z))))
543 + x * (-1_480.222_530_425_046
544 + x * (2_175.341_332_000_392
545 + x * (-980.141_533_448_88 + 220.542_973_797_483 * x)
546 + y * (-548.458_007_363_592_9
547 + y * (592.401_233_827_504_7
548 + y * (-274.236_123_871_660_8 + 49.939_401_913_901_6 * y)))
549 - 90.673_423_405_131_6 * z)
550 + z * (-525.876_123_559_641
551 + (249.577_178_340_545_71 - 88.449_193_048_287 * z) * z)
552 + y * (-258.398_805_586_825_2
553 + z * (2_298.348_396_014_856
554 + z * (-325.150_357_510_267_2 + 153.839_092_433_948_4 * z))
555 + y * (-90.204_633_775_687_5 - 4_142.879_386_211_312_5 * z
556 + y * (10.507_207_941_707_34 + 2_814.782_251_336_26 * z))))
557 + y * (3_520.125_411_988_816
558 + y * (-1_351.605_895_580_406
559 + y * (731.408_358_201_007_2
560 + y * (-216.603_240_875_311_03 + 25.562_036_501_661_96 * y)
561 + z * (-2_381.829_935_897_496
562 + (597.809_129_110_048 - 291.898_335_201_270_4 * z) * z))
563 + z * (4_165.468_884_799_608_5
564 + z * (-1_229.337_851_789_418
565 + (681.370_187_043_564 - 66.769_640_595_847_8 * z) * z)))
566 + z * (-3_443.057_215_135_908
567 + z * (1_349.638_121_077_468
568 + z * (-713.258_224_830_552
569 + (176.816_143_323_2 - 31.680_061_888_467_28 * z) * z))));
570
571 if sa == 0.0 {
572 g08 = f64::NAN;
573 } else if x > 0.0 {
574 g08 += 1_702.453_469_893_412 * libm::log(x);
575 }
576
577 Ok(0.5 * GSW_SFAC * 0.025 * g08)
578 } else if (ns == 1) & (nt == 0) & (np == 1) {
579 let g08 = -6_620.983_080_896_78
580 + z * (1_539.176_611_914_396
581 + z * (-579.194_592_064_474_8
582 + (126.726_538_213_459_2 - 26.248_015_659_099_2 * z) * z))
583 + x * (598.378_809_221_703
584 + x * (-219.167_653_413_154_8 + 180.142_097_805_543 * x
585 - 90.673_423_405_131_6 * y
586 + (-32.655_518_312_980_88 - 362.106_134_365_393_25 * z) * z)
587 + z * (-313.764_545_568_801
588 + (612.400_448_453_813_2 - 40.950_231_892_953_84 * z) * z)
589 + y * (-525.876_123_559_641
590 + (499.154_356_681_091_43 - 265.347_579_144_861 * z) * z
591 + y * (1_149.174_198_007_428
592 + y * (-1_380.959_795_403_770_8 + 703.695_562_834_065 * y)
593 + z * (-325.150_357_510_267_2 + 230.758_638_650_922_6 * z))))
594 + y * (1_458.233_059_470_092
595 + z * (-1_375.827_611_846_244
596 + z * (748.126_026_697_488
597 + z * (-253.255_715_088_584 + 70.465_880_331_544_9 * z)))
598 + y * (-1_721.528_607_567_954
599 + y * (1_388.489_628_266_536
600 + y * (-595.457_483_974_374
601 + (298.904_564_555_024 - 218.923_751_400_952_82 * z) * z)
602 + z * (-819.558_567_859_612
603 + (681.370_187_043_564 - 89.026_187_461_130_4 * z) * z))
604 + z * (1_349.638_121_077_468
605 + z * (-1_069.887_337_245_828
606 + (353.632_286_646_4 - 79.200_154_721_168_19 * z) * z))));
607
608 Ok(g08 * GSW_SFAC * 0.5e-8)
609 } else if (ns == 0) & (nt == 1) & (np == 1) {
613 let g03 = -270.983_805_184_062
614 + z * (1_552.307_223_226_202
615 + z * (-589.537_652_643_66
616 + (115.918_610_517_67 - 10.664_504_175_916_349 * z) * z))
617 + y * (2_910.072_908_093_6
618 + z * (-3_026.233_543_077_436
619 + z * (1_640.877_973_941_168
620 + z * (-444.483_251_053_774_4 + 43.442_067_191_719_7 * z)))
621 + y * (-2_017.523_349_435_21
622 + z * (2_996.162_344_914_912
623 + z * (-2_155.907_975_889_708
624 + (585.615_022_312_646_4 - 24.946_065_931_335_752 * z) * z))
625 + y * (1_591.873_781_627_888
626 + z * (-2_414.523_044_975_008
627 + (1_826.356_460_806_092 - 421.997_403_572_483_2 * z) * z)
628 + y * (-973.091_553_087_975
629 + z * (1_205.206_549_020_25
630 + z * (-829.084_578_510_228 + 129.638_133_615_444_2 * z))
631 + y * (381.068_361_985_070_96 - 67.417_568_357_514_34 * y
632 + z * (-267.476_780_568_550_8 + 147.070_897_527_260_17 * z))))));
633
634 let g08 = x2
635 * (729.116_529_735_046
636 + z * (-687.913_805_923_122
637 + z * (374.063_013_348_744
638 + z * (-126.627_857_544_292 + 35.232_940_165_772_45 * z)))
639 + x * (-175.292_041_186_547 - 22.668_355_851_282_9 * x
640 + (166.384_785_560_363_8 - 88.449_193_048_287 * z) * z
641 + y * (766.116_132_004_952
642 + y * (-1_380.959_795_403_770_8 + 938.260_750_445_42 * y)
643 + z * (-216.766_905_006_844_8 + 153.839_092_433_948_4 * z)))
644 + y * (-1_721.528_607_567_954
645 + y * (2_082.734_442_399_804_3
646 + y * (-1_190.914_967_948_748
647 + (597.809_129_110_048 - 437.847_502_801_905_65 * z) * z)
648 + z * (-1_229.337_851_789_418
649 + (1_022.055_280_565_346 - 133.539_281_191_695_6 * z) * z))
650 + z * (1_349.638_121_077_468
651 + z * (-1_069.887_337_245_828
652 + (353.632_286_646_4 - 79.200_154_721_168_19 * z) * z))));
653
654 Ok((g03 + g08) * 2.5e-10)
655 } else if (ns == 2) & (nt == 0) & (np == 0) {
658 let mut g08 = 5_812.814_566_267_320
659 + 851.226_734_946_706_0 * y
660 + x * (-3_648.219_935_726_910
661 + x * (8_103.204_624_147_880
662 + x * (-8_187.513_078_222_526
663 + x * (4_495.214_854_534_080 - 850.309_370_794_465_7 * x)))
664 + y * (-740.111_265_212_523_0
665 + x * (2_175.341_332_000_392
666 + x * (-1_470.212_300_173_320 + 441.085_947_594_966_0 * x))
667 + y * (-64.599_701_396_706_29 - 274.229_003_681_796_4 * x
668 + y * (-15.034_105_629_281_25
669 + 197.467_077_942_501_6 * x
670 + y * (1.313_400_992_713_418 - 68.559_030_967_915_21 * x
671 + 9.987_880_382_780_312 * x * y))))
672 + z * (299.189_404_610_851_5
673 + x * (-219.167_653_413_154_8 + 270.213_146_708_314_5 * x)
674 + y * (-262.938_061_779_820_5 - 90.673_423_405_131_60 * x
675 + y * (574.587_099_003_714_0
676 + y * (-690.479_897_701_885_4 + 351.847_781_417_032_5 * y)))
677 + z * (-78.441_136_392_200_25 - 16.327_759_156_490_44 * x
678 + y * (124.788_589_170_272_9 - 81.287_589_377_566_80 * y)
679 + z * (102.066_741_408_968_9 - 120.702_044_788_464_4 * x
680 + y * (-44.224_596_524_143_50 + 38.459_773_108_487_10 * y)
681 - 5.118_778_986_619_230 * z))));
682
683 if x > 0.0 {
684 g08 /= x2;
685 }
686 if x == 0.0 {
687 g08 = f64::NAN;
688 }
689
690 Ok(0.5 * GSW_SFAC * GSW_SFAC * g08)
691 } else if (ns == 0) & (nt == 2) & (np == 0) {
692 let g03 = -24_715.571_866_078
693 + z * (2_910.072_908_093_6
694 + z * (-1_513.116_771_538_718
695 + z * (546.959_324_647_056
696 + z * (-111.120_812_763_443_6 + 8.688_413_438_343_94 * z))))
697 + y * (4_420.447_224_909_672_5
698 + z * (-4_035.046_698_870_42
699 + z * (2_996.162_344_914_912
700 + z * (-1_437.271_983_926_471_9
701 + (292.807_511_156_323_2 - 9.978_426_372_534_301 * z) * z)))
702 + y * (-1_778.231_237_203_896
703 + z * (4_775.621_344_883_664
704 + z * (-3_621.784_567_462_512
705 + (1_826.356_460_806_092 - 316.498_052_679_362_44 * z) * z))
706 + y * (1_160.518_251_685_141_9
707 + z * (-3_892.366_212_351_9
708 + z * (2_410.413_098_040_5
709 + z * (-1_105.446_104_680_304 + 129.638_133_615_444_2 * z)))
710 + y * (-569.531_539_542_516
711 + y * (128.134_291_524_946_15 - 404.505_410_145_086_05 * z)
712 + z * (1_905.341_809_925_355
713 + z * (-668.691_951_421_377 + 245.118_162_545_433_62 * z))))));
714
715 let g08 = x2
716 * (1_760.062_705_994_408
717 + x * (-86.132_935_195_608_4
718 + x * (-137.114_501_840_898_2
719 + y * (296.200_616_913_752_36
720 + y * (-205.677_092_903_745_63 + 49.939_401_913_901_6 * y)))
721 + z * (766.116_132_004_952
722 + z * (-108.383_452_503_422_4 + 51.279_697_477_982_8 * z))
723 + y * (-60.136_422_517_125 - 2_761.919_590_807_541_7 * z
724 + y * (10.507_207_941_707_34 + 2_814.782_251_336_26 * z)))
725 + y * (-1_351.605_895_580_406
726 + y * (1_097.112_537_301_510_9
727 + y * (-433.206_481_750_622_06 + 63.905_091_254_154_904 * y)
728 + z * (-3_572.744_903_846_243_7
729 + (896.713_693_665_072 - 437.847_502_801_905_65 * z) * z))
730 + z * (4_165.468_884_799_608_5
731 + z * (-1_229.337_851_789_418
732 + (681.370_187_043_564 - 66.769_640_595_847_8 * z) * z)))
733 + z * (-1_721.528_607_567_954
734 + z * (674.819_060_538_734
735 + z * (-356.629_112_415_276
736 + (88.408_071_661_6 - 15.840_030_944_233_64 * z) * z))));
737
738 Ok((g03 + g08) * 0.000_625)
739 } else if (ns == 0) & (nt == 0) & (np == 2) {
740 let g03 = -5_089.153_084_072_6
741 + z * (1_707.106_670_677_722_1
742 + z * (-399.776_105_104_333_2
743 + (84.052_621_760_616_8 - 16.392_855_344_131_17 * z) * z))
744 + y * (1_552.307_223_226_202
745 + z * (-1_179.075_305_287_32
746 + (347.755_831_553_01 - 42.658_016_703_665_396 * z) * z)
747 + y * (-1_513.116_771_538_718
748 + z * (1_640.877_973_941_168
749 + z * (-666.724_876_580_661_5 + 86.884_134_383_439_4 * z))
750 + y * (998.720_781_638_304
751 + z * (-1_437.271_983_926_471_9
752 + (585.615_022_312_646_4 - 33.261_421_241_781 * z) * z)
753 + y * (-603.630_761_243_752
754 + (913.178_230_403_046 - 316.498_052_679_362_44 * z) * z
755 + y * (241.041_309_804_05
756 + y * (-44.579_463_428_091_8 + 49.023_632_509_086_724 * z)
757 + z * (-331.633_831_404_091_2 + 77.782_880_169_266_52 * z))))));
758
759 let g08 = x2
760 * (769.588_305_957_198
761 + z * (-579.194_592_064_474_8
762 + (190.089_807_320_188_78 - 52.496_031_318_198_4 * z) * z)
763 + x * (-104.588_181_856_267
764 + x * (-8.163_879_578_245_22 - 181.053_067_182_696_62 * z)
765 + (408.266_965_635_875_4 - 40.950_231_892_953_84 * z) * z
766 + y * (166.384_785_560_363_8 - 176.898_386_096_574 * z
767 + y * (-108.383_452_503_422_4 + 153.839_092_433_948_4 * z)))
768 + y * (-687.913_805_923_122
769 + z * (748.126_026_697_488
770 + z * (-379.883_572_632_876 + 140.931_760_663_089_8 * z))
771 + y * (674.819_060_538_734
772 + z * (-1_069.887_337_245_828
773 + (530.448_429_969_6 - 158.400_309_442_336_38 * z) * z)
774 + y * (-409.779_283_929_806
775 + y * (149.452_282_277_512 - 218.923_751_400_952_82 * z)
776 + (681.370_187_043_564 - 133.539_281_191_695_6 * z) * z))));
777
778 Ok((g03 + g08) * 1e-16)
779 } else if (ns == 0) & (nt == 3) & (np == 0) {
782 let g03 = 4_420.447_224_909_672_51
783 + y * (-3_556.462_474_407_791_89
784 + y * (3_481.554_755_055_425_63
785 + y * (-2_278.126_158_170_064_17 + 640.671_457_624_730_749 * y)))
786 + z * (-4_035.046_698_870_420_19
787 + y * (9_551.242_689_767_328_56
788 + y * (-11_677.098_637_055_699_3
789 + y * (7_621.367_239_701_419_75 - 2_022.527_050_725_430_23 * y)))
790 + z * (2_996.162_344_914_911_96
791 + y * (-7_243.569_134_925_023_72
792 + y * (7_231.239_294_121_499_37 - 2_674.767_805_685_507_94 * y))
793 + z * (-1_437.271_983_926_471_88
794 + y * (3_652.712_921_612_183_89
795 + y * (-3_316.338_314_040_911_88 + 980.472_650_181_734_480 * y))
796 + z * (292.807_511_156_323_187
797 + y * (-632.996_105_358_724_890 + 388.914_400_846_332_569 * y)
798 - 9.978_426_372_534_300_98 * z))));
799
800 let g08 = x2
801 * (-1_351.605_895_580_406
802 + x * (-60.136_422_517_125_0 + 296.200_616_913_752 * x)
803 + y * (2_194.225_074_603_02
804 + y * (-1_299.619_445_251_87 + 255.620_365_016_620 * y)
805 + x * (21.014_415_883_414_7
806 + x * (-411.354_185_807_491 + 149.818_205_741_705 * y)))
807 + z * (4_165.468_884_799_61 - 2_761.919_590_807_54 * x
808 + y * (-7_145.489_807_692_49 + 5_629.564_502_672_52 * x)
809 + z * (-1_229.337_851_789_42
810 + 1_793.427_387_330_14 * y
811 + z * (681.370_187_043_564
812 - 875.695_005_603_811 * y
813 - 66.769_640_595_847_8 * z))));
814
815 Ok((g03 + g08) * 0.000_625 * 0.025)
816 } else if (ns == 0) & (nt == 2) & (np == 1) {
817 let g03 = 2_910.072_908_093_60
818 + y * (-4_035.046_698_870_42
819 + y * (4_775.621_344_883_66
820 + y * (-3_892.366_212_351_90
821 + y * (1_905.341_809_925_35 - 404.505_410_145_086 * y))))
822 + z * (-3_026.233_543_077_44
823 + y * (5_992.324_689_829_82
824 + y * (-7_243.569_134_925_02
825 + y * (4_820.826_196_081_00 - 1_337.383_902_842_75 * y)))
826 + z * (1_640.877_973_941_17
827 + y * (-4_311.815_951_779_42
828 + y * (5_479.069_382_418_28
829 + y * (-3_316.338_314_040_91 + 735.354_487_636_301 * y)))
830 + z * (-444.483_251_053_774
831 + y * (1_171.230_044_625_29
832 + y * (-1_265.992_210_717_45 + 518.552_534_461_777 * y))
833 + z * (43.442_067_191_719_7 - 49.892_131_862_671_5 * y))));
834
835 let g08 = x2
836 * (-1_721.528_607_567_95 + 766.116_132_004_952 * x - 2_761.919_590_807_54 * x * y
837 + y * (4_165.468_884_799_61
838 + y * (-3_572.744_903_846_24 + 2_814.782_251_336_26 * x))
839 + z * (1_349.638_121_077_47 - 216.766_905_006_845 * x
840 + y * (-2_458.675_703_578_84 + 1_793.427_387_330_14 * y)
841 + z * (-1_069.887_337_245_83
842 + 153.839_092_433_949 * x
843 + y * (2_044.110_561_130_69 - 1_313.542_508_405_72 * y)
844 + z * (353.632_286_646_400
845 - 267.078_562_383_391 * y
846 - 79.200_154_721_168_2 * z))));
847
848 Ok((g03 + g08) * 2.5e-10 * 0.025)
849 } else if (ns == 1) & (nt == 1) & (np == 1) {
850 let g08 = 1_458.233_059_470_09
851 + x * (-525.876_123_559_641 - 90.673_423_405_131_6 * x
852 + y * (2_298.348_396_014_86
853 + y * (-4_142.879_386_211_31 + 2_814.782_251_336_26 * y)))
854 + y * (-3_443.057_215_135_91 + y * (4_165.468_884_799_61 - 2_381.829_935_897_50 * y))
855 + z * (-1_375.827_611_846_24
856 + x * (499.154_356_681_091 - 650.300_715_020_534 * y)
857 + y * (2_699.276_242_154_94
858 + y * (-2_458.675_703_578_84 + 1_195.618_258_220_10 * y))
859 + z * (748.126_026_697_488
860 + x * (-265.347_579_144_861 + 461.517_277_301_845 * y)
861 + y * (-2_139.774_674_491_66
862 + y * (2_044.110_561_130_69 - 875.695_005_603_811 * y))
863 + z * (-253.255_715_088_584
864 + y * (707.264_573_292_800 - 267.078_562_383_391 * y)
865 + z * (70.465_880_331_544_9 - 158.400_309_442_336 * y))));
866
867 Ok(g08 * GSW_SFAC * 0.5e-8 * 0.025)
868 } else if (ns == 2) & (nt == 0) & (np == 1) {
869 let mut g08 = 299.189_404_610_851_5
870 + x * (-219.167_653_413_154_8 + 270.213_146_708_314_5 * x)
871 + y * (-262.938_061_779_820_5 - 90.673_423_405_131_60 * x
872 + y * (574.587_099_003_714_0
873 + y * (-690.479_897_701_885_4 + 351.847_781_417_032_5 * y)))
874 + z * (-156.882_272_784_400_5 - 32.655_518_312_980_88 * x
875 + y * (249.577_178_340_545_7 - 162.575_178_755_133_6 * y)
876 + z * (306.200_224_226_906_6 - 362.106_134_365_393_2 * x
877 + y * (-132.673_789_572_430_5 + 115.379_319_325_461_3 * y)
878 - 20.475_115_946_476_92 * z));
879
880 if x > 0.0 {
881 g08 /= x;
882 }
883 if x == 0.0 {
884 g08 = f64::NAN;
885 }
886
887 Ok(0.5 * GSW_SFAC * GSW_SFAC * g08 * 1e-8)
888 } else if (ns == 1) & (nt == 2) & (np == 0) {
889 let mut g08 = 3_520.125_411_988_816
890 + x * (-258.398_805_586_825_2 - 548.458_007_363_592_9 * x)
891 + y * (-2_703.211_791_160_812
892 + x * (-180.409_267_551_375 + 1_184.802_467_655_009_4 * x)
893 + y * (2_194.225_074_603_021_7
894 + x * (31.521_623_825_122_02
895 + x * (-822.708_371_614_982_47 + 199.757_607_655_606_4 * y))
896 + y * (-866.412_963_501_244_1 + 127.810_182_508_309_8 * y)))
897 + z * (-3_443.057_215_135_908
898 + 2_298.348_396_014_856 * x
899 + y * (8_330.937_769_599_217 - 8_285.758_772_422_625 * x
900 + y * (-7_145.489_807_692_487_8 + 8_444.346_754_008_78 * x))
901 + z * (1_349.638_121_077_468 - 325.150_357_510_267_2 * x
902 + y * (-2_458.675_703_578_836 + 1_793.427_387_330_144 * y)
903 + z * (-713.258_224_830_552
904 + 153.839_092_433_948_4 * x
905 + y * (1_362.740_374_087_128 - 875.695_005_603_811_2 * y)
906 + z * (176.816_143_323_2
907 - 133.539_281_191_695_6 * y
908 - 31.680_061_888_467_3 * z))));
909
910 if x == 0.0 {
911 g08 = f64::NAN;
912 }
913
914 Ok(0.5 * GSW_SFAC * 0.025 * g08 * 0.025)
915 } else if (ns == 2) & (nt == 1) & (np == 0) {
916 let mut g08 = 851.226_734_946_705_96
917 + x * (-740.111_265_212_522_99
918 + x * (2_175.341_332_000_392_0
919 + x * (-1_470.212_300_173_319_9 + 441.085_947_594_966_00 * x))
920 + y * (-129.199_402_793_412_59 - 548.458_007_363_592_86 * x
921 + y * (-45.102_316_887_843_749
922 + 592.401_233_827_504_77 * x
923 + y * (5.253_603_970_853_670_4
924 + x * (-274.236_123_871_660_82 + 49.939_401_913_901_600 * y))))
925 + z * (-262.938_061_779_820_49 - 90.673_423_405_131_601 * x
926 + y * (1_149.174_198_007_428_0
927 + y * (-2_071.439_693_105_656_3 + 1_407.391_125_668_129_9 * y))
928 + z * (124.788_589_170_272_86 - 162.575_178_755_133_61 * y
929 + z * (-44.224_596_524_143_500 + 76.919_546_216_974_197 * y))));
930
931 if x > 0.0 {
932 g08 /= x2;
933 }
934 if x == 0.0 {
935 g08 = f64::NAN;
936 }
937
938 Ok(0.5 * GSW_SFAC * GSW_SFAC * g08 * 0.025)
939 } else if (ns == 1) & (nt == 0) & (np == 2) {
940 let g08 = 1_539.176_611_914_396_06
941 + x * (-313.764_545_568_801 - 32.655_518_312_980_9 * x)
942 + y * (-1_375.827_611_846_244
943 + 499.154_356_681_091_43 * x
944 + y * (1_349.638_121_077_468 - 325.150_357_510_267 * x
945 + y * (-819.558_567_859_612 + 298.904_564_555_024 * y)))
946 + z * (-1_158.389_184_128_949_6
947 + x * (1_224.800_896_907_626_3 - 724.212_268_730_786_5 * x)
948 + y * (1_496.252_053_394_976 - 530.695_158_289_722 * x
949 + y * (-2_139.774_674_491_656
950 + 461.517_277_301_845_2 * x
951 + y * (1_362.740_374_087_128 - 437.847_502_801_906 * y)))
952 + z * (380.179_614_640_378 - 122.850_695_678_862 * x
953 + y * (-759.767_145_265_752
954 + y * (1_060.896_859_939_2 - 267.078_562_383_391 * y))
955 + z * (-104.992_062_636_397
956 + y * (281.863_521_326_18 - 316.800_618_884_673 * y))));
957 Ok(g08 * GSW_SFAC * 0.5e-8 * 1e-8)
958 } else if (ns == 0) & (nt == 1) & (np == 2) {
959 let g03 = 1_552.307_223_226_202
960 + y * (-3_026.233_543_077_436
961 + y * (2_996.162_344_914_912
962 + y * (-2_414.523_044_975_008
963 + y * (1_205.206_549_020_25 - 267.476_780_568_550_8 * y))))
964 + z * (-1_179.075_305_287_32
965 + y * (3_281.755_947_882_336
966 + y * (-4_311.815_951_779_416
967 + y * (3_652.712_921_612_184
968 + y * (-1_658.169_157_020_456 + 294.141_795_054_520 * y))))
969 + z * (347.755_831_553_010
970 + y * (-1_333.449_753_161_323
971 + y * (1_756.845_066_937_94
972 + y * (-1_265.992_210_717_45 + 388.914_400_846_332_6 * y)))
973 + z * (-42.658_016_703_665_4
974 + y * (173.768_268_766_878_8 - 99.784_263_725_343_0 * y))));
975
976 let g08 = x2
977 * (-687.913_805_923_122_0
978 + 166.384_785_560_363_8 * x
979 + y * (1_349.638_121_077_468 - 216.766_905_006_844_8 * x
980 + y * (-1_229.337_851_789_418 + 597.809_129_110_048_0 * y))
981 + z * (748.126_026_697_488_0 - 176.898_386_096_574_0 * x
982 + y * (-2_139.774_674_491_656
983 + 307.678_184_867_896_8 * x
984 + y * (2_044.110_561_130_692 - 875.695_005_603_811_3 * y))
985 + z * (-379.883_572_632_876
986 + y * (1_060.896_859_939_20 - 400.617_843_575_086_8 * y)
987 + z * (140.931_760_663_089_8 - 316.800_618_884_672_8 * y))));
988
989 Ok((g03 + g08) * 2.5e-10 * 1e-8)
990 } else {
992 Err(Error::Undefined)
993 }
994}
995
996#[cfg(test)]
997mod test_gibbs {
998 use super::gibbs;
999
1000 #[test]
1001 fn nan() {
1005 for ns in 0..=1 {
1006 for nt in 0..=1 {
1007 for np in 0..=1 {
1008 let v = gibbs(ns, nt, np, f64::NAN, 1.0, 1.0);
1009 assert!(v.unwrap().is_nan());
1010
1011 let v = gibbs(ns, nt, np, 1.0, f64::NAN, 1.0);
1012 assert!(v.unwrap().is_nan());
1013
1014 let v = gibbs(ns, nt, np, 1.0, 1.0, f64::NAN);
1015 assert!(v.unwrap().is_nan());
1016 }
1017 }
1018 }
1019 }
1020
1021 #[test]
1022 fn checking_values() {
1025 let sa = 32.0;
1026 let t = 10.0;
1027 let p = 100.0;
1028 let check_values = [
1029 (0, 0, 0, 50.249_433_022_084_645),
1030 (0, 0, 1, 9.756_573_803_380_614e-4),
1031 (0, 0, 2, -4.319_267_169_958_817e-13),
1032 (0, 1, 0, -144.761_662_219_825_35),
1033 (0, 1, 1, 1.579_419_118_574_033e-7),
1034 (0, 1, 2, 1.731_843_128_190_281e-15),
1035 (0, 2, 0, -14.141_773_253_302_12),
1036 (0, 2, 1, 9.947_007_722_211_213e-9),
1037 (0, 3, 0, 4.830_012_068_790_147e-2),
1038 (1, 0, 0, 60.388_852_305_031_49),
1039 (1, 0, 1, -7.383_641_712_245_458e-7),
1040 (1, 0, 2, 1.306_882_540_566_367e-15),
1041 (1, 1, 0, 0.471_143_208_002_190_2),
1042 (1, 1, 1, 1.849_778_736_567_631e-9),
1043 (1, 2, 0, 1.904_117_940_743_395e-2),
1044 (2, 0, 0, 2.269_679_195_264_845),
1045 (2, 0, 1, 8.949_706_277_002_558e-10),
1046 (2, 1, 0, 1.013_083_889_176_643e-2),
1047 ];
1048
1049 for (ns, nt, np, ans) in check_values.iter() {
1050 assert!((gibbs(*ns, *nt, *np, sa, t, p).unwrap() - *ans).abs() < f64::EPSILON);
1051 }
1052 }
1053}
1054
1055#[allow(dead_code)]
1071pub(crate) fn gibbs_ice(nt: u8, np: u8, t: f64, p: f64) -> Result<f64> {
1072 use num_complex::Complex;
1074
1075 const GSW_T0: f64 = 273.15;
1076 const REC_TT: f64 = 3.660_858_105_139_845_e-3;
1077 const REC_PT: f64 = 1.634_903_221_903_779_e-3;
1078 const T1: Complex<f64> = Complex::new(3.680_171_128_550_51_e-2, 5.108_781_149_595_72_e-2);
1079 const T2: Complex<f64> = Complex::new(3.373_157_410_654_16_e-1, 3.354_494_159_193_09_e-1);
1080 const G00: f64 = -6.320_202_333_358_86_e5;
1081 const G01: f64 = 6.550_222_136_589_55_e-1;
1082 const G02: f64 = -1.893_699_293_261_31_e-8;
1083 const G03: f64 = 3.397_461_232_710_53_e-15; const G04: f64 = -5.564_648_690_589_91_e-22; const R21: Complex<f64> = Complex::new(-5.571_076_980_301_23_e-5, 4.645_786_345_808_06_e-5);
1086 const R22: Complex<f64> = Complex::new(2.348_014_092_159_13_e-11, -2.856_511_429_049_72_e-11);
1087 const TT: f64 = 273.16;
1088 const R20_GIBBS_ICE: Complex<f64> =
1090 Complex::new(-7.259_745_743_292_20_e1, -7.810_084_271_128_70_e1);
1091 const R1_GIBBS_ICE: Complex<f64> =
1093 Complex::new(4.470_507_162_853_88_e1, 6.568_768_474_634_81_e1);
1094
1095 let s0: f64 = -3.327_337_564_921_68_e3;
1097 let tau = Complex::new((t + GSW_T0) * REC_TT, 0.0);
1098 let dzi: f64 = DB2PA * p * REC_PT;
1099
1100 let tau_t1 = tau / T1;
1102 let sqtau_t1 = tau_t1 * tau_t1;
1103 let tau_t2 = tau / T2;
1104 let sqtau_t2 = tau_t2 * tau_t2;
1105 let r2 = R20_GIBBS_ICE + dzi * (R21 + R22 * dzi);
1106 let r2p = REC_PT * (R21 + 2.0 * R22 * dzi);
1107
1108 if nt == 0 && np == 0 {
1109 let g0: f64 = G00 + dzi * (G01 + dzi * (G02 + dzi * (G03 + dzi * G04)));
1110
1111 let g = R1_GIBBS_ICE
1112 * (tau * ((1.0 + tau_t1) / (1.0 - tau_t1)).ln()
1113 + T1 * ((1.0 - sqtau_t1).ln() - sqtau_t1))
1114 + r2 * ((tau * ((1.0 + tau_t2) / (1.0 - tau_t2)).ln())
1115 + T2 * ((1.0 - sqtau_t2).ln() - sqtau_t2));
1116
1117 Ok((g0 - TT * (s0 * tau - g.re)).re)
1118 } else if nt == 1 && np == 0 {
1119 let g = R1_GIBBS_ICE * (((1.0 + tau_t1) / (1.0 - tau_t1)).ln() - 2.0 * tau_t1)
1120 + r2 * (((1.0 + tau_t2) / (1.0 - tau_t2)).ln() - 2.0 * tau_t2);
1121
1122 Ok(-s0 + g.re)
1123 } else if nt == 0 && np == 1 {
1124 let g0p = REC_PT * (G01 + dzi * (2.0 * G02 + dzi * (3.0 * G03 + 4.0 * G04 * dzi)));
1125
1126 let g = r2p
1127 * (tau * ((1.0 + tau_t2) / (1.0 - tau_t2)).ln()
1128 + T2 * ((1.0 - sqtau_t2).ln() - sqtau_t2));
1129
1130 Ok(g0p + TT * g.re)
1131 } else if nt == 1 && np == 1 {
1132 let g = r2p * (((1.0 + tau_t2) / (1.0 - tau_t2)).ln() - 2.0 * tau_t2);
1133
1134 Ok(g.re)
1135 } else if nt == 2 && np == 0 {
1136 let g = R1_GIBBS_ICE * (1.0 / (T1 - tau) + 1.0 / (T1 + tau) - 2.0 / T1)
1139 + r2 * (1.0 / (T2 - tau));
1140
1141 Ok(REC_TT * g.re)
1142 } else if nt == 0 && np == 2 {
1143 let sqrec_pt = REC_PT * REC_PT;
1144
1145 let g0pp = sqrec_pt * (2.0 * G02 + dzi * (6.0 * G03 + 12.0 * G04 * dzi));
1146
1147 let r2pp = 2.0 * R22 * sqrec_pt;
1148
1149 let g = r2pp
1150 * (tau * ((1.0 + tau_t2) / (1.0 - tau_t2)).ln()
1151 + T2 * ((1.0 - sqtau_t2).ln() - sqtau_t2));
1152
1153 Ok(g0pp + TT * g.re)
1154 } else {
1155 Err(Error::OutOfBounds)
1156 }
1157}
1158
1159#[cfg(test)]
1160mod test_gibbs_ice {
1161
1162 use crate::gsw_internal_funcs::gibbs_ice;
1163 use crate::Error;
1164
1165 #[test]
1166 fn check_values() {
1167 let answers = [
1170 (0, 0, 98.267_598_402_919_25),
1171 (1, 0, 1_220.788_661_299_952_8),
1172 (0, 1, 0.001_090_843_442_926_435),
1173 (1, 1, 1.743_608_249_608_496_2E-7),
1174 (2, 0, -9.078_428_407_946_305),
1175 (0, 2, -1.284_848_246_397_617_7E-13),
1176 ];
1177 for (nt, np, ans) in answers.iter() {
1178 assert!(
1179 (gibbs_ice(*nt, *np, 0.0, 0.0).unwrap() - *ans).abs() < f64::EPSILON,
1180 "nt = {nt}, np = {np}, ans = {ans}"
1181 );
1182 }
1183 }
1185
1186 #[test]
1187 fn out_of_bounds() {
1188 match gibbs_ice(0, 3, 0.0, 0.0) {
1189 Err(Error::OutOfBounds) => (),
1190 _ => panic!("error should be OutOfBounds"),
1191 }
1192 }
1193
1194 #[test]
1195 fn nan() {
1199 let v = gibbs_ice(0, 0, 0.0, f64::NAN);
1200 assert!(v.unwrap().is_nan());
1201
1202 let v = gibbs_ice(0, 0, f64::NAN, 0.0);
1203 assert!(v.unwrap().is_nan());
1204
1205 let v = gibbs_ice(0, 0, f64::NAN, f64::NAN);
1206 assert!(v.unwrap().is_nan());
1207 }
1208}
1209
1210