@@ -3,9 +3,10 @@ use crate::state::StateHD;
3
3
use crate :: EosUnit ;
4
4
use ndarray:: prelude:: * ;
5
5
use 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 ,
7
8
} ;
8
- use num_traits:: { One , Zero } ;
9
+ use num_traits:: Zero ;
9
10
use quantity:: si:: { SIArray1 , SINumber , SIUnit } ;
10
11
use std:: fmt;
11
12
@@ -28,16 +29,17 @@ pub trait HelmholtzEnergyDual<D: DualNum<f64>> {
28
29
pub trait HelmholtzEnergy :
29
30
HelmholtzEnergyDual < f64 >
30
31
+ HelmholtzEnergyDual < Dual64 >
31
- + HelmholtzEnergyDual < Dual < DualVec64 < 3 > , f64 > >
32
+ + HelmholtzEnergyDual < Dual < DualSVec64 < 3 > , f64 > >
32
33
+ HelmholtzEnergyDual < HyperDual64 >
33
34
+ HelmholtzEnergyDual < Dual2_64 >
34
35
+ HelmholtzEnergyDual < Dual3_64 >
35
36
+ 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 > >
38
40
+ 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 > >
41
43
+ fmt:: Display
42
44
+ Send
43
45
+ Sync
@@ -47,16 +49,17 @@ pub trait HelmholtzEnergy:
47
49
impl < T > HelmholtzEnergy for T where
48
50
T : HelmholtzEnergyDual < f64 >
49
51
+ HelmholtzEnergyDual < Dual64 >
50
- + HelmholtzEnergyDual < Dual < DualVec64 < 3 > , f64 > >
52
+ + HelmholtzEnergyDual < Dual < DualSVec64 < 3 > , f64 > >
51
53
+ HelmholtzEnergyDual < HyperDual64 >
52
54
+ HelmholtzEnergyDual < Dual2_64 >
53
55
+ HelmholtzEnergyDual < Dual3_64 >
54
56
+ 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 > >
57
60
+ 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 > >
60
63
+ fmt:: Display
61
64
+ Send
62
65
+ Sync
@@ -70,7 +73,7 @@ impl<T> HelmholtzEnergy for T where
70
73
/// the specific types in the supertraits of [IdealGasContribution]
71
74
/// so that the implementor can be used as an ideal gas
72
75
/// contribution in the equation of state.
73
- pub trait IdealGasContributionDual < D : DualNum < f64 > > {
76
+ pub trait IdealGasContributionDual < D : DualNum < f64 > + Copy > {
74
77
/// The thermal de Broglie wavelength of each component in the form $\ln\left(\frac{\Lambda^3}{\AA^3}\right)$
75
78
fn de_broglie_wavelength ( & self , temperature : D , components : usize ) -> Array1 < D > ;
76
79
@@ -101,39 +104,41 @@ pub trait IdealGasContributionDual<D: DualNum<f64>> {
101
104
pub trait IdealGasContribution :
102
105
IdealGasContributionDual < f64 >
103
106
+ IdealGasContributionDual < Dual64 >
104
- + IdealGasContributionDual < Dual < DualVec64 < 3 > , f64 > >
107
+ + IdealGasContributionDual < Dual < DualSVec64 < 3 > , f64 > >
105
108
+ IdealGasContributionDual < HyperDual64 >
106
109
+ IdealGasContributionDual < Dual2_64 >
107
110
+ IdealGasContributionDual < Dual3_64 >
108
111
+ 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 > >
111
115
+ 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 > >
114
118
+ fmt:: Display
115
119
{
116
120
}
117
121
118
122
impl < T > IdealGasContribution for T where
119
123
T : IdealGasContributionDual < f64 >
120
124
+ IdealGasContributionDual < Dual64 >
121
- + IdealGasContributionDual < Dual < DualVec64 < 3 > , f64 > >
125
+ + IdealGasContributionDual < Dual < DualSVec64 < 3 > , f64 > >
122
126
+ IdealGasContributionDual < HyperDual64 >
123
127
+ IdealGasContributionDual < Dual2_64 >
124
128
+ IdealGasContributionDual < Dual3_64 >
125
129
+ 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 > >
128
133
+ 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 > >
131
136
+ fmt:: Display
132
137
{
133
138
}
134
139
135
140
struct DefaultIdealGasContribution ;
136
- impl < D : DualNum < f64 > > IdealGasContributionDual < D > for DefaultIdealGasContribution {
141
+ impl < D : DualNum < f64 > + Copy > IdealGasContributionDual < D > for DefaultIdealGasContribution {
137
142
fn de_broglie_wavelength ( & self , _: D , components : usize ) -> Array1 < D > {
138
143
Array1 :: zeros ( components)
139
144
}
@@ -175,7 +180,7 @@ pub trait EquationOfState: Send + Sync {
175
180
fn residual ( & self ) -> & [ Box < dyn HelmholtzEnergy > ] ;
176
181
177
182
/// 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
179
184
where
180
185
dyn HelmholtzEnergy : HelmholtzEnergyDual < D > ,
181
186
{
@@ -187,7 +192,7 @@ pub trait EquationOfState: Send + Sync {
187
192
188
193
/// Evaluate the reduced Helmholtz energy of each individual contribution
189
194
/// 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 > (
191
196
& self ,
192
197
state : & StateHD < D > ,
193
198
) -> Vec < ( String , D ) >
@@ -252,12 +257,10 @@ pub trait EquationOfState: Send + Sync {
252
257
) -> EosResult < SINumber > {
253
258
let mr = self . validate_moles ( moles) ?;
254
259
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 ( ) )
261
264
}
262
265
263
266
/// Calculate the third virial coefficient $C(T)$
@@ -268,10 +271,10 @@ pub trait EquationOfState: Send + Sync {
268
271
) -> EosResult < SINumber > {
269
272
let mr = self . validate_moles ( moles) ?;
270
273
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 ) )
275
278
}
276
279
277
280
/// Calculate the temperature derivative of the second virial coefficient $B'(T)$
@@ -282,15 +285,16 @@ pub trait EquationOfState: Send + Sync {
282
285
) -> EosResult < SINumber > {
283
286
let mr = self . validate_moles ( moles) ?;
284
287
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 ( ) ) )
294
298
}
295
299
296
300
/// Calculate the temperature derivative of the third virial coefficient $C'(T)$
@@ -301,14 +305,15 @@ pub trait EquationOfState: Send + Sync {
301
305
) -> EosResult < SINumber > {
302
306
let mr = self . validate_moles ( moles) ?;
303
307
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 ( ) ) )
312
317
}
313
318
}
314
319
0 commit comments