1use super::functions::R_UNIVERSAL;
6#[allow(unused_imports)]
7use super::functions::*;
8
9#[derive(Debug, Clone, Copy)]
14pub struct ShockHugoniot {
15 pub rho0: f64,
17 pub c0: f64,
19 pub s: f64,
21 pub p0: f64,
23}
24impl ShockHugoniot {
25 pub fn new(rho0: f64, c0: f64, s: f64) -> Self {
27 Self {
28 rho0,
29 c0,
30 s,
31 p0: 0.0,
32 }
33 }
34 pub fn aluminum() -> Self {
36 Self::new(2700.0, 5240.0, 1.4)
37 }
38 pub fn iron() -> Self {
40 Self::new(7874.0, 3574.0, 1.92)
41 }
42 pub fn shock_velocity(&self, u_p: f64) -> f64 {
44 self.c0 + self.s * u_p
45 }
46 pub fn hugoniot_pressure(&self, u_p: f64) -> f64 {
50 let u_s = self.shock_velocity(u_p);
51 self.rho0 * u_s * u_p + self.p0
52 }
53 pub fn post_shock_density(&self, u_p: f64) -> f64 {
57 let u_s = self.shock_velocity(u_p);
58 if (u_s - u_p).abs() < 1e-10 {
59 return f64::INFINITY;
60 }
61 self.rho0 * u_s / (u_s - u_p)
62 }
63 pub fn hugoniot_energy(&self, u_p: f64) -> f64 {
67 let p_h = self.hugoniot_pressure(u_p);
68 let rho_h = self.post_shock_density(u_p);
69 0.5 * (self.p0 + p_h) * (1.0 / self.rho0 - 1.0 / rho_h)
70 }
71}
72#[derive(Debug, Clone, Copy)]
77pub struct VinetEos {
78 pub v0: f64,
80 pub k0: f64,
82 pub k0_prime: f64,
84}
85impl VinetEos {
86 pub fn new(v0: f64, k0: f64, k0_prime: f64) -> Self {
88 Self { v0, k0, k0_prime }
89 }
90 pub fn diamond() -> Self {
92 Self::new(1.0 / 3515.0, 443.0e9, 3.6)
93 }
94 pub fn copper() -> Self {
96 Self::new(1.0 / 8960.0, 136.7e9, 5.3)
97 }
98 pub fn pressure_from_volume(&self, v: f64) -> f64 {
100 let x = (v / self.v0).powf(1.0 / 3.0);
101 if (x - 1.0).abs() < 1e-15 {
102 return 0.0;
103 }
104 let eta = 1.5 * (self.k0_prime - 1.0);
105 3.0 * self.k0 * (1.0 - x) / (x * x) * (eta * (1.0 - x)).exp()
106 }
107 pub fn volume(&self, pressure: f64) -> f64 {
109 let mut lo = self.v0 * 0.3;
110 let mut hi = self.v0 * 2.0;
111 for _ in 0..80 {
112 let mid = 0.5 * (lo + hi);
113 if self.pressure_from_volume(mid) > pressure {
114 lo = mid;
115 } else {
116 hi = mid;
117 }
118 }
119 0.5 * (lo + hi)
120 }
121}
122#[derive(Debug, Clone, Copy)]
128#[allow(dead_code)]
129pub struct JwlEos {
130 pub big_a: f64,
132 pub big_b: f64,
134 pub r1: f64,
136 pub r2: f64,
138 pub omega: f64,
140 pub e0: f64,
142 pub rho0: f64,
144}
145#[allow(dead_code)]
146impl JwlEos {
147 #[allow(clippy::too_many_arguments)]
149 pub fn new(big_a: f64, big_b: f64, r1: f64, r2: f64, omega: f64, e0: f64, rho0: f64) -> Self {
150 Self {
151 big_a,
152 big_b,
153 r1,
154 r2,
155 omega,
156 e0,
157 rho0,
158 }
159 }
160 pub fn tnt() -> Self {
162 Self::new(3.712e11, 3.231e9, 4.15, 0.95, 0.30, 7.0e9, 1630.0)
163 }
164 pub fn pressure(&self, rho: f64, e: f64) -> f64 {
169 let v = self.rho0 / rho.max(1e-30);
170 let term1 = self.big_a * (1.0 - self.omega / (self.r1 * v)) * (-self.r1 * v).exp();
171 let term2 = self.big_b * (1.0 - self.omega / (self.r2 * v)) * (-self.r2 * v).exp();
172 let term3 = self.omega * e / v;
173 term1 + term2 + term3
174 }
175}
176#[derive(Debug, Clone, Copy)]
182pub struct PolynomialEos {
183 pub rho0: f64,
185 pub a: [f64; 3],
187 pub b: [f64; 3],
189 pub t: [f64; 2],
191}
192impl PolynomialEos {
193 pub fn new(rho0: f64, a: [f64; 3], b: [f64; 3], t: [f64; 2]) -> Self {
195 Self { rho0, a, b, t }
196 }
197 pub fn mu(&self, density: f64) -> f64 {
199 density / self.rho0 - 1.0
200 }
201 pub fn pressure_energy(&self, density: f64, energy: f64) -> f64 {
203 let mu = self.mu(density);
204 if mu >= 0.0 {
205 let poly = self.a[0] * mu + self.a[1] * mu * mu + self.a[2] * mu * mu * mu;
206 let energy_term = (self.b[0] + self.b[1] * mu + self.b[2] * mu * mu) * density * energy;
207 poly + energy_term
208 } else {
209 self.t[0] * mu + self.t[1] * mu * mu
210 }
211 }
212}
213#[derive(Debug, Clone, Copy)]
217pub struct GruneisenParameter {
218 pub gamma_0: f64,
220 pub v0: f64,
222 pub q: f64,
224}
225impl GruneisenParameter {
226 pub fn new(gamma_0: f64, v0: f64, q: f64) -> Self {
228 Self { gamma_0, v0, q }
229 }
230 pub fn evaluate(&self, v: f64) -> f64 {
232 self.gamma_0 * (v / self.v0).powf(self.q)
233 }
234 pub fn thermal_pressure(&self, density: f64, cv: f64, temperature: f64, t0: f64) -> f64 {
236 let v = 1.0 / density;
237 self.evaluate(v) * density * cv * (temperature - t0)
238 }
239}
240#[derive(Debug, Clone, Copy)]
244#[allow(dead_code)]
245pub struct PengRobinson {
246 pub tc: f64,
248 pub pc: f64,
250 pub omega: f64,
252}
253#[allow(dead_code)]
254impl PengRobinson {
255 pub fn new(tc: f64, pc: f64, omega: f64) -> Self {
257 Self { tc, pc, omega }
258 }
259 pub fn b_param(&self) -> f64 {
261 0.07780 * R_UNIVERSAL * self.tc / self.pc
262 }
263 pub fn a_critical(&self) -> f64 {
265 0.45724 * R_UNIVERSAL * R_UNIVERSAL * self.tc * self.tc / self.pc
266 }
267 pub fn acentric_factor_correction(&self, t: f64) -> f64 {
272 let kappa = 0.37464 + 1.54226 * self.omega - 0.26992 * self.omega * self.omega;
273
274 (1.0 + kappa * (1.0 - (t / self.tc).sqrt())).powi(2)
275 }
276 pub fn a_param(&self, t: f64) -> f64 {
278 self.a_critical() * self.acentric_factor_correction(t)
279 }
280 pub fn pressure(&self, t: f64, v_mol: f64) -> f64 {
282 let b = self.b_param();
283 let a_t = self.a_param(t);
284 if (v_mol - b).abs() < 1e-20 {
285 return f64::INFINITY;
286 }
287 R_UNIVERSAL * t / (v_mol - b) - a_t / (v_mol * (v_mol + b) + b * (v_mol - b))
288 }
289}
290#[derive(Debug, Clone, Copy)]
296#[allow(dead_code)]
297pub struct MurnaghanEos {
298 pub v0: f64,
300 pub k0: f64,
302 pub n: f64,
304}
305#[allow(dead_code)]
306impl MurnaghanEos {
307 pub fn new(v0: f64, k0: f64, n: f64) -> Self {
309 Self { v0, k0, n }
310 }
311 pub fn aluminum() -> Self {
313 Self::new(1.0 / 2700.0, 76.0e9, 4.5)
314 }
315 pub fn iron() -> Self {
317 Self::new(1.0 / 7874.0, 170.0e9, 4.9)
318 }
319 pub fn pressure_from_volume(&self, v: f64) -> f64 {
323 if self.n.abs() < f64::EPSILON {
324 return 0.0;
325 }
326 (self.k0 / self.n) * ((self.v0 / v).powf(self.n) - 1.0)
327 }
328 pub fn volume_from_pressure(&self, pressure: f64) -> f64 {
332 let x = 1.0 + self.n * pressure / self.k0;
333 if x <= 0.0 {
334 return self.v0 * 0.01;
335 }
336 self.v0 / x.powf(1.0 / self.n)
337 }
338 pub fn bulk_modulus(&self, v: f64) -> f64 {
340 self.k0 * (self.v0 / v).powf(self.n)
341 }
342}
343#[derive(Debug, Clone, Copy)]
350#[allow(dead_code)]
351pub struct TaitBulkEos {
352 pub k0: f64,
354 pub k0_prime: f64,
356 pub rho0: f64,
358}
359#[allow(dead_code)]
360impl TaitBulkEos {
361 pub fn new(k0: f64, k0_prime: f64, rho0: f64) -> Self {
363 Self { k0, k0_prime, rho0 }
364 }
365 pub fn water() -> Self {
367 Self::new(2.2e9, 6.0, 997.0)
368 }
369 pub fn pressure(&self, rho: f64) -> f64 {
375 let ratio = rho / self.rho0;
376 self.k0 / self.k0_prime * (ratio.powf(self.k0_prime) - 1.0)
377 }
378 #[allow(dead_code)]
380 pub fn sound_speed(&self, rho: f64) -> f64 {
381 let ratio = rho / self.rho0;
382 (self.k0 * ratio.powf(self.k0_prime - 1.0) / self.rho0).sqrt()
383 }
384}
385#[derive(Debug, Clone, Copy)]
387pub struct IdealGasEos {
388 pub gamma: f64,
390 pub specific_gas_constant: f64,
392}
393impl IdealGasEos {
394 pub fn new(gamma: f64, specific_gas_constant: f64) -> Self {
396 Self {
397 gamma,
398 specific_gas_constant,
399 }
400 }
401 pub fn air() -> Self {
403 Self::new(1.4, 287.0)
404 }
405 pub fn hydrogen() -> Self {
407 Self::new(1.4, 4157.0)
408 }
409 pub fn pressure_at_temperature(&self, density: f64, temperature: f64) -> f64 {
411 density * self.specific_gas_constant * temperature
412 }
413 pub fn temperature(&self, density: f64, pressure: f64) -> f64 {
415 if density.abs() < f64::EPSILON {
416 return 0.0;
417 }
418 pressure / (density * self.specific_gas_constant)
419 }
420}
421#[derive(Debug, Clone, Copy)]
426pub struct BirchMurnaghan3Eos {
427 pub v0: f64,
429 pub k0: f64,
431 pub k0_prime: f64,
433}
434impl BirchMurnaghan3Eos {
435 pub fn new(v0: f64, k0: f64, k0_prime: f64) -> Self {
437 Self { v0, k0, k0_prime }
438 }
439 pub fn iron() -> Self {
441 Self::new(1.0 / 7874.0, 170.0e9, 4.9)
442 }
443 pub fn mgo() -> Self {
445 Self::new(1.0 / 3580.0, 160.2e9, 3.99)
446 }
447 pub fn pressure_from_volume(&self, v: f64) -> f64 {
449 let x = self.v0 / v;
450 let x23 = x.powf(2.0 / 3.0);
451 let x73 = x.powf(7.0 / 3.0);
452 let x53 = x.powf(5.0 / 3.0);
453 let correction = 1.0 + 0.75 * (self.k0_prime - 4.0) * (x23 - 1.0);
454 1.5 * self.k0 * (x73 - x53) * correction
455 }
456 pub fn volume(&self, pressure: f64) -> f64 {
458 let mut lo = self.v0 * 0.1;
459 let mut hi = self.v0 * 10.0;
460 for _ in 0..80 {
461 let mid = 0.5 * (lo + hi);
462 if self.pressure_from_volume(mid) > pressure {
463 lo = mid;
464 } else {
465 hi = mid;
466 }
467 }
468 0.5 * (lo + hi)
469 }
470 pub fn bulk_modulus(&self, v: f64) -> f64 {
472 let h = v * 1e-6;
473 let dp = self.pressure_from_volume(v - h) - self.pressure_from_volume(v + h);
474 v * dp / (2.0 * h)
475 }
476}
477#[derive(Debug, Clone, Copy)]
484#[allow(dead_code)]
485pub struct VanDerWaals {
486 pub a: f64,
488 pub b: f64,
490 pub r_gas: f64,
492}
493#[allow(dead_code)]
494impl VanDerWaals {
495 pub fn new(a: f64, b: f64, r_gas: f64) -> Self {
497 Self { a, b, r_gas }
498 }
499 pub fn with_r(a: f64, b: f64) -> Self {
501 Self::new(a, b, 8.314_462_618)
502 }
503 pub fn pressure(&self, t: f64, v: f64, _n: f64) -> f64 {
510 if (v - self.b).abs() < 1e-20 {
511 return f64::INFINITY;
512 }
513 self.r_gas * t / (v - self.b) - self.a / (v * v)
514 }
515 pub fn compressibility(&self, t: f64, p: f64, _n: f64) -> f64 {
522 let rt = self.r_gas * t;
523 if rt.abs() < 1e-30 {
524 return 0.0;
525 }
526 let mut lo = self.b + 1e-10;
527 let mut hi = rt / p.max(1.0) * 100.0 + 1.0;
528 hi = hi.max(lo * 1000.0);
529 for _ in 0..80 {
530 let mid = 0.5 * (lo + hi);
531 if self.pressure(t, mid, 1.0) > p {
532 lo = mid;
533 } else {
534 hi = mid;
535 }
536 }
537 let v_m = 0.5 * (lo + hi);
538 p * v_m / rt
539 }
540}
541#[derive(Debug, Clone, Copy)]
546pub struct MieGruneisenEos {
547 pub rho0: f64,
549 pub gamma_0: f64,
551 pub c0: f64,
553 pub s: f64,
555}
556impl MieGruneisenEos {
557 pub fn new(rho0: f64, gamma_0: f64, c0: f64, s: f64) -> Self {
559 Self {
560 rho0,
561 gamma_0,
562 c0,
563 s,
564 }
565 }
566 pub fn copper() -> Self {
568 Self::new(8930.0, 2.0, 3933.0, 1.5)
569 }
570 pub fn aluminum() -> Self {
572 Self::new(2785.0, 2.0, 5386.0, 1.339)
573 }
574 pub fn iron() -> Self {
576 Self::new(7896.0, 1.81, 3574.0, 1.92)
577 }
578 pub fn compression(&self, density: f64) -> f64 {
580 1.0 - self.rho0 / density
581 }
582 pub fn hugoniot_pressure(&self, density: f64) -> f64 {
584 let mu = density / self.rho0 - 1.0;
585 if mu <= 0.0 {
586 return 0.0;
587 }
588 let denom = (1.0 - self.s * mu).powi(2);
589 if denom.abs() < f64::EPSILON {
590 return 0.0;
591 }
592 self.rho0 * self.c0 * self.c0 * mu / denom
593 }
594 pub fn pressure_from_energy(&self, density: f64, energy: f64) -> f64 {
596 let ph = self.hugoniot_pressure(density);
597 let eh = if density > self.rho0 {
598 ph * 0.5 * (1.0 / self.rho0 - 1.0 / density)
599 } else {
600 0.0
601 };
602 ph + self.gamma_0 * density * (energy - eh)
603 }
604}
605#[derive(Debug, Clone, Copy)]
610pub struct TaitEos {
611 pub reference_density: f64,
613 pub reference_pressure: f64,
615 pub speed_of_sound: f64,
617 pub gamma: f64,
619}
620impl TaitEos {
621 pub fn new(
623 reference_density: f64,
624 reference_pressure: f64,
625 speed_of_sound: f64,
626 gamma: f64,
627 ) -> Self {
628 Self {
629 reference_density,
630 reference_pressure,
631 speed_of_sound,
632 gamma,
633 }
634 }
635 pub fn water() -> Self {
637 Self::new(1000.0, 0.0, 1500.0, 7.0)
638 }
639 pub fn b_coefficient(&self) -> f64 {
641 self.reference_density * self.speed_of_sound.powi(2) / self.gamma
642 }
643}
644#[derive(Debug, Clone, Copy)]
650#[allow(dead_code)]
651pub struct RedlichKwong {
652 pub a: f64,
654 pub b: f64,
656}
657#[allow(dead_code)]
658impl RedlichKwong {
659 pub fn new(a: f64, b: f64) -> Self {
661 Self { a, b }
662 }
663 pub fn from_critical(tc: f64, pc: f64) -> Self {
668 let a = 0.42748 * R_UNIVERSAL * R_UNIVERSAL * tc.powf(2.5) / pc;
669 let b = 0.08664 * R_UNIVERSAL * tc / pc;
670 Self { a, b }
671 }
672 pub fn pressure(&self, t: f64, v_mol: f64) -> f64 {
674 if (v_mol - self.b).abs() < 1e-20 {
675 return f64::INFINITY;
676 }
677 R_UNIVERSAL * t / (v_mol - self.b) - self.a / (t.sqrt() * v_mol * (v_mol + self.b))
678 }
679}
680#[derive(Debug, Clone, Copy)]
685pub struct VanDerWaalsEos {
686 pub a: f64,
688 pub b: f64,
690 pub molar_mass: f64,
692 pub r_gas: f64,
694}
695impl VanDerWaalsEos {
696 pub fn new(a: f64, b: f64, molar_mass: f64) -> Self {
698 Self {
699 a,
700 b,
701 molar_mass,
702 r_gas: 8.314,
703 }
704 }
705 pub fn co2() -> Self {
707 Self::new(0.3658, 42.9e-6, 0.044)
708 }
709 pub fn water_vapor() -> Self {
711 Self::new(0.5537, 30.5e-6, 0.018)
712 }
713 pub fn nitrogen() -> Self {
715 Self::new(0.1370, 38.7e-6, 0.028)
716 }
717 pub fn pressure_at_temperature(&self, density: f64, temperature: f64) -> f64 {
719 let specific_volume = 1.0 / density;
720 let molar_volume = specific_volume * self.molar_mass;
721 if (molar_volume - self.b).abs() < 1e-15 {
722 return f64::INFINITY;
723 }
724 self.r_gas * temperature / (molar_volume - self.b) - self.a / (molar_volume * molar_volume)
725 }
726}
727#[derive(Debug, Clone, Copy)]
731pub struct TillotsonEos {
732 pub rho0: f64,
734 pub e0: f64,
736 pub a: f64,
738 pub b: f64,
740 pub big_a: f64,
742 pub big_b: f64,
744 pub e_iv: f64,
746 pub e_cv: f64,
748 pub alpha: f64,
750 pub beta: f64,
752}
753impl TillotsonEos {
754 #[allow(clippy::too_many_arguments)]
756 pub fn new(
757 rho0: f64,
758 e0: f64,
759 a: f64,
760 b: f64,
761 big_a: f64,
762 big_b: f64,
763 e_iv: f64,
764 e_cv: f64,
765 alpha: f64,
766 beta: f64,
767 ) -> Self {
768 Self {
769 rho0,
770 e0,
771 a,
772 b,
773 big_a,
774 big_b,
775 e_iv,
776 e_cv,
777 alpha,
778 beta,
779 }
780 }
781 pub fn granite() -> Self {
783 Self::new(
784 2680.0, 16.0e6, 0.5, 1.3, 18.0e9, 18.0e9, 3.5e6, 18.0e6, 5.0, 5.0,
785 )
786 }
787 pub fn basalt() -> Self {
789 Self::new(
790 2860.0, 49.0e6, 0.49, 1.39, 26.7e9, 26.7e9, 4.72e6, 14.0e6, 5.0, 5.0,
791 )
792 }
793 pub fn eta(&self, density: f64) -> f64 {
795 density / self.rho0
796 }
797 pub fn pressure_compressed(&self, density: f64, energy: f64) -> f64 {
799 let eta = self.eta(density);
800 let mu = eta - 1.0;
801 let z = energy / (self.e0 * eta * eta);
802 (self.a + self.b / (z + 1.0)) * density * energy + self.big_a * mu + self.big_b * mu * mu
803 }
804 pub fn pressure_expanded(&self, density: f64, energy: f64) -> f64 {
806 let eta = self.eta(density);
807 let mu = eta - 1.0;
808 let z = energy / (self.e0 * eta * eta);
809 let term1 = self.a * density * energy;
810 let term2 = (self.b * density * energy / (z + 1.0)
811 + self.big_a * mu * (-self.beta * (1.0 / eta - 1.0)).exp())
812 * (-self.alpha * (1.0 / eta - 1.0).powi(2)).exp();
813 term1 + term2
814 }
815 pub fn pressure_from_energy(&self, density: f64, energy: f64) -> f64 {
817 let eta = self.eta(density);
818 if eta >= 1.0 || energy <= self.e_iv {
819 self.pressure_compressed(density, energy)
820 } else if energy >= self.e_cv {
821 self.pressure_expanded(density, energy)
822 } else {
823 let t = (energy - self.e_iv) / (self.e_cv - self.e_iv);
824 let pc = self.pressure_compressed(density, energy);
825 let pe = self.pressure_expanded(density, energy);
826 (1.0 - t) * pc + t * pe
827 }
828 }
829}
830#[derive(Debug, Clone, Copy)]
836#[allow(dead_code)]
837pub struct SoaveRedlichKwong {
838 pub a: f64,
840 pub b: f64,
842 pub omega: f64,
844 pub tc: f64,
846}
847#[allow(dead_code)]
848impl SoaveRedlichKwong {
849 pub fn new(a: f64, b: f64, omega: f64, tc: f64) -> Self {
851 Self { a, b, omega, tc }
852 }
853 pub fn from_critical(tc: f64, pc: f64, omega: f64) -> Self {
858 let a = 0.42748 * R_UNIVERSAL * R_UNIVERSAL * tc * tc / pc;
859 let b = 0.08664 * R_UNIVERSAL * tc / pc;
860 Self { a, b, omega, tc }
861 }
862 fn alpha(&self, t: f64) -> f64 {
864 let m = 0.480 + 1.574 * self.omega - 0.176 * self.omega * self.omega;
865 (1.0 + m * (1.0 - (t / self.tc).sqrt())).powi(2)
866 }
867 pub fn pressure(&self, t: f64, v_mol: f64) -> f64 {
869 let a_t = self.a * self.alpha(t);
870 if (v_mol - self.b).abs() < 1e-20 {
871 return f64::INFINITY;
872 }
873 R_UNIVERSAL * t / (v_mol - self.b) - a_t / (v_mol * (v_mol + self.b))
874 }
875}
876#[derive(Debug, Clone, Copy)]
881pub struct StiffenedGasEos {
882 pub gamma: f64,
884 pub p_inf: f64,
886 pub reference_density: f64,
888 pub reference_energy: f64,
890}
891impl StiffenedGasEos {
892 pub fn new(gamma: f64, p_inf: f64, reference_density: f64, reference_energy: f64) -> Self {
894 Self {
895 gamma,
896 p_inf,
897 reference_density,
898 reference_energy,
899 }
900 }
901 pub fn water() -> Self {
903 Self::new(6.59, 4.02e8, 1000.0, 0.0)
904 }
905 pub fn air() -> Self {
907 Self::new(1.4, 0.0, 1.225, 0.0)
908 }
909 pub fn pressure_from_energy(&self, density: f64, energy: f64) -> f64 {
911 (self.gamma - 1.0) * density * (energy - self.reference_energy) - self.p_inf
912 }
913}
914#[derive(Debug, Clone, Copy)]
920#[allow(dead_code)]
921pub struct NobleAbelEos {
922 pub r_specific: f64,
924 pub b_covolume: f64,
926}
927#[allow(dead_code)]
928impl NobleAbelEos {
929 pub fn new(r_specific: f64, b_covolume: f64) -> Self {
931 Self {
932 r_specific,
933 b_covolume,
934 }
935 }
936 pub fn propellant() -> Self {
938 Self::new(290.0, 0.001)
939 }
940 pub fn pressure_at_temperature(&self, density: f64, temperature: f64) -> f64 {
942 let denom = 1.0 - self.b_covolume * density;
943 if denom <= 0.0 {
944 return f64::INFINITY;
945 }
946 density * self.r_specific * temperature / denom
947 }
948 pub fn density_at_temperature(&self, pressure: f64, temperature: f64) -> f64 {
950 let rt = self.r_specific * temperature;
951 if rt.abs() < 1e-30 {
952 return 0.0;
953 }
954 pressure / (rt + pressure * self.b_covolume)
955 }
956}
957pub struct PvtEos {
961 pub cold_eos: BirchMurnaghan3Eos,
963 pub gruneisen: GruneisenParameter,
965 pub cv: f64,
967 pub t0: f64,
969}
970impl PvtEos {
971 pub fn new(
973 cold_eos: BirchMurnaghan3Eos,
974 gruneisen: GruneisenParameter,
975 cv: f64,
976 t0: f64,
977 ) -> Self {
978 Self {
979 cold_eos,
980 gruneisen,
981 cv,
982 t0,
983 }
984 }
985 pub fn iron() -> Self {
987 let cold = BirchMurnaghan3Eos::iron();
988 let v0 = cold.v0;
989 let gruneisen = GruneisenParameter::new(1.81, v0, 1.0);
990 Self::new(cold, gruneisen, 450.0, 300.0)
991 }
992 pub fn pressure(&self, v: f64, temperature: f64) -> f64 {
994 let density = 1.0 / v;
995 let p_cold = self.cold_eos.pressure_from_volume(v);
996 let p_th = self
997 .gruneisen
998 .thermal_pressure(density, self.cv, temperature, self.t0);
999 p_cold + p_th
1000 }
1001 pub fn density(&self, pressure: f64, temperature: f64) -> f64 {
1003 let mut lo = 1.0 / (self.cold_eos.v0 * 3.0);
1004 let mut hi = 1.0 / (self.cold_eos.v0 * 0.3);
1005 for _ in 0..80 {
1006 let mid = 0.5 * (lo + hi);
1007 if self.pressure(1.0 / mid, temperature) < pressure {
1008 lo = mid;
1009 } else {
1010 hi = mid;
1011 }
1012 }
1013 0.5 * (lo + hi)
1014 }
1015}