11use crate :: ReferenceSystem ;
22use crate :: state:: StateHD ;
33use nalgebra:: {
4- Const , DVector , DefaultAllocator , Dim , Dyn , OVector , SVector , U1 , allocator:: Allocator ,
4+ Const , DVector , DefaultAllocator , Dim , Dyn , OVector , SVector , allocator:: Allocator ,
55} ;
66use num_dual:: DualNum ;
77use quantity:: { Dimensionless , MolarEnergy , MolarVolume , Temperature } ;
@@ -114,11 +114,27 @@ impl<I: Clone, R: Residual<Const<N>, D>, D: DualNum<f64> + Copy, const N: usize>
114114}
115115
116116/// Ideal gas Helmholtz energy contribution.
117- pub trait IdealGas < D = f64 > {
117+ pub trait IdealGas {
118118 /// Implementation of an ideal gas model in terms of the
119119 /// logarithm of the cubic thermal de Broglie wavelength
120120 /// in units ln(A³) for each component in the system.
121- fn ln_lambda3 < D2 : DualNum < f64 , Inner = D > + Copy > ( & self , temperature : D2 ) -> D2 ;
121+ fn ln_lambda3 < D : DualNum < f64 > + Copy > ( & self , temperature : D ) -> D ;
122+
123+ /// The name of the ideal gas model.
124+ fn ideal_gas_model ( & self ) -> & ' static str ;
125+ }
126+
127+ /// Ideal gas Helmholtz energy contribution.
128+ pub trait IdealGasAD < D = f64 > : Clone {
129+ type Real : IdealGasAD ;
130+ type Lifted < D2 : DualNum < f64 , Inner = D > + Copy > : IdealGasAD < D2 > ;
131+ fn re ( & self ) -> Self :: Real ;
132+ fn lift < D2 : DualNum < f64 , Inner = D > + Copy > ( & self ) -> Self :: Lifted < D2 > ;
133+
134+ /// Implementation of an ideal gas model in terms of the
135+ /// logarithm of the cubic thermal de Broglie wavelength
136+ /// in units ln(A³) for each component in the system.
137+ fn ln_lambda3 ( & self , temperature : D ) -> D ;
122138
123139 /// The name of the ideal gas model.
124140 fn ideal_gas_model ( & self ) -> & ' static str ;
@@ -129,45 +145,44 @@ pub trait Total<N: Dim = Dyn, D: DualNum<f64> + Copy = f64>: Residual<N, D>
129145where
130146 DefaultAllocator : Allocator < N > ,
131147{
132- type IdealGas : IdealGas < D > ;
148+ type RealTotal : Total < N , f64 > ;
149+ type LiftedTotal < D2 : DualNum < f64 , Inner = D > + Copy > : Total < N , D2 > ;
150+ fn re_total ( & self ) -> Self :: RealTotal ;
151+ fn lift_total < D2 : DualNum < f64 , Inner = D > + Copy > ( & self ) -> Self :: LiftedTotal < D2 > ;
133152
134153 fn ideal_gas_model ( & self ) -> & ' static str ;
135154
136- fn ideal_gas ( & self ) -> impl Iterator < Item = & Self :: IdealGas > ;
155+ fn ln_lambda3 ( & self , temperature : D ) -> OVector < D , N > ;
137156
138- fn ln_lambda3 < D2 : DualNum < f64 , Inner = D > + Copy > ( & self , temperature : D2 ) -> OVector < D2 , N > {
139- OVector :: from_iterator_generic (
140- N :: from_usize ( self . components ( ) ) ,
141- U1 ,
142- self . ideal_gas ( ) . map ( |i| i. ln_lambda3 ( temperature) ) ,
143- )
144- }
145-
146- fn ideal_gas_molar_helmholtz_energy < D2 : DualNum < f64 , Inner = D > + Copy > (
157+ fn ideal_gas_molar_helmholtz_energy (
147158 & self ,
148- temperature : D2 ,
149- molar_volume : D2 ,
150- molefracs : & OVector < D2 , N > ,
151- ) -> D2 {
159+ temperature : D ,
160+ molar_volume : D ,
161+ molefracs : & OVector < D , N > ,
162+ ) -> D {
152163 let partial_density = molefracs / molar_volume;
153- let mut res = D2 :: from ( 0.0 ) ;
154- for ( i, & r) in self . ideal_gas ( ) . zip ( partial_density. iter ( ) ) {
164+ let mut res = D :: from ( 0.0 ) ;
165+ for ( & l, & r) in self
166+ . ln_lambda3 ( temperature)
167+ . iter ( )
168+ . zip ( partial_density. iter ( ) )
169+ {
155170 let ln_rho_m1 = if r. re ( ) == 0.0 {
156- D2 :: from ( 0.0 )
171+ D :: from ( 0.0 )
157172 } else {
158173 r. ln ( ) - 1.0
159174 } ;
160- res += r * ( i . ln_lambda3 ( temperature ) + ln_rho_m1)
175+ res += r * ( l + ln_rho_m1)
161176 }
162177 res * molar_volume * temperature
163178 }
164179
165- fn ideal_gas_helmholtz_energy < D2 : DualNum < f64 , Inner = D > + Copy > (
180+ fn ideal_gas_helmholtz_energy (
166181 & self ,
167- temperature : Temperature < D2 > ,
168- volume : MolarVolume < D2 > ,
169- moles : & OVector < D2 , N > ,
170- ) -> MolarEnergy < D2 > {
182+ temperature : Temperature < D > ,
183+ volume : MolarVolume < D > ,
184+ moles : & OVector < D , N > ,
185+ ) -> MolarEnergy < D > {
171186 let total_moles = moles. sum ( ) ;
172187 let molefracs = moles / total_moles;
173188 let molar_volume = volume. into_reduced ( ) / total_moles;
@@ -180,32 +195,59 @@ where
180195}
181196
182197impl <
183- I : IdealGas + Clone + ' static ,
198+ I : IdealGas + ' static ,
184199 C : Deref < Target = EquationOfState < Vec < I > , R > > + Clone ,
185200 R : ResidualDyn + ' static ,
186- > Total < Dyn , f64 > for C
201+ D : DualNum < f64 > + Copy ,
202+ > Total < Dyn , D > for C
187203{
188- type IdealGas = I ;
204+ type RealTotal = Self ;
205+ type LiftedTotal < D2 : DualNum < f64 , Inner = D > + Copy > = Self ;
206+ fn re_total ( & self ) -> Self :: RealTotal {
207+ self . clone ( )
208+ }
209+ fn lift_total < D2 : DualNum < f64 , Inner = D > + Copy > ( & self ) -> Self :: LiftedTotal < D2 > {
210+ self . clone ( )
211+ }
189212
190213 fn ideal_gas_model ( & self ) -> & ' static str {
191214 self . ideal_gas [ 0 ] . ideal_gas_model ( )
192215 }
193216
194- fn ideal_gas ( & self ) -> impl Iterator < Item = & Self :: IdealGas > {
195- self . ideal_gas . iter ( )
217+ fn ln_lambda3 ( & self , temperature : D ) -> DVector < D > {
218+ DVector :: from_vec (
219+ self . ideal_gas
220+ . iter ( )
221+ . map ( |i| i. ln_lambda3 ( temperature) )
222+ . collect ( ) ,
223+ )
196224 }
197225}
198226
199- impl < I : IdealGas < D > + Clone , R : Residual < Const < N > , D > , D : DualNum < f64 > + Copy , const N : usize >
227+ impl < I : IdealGasAD < D > , R : Residual < Const < N > , D > , D : DualNum < f64 > + Copy , const N : usize >
200228 Total < Const < N > , D > for EquationOfState < [ I ; N ] , R >
201229{
202- type IdealGas = I ;
230+ type RealTotal = EquationOfState < [ I :: Real ; N ] , R :: Real > ;
231+ type LiftedTotal < D2 : DualNum < f64 , Inner = D > + Copy > =
232+ EquationOfState < [ I :: Lifted < D2 > ; N ] , R :: Lifted < D2 > > ;
233+ fn re_total ( & self ) -> Self :: RealTotal {
234+ EquationOfState :: new (
235+ self . ideal_gas . each_ref ( ) . map ( |i| i. re ( ) ) ,
236+ self . residual . re ( ) ,
237+ )
238+ }
239+ fn lift_total < D2 : DualNum < f64 , Inner = D > + Copy > ( & self ) -> Self :: LiftedTotal < D2 > {
240+ EquationOfState :: new (
241+ self . ideal_gas . each_ref ( ) . map ( |i| i. lift ( ) ) ,
242+ self . residual . lift ( ) ,
243+ )
244+ }
203245
204246 fn ideal_gas_model ( & self ) -> & ' static str {
205247 self . ideal_gas [ 0 ] . ideal_gas_model ( )
206248 }
207249
208- fn ideal_gas ( & self ) -> impl Iterator < Item = & Self :: IdealGas > {
209- self . ideal_gas . iter ( )
250+ fn ln_lambda3 ( & self , temperature : D ) -> SVector < D , N > {
251+ SVector :: from ( self . ideal_gas . each_ref ( ) . map ( |i| i . ln_lambda3 ( temperature ) ) )
210252 }
211253}
0 commit comments