@@ -3,9 +3,10 @@ use crate::state::StateHD;
33use crate :: EosUnit ;
44use ndarray:: prelude:: * ;
55use num_dual:: {
6- Dual , Dual2_64 , Dual3 , Dual3_64 , Dual64 , DualNum , DualVec64 , HyperDual , HyperDual64 ,
6+ first_derivative, second_derivative, third_derivative, Dual , Dual2 , Dual2_64 , Dual3 , Dual3_64 ,
7+ Dual64 , DualNum , DualSVec64 , HyperDual , HyperDual64 ,
78} ;
8- use num_traits:: { One , Zero } ;
9+ use num_traits:: Zero ;
910use quantity:: si:: { SIArray1 , SINumber , SIUnit } ;
1011use std:: fmt;
1112
@@ -28,16 +29,17 @@ pub trait HelmholtzEnergyDual<D: DualNum<f64>> {
2829pub trait HelmholtzEnergy :
2930 HelmholtzEnergyDual < f64 >
3031 + HelmholtzEnergyDual < Dual64 >
31- + HelmholtzEnergyDual < Dual < DualVec64 < 3 > , f64 > >
32+ + HelmholtzEnergyDual < Dual < DualSVec64 < 3 > , f64 > >
3233 + HelmholtzEnergyDual < HyperDual64 >
3334 + HelmholtzEnergyDual < Dual2_64 >
3435 + HelmholtzEnergyDual < Dual3_64 >
3536 + HelmholtzEnergyDual < HyperDual < Dual64 , f64 > >
36- + HelmholtzEnergyDual < HyperDual < DualVec64 < 2 > , f64 > >
37- + HelmholtzEnergyDual < HyperDual < DualVec64 < 3 > , f64 > >
37+ + HelmholtzEnergyDual < HyperDual < DualSVec64 < 2 > , f64 > >
38+ + HelmholtzEnergyDual < HyperDual < DualSVec64 < 3 > , f64 > >
39+ + HelmholtzEnergyDual < Dual2 < Dual64 , f64 > >
3840 + HelmholtzEnergyDual < Dual3 < Dual64 , f64 > >
39- + HelmholtzEnergyDual < Dual3 < DualVec64 < 2 > , f64 > >
40- + HelmholtzEnergyDual < Dual3 < DualVec64 < 3 > , f64 > >
41+ + HelmholtzEnergyDual < Dual3 < DualSVec64 < 2 > , f64 > >
42+ + HelmholtzEnergyDual < Dual3 < DualSVec64 < 3 > , f64 > >
4143 + fmt:: Display
4244 + Send
4345 + Sync
@@ -47,16 +49,17 @@ pub trait HelmholtzEnergy:
4749impl < T > HelmholtzEnergy for T where
4850 T : HelmholtzEnergyDual < f64 >
4951 + HelmholtzEnergyDual < Dual64 >
50- + HelmholtzEnergyDual < Dual < DualVec64 < 3 > , f64 > >
52+ + HelmholtzEnergyDual < Dual < DualSVec64 < 3 > , f64 > >
5153 + HelmholtzEnergyDual < HyperDual64 >
5254 + HelmholtzEnergyDual < Dual2_64 >
5355 + HelmholtzEnergyDual < Dual3_64 >
5456 + HelmholtzEnergyDual < HyperDual < Dual64 , f64 > >
55- + HelmholtzEnergyDual < HyperDual < DualVec64 < 2 > , f64 > >
56- + HelmholtzEnergyDual < HyperDual < DualVec64 < 3 > , f64 > >
57+ + HelmholtzEnergyDual < HyperDual < DualSVec64 < 2 > , f64 > >
58+ + HelmholtzEnergyDual < HyperDual < DualSVec64 < 3 > , f64 > >
59+ + HelmholtzEnergyDual < Dual2 < Dual64 , f64 > >
5760 + HelmholtzEnergyDual < Dual3 < Dual64 , f64 > >
58- + HelmholtzEnergyDual < Dual3 < DualVec64 < 2 > , f64 > >
59- + HelmholtzEnergyDual < Dual3 < DualVec64 < 3 > , f64 > >
61+ + HelmholtzEnergyDual < Dual3 < DualSVec64 < 2 > , f64 > >
62+ + HelmholtzEnergyDual < Dual3 < DualSVec64 < 3 > , f64 > >
6063 + fmt:: Display
6164 + Send
6265 + Sync
@@ -70,7 +73,7 @@ impl<T> HelmholtzEnergy for T where
7073/// the specific types in the supertraits of [IdealGasContribution]
7174/// so that the implementor can be used as an ideal gas
7275/// contribution in the equation of state.
73- pub trait IdealGasContributionDual < D : DualNum < f64 > > {
76+ pub trait IdealGasContributionDual < D : DualNum < f64 > + Copy > {
7477 /// The thermal de Broglie wavelength of each component in the form $\ln\left(\frac{\Lambda^3}{\AA^3}\right)$
7578 fn de_broglie_wavelength ( & self , temperature : D , components : usize ) -> Array1 < D > ;
7679
@@ -101,39 +104,41 @@ pub trait IdealGasContributionDual<D: DualNum<f64>> {
101104pub trait IdealGasContribution :
102105 IdealGasContributionDual < f64 >
103106 + IdealGasContributionDual < Dual64 >
104- + IdealGasContributionDual < Dual < DualVec64 < 3 > , f64 > >
107+ + IdealGasContributionDual < Dual < DualSVec64 < 3 > , f64 > >
105108 + IdealGasContributionDual < HyperDual64 >
106109 + IdealGasContributionDual < Dual2_64 >
107110 + IdealGasContributionDual < Dual3_64 >
108111 + IdealGasContributionDual < HyperDual < Dual64 , f64 > >
109- + IdealGasContributionDual < HyperDual < DualVec64 < 2 > , f64 > >
110- + IdealGasContributionDual < HyperDual < DualVec64 < 3 > , f64 > >
112+ + IdealGasContributionDual < HyperDual < DualSVec64 < 2 > , f64 > >
113+ + IdealGasContributionDual < HyperDual < DualSVec64 < 3 > , f64 > >
114+ + IdealGasContributionDual < Dual2 < Dual64 , f64 > >
111115 + IdealGasContributionDual < Dual3 < Dual64 , f64 > >
112- + IdealGasContributionDual < Dual3 < DualVec64 < 2 > , f64 > >
113- + IdealGasContributionDual < Dual3 < DualVec64 < 3 > , f64 > >
116+ + IdealGasContributionDual < Dual3 < DualSVec64 < 2 > , f64 > >
117+ + IdealGasContributionDual < Dual3 < DualSVec64 < 3 > , f64 > >
114118 + fmt:: Display
115119{
116120}
117121
118122impl < T > IdealGasContribution for T where
119123 T : IdealGasContributionDual < f64 >
120124 + IdealGasContributionDual < Dual64 >
121- + IdealGasContributionDual < Dual < DualVec64 < 3 > , f64 > >
125+ + IdealGasContributionDual < Dual < DualSVec64 < 3 > , f64 > >
122126 + IdealGasContributionDual < HyperDual64 >
123127 + IdealGasContributionDual < Dual2_64 >
124128 + IdealGasContributionDual < Dual3_64 >
125129 + IdealGasContributionDual < HyperDual < Dual64 , f64 > >
126- + IdealGasContributionDual < HyperDual < DualVec64 < 2 > , f64 > >
127- + IdealGasContributionDual < HyperDual < DualVec64 < 3 > , f64 > >
130+ + IdealGasContributionDual < HyperDual < DualSVec64 < 2 > , f64 > >
131+ + IdealGasContributionDual < HyperDual < DualSVec64 < 3 > , f64 > >
132+ + IdealGasContributionDual < Dual2 < Dual64 , f64 > >
128133 + IdealGasContributionDual < Dual3 < Dual64 , f64 > >
129- + IdealGasContributionDual < Dual3 < DualVec64 < 2 > , f64 > >
130- + IdealGasContributionDual < Dual3 < DualVec64 < 3 > , f64 > >
134+ + IdealGasContributionDual < Dual3 < DualSVec64 < 2 > , f64 > >
135+ + IdealGasContributionDual < Dual3 < DualSVec64 < 3 > , f64 > >
131136 + fmt:: Display
132137{
133138}
134139
135140struct DefaultIdealGasContribution ;
136- impl < D : DualNum < f64 > > IdealGasContributionDual < D > for DefaultIdealGasContribution {
141+ impl < D : DualNum < f64 > + Copy > IdealGasContributionDual < D > for DefaultIdealGasContribution {
137142 fn de_broglie_wavelength ( & self , _: D , components : usize ) -> Array1 < D > {
138143 Array1 :: zeros ( components)
139144 }
@@ -175,7 +180,7 @@ pub trait EquationOfState: Send + Sync {
175180 fn residual ( & self ) -> & [ Box < dyn HelmholtzEnergy > ] ;
176181
177182 /// Evaluate the residual reduced Helmholtz energy $\beta A^\mathrm{res}$.
178- fn evaluate_residual < D : DualNum < f64 > > ( & self , state : & StateHD < D > ) -> D
183+ fn evaluate_residual < D : DualNum < f64 > + Copy > ( & self , state : & StateHD < D > ) -> D
179184 where
180185 dyn HelmholtzEnergy : HelmholtzEnergyDual < D > ,
181186 {
@@ -187,7 +192,7 @@ pub trait EquationOfState: Send + Sync {
187192
188193 /// Evaluate the reduced Helmholtz energy of each individual contribution
189194 /// and return them together with a string representation of the contribution.
190- fn evaluate_residual_contributions < D : DualNum < f64 > > (
195+ fn evaluate_residual_contributions < D : DualNum < f64 > + Copy > (
191196 & self ,
192197 state : & StateHD < D > ,
193198 ) -> Vec < ( String , D ) >
@@ -252,12 +257,10 @@ pub trait EquationOfState: Send + Sync {
252257 ) -> EosResult < SINumber > {
253258 let mr = self . validate_moles ( moles) ?;
254259 let x = mr. to_reduced ( mr. sum ( ) ) ?;
255- let mut rho = HyperDual64 :: zero ( ) ;
256- rho. eps1 [ 0 ] = 1.0 ;
257- rho. eps2 [ 0 ] = 1.0 ;
258- let t = HyperDual64 :: from ( temperature. to_reduced ( SIUnit :: reference_temperature ( ) ) ?) ;
259- let s = StateHD :: new_virial ( t, rho, x) ;
260- Ok ( self . evaluate_residual ( & s) . eps1eps2 [ ( 0 , 0 ) ] * 0.5 / SIUnit :: reference_density ( ) )
260+ let t = temperature. to_reduced ( SIUnit :: reference_temperature ( ) ) ?;
261+ let a_res = |rho| self . evaluate_residual ( & StateHD :: new_virial ( t. into ( ) , rho, x) ) ;
262+ let ( _, _, b) = second_derivative ( a_res, 0.0 ) ;
263+ Ok ( b * 0.5 / SIUnit :: reference_density ( ) )
261264 }
262265
263266 /// Calculate the third virial coefficient $C(T)$
@@ -268,10 +271,10 @@ pub trait EquationOfState: Send + Sync {
268271 ) -> EosResult < SINumber > {
269272 let mr = self . validate_moles ( moles) ?;
270273 let x = mr. to_reduced ( mr. sum ( ) ) ?;
271- let rho = Dual3_64 :: zero ( ) . derive ( ) ;
272- let t = Dual3_64 :: from ( temperature . to_reduced ( SIUnit :: reference_temperature ( ) ) ? ) ;
273- let s = StateHD :: new_virial ( t , rho , x ) ;
274- Ok ( self . evaluate_residual ( & s ) . v3 / 3.0 / SIUnit :: reference_density ( ) . powi ( 2 ) )
274+ let t = temperature . to_reduced ( SIUnit :: reference_temperature ( ) ) ? ;
275+ let a_res = |rho| self . evaluate_residual ( & StateHD :: new_virial ( t . into ( ) , rho , x ) ) ;
276+ let ( _ , _ , _ , c ) = third_derivative ( a_res , 0.0 ) ;
277+ Ok ( c / 3.0 / SIUnit :: reference_density ( ) . powi ( 2 ) )
275278 }
276279
277280 /// Calculate the temperature derivative of the second virial coefficient $B'(T)$
@@ -282,15 +285,16 @@ pub trait EquationOfState: Send + Sync {
282285 ) -> EosResult < SINumber > {
283286 let mr = self . validate_moles ( moles) ?;
284287 let x = mr. to_reduced ( mr. sum ( ) ) ?;
285- let mut rho = HyperDual :: zero ( ) ;
286- rho. eps1 [ 0 ] = Dual64 :: one ( ) ;
287- rho. eps2 [ 0 ] = Dual64 :: one ( ) ;
288- let t = HyperDual :: from_re (
289- Dual64 :: from ( temperature. to_reduced ( SIUnit :: reference_temperature ( ) ) ?) . derive ( ) ,
290- ) ;
291- let s = StateHD :: new_virial ( t, rho, x) ;
292- Ok ( self . evaluate_residual ( & s) . eps1eps2 [ ( 0 , 0 ) ] . eps [ 0 ] * 0.5
293- / ( SIUnit :: reference_density ( ) * SIUnit :: reference_temperature ( ) ) )
288+ let t = temperature. to_reduced ( SIUnit :: reference_temperature ( ) ) ?;
289+ let b = |t| {
290+ let a_res = |rho : Dual2 < Dual64 , f64 > | {
291+ self . evaluate_residual ( & StateHD :: new_virial ( Dual2 :: from_re ( t) , rho, x) )
292+ } ;
293+ let ( _, _, b) = second_derivative ( a_res, Dual64 :: zero ( ) ) ;
294+ b
295+ } ;
296+ let ( _, b_t) = first_derivative ( b, t) ;
297+ Ok ( b_t * 0.5 / ( SIUnit :: reference_density ( ) * SIUnit :: reference_temperature ( ) ) )
294298 }
295299
296300 /// Calculate the temperature derivative of the third virial coefficient $C'(T)$
@@ -301,14 +305,15 @@ pub trait EquationOfState: Send + Sync {
301305 ) -> EosResult < SINumber > {
302306 let mr = self . validate_moles ( moles) ?;
303307 let x = mr. to_reduced ( mr. sum ( ) ) ?;
304- let rho = Dual3 :: zero ( ) . derive ( ) ;
305- let t = Dual3 :: from_re (
306- Dual64 :: from ( temperature. to_reduced ( SIUnit :: reference_temperature ( ) ) ?) . derive ( ) ,
307- ) ;
308- let s = StateHD :: new_virial ( t, rho, x) ;
309- Ok ( self . evaluate_residual ( & s) . v3 . eps [ 0 ]
310- / 3.0
311- / ( SIUnit :: reference_density ( ) . powi ( 2 ) * SIUnit :: reference_temperature ( ) ) )
308+ let t = temperature. to_reduced ( SIUnit :: reference_temperature ( ) ) ?;
309+ let c = |t| {
310+ let a_res =
311+ |rho| self . evaluate_residual ( & StateHD :: new_virial ( Dual3 :: from_re ( t) , rho, x) ) ;
312+ let ( _, _, _, c) = third_derivative ( a_res, Dual64 :: zero ( ) ) ;
313+ c
314+ } ;
315+ let ( _, c_t) = first_derivative ( c, t) ;
316+ Ok ( c_t / 3.0 / ( SIUnit :: reference_density ( ) . powi ( 2 ) * SIUnit :: reference_temperature ( ) ) )
312317 }
313318}
314319
0 commit comments