Source code for burnman.eos.macaw

# This file is part of BurnMan - a thermoelastic and thermodynamic toolkit
# for the Earth and Planetary Sciences.
# Copyright (C) 2012 - 2024 by the BurnMan team, released under the GNU
# GPL v2 or later.


import scipy.optimize as opt
from . import equation_of_state as eos
import warnings
import numpy as np


# Try to import the jit from numba.  If it is
# not available, just go with the standard
# python interpreter
try:
    from numba import jit
except ImportError:

    def jit(nopython=True):
        def decorator(fn):
            return fn

        return decorator


[docs] @jit(nopython=True) def make_params(K0, K0_prime, K_infinity_prime): a = ( 16.0 * np.power(K0_prime, 3.0) + 84.0 * np.power(K0_prime, 2.0) + 192.0 * K0_prime - 972.0 * K_infinity_prime + 1177.0 ) b = 2.0 * np.power(K0_prime, 2.0) + 7.0 * K0_prime - 27.0 * K_infinity_prime + 38.0 omega = np.power((a + np.sqrt(a * a - 32.0 * b * b * b)), 1.0 / 3.0) C = ( (11.0 / 6.0) + (1.0 / 3.0) * K0_prime - K_infinity_prime + (np.power(2, -1.0 / 3.0) / 6) * omega + (np.power(2, 1.0 / 3.0) / 3) * (b / omega) ) B = K_infinity_prime - 1.0 A = K0 / (B - 0.5 * C + np.power(B + C, 2.0)) return A, B, C
[docs] class MACAW(eos.IsothermalEquationOfState): """ Class for the MACAW equation of state detailed in :cite:`Lozano2022`. This equation of state has no temperature dependence. .. list-table:: :widths: 25 75 20 :header-rows: 1 * - Parameter - Description - Units * - ``F_0`` - Reference Helmholtz free energy. - :math:`\\text{J/mol}` * - ``P_0`` - Reference pressure. - :math:`\\text{Pa}` * - ``V_0`` - Reference volume. - :math:`\\text{m}^3` * - ``K_0`` - Reference bulk modulus. - :math:`\\text{Pa}` * - ``Kprime_0`` - Pressure derivative of the bulk modulus at reference pressure. - Dimensionless * - ``Kprime_inf`` - Infinite pressure derivative of the bulk modulus. - Dimensionless """
[docs] def isothermal_bulk_modulus_reuss(self, pressure, temperature, volume, params): """ Returns isothermal bulk modulus :math:`K_T` :math:`[Pa]` as a function of pressure :math:`[Pa]`, temperature :math:`[K]` and volume :math:`[m^3]`. """ A, B, C = make_params(params["K_0"], params["Kprime_0"], params["Kprime_inf"]) Vrel = volume / params["V_0"] term1 = A * np.power(Vrel, -(B + 1)) term2 = np.exp((2.0 / 3.0) * C * (1 - np.power(Vrel, 1.5))) term3 = np.power(C * np.power(Vrel, 1.5) + B, 2.0) - ( 0.5 * C * np.power(Vrel, 1.5) - B ) return term1 * term2 * term3
[docs] def volume(self, pressure, temperature, params): """ Get the Vinet volume at a reference temperature for a given pressure :math:`[Pa]`. Returns molar volume in :math:`[m^3]` """ def delta_pressure(x): return self.pressure(0.0, x, params) - pressure V = opt.brentq(delta_pressure, 0.1 * params["V_0"], 1.5 * params["V_0"]) return V
[docs] def pressure(self, temperature, volume, params): """ Returns pressure :math:`[Pa]` as a function of volume :math:`[m^3]`. """ A, B, C = make_params(params["K_0"], params["Kprime_0"], params["Kprime_inf"]) Vrel = volume / params["V_0"] term1 = A * np.power(Vrel, -(B + 1.0)) term2 = np.exp((2.0 / 3.0) * C * (1.0 - np.power(Vrel, 1.5))) term3 = C * np.power(Vrel, 1.5) + B return term1 * term2 * term3 - A * (B + C) + params["P_0"]
def _molar_helmholtz_energy(self, pressure, temperature, volume, params): """ Returns the Helmholtz energy :math:`\\mathcal{F}` of the mineral. :math:`[J/mol]` """ A, B, C = make_params(params["K_0"], params["Kprime_0"], params["Kprime_inf"]) Vrel = volume / params["V_0"] I1 = -params["V_0"] * ( np.power(Vrel, -B) * np.exp((2.0 / 3.0) * C * (1.0 - np.power(Vrel, 1.5))) - 1.0 ) I0 = (-A * (B + C) + params["P_0"]) * params["V_0"] * (Vrel - 1.0) return params["F_0"] - A * I1 - I0
[docs] def gibbs_energy(self, pressure, temperature, volume, params): """ Returns the Gibbs free energy :math:`\\mathcal{G}` of the mineral. :math:`[J/mol]` """ return ( self._molar_helmholtz_energy(pressure, temperature, volume, params) + pressure * volume )
[docs] def shear_modulus(self, pressure, temperature, volume, params): """ Returns shear modulus :math:`G` of the mineral. :math:`[Pa]` """ return 1.0e99
[docs] def validate_parameters(self, params): """ Check for existence and validity of the parameters. The value for :math:`K'_{\\infty}` is thermodynamically bounded between 5/3 and :math:`K'_0` :cite:`StaceyDavis2004`. """ if "F_0" not in params: params["F_0"] = 0.0 if "P_0" not in params: params["P_0"] = 1.0e5 if "E_0" in params: raise KeyError( "Isothermal equations of state should be " "defined in terms of Helmholtz free energy " "F_0, not internal energy E_0." ) # Check that all the required keys are in the dictionary expected_keys = ["V_0", "K_0", "Kprime_0", "Kprime_inf"] for k in expected_keys: if k not in params: raise KeyError("params object missing parameter : " + k) # Finally, check that the values are reasonable. if params["P_0"] < 0.0: warnings.warn("Unusual value for P_0", stacklevel=2) if params["V_0"] < 1.0e-7 or params["V_0"] > 1.0e-3: warnings.warn("Unusual value for V_0", stacklevel=2) if params["K_0"] < 1.0e9 or params["K_0"] > 1.0e13: warnings.warn("Unusual value for K_0", stacklevel=2) if params["Kprime_0"] < 0.0 or params["Kprime_0"] > 10.0: warnings.warn("Unusual value for Kprime_0", stacklevel=2) if params["Kprime_inf"] < 1 + 45.0 / 29.0: warnings.warn("Value for Kprime_inf below recommended value", stacklevel=2) if params["Kprime_inf"] > params["Kprime_0"]: warnings.warn("Kprime_inf should be less than Kprime_0", stacklevel=2)