******************
Equations of State
******************

The general interface to the equation of state is:

.. code:: c++

   template <typename I, typename T>
   AMREX_GPU_HOST_DEVICE AMREX_INLINE
   void eos (const I input, T& state, bool use_raw_inputs = false)

where ``input`` specifies which thermodynamic quantities are taken as
the input and ``state`` is a C++ struct that holds all of the
thermodynamic information.


Interface and modes
===================

.. index:: eos_t, eos_re_t, eos_rep_t, eos_rh_t, chem_eos_t

The EOS is called as:

.. code:: c++

   eos(mode, eos_type)

where *mode* determines which thermodynamic quantities are inputs,
and is one of:

* ``eos_input_rt`` : density and temperature are inputs

* ``eos_input_rh`` : density and specific enthalpy are inputs

* ``eos_input_tp`` : temperature and pressure are inputs

* ``eos_input_rp`` : density and pressure are inputs

* ``eos_input_re`` : density and specific internal energy are inputs

* ``eos_input_ps`` : pressure and entropy are inputs

* ``eos_input_ph`` : pressure and specific enthalpy are inputs

* ``eos_input_th`` : temperature and specific enthalpy are inputs

The *eos_type* passed in is one of

* ``eos_t`` : provides access to all available thermodynamic information,
  including derivatives.

* ``eos_re_t`` : only provides the energy-based thermodynamic information, including
  energy derivatives.

* ``eos_rep_t`` : expands on ``eos_re_t`` to include pressure information

* ``eos_rh_t`` : expands on ``eos_rep_t`` to include enthalpy information

* ``chem_eos_t`` : adds some quantities needed for the primordial chemistry EOS
  and explicitly does not include the mass fractions.

.. tip::

   The EOS implementations make heavy use of templating to
   "compile-out" the thermodynamic quantities that are not needed
   (depending on the input type).  This can greatly increase
   performance.  As such, you should pick the smallest EOS structure
   (``eos_re_t``, ``eos_rep_t``, ...) that contains the thermodynamic
   information you need.

.. tip::

   You can also pass a ``burn_t`` struct into the EOS, although this
   will give you access to a much smaller range of data.


Composition
===========

All input modes for ``eos()`` require a composition.  Usually this is
via the set of mass fractions, ``eos_t xn[]``, but if ``USE_AUX_THERMO``
is set to ``TRUE``, then we instead use the auxiliary quantities
stored in ``eos_t.aux[]``.

.. _aux_eos_comp:

Auxiliary composition
---------------------

.. index:: USE_AUX_THERMO

.. note::

   The main use-case for the auxiliary composition is when using a reaction
   network together with the tabulated NSE state.

With ``USE_AUX_THERMO=TRUE``, we interpret the composition from the auxiliary variables.
For ``eos_t eos_state``, the auxiliary variables are


* ``eos_state.aux[AuxZero::iye]`` : electron fraction, defined as

  .. math::

     Y_e = \sum_k \frac{X_k Z_k}{A_k}

* ``eos_state.aux[AuxZero::iabar]`` : the average mass of the nuclei, :math:`\bar{A}`, defined as:

  .. math::

     \frac{1}{\bar{A}} = \sum_k \frac{X_k}{A_k}

  In many stellar evolutions texts, this would be written as :math:`\mu_I`.

* ``eos_state.aux[AuxZero::ibea]`` : the binding energy per nucleon (units of
  MeV), defined as

  .. math::

     \left \langle \frac{B}{A} \right \rangle  = \sum_k \frac{X_k B_k}{A_k}

  where :math:`B_k` is the binding energy of nucleus :math:`k`

Given a composition of mass fractions, the function:

.. code:: c++

   template <class state_t>
   AMREX_GPU_HOST_DEVICE AMREX_INLINE
   void set_aux_comp_from_X(state_t& state)

will initialize the auxiliary data.

Many equations of state also need :math:`\bar{Z}` which is easily computed as

.. math::

   \bar{Z} = \bar{A} Y_e


Composition derivatives
-----------------------

.. index:: eos_extra_t, eos_re_extra_t, eos_rep_extra_t

The derivatives $\partial p/\partial A$, $\partial p/\partial Z$,
and $\partial e/\partial A$, $\partial e/\partial Z$ are available via
the ``eos_extra_t``, ``eos_re_extra_t``, ``eos_rep_extra_t``, which
extends the non-"extra" variants with these additional fields.

The composition derivatives can be used via the ``composition_derivatives()`` function
in ``eos_composition.H``
to compute :math:`\partial p/\partial X_k |_{\rho, T, X_j}`, :math:`\partial e/\partial X_k |_{\rho, T, X_j}`, and :math:`\partial h/\partial X_k |_{\rho, T, X_j}`.  This has the interface:

.. code:: c++

   template <typename T>
   AMREX_GPU_HOST_DEVICE AMREX_INLINE
   eos_xderivs_t composition_derivatives (const T& state)



Initialization and cutoff values
================================


The EOS will make sure that the inputs are within an acceptable range,
(e.g., ``small_temp`` :math:`< T <` ``maxT``). If they are not, then it
resets them silently—no error is thrown.

If you are calling the EOS with ``eos_input_re``, and if :math:`e <
10^{-200}`, then it calls the EOS with ``eos_input_rt`` with T =
max ( ``small_temp``, T ).

.. note::

   User’s are encourage to do their own validation of inputs before calling
   the EOS.

EOS structure
=============

Each EOS should have two main routines through which it interfaces to the
rest of Microphysics.

* ``actual_eos_init()`` :  At the beginning of the simulation,
  ``actual_eos_init`` will perform any initialization steps and save
  EOS variables (mainly ``smallt``, the temperature floor, and
  ``smalld``, the density floor). These variables are stored in the
  main EOS module of the code calling these routines.

  This is also where an EOS with tables would read in the tables
  and initialize the memory they are stored in.

* ``actual_eos()`` : this is the main evaluation routine.  It should
  accept an ``eos_input_t`` specifying the thermodynamic inputs and a
  struct (like ``eos_t``) that stores the thermodynamic quantities.