\chapter{The Haero Library}
\labelchapter{library}

In this chapter, we describe the Haero software library itself, and its usage
within an atmospheric model.

\section{Overview}
\labelsection{lib:overview}

Haero is designed to provide a modal aerosol capability to an atmospheric model
written in C++ and/or Fortran. It makes no attempt to describe or evolve any
atmospheric phenomena outside of aerosols. Instead, Haero evolves the state of
aerosols within a modal aerosol model as part of a broader atmospheric
{\bf host model}---a mathematically consistent description of the atmosphere.

To use Haero in your own host model, you write code to interact to construct
a modal aerosol system and invoke aerosol processes on that system. Haero gives
you all the flexibility and control you need to define how the aerosol processes
couple with and interoperate with the other processes in the host model. In this
sense, Haero is a set of building blocks you can use to construct the most
appropriate modal aerosol representation for your host model.

Haero provides an interface for running aerosol processes to evolve a set of
state data within a single atmospheric column. You can evolve several columns
in parallel, as long as state data is provided for each column.

All quantities in Haero are specified using the International System of Units
(SI) unless otherwise specified. In both code comments and documentation, we
place square brackets indicating units after the description of a quantity
(e.g. simulation time [s]).

\subsection{Aerosol Systems}
\labelsubsection{lib:systems}

Haero's representation of aerosols relies on a set of simple data structures
that define the assumptions underlying a specific modal aerosol system. These
elements are:

\begin{itemize}
  \item {\bf Modes}: statistical representations of aerosol particle populations
        organized by particle size
  \item {\bf Species}: aerosol and gas molecules of interest. Each aerosol
        species belongs to a single aerosol mode and is tracked by mass and
        number.
  \item An {\bf Aerosol Configuration}: the collection of modes and species of
        interested within a specific modal aerosol system to be simulated
\end{itemize}

These entities define the aerosol system of interest in Haero, and provide
any related {\bf metadata} needed to make decisions about how an aerosol
processes does its work.

\subsection{Aerosol State Data}
\labelsubsection{lib:state}

Haero deals with two distinct types of state variables:

\begin{itemize}
  \item {\bf Prognostic variables}: variables that are evolved in time according
        to a system of differential equations
  \item {\bf Diagnostic variables}: variables that are algebraically related to
        other variables, whether those variables are prognostic or diagnostic
\end{itemize}

Prognostic variables are quantities that possess an initial state and are
evolved forward in time by their {\bf tendencies} (time derivatives). It is
not possible to construct the value of a prognostic variable at time $t$ without
an initial condition at some time $t_0$ and a tendency defined over the period
$\left[t_0, t\right]$.

The concept of a ``diagnostic'' variable is more general than its name suggests.
The word "diagnostic" suggests that the variable is used only as an indicator
by a human attempting to ``diagnose'' some atmospheric condition. In fact, a
diagnostic variable can be any variable whose state can be constructed at any
instant in time, using only the relevant prognostic variables. In this sense,
a diagnostic variable serves as a ``shared'' variable that can be computed at
the appropriate time, and used by one or more prognostic processes.

Haero's aerosol state data lives in multi-dimensional arrays within ``smart
containers'':

\begin{itemize}
  \item The \texttt{Prognostics} container contains prognostic state variables
        specific to aerosols
  \item The \texttt{Atmosphere} container contains a thermodynamic description
        of the atmosphere in which an aerosol system is embedded
  \item The \texttt{Diagnostics} container contains a registry of diagnostic
        variables shared amongst various aerosol processes, and made available
        for output
\end{itemize}

The arrays in these data structures are stored in \texttt{View} objects provided
by the Kokkos C++ library. Aerosol state data is allocated in C++, but available
for use in Fortran for implementing aerosol processes or for using Haero
from within a Fortran host model. Atmospheric state data is provided by the
host model.

\subsection{Aerosol Processes}
\labelsubsection{lib:processes}

The aerosol ``life cycle'' consists of a set of complicated physical processes
involving many participants, with a wide range of length and time scales. These
different scales demand a degree of flexibility in how we evaluate changes to
the state of an aerosol system. For example, we expect to be able to resolve
processes whose time scale is similar to or larger than the time scale for
convection in the atmosphere, whereas processes with faster time scales must be
treated in some special way that accommodates a relaxation or equilibration
process.

In Haero, an ``aerosol process'' accepts a set of completely specified input
(prognostic and diagnostic variables, an atmospheric state, etc) and calculates
a set of tendencies for prognostic aerosol and gas variables.

An aerosol process consists of a set of parameterizations that encode simplifying
assumptions about a specific stage of the aerosol life cycle into an algorithm
that computes the relevant quantities of interest. The processes provided by
Haero, and their various parameterizations, are described in \refchapter{processes}.

These processes are the true assets of the Haero library. They can be
implemented in C++, in Fortran, or in both. This allows aerosol researchers to
make their latest parameterizations available in the Haero library, while
providing software engineers with a ``future-proof'' environment for optimizing
these and other parameterizations for DOE's Leadership Class Facilities.

That's an orbit-level view of the Haero library. Now let's take a closer look at
each of these aspects.

\section{Aerosol Systems in Haero}
\labelsection{lib:systems}

To model a specific aerosol system in Haero, we must answer some questions:

\begin{itemize}
  \item How are aerosol particle sizes represented?
  \item What species are present in the system, and how are their sizes
        reflected in the particle size distribution?
  \item How is the state of an aerosol system represented mathematically?
  \item How many vertical levels are needed to resolve the profile of aerosols
        in the system?
  \item What are the relevent physical processes that describe the evolution
        of the aerosol system?
\end{itemize}

Each of these decisions greatly affects the nature of the system---systems with
different answers to these questions can have very different behavior. Haero
attempts to answer these questions with a few basic data structures.

\subsection{Particle Sizes: the Mode Type}
\labelsubsection{lib:modes}

We've seen how the dynamics of aerosols can be represented mathematically
by evolution equations for moments of modal distribution functions. Modes
simplify the description of aerosol particles in terms of their size: instead of
representing a population of particles with a distribution function
$n(V_p, \vec{x}, t)$ that varies continuously with the size of the particle, we
introduced $M$ discrete modes and declared that these modes partition the
population of aerosol particles in the sense of the modal assumption as given
by \refeq{modal_n}.

The essential information in a mode is the range of particle sizes it
encompasses, $[D_{\min}, D_{\max}]$, and its geometric standard deviation,
$\sigma_g$. In Haero's C and C++ interfaces,
we represent an aerosol mode with the \texttt{Mode} struct:

\lstset{language=[11]{c++}}
\begin{lstlisting}
struct Mode {
  std::string name;  // a unique identifier for the mode
  Real min_diameter; // the mode's minimum particle diameter [m]
  Real max_diameter; // the mode's maximum particle diameter [m]
  Real mean_std_dev; // the geometric mean standard deviation for the mode [m]
};
\end{lstlisting}

Haero's Fortran interface offers a \texttt{mode\_t} data structure, equivalent to
the C++ \texttt{Mode} class. This data structure is defined in the \texttt{haero}
Fortran module:

\lstset{language=[03]{fortran}}
\begin{lstlisting}
type :: mode_t
  ! Mode name
  character(len=:), allocatable :: name
  ! Minimum particle diameter [m]
  real(wp) :: min_diameter
  ! Maximum particle diameter [m]
  real(wp) :: max_diameter
  ! Geometric mean standard deviation [m]
  real(wp) :: mean_std_dev
end type
\end{lstlisting}

The log-normal PDF for each mode is defined by two quantities, the (constant) mean standard deviation contained within the \texttt{Mode} class, and the geometric mean.
The geometric mean is a variable function of the mass mixing ratios of all species contained within the mode and the number mixing ratio of the mode itself. 
Since these are time-dependent variables, they are not contained in the \texttt{Mode} class, which is for constant metadata only.

We also note that, mathematically, the log-normal size distributions of each mode do not have a maximum or minimum; they are bounded by 0 and $\infty$.
The \texttt{min\_diameter} and \texttt{max\_diameter} member variables should therefore not be interpreted in the context of the log-normal functions defined by e.g., \eqref{eq:log_normal_pdf_log}.
Instead they represent the boundaries beyond which particles are better described by a different mode.  
These minimum and maximum sizes are used to trigger redistribution of particles' mass and number mixing ratios between modes.

In principle, a Haero calculation can support any number of modes, but care
must be taken to ensure that the modal assumptions remain valid, and that
the parametrizations selected can accommodate the given modes.

\subsection{Aerosol Species: the Species Type}
\labelsubsection{lib:species}

Each aerosol mode consists of one or more particle species. Additionally,
gas particles also come in different species. Both aerosol particles and
gas particles have physical properties that are described by the
\texttt{Species} data type.

A particle species is a specifically-identified molecular assembly with
a number of relevant physical properties. The fundamental description of a
species includes

\begin{itemize}
  \item a descriptive name (e.g. \texttt{"sulfate"})
  \item a symbolic name (e.g. \texttt{SO4}, for sulfate)
  \item information about the chemical properties of the species
\end{itemize}

In C++, we represent this information in the following way:

\lstset{language=[11]{c++}}
\begin{lstlisting}
struct Species {
  std::string name;          // full species name
  std::string symbol;        // abbreviated symbolic name
  Real molecular weight;     // molecular weight [g/mol]
  Real crystalization_point; // crystalization point [?]
  Real deliquescence_point;  // deliquenscence point [?]
};
\end{lstlisting}

In Fortran, a species is defined by the following derived type:
\lstset{language=[03]{fortran}}
\begin{lstlisting}
type :: species_t
  ! Species name
  character(len=:), allocatable :: name
  ! Species symbol (abbreviation)
  character(len=:), allocatable :: symbol
  ! Molecular weight [g/mol]
  real(wp) :: molecular_wt
  ! Crystalization point [?]
  real(wp) :: crystal_pt
  ! Deliquenscence point [?]
  real(wp) :: deliques_pt
end type
\end{lstlisting}

\subsection{Species and Their Sizes: the Modal Aerosol Configuration Type}
\labelsubsection{lib:modal_aerosol_config}

We have data types that express particle sizes and particle species. Now we
need something that relates these two pieces of information. In other words,
we need a way to express how particles of a specific aerosol species are allowed
to grow and shrink, and how that activity is reflected in our representation
of particle sizes.

In the past, aerosol models have often elected to fix the modes and aerosol/gas
species that they treat, in order to simplify code development. Haero instead
allows a researcher to select these modes and species at runtime, allowing a
far greater family of aerosol models to be represented.

\lstset{language=[11]{c++}}
\begin{lstlisting}
class ModalAerosolConfig final {
  public:
  // Constructor -- creates a new modal aerosol configuration given all relevant
  // data.
  ModalAerosolConfig(const std::vector<Mode>& aerosol_modes,
                     const std::vector<Species>& aerosol_species,
                     const std::map<std::string, std::vector<std::string> >& mode_species,
                     const std::vector<Species>& gas_species);

  // The list of aerosol modes.
  std::vector<Mode> aerosol_modes;

  // The list of aerosol species.
  std::vector<Species> aerosol_species;

  // The list of gas species.
  std::vector<Species> gas_species;

  // The total number of distinct aerosol species populations in the
  // system, counting appearances of one species in different modes separately.
  int num_aerosol_populations;

  // Returns the list of aerosol species associated with the system with the
  // given mode index.
  std::vector<Species> aerosol_species_for_mode(int mode_index) const;
};
\end{lstlisting}

Once you have a modal aerosol configuration, you can answer the first two
questions at the beginning of this section. Next, we look at how the state of
an aerosol system is represented mathematically.

\subsection{Aerosol and Atmospheric State: Container Types}
\labelsection{lib:state}

Once you've described the constituents of your aerosol system with a modal
aerosol configuration, you can create state variables for that system. The state
of an aerosol system is defined by the following prognostic variables within the
\texttt{Prognostics} data structure:

\begin{itemize}
  \item {\bf aerosol modal mass mix fraction} $q_{m,s}$ [kg aerosol species $s$ /kg dry air]:
        the ratio of aerosol mass to dry air mass for aerosol species $s$
        occupying mode $m$
  \item {\bf gas mass mix fraction} $q_g$ [kg gas species $g$/kg dry air]: the
        ratio of the mass of gas species $g$ to dry air mass
  \item {\bf modal number concentrations} $n_m$ [\# /kg dry air]: the total number of
        particles per unit mass of dry air in the mode $m$
\end{itemize}

The state of the atmosphere (expressed in averaged thermodynamic quantities
like pressure and temperature) greatly affects the behavior of aerosols, so
this atmosphere state information is made available in the \texttt{Atmosphere} data
structure.

Finally, the system can use a set of diagnostic variables, stored in the
\texttt{Diagnostics} data structure, that depend on a set of aerosol processes
(which are discussed in a later section).

The \texttt{Prognostics}, \texttt{Atmosphere}, and \texttt{Diagnostics}
containers store state data in multidimensional arrays allocated in C++ but made
available to both C++ and Fortran. The data for each array is stored within a
Kokkos \texttt{View}.

\subsection*{Digression: Kokkos Views as Multidimensional Arrays}
\labelsubsection{lib:views}

The C++ programming language has lots of features, but remarkably it includes no
mechanism for allocating multidimensional arrays at runtime. The Kokkos C++
library fills this gap by providing a data structure called a \texttt{View}. A
\texttt{View} is essentially an interface that allows a C++ programmer to treat a
chunk of memory like a multidimensional array.

A \texttt{View} has a rank and a set of dimensions, just like an allocatable
Fortran array. You access a \texttt{View} in the same way that you'd access a
Fortran array, except that C++ uses row-major indexing instead of Fortran's
column-major indexing. So for a rank-3 view \texttt{f} that you access in C++
as \texttt{f(i,j,k)}, you would access the corresponding array in Fortran as
\texttt{f(k,j,i)}.

\subsubsection*{Packs and Vectorization}
\labelsubsubsection{lib:packs}

Haero uses Views that consist of \texttt{Pack} objects instead of floating
point numbers. A \texttt{Pack} (or just ``pack'') is a contiguous array of numbers
that allows a modern CPU or GPU to vectorize calculations using special
instructions.

When executing a vector instruction, a processor performs arithmetic on more
than one number at a time within a mathematical expression. In many cases,
vectorizing expressions can produce significantly faster code. The cost of this
optimization is that a pack represents several numbers, not one. This can make
it tricky to reason about the physical quantities stored in a pack.

Haero uses packs with a size (number of contiguously stored numbers) set at
compile time by the CMake variable \texttt{HAERO\_PACK\_SIZE}. To simplify the
process of reasoning about packs, Haero uses these objects one way only:
in Haero a pack stores data for \texttt{HAERO\_PACK\_SIZE} vertical levels in
a column. Thus, a pack contains data for exactly one variable (with the same
units and physical interpretation) whose values span one or more vertical
levels.

This is the easiest way for Haero to support vectorization. It does mean,
however, that the number of vertical levels in a column differs in general from
the number of packs spanning a vertical level. For example, a column of data
with 72 vertical levels running in a Haero build with a \texttt{HAERO\_PACK\_SIZE}
of 2 contains $36 = 72 / 2 $ packs in its vertical extent.

\subsubsection*{Haero Views}

Because Haero is concerned with arrays having very specific dimensions, we
define some named types that correspond to views/arrays that span specific
spaces:

\begin{table}[htbp]
\centering
\caption{Named C++ View Types}
\label{tab:viewtypes}
\begin{tabular}{|l|l|p{6cm}|l|l|}
  \toprule
  View Name & Rank & Description & C++ & Fortran \\
  \midrule
  \texttt{ColumnView} & 1 & Maps a vertical level index $k$ to a pack & \texttt{v(k)} & \texttt{v(k)} \\
  \texttt{SpeciesColumnView} & 2 & Maps a population index $p$ and a vertical level index $k$ to a pack & \texttt{v(p,k)}  & \texttt{v(k,p)} \\
  \texttt{ModeColumnView} & 2 & Maps a mode index $m$ and a vertical level index $k$ to a pack & \texttt{v(m,k)}  & \texttt{v(k,m)} \\
  \bottomrule
\end{tabular}
\end{table}

The \texttt{Prognostics}, \texttt{Atmosphere}, and \texttt{Diagnostics} containers
described below make use of these named types.

\subsection{Prognostics Type}
\labelsubsection{lib:prognostics}

The \texttt{Prognostics} C++ class provides access to prognostic variables
that describe aerosols in a modal description. Here's the C++ class interface
(abbreviated for brevity---see the full interface in \texttt{haero/prognostics.hpp}):

\lstset{language=[11]{c++}}
\begin{lstlisting}
class Prognostics final {
  public:
  // Returns the number of aerosol modes in the system.
  int num_aerosol_modes() const;

  // Returns the number of aerosol species in the mode with the given index.
  int num_aerosol_species(int mode_index) const;

  // Returns the number of gas species in the system.
  int num_gas_species() const;

  // Returns the number of vertical levels in the system.
  int num_levels() const;

  // Returns the view storing interstitial aerosol species mass mixing fraction
  // data.
  const SpeciesColumnView& interstitial_aerosols() const;

  // Returns the view storing cloud-borne aerosol species mass mixing fraction
  // data.
  const SpeciesColumnView& cloudborne_aerosols() const;

  // Returns the view storing mass mixing fraction data for gas species.
  const SpeciesColumnView& gases() const;

  // Returns the view storing modal number concentrations.
  const ModeColumnView& modal_num_concs() const;

  // Scales the given set of tendencies and adds it into this state, summing
  // the values of the prognostic variables in place.
  void scale_and_add(Real scale_factor, const Tendencies& tendencies);
};
\end{lstlisting}

Typically, you never modify a \texttt{Prognostics} variable directly. Instead, you
compute a set of tendencies (in a \texttt{Tendencies} variable, which is very
similar to a \texttt{Prognostics} variable) and accumulate them into your
\texttt{Prognostics} variable by calling \texttt{scale\_and\_add}.

The Fortran version of the \texttt{Prognostics} type is similar, and offers
access to Fortran multidimensional arrays instead of C++ views. For cleaner
syntax, this type uses bound procedures to return pointers to its arrays.

\lstset{language=[03]{fortran}}
\begin{lstlisting}
  type :: prognostics_t
  contains
    ! Access to interstitial aerosol mix fractions array (no dummy arguments)
    procedure :: interstitial_aerosols => p_int_aero_mix_frac
    ! Access to cloudborne aerosol mix fractions array (no dummy arguments)
    procedure :: cloudborne_aerosols => p_cld_aero_mix_frac
    ! Access to gas mix fractions array (no dummy arguments)
    procedure :: gases => p_gas_mix_frac
    ! Access to modal number concentrations array (no dummy arguments)
    procedure :: modes => p_modal_num_concs
  end type
\end{lstlisting}

\subsection{Atmosphere Type}
\labelsubsection{lib:atmosphere}

The \texttt{Atmosphere} C++ class stores a fixed set of state variables that
describe the atmosphere, such as

\begin{itemize}
  \item temperature [K]
  \item pressure [Pa]
  \item relative humidity [-]
  \item heights at level interfaces [m]
\end{itemize}

Each of these variables are stored in \texttt{ColumnView} objects whose memory
is managed by the host model.

{\em This data structure is new, so we'll be adding and changing these state
variables a bit in the near future.}

The \texttt{Diagnostics} C++ class stores a dynamically-determined set of
diagnostic variables that correspond to the specific parameterizations available
to a specific aerosol system. The variables are identified by unique tokens that
can be retrieved by name.

\lstset{language=[11]c++}
\begin{lstlisting}
class Diagnostics final {
  public:
  // Returns the number of aerosol modes in the system.
  int num_aerosol_modes() const;

  // Returns the number of aerosol species in the mode with the given index.
  int num_aerosol_species(int mode_index) const;

  // Returns the number of gas species in the system.
  int num_gas_species() const;

  // Returns the number of vertical levels in the system.
  int num_levels() const;

  // Returns a unique token that identifies the given (non-modal) variable
  // within this object. Returns VAR_NOT_FOUND if this variable does not exist.
  Token find_var(const std::string& name) const;

  // Returns the view storing the diagnostic variable with a name corresponding
  // to the given token. If such a variable does not exist, this throws an
  // exception.
  ColumnView& var(const Token token);

  // Returns a unique token that identifies the given modal aerosol variable
  // within this object. Returns VAR_NOT_FOUND if this variable does not exist.
  Token find_aerosol_var(const std::string& name) const;

  // Returns the view storing the modal aerosol diagnostic variable with a name
  // corresponding to the given token. If such a variable does not exist, this
  // throws an exception.
  SpeciesColumnView& aerosol_var(const Token token);

  // Returns a unique token that identifies the given gas variable within this
  // object. Returns VAR_NOT_FOUND if this variable does not exist.
  Token find_gas_var(const std::string& name) const;

  // Returns the view storing the gas diagnostic variable with a name
  // corresponding to the given token. If such a variable does not exist, this
  // throws an exception.
  SpeciesColumnView& gas_var(const Token token);

  // Returns a unique token that identifies the given modal variable within
  // this object. Returns VAR_NOT_FOUND if this variable does not exist.
  Token find_modal_var(const std::string& name) const;

  // Returns the view storing the mode-specific diagnostic variable with a name
  // corresponding to the given token. If such a variable does not exist, this
  // throws an exception.
  ModeColumnView& modal_var(const Token token);
};
\end{lstlisting}

The Fortran version of \texttt{Diagnostics}, like its \texttt{Prognostics} counterpart,
uses bound procedures to provide access to its array data. Each one of these
bound procedures accepts a single dummy argument: the name of the desired
diagnostic variable. This Fortran pseudocode illustrates the interface for the
\texttt{Diagnostics} derived-type \texttt{diagnostics\_t}.

\lstset{language=[03]{fortran}}
\begin{lstlisting}
  type :: diagnostics_t
  contains
    ! Returns a token that can be used to retrieve a variable with the given
    ! name from a diagnostics object, or var_not_found (-1) if no such variable
    ! exists.
    procedure :: find_var(name) -> token
    ! Provides access to the given (non-modal) variable in the given
    ! diagnostics object, given its token
    procedure :: var(token) -> array pointer
    ! Returns a token that can be used to retrieve an aerosol variable with the
    ! given name and mode from a diagnostics object, or var_not_found (-1) if no such
    ! variable exists.
    procedure :: find_aerosol_var(name) -> token
    ! Provides access to the given (non-modal) variable in the given
    ! diagnostics object, given its token.
    procedure :: aerosol_var(token) -> array pointer
    ! Returns a token that can be used to retrieve a gas variable with the
    ! given name from a diagnostics object, or var_not_found (-1) if no such
    ! variable exists.
    procedure :: find_gas_var(name) -> token
    ! Provides access to the given gas variable in the given diagnostics object,
    ! given its token.
    procedure :: gas_var(token) -> array pointer
    ! Returns a token that can be used to retrieve a modal variable with the
    ! given name from a diagnostics object, or var_not_found (-1) if no such
    ! variable exists.
    procedure :: has_modal_var(name) -> token
    ! Provides access to the given modal variable in the given
    ! diagnostics object, given its token.
    procedure :: modal_var(token) -> array pointer
  end type
\end{lstlisting}

At this point, you might wonder how a \texttt{Diagnostics} variable knows which
variables it needs. In fact, the \texttt{Diagnostics} class provides functions
for creating variables that it needs when it needs them.

For examples of how the \texttt{Prognostics}, \texttt{Atmosphere}, and
\texttt{Diagnostics} types are used in practice, take a look at one of the
existing aerosol process implementations.

\section{Aerosol Processes in Haero}
\labelsection{lib:processes}

The aerosol life cycle consists of several important and distinct physical
processes. As we mentioned in \refsubsection{lib:processes}, there are
{\bf prognostic processes}, which compute tendencies for prognostic variables,
and there are {\bf diagnostic processes}, which update diagnostic variables
in place.

Haero offers data structures that make it very easy to implement these two types
of processes. Because the structure of a given process doesn't depend on the
details of its implementation, we can define abstract interfaces for these
processes. These abstract interfaces simplify the development of a process---
instead of designing a new process from the ground up every time you want to
add new functionality to Haero, you can simply implement a small number of
functions (or subroutines) that define the behavior of a process, and let the
Haero library handle the details of how these processes are created and used.

For detailed descriptions of the specific processes provided by Haero, take a
look at \refchapter{processes}. You can find examples of source code for
Haero's processes in the \texttt{haero/processes} subdirectory.

\subsection{The Aerosol Process Interface}
\labelsubsection{lib:aerosol_process}

An aerosol process has three behaviors which must be defined by any
implementation. Each of these behaviors is implemented in a C++ function or
a Fortran subroutine.

\begin{enumerate}
  \item {\bf initialization}: the process must be able to allocate any resources
        it needs to do its work. These resources include temporary work arrays,
        look-up tables, and quantities that need to be precomputed. State data
        is not managed by processes, so it's not included in process
        initialization. If nothing needs to be done for initialization, its
        function or subroutine body can be empty.
  \item {\bf running}: the process must know how to ``run''. In other words, it
        must define a procedure for computing tendencies for a relevant set of
        prognostic variables given their current values, and the current values
        of any diagnostic variables. The function or subroutine that implements
        this behavior does not apply these tendencies to any prognostic
        variables---it simply computes the tendencies and returns.
  \item {\bf finalization}: at the end of a simulation program, when the aerosol
        system is destroyed, the process must free all resources it allocated
        in its initialization. If no resources are allocated, the function or
        subroutine body implementing finalization can be empty.
\end{enumerate}

In addition, the process may support named parameters that can be set to
specific values. Some examples of these kinds of parameters are

\begin{itemize}
  \item Integer-valued parameters that select one of several supported algorithms
  \item Boolean flags for enabling or disabling features
  \item Real-valued scale factors for quantities based on tuning or assumptions
\end{itemize}

Haero provides an object-oriented approach for implementing a process in terms
of this simple interface. In an object-oriented approach, an abstract interface
is encoded in a ``base class''---a data type that declares the necessary
functions and subroutines. Then any implementation of this interface is defined
in a data type ``derived'' from that base class.

Haero uses the object-oriented features of C++ for process development. All
aerosol process implementations are derived from a C++ base class called
\texttt{AerosolProcess}. This is true regardless of whether you implement the
process using C++ or Fortran.

The \texttt{AerosolProcess} provides the following interface (see
\texttt{haero/process.hpp} for more details):

\lstset{language=[11]{c++}}
\begin{lstlisting}
class AerosolProcess {
 public:

  // Constructor, called by all AerosolProcess subclasses.
  explicit AerosolProcess(const std::string& name):
    name_(name) {}

  // Destructor.
  virtual ~AerosolProcess() {}

  // Initializes the process with the aerosol configuration.
  void init(const ModalAerosolConfig& config);

  // Runs the process at the given time with the given aerosol data.
  void run(Real t, Real dt, const Prognostics& prognostics,
           const Atmosphere& atmosphere, const Diagnostics& diagnostics,
           Tendencies& tendencies) const;

  // Set named integer, boolean, and real-valued parameters.
  void set_param(const std::string& name, int value);
  void set_param(const std::string& name, bool value);
  void set_param(const std::string& name, Real value);

 protected:

  // Override this method if your aerosol process needs to be initialized
  // with information about the system. The default implementation does nothing.
  virtual void init_(const ModalAerosolConfig& config) {}

  // Override this method to implement the aerosol process using the specific
  // parameterization for the subclass.
  virtual void run_(Real t, Real dt,
                    const Prognostics& prognostics,
                    const Atmosphere& atmosphere,
                    const Diagnostics& diagnostics,
                    Tendencies& tendencies) const = 0;

  // Override these methods to set a parameter to a given value based on its
  // name.
  virtual void set_param_(const std::string& name, int value) {}
  virtual void set_param_(const std::string& name, bool value) {}
  virtual void set_param_(const std::string& name, Real value) {}
};
\end{lstlisting}

In addition to the ``constructor'' function used to create an instance of a
\texttt{AerosolProcess}, this interface declares three functions (\texttt{init\_},
\texttt{run\_}, and the destructor function \texttt{\~AerosolProcess})
that correspond to the three behaviors described above and must be overridden.
Additionally, one or more of the \texttt{set\_param\_} methods can be overridden
to support process-specific parameters. These parameters should be documented
with the process.

The constructor accepts a single argument: a string containing the name of the
aerosol process. This can be helpful for debugging.

Let's explore how we might implement an aerosol process in C++ and in Fortran.
Here we describe only the steps needed to implement the process itself. You must
also test your process to make sure it behaves the way you think it does! The
procedure for testing an aerosol process is described in
\refchapter{testing}.

\subsubsection{C++ aerosol processes}
\labelsubsubsection{lib:aerosol_process_cxx}

In C++, all you have to do in order to implement an aerosol process is to define
a class with a specific name, derived from the \texttt{AerosolProcess} base
class. For example, the MAM4 implementation of the nucleation process, described
in \refsubsection{nuc:mam4}, is defined in a C++ class named
\texttt{MAMNucleationProcess}. A C++ class derived from a base class is called a
{\bf subclass} of that base class, so \texttt{MAMNucleationProcess} is a
subclass of \texttt{AerosolProcess}.

To create a C++ implemention for an aerosol process:

\begin{enumerate}
  \item Create a header file that declares your subclass of
        \texttt{AerosolProcess}. This header file must declare a constructor,
        a destructor, the \texttt{init} function, and the \texttt{run} function.
        This file lives in the \texttt{haero/processes} subdirectory within the
        repository. See \texttt{haero/processes/MAMNucleationProcess.hpp} for an
        example.
  \item Create a source file containing implementations for the constructor, the
        destructor, the \texttt{init} function, and the \texttt{run} function for
        your subclass. This lives alongside the header file you just created.
        See \texttt{haero/processes/MAMNucleationProcess.cpp} for an example.
  \item Add your source file to the set of source files in the
        \texttt{PROCESS\_SOURCES} variable in \texttt{haero/processes/CMakeLists.txt}.
  \item Write one or more tests for your new aerosol process.
        \refchapter{testing} provides extensive details about how to do this.
\end{enumerate}

\subsubsection{Fortran aerosol processes}
\labelsubsubsection{lib:prognostic_f90}

A Fortran aerosol process implementation consists of a Fortran module that
contains \texttt{init}, \texttt{run}, and \texttt{finalize} subroutines that
implement the same functionality as their C++ counterparts:

\begin{lstlisting}
module <module_name>
  use haero, only: wp, modal_aerosol_config_t, prognostics_t, atmosphere_t, &
                   diagnostics_t, tendencies_t
  ...
  implicit none

  ! Aerosol process interface subroutines
  public :: init, run, finalize

  ! Parameter setting subroutines
  public :: set_integer_param, set_logical_param, set_real_param

  ! Module variables, including settable parameters
  integer :: my_option
  logical :: my_flag
  real(wp) :: my_scale_factor

  ! SAVE keyword for retaining module variables
  save

contains

subroutine init(config)
  implicit none

  ! Arguments
  type(modal_aerosol_config_t), intent(in) :: config

  ...
end subroutine

subroutine run(t, dt, prognostics, atmosphere, diagnostics, tendencies)
  implicit none

  ! Arguments
  real(wp), value, intent(in)       :: t
  real(wp), value, intent(in)       :: dt
  type(prognostics_t), intent(in)   :: prognostics
  type(atmosphere_t), intent(in)    :: atmosphere
  type(diagnostics_t), intent(in)   :: diagnostics
  type(tendencies_t), intent(inout) :: tendencies

  ...
end subroutine

subroutine finalize()
  implicit none

  ...
end subroutine

subroutine set_integer_param(name, val)
  implicit none

  ! Arguments
  character(len=*), intent(in) :: name
  integer, intent(in)          :: val

  if (trim(name) == "my_option") then
    my_option = val
  end if
end subroutine

subroutine set_logical_param(name, val)
  implicit none

  ! Arguments
  character(len=*), intent(in) :: name
  logical, intent(in)          :: val

  if (trim(name) == "my_flag") then
    my_flag = val
  end if
end subroutine

subroutine set_real_param(name, val)
  implicit none

  ! Arguments
  character(len=*), intent(in) :: name
  real(wp), intent(in)         :: val

  if (trim(name) == "my_scale_factor") then
    my_scale_factor = val
  end if
end subroutine

...

end module
\end{lstlisting}

Note that you {\bf must} implement subroutines for \texttt{set\_integer\_param},
\texttt{set\_logical\_param}, and \texttt{set\_real\_param}, even if your process
doesn't support settable parameters.

To implement an aerosol process in Fortran, you create such a module in a
Fortran source file and then declare it as a \texttt{faerosol\_process} in the
\texttt{CMakeLists.txt} file within the \texttt{haero/processes} subdirectory.
There are instructions on how to declare your process in that file.

For example, the Fortran MAM nucleation process is implemented in a Fortran
module named \texttt{mam\_nucleation}, implemented in the source file
\texttt{haero/processes/mam\_nucleation.F90}. In
\texttt{haero/processes/CMakeLists.txt}, it's declared as a Fortran aerosol
process the following way:

\begin{lstlisting}
if (HAERO_FORTRAN)
  ...
  faerosol_process(MAMNucleationFProcess NucleationProcess mam_nucleation)
  ...
endif()
\end{lstlisting}

The declaration takes three arguments:

\begin{enumerate}
  \item The name of a C++ class that will be created that exposes the Fortran
        implementation of the process
  \item The C++ enumerated type that identifies what kind of aerosol process
        is being implemented
  \item The name of the Fortran module that implements the process.
\end{enumerate}

The build system automatically generates a C++ class for the Fortran module that
allows the process to be used in a Haero simulation. The name of this C++ class
is important for exposing it to the Haero library.

Once you've done these things and rebuilt Haero, your new aerosol process
implementation is available for use.

\subsection{Diagnostic Functions}
\labelsubsection{lib:diagnostic_functions}

Aerosol processes compute tendencies for prognostic variables. But how are
diagnostic variables updated? These variables are quite different in nature from
their prognostic counterparts:

\begin{enumerate}
  \item they depend algebraically on prognostic variables and other diagnostic
        variables
  \item they are updated in place instead of being evolved in time by
        differential equations
  \item they are often shared/needed by several distinct aerosol processes, and
        at various points in time, depending on a given process ordering
\end{enumerate}

Because of these considerations, it's not clear that we can update more than a
single diagnostic variable at once. To do so implies a knowledge of how the
aerosol processes are invoked during a time step, and Haero does not make any
such decision on behalf of a host model. This means we must provide a diagnostic
variable update mechanism that is flexible but easy to understand. This
mechanism, which updates a single diagnostic variable, is called a
{\bf diagnostic function}.

Unlike aerosol processes, which have multiple behaviors associated with
initialization, finalization, and the execution of the process itself, a
diagnostic function only ever does one thing: it takes a set of input and
uses it to update its diagnostic variable. In other words, it has no internal
state of its own---it's just a function that you can call whenever you need
to update a particular diagnostic variable.



