Path: blob/main/src/equations/equations_of_state.jl
5586 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67@doc raw"""8AbstractEquationOfState910The interface for an `AbstractEquationOfState` requires specifying11the following four functions:12- `pressure(V, T, eos)`13- `energy_internal_specific(V, T, eos)`, the specific internal energy14- `entropy_specific(V, T, eos)`, the specific entropy15- `speed_of_sound(V, T, eos)`1617where `eos = equations.equation_of_state`.18`entropy_specific` is required to calculate the mathematical entropy and entropy variables,19and `speed_of_sound` is required to calculate wavespeed estimates for e.g., [`FluxLaxFriedrichs`](@ref).2021Additional functions can also be specialized to particular equations of state to improve22efficiency.23"""24abstract type AbstractEquationOfState end2526include("equation_of_state_ideal_gas.jl")27include("equation_of_state_vdw.jl")28include("equation_of_state_peng_robinson.jl")2930include("equations_of_state_helmholtz.jl")31include("equation_of_state_helmholtz_ideal_gas.jl")3233#######################################################34#35# Some general fallback routines are provided below36#37#######################################################3839function gibbs_free_energy(V, T, eos)40s = entropy_specific(V, T, eos)41p = pressure(V, T, eos)42e_internal = energy_internal_specific(V, T, eos)43h = e_internal + p * V44return h - T * s45end4647# compute c_v = de/dT48@inline function heat_capacity_constant_volume(V, T, eos::AbstractEquationOfState)49return ForwardDiff.derivative(T -> energy_internal_specific(V, T, eos), T)50end5152# this is used in [`flux_terashima_etal`](@ref) and [`flux_terashima_etal_central`](@ref)53function calc_pressure_derivatives(V, T, eos)54dpdV_T = ForwardDiff.derivative(V -> pressure(V, T, eos), V)55dpdT_V = ForwardDiff.derivative(T -> pressure(V, T, eos), T)56return dpdT_V, dpdV_T57end5859# relative tolerance, initial guess, and maximum number of iterations60# for the Newton solver for temperature.61eos_newton_tol(eos::AbstractEquationOfState) = 10 * eps()62eos_initial_temperature(V, e_internal, eos::AbstractEquationOfState) = 163eos_newton_maxiter(eos) = 206465"""66temperature(V, e_internal, eos::AbstractEquationOfState; initial_T = 1.0,67tol = eos_newton_tol(eos), maxiter = 100)6869Calculates the temperature as a function of specific volume `V` and internal energy `e`70by using Newton's method to determine `T` such that `energy_internal_specific(V, T, eos) = e`.71Note that the tolerance may need to be adjusted based on the specific equation of state.72"""73function temperature(V, e_internal, eos::AbstractEquationOfState;74initial_T = eos_initial_temperature(V, e_internal, eos),75tol = eos_newton_tol(eos), maxiter = eos_newton_maxiter(eos))76T = initial_T77de = energy_internal_specific(V, T, eos) - e_internal78iter = 179while abs(de) > tol * abs(e_internal) && iter < maxiter80de = energy_internal_specific(V, T, eos) - e_internal8182# for thermodynamically admissible states, c_v = de_dT_V > 0, which should83# guarantee convergence of this iteration.84de_dT_V = heat_capacity_constant_volume(V, T, eos)8586# guard against negative temperatures87T = max(tol, T - de / de_dT_V)88iter += 189end90if iter == maxiter91@warn "Solver in `temperature(V, e_internal, eos)` did not converge within $maxiter iterations. " *92"Final states: iter = $iter, V, e_internal = $V, $(e_internal) with de = $de"93end94return T95end9697# helper function used in [`flux_terashima_etal`](@ref) and [`flux_terashima_etal_central`](@ref)98@inline function drho_e_internal_drho_at_const_p(V, T, eos::AbstractEquationOfState)99rho = inv(V)100e_internal = energy_internal_specific(V, T, eos)101102dpdT_V, dpdV_T = calc_pressure_derivatives(V, T, eos)103dpdrho_T = dpdV_T * (-V / rho) # V = inv(rho), so dVdrho = -1/rho^2 = -V^2.104de_dV_T = T * dpdT_V - pressure(V, T, eos)105drho_e_internal_drho_T = e_internal + rho * de_dV_T * (-V / rho) # d(rho_e)/drho_|T = e + rho * de_dV|T * dVdrho106107c_v = heat_capacity_constant_volume(V, T, eos)108return ((-rho * c_v) / (dpdT_V) * dpdrho_T + drho_e_internal_drho_T)109end110end # @muladd111112113