@@ -19,10 +19,10 @@ pub fn vapor_pressure<R: ResidualHelmholtzEnergy<1>, const P: usize>(
1919 let v2 = 1.0 / vle. vapor ( ) . density . to_reduced ( ) ;
2020 let t = temperature. into_reduced ( ) ;
2121 let ( a1, a2) = {
22- let t = DualVec :: from ( t) ;
23- let v1 = DualVec :: from ( v1) ;
24- let v2 = DualVec :: from ( v2) ;
25- let x = SVector :: from ( [ DualVec :: from ( 1.0 ) ] ) ;
22+ let t = Gradient :: from ( t) ;
23+ let v1 = Gradient :: from ( v1) ;
24+ let v2 = Gradient :: from ( v2) ;
25+ let x = SVector :: from ( [ Gradient :: from ( 1.0 ) ] ) ;
2626
2727 let a1 = R :: residual_molar_helmholtz_energy ( & eos. parameters , t, v1, & x) ;
2828 let a2 = R :: residual_molar_helmholtz_energy ( & eos. parameters , t, v2, & x) ;
@@ -43,10 +43,10 @@ pub fn equilibrium_liquid_density<R: ResidualHelmholtzEnergy<1>, const P: usize>
4343 let v_v = 1.0 / vle. vapor ( ) . density . to_reduced ( ) ;
4444 let t = temperature. into_reduced ( ) ;
4545 let ( f_l, p_l, dp_l, a_v) = {
46- let t = DualVec :: from ( temperature. into_reduced ( ) ) ;
47- let v_l = DualVec :: from ( v_l) ;
48- let v_v = DualVec :: from ( v_v) ;
49- let x = SVector :: from ( [ DualVec :: from ( 1.0 ) ] ) ;
46+ let t = Gradient :: from ( temperature. into_reduced ( ) ) ;
47+ let v_l = Gradient :: from ( v_l) ;
48+ let v_v = Gradient :: from ( v_v) ;
49+ let x = SVector :: from ( [ Gradient :: from ( 1.0 ) ] ) ;
5050
5151 let ( f_l, p_l, dp_l) = R :: dp_drho ( & eos. parameters , t, v_l, & x) ;
5252 let a_v = R :: residual_molar_helmholtz_energy ( & eos. parameters , t, v_v, & x) ;
@@ -70,9 +70,9 @@ pub fn liquid_density<R: ResidualHelmholtzEnergy<1>, const P: usize>(
7070 let v = 1.0 / state. density . to_reduced ( ) ;
7171 let p0 = pressure. into_reduced ( ) ;
7272 let ( p, dp) = {
73- let t = DualVec :: from ( t) ;
74- let v = DualVec :: from ( v) ;
75- let x = SVector :: from ( [ DualVec :: from ( 1.0 ) ] ) ;
73+ let t = Gradient :: from ( t) ;
74+ let v = Gradient :: from ( v) ;
75+ let x = SVector :: from ( [ Gradient :: from ( 1.0 ) ] ) ;
7676 let ( _, p, dp) = R :: dp_drho ( & eos. parameters , t, v, & x) ;
7777
7878 ( p, dp)
@@ -82,11 +82,101 @@ pub fn liquid_density<R: ResidualHelmholtzEnergy<1>, const P: usize>(
8282 Ok ( Density :: from_reduced ( rho) )
8383}
8484
85+ pub fn bubble_point_pressure < R : ResidualHelmholtzEnergy < 2 > , const P : usize > (
86+ eos : & HelmholtzEnergyWrapper < R , Gradient < P > , 2 > ,
87+ temperature : Temperature ,
88+ pressure : Option < Pressure > ,
89+ liquid_molefracs : SVector < f64 , 2 > ,
90+ ) -> EosResult < Pressure < Gradient < P > > > {
91+ let x = arr1 ( liquid_molefracs. as_slice ( ) ) ;
92+ let vle = PhaseEquilibrium :: bubble_point (
93+ & eos. eos ,
94+ temperature,
95+ & x,
96+ pressure,
97+ None ,
98+ Default :: default ( ) ,
99+ ) ?;
100+
101+ let v_l = 1.0 / vle. liquid ( ) . density . to_reduced ( ) ;
102+ let v_v = 1.0 / vle. vapor ( ) . density . to_reduced ( ) ;
103+ let y = & vle. vapor ( ) . molefracs ;
104+ let y: SVector < _ , 2 > = SVector :: from_fn ( |i, _| y[ i] ) ;
105+ let t = temperature. into_reduced ( ) ;
106+ let ( a_l, a_v, v_l, v_v) = {
107+ let t = Gradient :: from ( t) ;
108+ let v_l = Gradient :: from ( v_l) ;
109+ let v_v = Gradient :: from ( v_v) ;
110+ let y = y. map ( Gradient :: from) ;
111+ let x = liquid_molefracs. map ( Gradient :: from) ;
112+
113+ let a_v = R :: residual_molar_helmholtz_energy ( & eos. parameters , t, v_v, & y) ;
114+ let ( p_l, mu_res_l, dp_l, dmu_l) = R :: dmu_dv ( & eos. parameters , t, v_l, & x) ;
115+ let vi_l = dmu_l / dp_l;
116+ let v_l = vi_l. dot ( & y) ;
117+ let a_l = ( mu_res_l - vi_l * p_l) . dot ( & y) ;
118+ ( a_l, a_v, v_l, v_v)
119+ } ;
120+ let rho_l = vle. liquid ( ) . partial_density . to_reduced ( ) ;
121+ let rho_l = [ rho_l[ 0 ] , rho_l[ 1 ] ] ;
122+ let rho_v = vle. vapor ( ) . partial_density . to_reduced ( ) ;
123+ let rho_v = [ rho_v[ 0 ] , rho_v[ 1 ] ] ;
124+ let p = -( a_v - a_l
125+ + t * ( y[ 0 ] * ( rho_v[ 0 ] / rho_l[ 0 ] ) . ln ( ) + y[ 1 ] * ( rho_v[ 1 ] / rho_l[ 1 ] ) . ln ( ) - 1.0 ) )
126+ / ( v_v - v_l) ;
127+ Ok ( Pressure :: from_reduced ( p) )
128+ }
129+
130+ pub fn dew_point_pressure < R : ResidualHelmholtzEnergy < 2 > , const P : usize > (
131+ eos : & HelmholtzEnergyWrapper < R , Gradient < P > , 2 > ,
132+ temperature : Temperature ,
133+ pressure : Option < Pressure > ,
134+ vapor_molefracs : SVector < f64 , 2 > ,
135+ ) -> EosResult < Pressure < Gradient < P > > > {
136+ let y = arr1 ( vapor_molefracs. as_slice ( ) ) ;
137+ let vle = PhaseEquilibrium :: dew_point (
138+ & eos. eos ,
139+ temperature,
140+ & y,
141+ pressure,
142+ None ,
143+ Default :: default ( ) ,
144+ ) ?;
145+
146+ let v_l = 1.0 / vle. liquid ( ) . density . to_reduced ( ) ;
147+ let v_v = 1.0 / vle. vapor ( ) . density . to_reduced ( ) ;
148+ let x = & vle. liquid ( ) . molefracs ;
149+ let x: SVector < _ , 2 > = SVector :: from_fn ( |i, _| x[ i] ) ;
150+ let t = temperature. into_reduced ( ) ;
151+ let ( a_l, a_v, v_l, v_v) = {
152+ let t = Gradient :: from ( t) ;
153+ let v_l = Gradient :: from ( v_l) ;
154+ let v_v = Gradient :: from ( v_v) ;
155+ let x = x. map ( Gradient :: from) ;
156+ let y = vapor_molefracs. map ( Gradient :: from) ;
157+
158+ let a_l = R :: residual_molar_helmholtz_energy ( & eos. parameters , t, v_l, & x) ;
159+ let ( p_v, mu_res_v, dp_v, dmu_v) = R :: dmu_dv ( & eos. parameters , t, v_v, & y) ;
160+ let vi_v = dmu_v / dp_v;
161+ let v_v = vi_v. dot ( & x) ;
162+ let a_v = ( mu_res_v - vi_v * p_v) . dot ( & x) ;
163+ ( a_l, a_v, v_l, v_v)
164+ } ;
165+ let rho_l = vle. liquid ( ) . partial_density . to_reduced ( ) ;
166+ let rho_l = [ rho_l[ 0 ] , rho_l[ 1 ] ] ;
167+ let rho_v = vle. vapor ( ) . partial_density . to_reduced ( ) ;
168+ let rho_v = [ rho_v[ 0 ] , rho_v[ 1 ] ] ;
169+ let p = -( a_l - a_v
170+ + t * ( x[ 0 ] * ( rho_l[ 0 ] / rho_v[ 0 ] ) . ln ( ) + x[ 1 ] * ( rho_l[ 1 ] / rho_v[ 1 ] ) . ln ( ) - 1.0 ) )
171+ / ( v_l - v_v) ;
172+ Ok ( Pressure :: from_reduced ( p) )
173+ }
174+
85175#[ cfg( test) ]
86176mod test {
87177 use super :: * ;
88- use crate :: eos:: pcsaft:: test:: { pcsaft, pcsaft_non_assoc} ;
89- use crate :: eos:: PcSaftPure ;
178+ use crate :: eos:: pcsaft:: test:: { pcsaft, pcsaft_binary , pcsaft_non_assoc} ;
179+ use crate :: eos:: { PcSaftBinary , PcSaftPure } ;
90180 use crate :: { ParametersAD , PhaseEquilibriumAD , StateAD } ;
91181 use approx:: assert_relative_eq;
92182 use nalgebra:: U1 ;
@@ -246,4 +336,64 @@ mod test {
246336 }
247337 Ok ( ( ) )
248338 }
339+
340+ #[ test]
341+ fn test_bubble_point_pressure ( ) -> EosResult < ( ) > {
342+ let ( pcsaft, _) = pcsaft_binary ( ) ?;
343+ let pcsaft = pcsaft. wrap ( ) ;
344+ let pcsaft_ad = pcsaft. named_derivatives ( [ "k_ij" ] ) ;
345+ let temperature = 500.0 * KELVIN ;
346+ let x = SVector :: from ( [ 0.5 , 0.5 ] ) ;
347+ let p = bubble_point_pressure ( & pcsaft_ad, temperature, None , x) ?;
348+ let p = p. convert_into ( BAR ) ;
349+ let ( p, [ [ grad] ] ) = ( p. re , p. eps . unwrap_generic ( U1 , U1 ) . data . 0 ) ;
350+
351+ println ! ( "{:.5}" , p) ;
352+ println ! ( "{:.5?}" , grad) ;
353+
354+ let ( params, mut kij) = pcsaft. parameters ;
355+ let h = 1e-7 ;
356+ kij += h;
357+ let pcsaft_h = PcSaftBinary :: new ( params, kij) . wrap ( ) ;
358+ let ( _, p_h) = PhaseEquilibriumAD :: bubble_point ( & pcsaft_h, temperature, x) ?;
359+ let dp_h = ( p_h. convert_into ( BAR ) - p) / h;
360+ println ! (
361+ "k_ij: {:11.5} {:11.5} {:.3e}" ,
362+ dp_h,
363+ grad,
364+ ( ( dp_h - grad) / grad) . abs( )
365+ ) ;
366+ assert_relative_eq ! ( grad, dp_h, max_relative = 1e-6 ) ;
367+ Ok ( ( ) )
368+ }
369+
370+ #[ test]
371+ fn test_dew_point_pressure ( ) -> EosResult < ( ) > {
372+ let ( pcsaft, _) = pcsaft_binary ( ) ?;
373+ let pcsaft = pcsaft. wrap ( ) ;
374+ let pcsaft_ad = pcsaft. named_derivatives ( [ "k_ij" ] ) ;
375+ let temperature = 500.0 * KELVIN ;
376+ let y = SVector :: from ( [ 0.5 , 0.5 ] ) ;
377+ let p = dew_point_pressure ( & pcsaft_ad, temperature, None , y) ?;
378+ let p = p. convert_into ( BAR ) ;
379+ let ( p, [ [ grad] ] ) = ( p. re , p. eps . unwrap_generic ( U1 , U1 ) . data . 0 ) ;
380+
381+ println ! ( "{:.5}" , p) ;
382+ println ! ( "{:.5?}" , grad) ;
383+
384+ let ( params, mut kij) = pcsaft. parameters ;
385+ let h = 1e-7 ;
386+ kij += h;
387+ let pcsaft_h = PcSaftBinary :: new ( params, kij) . wrap ( ) ;
388+ let ( _, p_h) = PhaseEquilibriumAD :: dew_point ( & pcsaft_h, temperature, y) ?;
389+ let dp_h = ( p_h. convert_into ( BAR ) - p) / h;
390+ println ! (
391+ "k_ij: {:11.5} {:11.5} {:.3e}" ,
392+ dp_h,
393+ grad,
394+ ( ( dp_h - grad) / grad) . abs( )
395+ ) ;
396+ assert_relative_eq ! ( grad, dp_h, max_relative = 1e-6 ) ;
397+ Ok ( ( ) )
398+ }
249399}
0 commit comments