Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/equations_of_state.jl
5586 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
@doc raw"""
9
AbstractEquationOfState
10
11
The interface for an `AbstractEquationOfState` requires specifying
12
the following four functions:
13
- `pressure(V, T, eos)`
14
- `energy_internal_specific(V, T, eos)`, the specific internal energy
15
- `entropy_specific(V, T, eos)`, the specific entropy
16
- `speed_of_sound(V, T, eos)`
17
18
where `eos = equations.equation_of_state`.
19
`entropy_specific` is required to calculate the mathematical entropy and entropy variables,
20
and `speed_of_sound` is required to calculate wavespeed estimates for e.g., [`FluxLaxFriedrichs`](@ref).
21
22
Additional functions can also be specialized to particular equations of state to improve
23
efficiency.
24
"""
25
abstract type AbstractEquationOfState end
26
27
include("equation_of_state_ideal_gas.jl")
28
include("equation_of_state_vdw.jl")
29
include("equation_of_state_peng_robinson.jl")
30
31
include("equations_of_state_helmholtz.jl")
32
include("equation_of_state_helmholtz_ideal_gas.jl")
33
34
#######################################################
35
#
36
# Some general fallback routines are provided below
37
#
38
#######################################################
39
40
function gibbs_free_energy(V, T, eos)
41
s = entropy_specific(V, T, eos)
42
p = pressure(V, T, eos)
43
e_internal = energy_internal_specific(V, T, eos)
44
h = e_internal + p * V
45
return h - T * s
46
end
47
48
# compute c_v = de/dT
49
@inline function heat_capacity_constant_volume(V, T, eos::AbstractEquationOfState)
50
return ForwardDiff.derivative(T -> energy_internal_specific(V, T, eos), T)
51
end
52
53
# this is used in [`flux_terashima_etal`](@ref) and [`flux_terashima_etal_central`](@ref)
54
function calc_pressure_derivatives(V, T, eos)
55
dpdV_T = ForwardDiff.derivative(V -> pressure(V, T, eos), V)
56
dpdT_V = ForwardDiff.derivative(T -> pressure(V, T, eos), T)
57
return dpdT_V, dpdV_T
58
end
59
60
# relative tolerance, initial guess, and maximum number of iterations
61
# for the Newton solver for temperature.
62
eos_newton_tol(eos::AbstractEquationOfState) = 10 * eps()
63
eos_initial_temperature(V, e_internal, eos::AbstractEquationOfState) = 1
64
eos_newton_maxiter(eos) = 20
65
66
"""
67
temperature(V, e_internal, eos::AbstractEquationOfState; initial_T = 1.0,
68
tol = eos_newton_tol(eos), maxiter = 100)
69
70
Calculates the temperature as a function of specific volume `V` and internal energy `e`
71
by using Newton's method to determine `T` such that `energy_internal_specific(V, T, eos) = e`.
72
Note that the tolerance may need to be adjusted based on the specific equation of state.
73
"""
74
function temperature(V, e_internal, eos::AbstractEquationOfState;
75
initial_T = eos_initial_temperature(V, e_internal, eos),
76
tol = eos_newton_tol(eos), maxiter = eos_newton_maxiter(eos))
77
T = initial_T
78
de = energy_internal_specific(V, T, eos) - e_internal
79
iter = 1
80
while abs(de) > tol * abs(e_internal) && iter < maxiter
81
de = energy_internal_specific(V, T, eos) - e_internal
82
83
# for thermodynamically admissible states, c_v = de_dT_V > 0, which should
84
# guarantee convergence of this iteration.
85
de_dT_V = heat_capacity_constant_volume(V, T, eos)
86
87
# guard against negative temperatures
88
T = max(tol, T - de / de_dT_V)
89
iter += 1
90
end
91
if iter == maxiter
92
@warn "Solver in `temperature(V, e_internal, eos)` did not converge within $maxiter iterations. " *
93
"Final states: iter = $iter, V, e_internal = $V, $(e_internal) with de = $de"
94
end
95
return T
96
end
97
98
# helper function used in [`flux_terashima_etal`](@ref) and [`flux_terashima_etal_central`](@ref)
99
@inline function drho_e_internal_drho_at_const_p(V, T, eos::AbstractEquationOfState)
100
rho = inv(V)
101
e_internal = energy_internal_specific(V, T, eos)
102
103
dpdT_V, dpdV_T = calc_pressure_derivatives(V, T, eos)
104
dpdrho_T = dpdV_T * (-V / rho) # V = inv(rho), so dVdrho = -1/rho^2 = -V^2.
105
de_dV_T = T * dpdT_V - pressure(V, T, eos)
106
drho_e_internal_drho_T = e_internal + rho * de_dV_T * (-V / rho) # d(rho_e)/drho_|T = e + rho * de_dV|T * dVdrho
107
108
c_v = heat_capacity_constant_volume(V, T, eos)
109
return ((-rho * c_v) / (dpdT_V) * dpdrho_T + drho_e_internal_drho_T)
110
end
111
end # @muladd
112
113