-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathdifferentials.jl
executable file
·203 lines (155 loc) · 5.28 KB
/
differentials.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#derivative logic
#ForwardDiff compiles one method per function, so separating the
#differentiation logic from the property logic allows the differentials
#to be compiled only once
"""
∂f∂T(model,V,T,z=SA[1.0])
returns `∂f/∂T` at constant total volume and composition, where f is the total helmholtz energy, given by `eos(model,V,T,z)`
"""
function ∂f∂T(model,V,T,z::AbstractVector)
f(∂T) = eos(model,V,∂T,z)
return Solvers.derivative(f,T)
end
"""
∂f∂V(model,V,T,z)
returns `∂f/∂V` at constant temperature and composition, where f is the total helmholtz energy, given by `eos(model,V,T,z)`, and V is the total volume
"""
function ∂f∂V(model,V,T,z::AbstractVector)
f(∂V) = a_res(model,∂V,T,z)
∂aᵣ∂V = Solvers.derivative(f,V)
sum(z)*Rgas(model)*T*(∂aᵣ∂V - 1/V)
end
#returns a tuple of the form ([∂f∂V,∂f∂T],f),using the least amount of computation
"""
∂f(model,V,T,z)
returns zeroth order (value) and first order derivative information of the total helmholtz energy (given by `eos(model,V,T,z)`).
the result is given in two values:
```julia
grad_f,fval = ∂2f(model,V,T,z)
```
where:
```julia
fval = f(V,T) = eos(model,V,T,z)
grad_f = [ ∂f/∂V; ∂f/∂T]
```
Where `V` is the total volume, `T` is the temperature and `f` is the total helmholtz energy.
"""
function ∂f(model,V,T,z)
f(∂V,∂T) = eos(model,∂V,∂T,z)
_f,_df = Solvers.fgradf2(f,V,T)
return _df,_f
end
function ∂f_vec(model,V,T,z::AbstractVector)
_df,_f = ∂f(model,V,T,z)
return SVector(_f,_df[1],_df[2])
end
function f∂fdV(model,V,T,z::AbstractVector)
f(x) = eos(model,x,T,z)
A,∂A∂V = Solvers.f∂f(f,V)
return SVector(A,∂A∂V)
end
function f∂fdT(model,V,T,z::AbstractVector)
f(x) = eos(model,V,x,z)
A,∂A∂T = Solvers.f∂f(f,T)
return SVector(A,∂A∂T)
end
function ∂f_res(model,V,T,z)
f(∂V,∂T) = eos_res(model,∂V,∂T,z)
_f,_df = Solvers.fgradf2(f,V,T)
return _df,_f
end
#returns p and ∂p∂V at constant T
#it doesnt do a pass over temperature, so its
#faster that d2f when only requiring d2fdV2
"""
p∂p∂V(model,V,T,z=SA[1.0])
returns `p` and `∂p/∂V` at constant temperature, where p is the pressure = `pressure(model,V,T,z)` and `V` is the total Volume.
"""
function p∂p∂V(model,V,T,z::AbstractVector=SA[1.0])
f(∂V) = pressure(model,∂V,T,z)
p,∂p∂V = Solvers.f∂f(f,V)
return SVector(p,∂p∂V)
end
"""
∂2f(model,V,T,z)
returns zeroth order (value), first order and second order derivative information of the total helmholtz energy (given by `eos(model,V,T,z)`).
the result is given in three values:
```
hess_f,grad_f,fval = ∂2f(model,V,T,z)
```
where:
```
fval = f(V,T) = eos(model,V,T,z)
grad_f = [ ∂f/∂V; ∂f/∂T]
hess_f = [ ∂²f/∂V²; ∂²f/∂V∂T
∂²f/∂V∂T; ∂²f/∂V²]
```
Where `V` is the total volume, `T` is the temperature and `f` is the total helmholtz energy.
"""
function ∂2f(model,V,T,z)
f(_V,_T) = eos(model,_V,_T,z)
_f,_∂f,_∂2f = Solvers.∂2(f,V,T)
return (_∂2f,_∂f,_f)
end
"""
∂2p(model,V,T,z)
returns zeroth order (value), first order and second order derivative information of the pressure.
the result is given in three values:
```
hess_p,grad_p,pval = ∂2p(model,V,T,z)
```
where:
```
pval = p(V,T) = pressure(model,V,T,z)
grad_p = [ ∂p/∂V; ∂p/∂T]
hess_p = [ ∂²p/∂V²; ∂²p/∂V∂T
∂²p/∂V∂T; ∂²p/∂V²]
```
Where `V` is the total volume, `T` is the temperature and `p` is the pressure.
"""
function ∂2p(model,V,T,z)
f(_V,_T) = pressure(model,_V,_T,z)
_f,_∂f,_∂2f = Solvers.∂2(f,V,T)
return (_∂2f,_∂f,_f)
end
"""
f_hess(model,V,T,z)
returns the second order volume (`V`) and temperature (`T`) derivatives of the total helmholtz energy (given by `eos(model,V,T,z)`). the result is given in a 2x2 `SMatrix`, in the form:
```
[ ∂²f/∂V² ∂²f/∂V∂T
∂²f/∂V∂T ∂²f/∂T²]
```
use this instead of the ∂2f if you only need second order information. ∂2f also gives zeroth and first order derivative information, but due to a bug in the used AD, it allocates more than necessary.
"""
function f_hess(model,V,T,z)
f(w) = eos(model,first(w),last(w),z)
V,T = promote(V,T)
VT_vec = SVector(V,T)
return Solvers.hessian(f,VT_vec)
end
"""
∂²³f(model,V,T,z=SA[1.0])
returns `∂²A/∂V²` and `∂³A/∂V³`, in a single ForwardDiff pass. used mainly in `crit_pure` objective function
"""
function ∂²³f(model,V,T,z=SA[1.0])
f(∂V) = pressure(model,∂V,T,z)
_, ∂²A∂V², ∂³A∂V³ = Solvers.f∂f∂2f(f,V)
return ∂²A∂V², ∂³A∂V³
end
"""
∂²f∂T²(model,V,T,z=SA[1.0])
returns `∂²A/∂T²` via Autodiff. Used mainly for ideal gas properties. It is recommended to overload this function for ideal models, as is equivalent to -Cv(T)/T
"""
function ∂²f∂T²(model,V,T,z)
A(x) = eos(model,V,x,z)
∂A∂T(x) = Solvers.derivative(A,x)
∂²A∂T²(x) = Solvers.derivative(∂A∂T,x)
return ∂²A∂T²(T)
end
function d2fdt2(model,V,T,z)
A(x) = eos(model,V,x,z)
∂A∂T(x) = Solvers.derivative(A,x)
∂²A∂T²(x) = Solvers.derivative(∂A∂T,x)
return ∂²A∂T²(T)
end
const _d23f = ∂²³f