/*
 * Copyright (C) 2019-2022 The ESPResSo project
 *
 * This file is part of ESPResSo.
 *
 * ESPResSo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ESPResSo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @page bondedIA Bonded interactions
 *
 *  @tableofcontents
 *
 *  @section bondedIA_new Adding new interactions
 *
 *  To add a new bonded interaction, the following steps are required:
 *  * C++ core:
 *    - Create a new header file for your new bond type, preferably inside the
 *      folder <tt>src/core/bonded_interactions</tt>.
 *    - Define a data structure for the interaction parameters (prefactors,
 *      etc.).
 *    - Write a constructor and force/energy kernels.
 *    - Add calls to these kernels in the force, energy and pressure
 *      calculation functions.
 *    - Register the new bond type.
 *  * ScriptInterface:
 *    - Define the %ScriptInterface class of the new bond type, which serves as
 *      the connection between the C++ core and the Python representation of the
 *      bond.
 *  * Python interface:
 *    - Import the definition of the interaction struct from the core
 *    - Implement a class for the bonded interaction derived from the Python
 *      \c BondedInteraction base class
 *
 *  @subsection bondedIA_new_struct Defining the new interaction
 *
 *  Every interaction resides in its own source .cpp and .hpp files. A simple
 *  example for a bonded interaction is the FENE bond in @ref fene.hpp and
 *  @ref fene.cpp. Use these two files as templates for your interaction.
 *
 *  The first step is to create a new \c struct which represents your new
 *  bond type inside the .hpp file. It needs to have the following members:
 *
 *  * @code{.cpp}
 *    static constexpr int num = 1;
 *    @endcode
 *    This is the number of particles involved in the bond, minus 1, i.e. 1
 *    for a pairwise bonded potential such as the FENE bond.
 *  * @code{.cpp}
 *    double cutoff() const { return r0 + drmax; }
 *    @endcode
 *    The return value of \c cutoff() should be as large as the interaction
 *    range of the new interaction. This is only relevant to pairwise bonds.
 *    In all other cases, the return value should be 0, namely angle bonds,
 *    dihedral bonds as well as other bonds that don't have an interaction
 *    range. The @ref VirtualBond is the exception to this rule; its range
 *    is @ref BONDED_INACTIVE_CUTOFF to ensure that it is always skipped by
 *    the short-range loop.
 *  * @code{.cpp}
 *    boost::optional<Utils::Vector3d> force(Utils::Vector3d const &dx) const;
 *    @endcode
 *    This function returns the bond force. If it is a bond involving three
 *    or four particles, a \c std::tuple with three or four force vectors
 *    has to be returned, respectively.
 *    - The returned value is in a \c boost::optional container if the bond is
 *      breakable. If the bond is broken, the returned object is empty; this
 *      will stop the integrator with a runtime error.
 *    - The function can make use of a pre-calculated distance vector (\p dx)
 *      pointing from particle 2 to particle 1, that takes periodic boundary
 *      conditions into account.
 *    - The function name and signature may be different, e.g. for angle bonds.
 *      To determine the right signature for the new interaction, you can have
 *      a look at @ref forces_inline.hpp to see where this function will be
 *      called and which other variables may be available for your calculation.
 *  * @code{.cpp}
 *    boost::optional<double> energy(Utils::Vector3d const &dx) const;
 *    @endcode
 *    This function returns the bond energy. The same information as given for
 *    the force calculation above applies here. This function will be called
 *    from @ref energy_inline.hpp .
 *  * A constructor which is used to set all parameters and to do
 *    preparatory calculations if necessary, for example
 *    @code{.cpp}
 *    FeneBond(double k, double drmax, double r0);
 *    @endcode
 *    All values the bond needs to function properly should be passed as
 *    arguments to this constructor.
 *  * A template function for serialization called \c serialize. This is for
 *    communication between nodes in parallel computations.
 *    The following function can serve as a starting point.
 *    @code{.cpp}
 *    private:
 *    friend boost::serialization::access;
 *    template <typename Archive>
 *    void serialize(Archive &ar, long int) {
 *      ar &k;
 *      ar &drmax;
 *      ar &r0;
 *      ar &drmax2;
 *      ar &drmax2i;
 *    }
 *    @endcode
 *    Replace all the <tt>ar&</tt> commands with the new bond's parameters.
 *    Every data member of your struct needs to be transmitted. This template
 *    function is private.
 *
 *  @subsection bondedIA_new_integration Integrating the new bond type into the C++ core
 *
 *  In most cases, there are three files that need to be updated to integrate
 *  the new bond type into the core, namely
 *  * @ref bonded_interaction_data.hpp
 *  * @ref forces_inline.hpp
 *  * @ref energy_inline.hpp
 *
 *  In some cases, you may also need to modify @ref pressure_inline.hpp.
 *
 *  * In bonded_interaction_data.cpp:
 *    - Include the header file containing the new bond type.
 *    - Add the new bond type to @ref Bonded_IA_Parameters at the end of the
 *      types list.
 *    - If by doing this, the length of the list in Bonded_IA_Parameters passes
 *      over a multiple of 10, you may have to update ESPResSo's top level
 *      CMakeLists.txt:
 *      @code
 *      # enable boost::variant with more than 20 types
 *      target_compile_options(
 *        EspressoCppFlags INTERFACE -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
 *                                   -DBOOST_MPL_LIMIT_LIST_SIZE=40)
 *      @endcode
 *  * In forces_inline.hpp:
 *    - A call to the new bond's force calculation needs to be placed in either
 *      of the functions @ref calc_bond_pair_force(), @ref
 *      calc_bonded_three_body_force() or @ref calc_bonded_four_body_force(),
 *      depending on how many bond partners there are.
 *    - Add the new entry to the \c if - \c else chain, like in the following
 *      example
 *      @code{.cpp}
 *      // ...
 *      else if (auto const *iap = boost::get<QuarticBond>(&iaparams)) {
 *        return iap->force(dx);
 *      }
 *      // ...
 *      @endcode
 *  * In energy_inline.hpp:
 *    - A call to the new bond's force calculation needs to be placed in @ref
 *      calc_bonded_energy. Find the \c if - \c else chain that corresponds
 *      to the correct number of bond partners.
 *    - Add the new entry to the \c if - \c else chain, like in the following
 *      example
 *      @code{.cpp}
 *      // ...
 *      else if (auto const *iap = boost::get<QuarticBond>(&iaparams)) {
 *        return iap->energy(dx);
 *      }
 *      // ...
 *      @endcode
 *  * Pressure tensor and virial calculation (pressure_inline.hpp): if your
 *    bonded interaction is not a pair bond or modifies the particles involved,
 *    you have to implement a custom solution for virial calculation.
 *    The pressure occurs twice, once for the parallelized isotropic pressure
 *    and once for the tensorial pressure calculation. For pair forces, the
 *    pressure is calculated using the virials; for many body interactions,
 *    currently no pressure is calculated.
 *
 *  Note that the force and energy functions cannot alter the particle states.
 *
 *  @subsection bondedIA_new_script_interface Registering the new interaction in the ScriptInterface
 *
 *  * In src/script_interface/interactions/BondedInteraction.hpp:
 *    Add a new class representing your new bond type in the %ScriptInterface.
 *    - We recommend that the new class has the same name as the interaction in the core.
 *    - You can use ScriptInterface::Interactions::FeneBond as a template.
 *    - The class must be derived from ScriptInterface::Interactions::BondedInteraction.
 *    - It is recommended to include the statement
 *      @code{.cpp}
 *      using CoreBondedInteraction = ::YourNewBond;
 *      @endcode
 *      where \c YourNewBond is the core type you defined.
 *    - Implement a member function with the signature
 *      @code{.cpp}
 *      void construct_bond(VariantMap const &params) override { /* ... */ }
 *      @endcode
 *      In this function, the member \c m_bonded_ia shall be initialized using
 *      the parameters that are given in <tt>params</tt>. Use the constructor
 *      of \c %FeneBond as a template. An instance of your core type
 *      \c %YourNewBond should be initialized, which is then used to initialize
 *      a \c std::shared_ptr to a \ref Bonded_IA_Parameters, which is then
 *      assigned to \c m_bonded_ia.
 *      The values of the parameters are extracted from \c params using
 *      @code{.cpp}
 *      get_value<parameter_type>(params, "parameter_name")
 *      @endcode
 *      where \c parameter_type is the type of the parameter, e.g. \c double or
 *      \c int or even \c std::string, and <tt>"parameter_name"</tt> must be
 *      replaced by the name of the respective parameter. This name must be the
 *      same as in the Python interface, but may differ from the name in the
 *      core interaction type. It is, however, recommended to use the same
 *      names for both the Python interface and the ESPResSo core for
 *      consistency whenever possible.
 *    - Implement a member function called <tt>get_struct()</tt>, which returns
 *      the bond parameters, which are stored in <tt>m_bonded_ia</tt>.
 *      The return type should be a reference to an object of the new type
 *      <tt>YourNewBond</tt> that you defined in the core. If you included the
 *      above <tt>using</tt> statement, you can simply copy the routine from
 *      \c %FeneBond, since <tt>CoreBondedInteraction</tt> is already set to
 *      the correct core type.
 *    - Implement the constructor. We recommend to adapt it from \c %FeneBond.
 *      All it needs to do is to register its parameters so they can be set
 *      from Python. For this purpose, call
 *      @code{.cpp}
 *      add_parameters(/* ... */);
 *      @endcode
 *      inside the constructors. It expects a vector of
 *      \ref ScriptInterface::AutoParameter. Usually, this vector is initialized
 *      using an initializer list, each element of which is in itself a list which
 *      initializes one instance of \c AutoParameter (see @ref AutoParameter.hpp).
 *      One of many ways to initialize these parameters is to pass the parameter name
 *      as a string, a custom setter and a custom getter function. The parameters
 *      are typically made read-only by passing <tt>AutoParameter::read_only</tt>
 *      instead of a setter function. The getter function can be a lambda function,
 *      which is directly passed to the constructor.
 *
 *  * In src/script_interface/interactions/initialize.cpp:
 *    Your new interaction type needs to be registered here so that the
 *    %ScriptInterface can find it by its name. In the function \c initialize
 *    add a new line of the form
 *    @code{.cpp}
 *    om->register_new<YourNewBond>("Interactions::YourNewBond");
 *    @endcode
 *    where \c YourNewBond must be replaced by the name of your new bond type.
 *    The string is used to match the %ScriptInterface class with the Python
 *    class (see below).
 *
 *
 *
 *  @subsection bondedIA_new_interface Adding the interaction in the Python interface
 *
 *  Please note that the following is Cython code (www.cython.org), rather than
 *  pure Python.
 *
 *  * In file <tt>src/python/espressomd/interactions.pxd</tt>:
 *    - Add the bonded interaction to \c enum_bonded_interaction.
 *      The order of the enum values must match the order of types in
 *      @ref Bonded_IA_Parameters exactly:
 *      @code{.py}
 *      cdef enum enum_bonded_interaction:
 *          BONDED_IA_NONE = 0,
 *          BONDED_IA_FENE,
 *          [...]
 *      @endcode
 *  * In file <tt>src/python/espressomd/interactions.pyx</tt>:
 *    - Implement the Cython class for the bonded interaction, using the one
 *      for the FENE bond as template. Please use pep8 naming convention.
 *    - Set the class' member
 *      @code{.py}
 *      _so_name = "Interactions::YourNewBond"
 *      @endcode
 *      where you put the name of your bond instead of \c YourNewBond.
 *      This connects the %ScriptInterface class with the Python class.
 *    - Create a new entry in the dictionary \c bonded_interaction_classes to
 *      register the new class you have written:
 *      @code{.py}
 *      bonded_interaction_classes = {
 *          int(BONDED_IA_FENE): FeneBond,
 *          int(BONDED_IA_HARMONIC): HarmonicBond,
 *          [...]
 *      }
 *      @endcode
 *  * In file <tt>testsuite/python/interactions_bonded_interface.py</tt>:
 *    - Add a test case to verify that parameters set and gotten from the
 *      interaction are consistent.
 *  * In file <tt>testsuite/python/interactions_bonded.py</tt> or
 *    <tt>testsuite/python/interactions_bond_angle.py</tt> or
 *    <tt>testsuite/python/interactions_dihedral.py</tt>:
 *    - Add a test case to verify the forces and energies are correct.
 *
 *  @section bondedIA_bond_angles Bond angle potentials
 *
 *  @subsection bondedIA_angle_force General expressions for the forces
 *
 *  This section uses the particle force expressions derived in @cite swope92a.
 *
 *  The gradient of the potential at particle @f$ i @f$ is given by the chain
 *  rule in equation 6:
 *
 *  @f{equation}{
 *      \label{eq:Swope-eq-6}
 *      \nabla_i U(\theta_{ijk})
 *          = \left(
 *                  \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *            \right)
 *            \left(
 *                  \frac{\mathrm{d}\theta_{ijk}}{\mathrm{d}\cos(\theta_{ijk})}
 *            \right)
 *            \left(
 *                  \nabla_i \cos(\theta_{ijk})
 *            \right)
 *  @f}
 *
 *  with
 *
 *  @f[
 *      \left(
 *            \frac{\mathrm{d}\theta_{ijk}}{\mathrm{d}\cos(\theta_{ijk})}
 *      \right)
 *          = \left(
 *                  \frac{-1}{\sin(\theta_{ijk})}
 *            \right)
 *  @f]
 *
 *  and @f$ \theta_{ijk} @f$ the angle formed by the three particles,
 *  @f$ U(\theta_{ijk}) @f$ the bond angle potential, @f$ \vec{r_{ij}} @f$
 *  the vector from particle @f$ j @f$ to particle @f$ i @f$ and
 *  @f$ \nabla_i @f$ the gradient in the direction @f$ \vec{r_{ij}} @f$.
 *
 *  The expression for @f$ \cos(\theta_{ijk}) @f$ is given by equation 4:
 *
 *  @f{equation}{
 *      \label{eq:Swope-eq-4}
 *      \cos(\theta_{ijk})
 *          = \frac{\vec{r_{ij}}\cdot\vec{r_{kj}}}
 *                 {\left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|}
 *  @f}
 *
 *  The expression for its gradient is given by equation 9:
 *
 *  @f{equation}{
 *      \label{eq:Swope-eq-9}
 *      \nabla_i \cos(\theta_{ijk})
 *          = \vec{e_x}\frac{\partial\cos(\theta_{ijk})}{\partial x_{ij}}
 *          + \vec{e_y}\frac{\partial\cos(\theta_{ijk})}{\partial y_{ij}}
 *          + \vec{e_z}\frac{\partial\cos(\theta_{ijk})}{\partial z_{ij}}
 *  @f}
 *
 *  with @f$ \left(\vec{e_x}, \vec{e_y}, \vec{e_z}\right) @f$ the unit vectors
 *  of the reference coordinate system and
 *  @f$ \vec{r_{ij}} = \left(x_{ij}, y_{ij}, z_{ij}\right) @f$.
 *
 *  Applying the quotient rule:
 *
 *  @f[
 *      \frac{\partial\cos(\theta_{ijk})}{\partial x_{ij}}
 *          = \frac{\partial}{\partial x_{ij}}
 *            \left(
 *                  \frac{\vec{r_{ij}}\cdot\vec{r_{kj}}}
 *                       {\left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|}
 *            \right)
 *          = \frac{\left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|
 *                  \partial \left(\vec{r_{ij}}\cdot\vec{r_{kj}}\right)
 *                /\, \partial x_{ij}
 *                - \vec{r_{ij}}\cdot\vec{r_{kj}}\cdot
 *                  \partial
 *                  \left(
 *                       \left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|
 *                  \right)
 *                /\, \partial x_{ij}}
 *                 {\left\|\vec{r_{ij}}\right\|^2\left\|\vec{r_{kj}}\right\|^2}
 *  @f]
 *
 *  with
 *
 *  @f[
 *      \frac{\partial \left(\vec{r_{ij}}\cdot\vec{r_{kj}}\right)}
 *           {\partial x_{ij}}
 *          = \frac{\partial \left(x_{ij} \cdot x_{kj} + y_{ij} \cdot y_{kj} + z_{ij} \cdot z_{kj}\right)}
 *           {\partial x_{ij}}
 *          = x_{kj}
 *  @f]
 *
 *  and
 *
 *  @f[
 *      \frac{\partial \left(\left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|\right)}
 *           {\partial x_{ij}}
 *          = \left\|\vec{r_{kj}}\right\|
 *            \frac{\partial}{\partial x_{ij}}
 *            \sqrt{x_{ij}^2 + y_{ij}^2 + z_{ij}^2}
 *          = \left\|\vec{r_{kj}}\right\|
 *            \frac{0.5 \cdot 2 \cdot x_{ij}}
 *                 {\sqrt{x_{ij}^2 + y_{ij}^2 + z_{ij}^2}}
 *          = x_{ij}
 *            \frac{\left\|\vec{r_{kj}}\right\|}
 *                 {\left\|\vec{r_{ij}}\right\|}
 *  @f]
 *
 *  leading to equation 12:
 *
 *  @f{align*}{
 *      \label{eq:Swope-eq-12}
 *      \frac{\partial\cos(\theta_{ijk})}{\partial x_{ij}}
 *         &= \frac{\left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|x_{kj}
 *                  - \vec{r_{ij}}\cdot\vec{r_{kj}}\cdot x_{ij}
 *                    \left\|\vec{r_{kj}}\right\|\left\|\vec{r_{ij}}\right\|^{-1}}
 *                 {\left\|\vec{r_{ij}}\right\|^2\left\|\vec{r_{kj}}\right\|^2}
 *      \\
 *         &= \frac{x_{kj}}
 *                 {\left\|\vec{r_{ij}}\right\|\left\|\vec{r_{kj}}\right\|}
 *          - \frac{\vec{r_{ij}}\cdot\vec{r_{kj}}\cdot x_{ij}}
 *                 {\left\|\vec{r_{ij}}\right\|^3\left\|\vec{r_{kj}}\right\|}
 *      \\
 *         &= \frac{1}{\left\|\vec{r_{ij}}\right\|}
 *                 \left(
 *                    \frac{x_{kj}}{\left\|\vec{r_{kj}}\right\|}
 *                  - \frac{x_{ij}}{\left\|\vec{r_{ij}}\right\|}
 *                    \cos(\theta_{ijk})
 *                 \right)
 *  @f}
 *
 *  Applying these steps to equations 9-11 leads to the force equations
 *  for all three particles:
 *
 *  @f{align*}{
 *      \vec{F_i}
 *          &= - K(\theta_{ijk})
 *                 \frac{1}{\left\|\vec{r_{ij}}\right\|}
 *                 \left(
 *                    \frac{\vec{r_{kj}}}{\left\|\vec{r_{kj}}\right\|}
 *                  - \frac{\vec{r_{ij}}}{\left\|\vec{r_{ij}}\right\|}
 *                    \cos(\theta_{ijk})
 *                 \right)
 *      \\
 *      \vec{F_k}
 *          &= - K(\theta_{ijk})
 *                 \frac{1}{\left\lVert\vec{r_{kj}}\right\rVert}
 *                 \left(
 *                    \frac{\vec{r_{ij}}}{\left\|\vec{r_{ij}}\right\|}
 *                  - \frac{\vec{r_{kj}}}{\left\|\vec{r_{kj}}\right\|}
 *                    \cos(\theta_{ijk})
 *                 \right)
 *      \\
 *      \vec{F_j} &= -\left(\vec{F_i} + \vec{F_k}\right)
 *  @f}
 *
 *  with @f$ K(\theta_{ijk}) @f$ the angle force term, which depends on the
 *  expression used for the angle potential. Forces @f$ \vec{F_i} @f$ and
 *  @f$ \vec{F_k} @f$ are perpendicular to the displacement vectors
 *  @f$ \vec{r_{ij}} @f$ resp. @f$ \vec{r_{kj}} @f$ and their magnitude
 *  are proportional to the potential gradient normalized by the displacement
 *  vectors:
 *
 *  @f{align*}{
 *      \left\|\vec{F_i}\right\|
 *          &= \left(
 *                  \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *             \right)
 *             \frac{1}{\left\|\vec{r_{ij}}\right\|}
 *      \\
 *      \left\|\vec{F_k}\right\|
 *          &= \left(
 *                  \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *             \right)
 *             \frac{1}{\left\|\vec{r_{kj}}\right\|}
 *  @f}
 *
 *
 *  @subsection bondedIA_angle_potentials Available potentials
 *
 *
 *  @subsubsection bondedIA_angle_harmonic Harmonic angle potential
 *
 *  The harmonic angle potential takes the form:
 *
 *  @f{equation}{
 *      \label{eq:harmonic-angle-pot}
 *      U(\theta_{ijk})
 *          = \frac{1}{2}k_{ijk}\left[\theta_{ijk} - \theta_{ijk}^0\right]^2
 *  @f}
 *
 *  with @f$ \theta_{ijk} @f$ the angle formed by the three particles,
 *  @f$ \theta_{ijk}^0 @f$ the equilibrium angle and @f$ k_{ijk} @f$
 *  the bond angle force constant.
 *
 *  The derivative with respect to the angle is:
 *
 *  @f[
 *      \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *          = k_{ijk}\left[\theta_{ijk} - \theta_{ijk}^0\right]
 *  @f]
 *
 *  resulting in the following angle force term:
 *
 *  @f{equation}{
 *      \label{eq:harmonic-angle-pot-angle-term}
 *      K(\theta_{ijk})
 *          = -k_{ijk}\frac{\theta_{ijk} - \theta_{ijk}^0}
 *                         {\sin(\theta_{ijk})}
 *  @f}
 *
 *  which can lead to numerical instability at @f$ \theta_{ijk} = 0 @f$ and
 *  @f$ \theta_{ijk} = \pi @f$.
 *
 *
 *  @subsubsection bondedIA_angle_cossquare Harmonic cosine potential
 *
 *  The harmonic cosine potential takes the form:
 *
 *  @f{equation}{
 *      \label{eq:harmonic-cosine-pot}
 *      U(\theta_{ijk})
 *          = \frac{1}{2}
 *            k_{ijk}\left[\cos(\theta_{ijk}) - \cos(\theta_{ijk}^0)\right]^2
 *  @f}
 *
 *  with @f$ \theta_{ijk} @f$ the angle formed by the three particles,
 *  @f$ \theta_{ijk}^0 @f$ the equilibrium angle and @f$ k_{ijk} @f$
 *  the bond angle force constant.
 *
 *  The derivative with respect to the angle is:
 *
 *  @f[
 *      \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *          = -k_{ijk}\sin(\theta_{ijk})
 *            \left[\cos(\theta_{ijk}) - \cos(\theta_{ijk}^0)\right]
 *  @f]
 *
 *  resulting in the following angle force term:
 *
 *  @f{equation}{
 *      \label{eq:harmonic-cosine-pot-angle-term}
 *      K(\theta_{ijk})
 *          = k_{ijk}\left[\cos(\theta_{ijk}) - \cos(\theta_{ijk}^0)\right]
 *  @f}
 *
 *  which does not suffer from numerical instability.
 *
 *
 *  @subsubsection bondedIA_angle_cosine Cosine potential
 *
 *  The cosine potential takes the form:
 *
 *  @f{equation}{
 *      \label{eq:cosine-pot}
 *      U(\theta_{ijk})
 *          = k_{ijk}\left[1 - \cos(\theta_{ijk} - \theta_{ijk}^0)\right]
 *  @f}
 *
 *  with @f$ \theta_{ijk} @f$ the angle formed by the three particles,
 *  @f$ \theta_{ijk}^0 @f$ the equilibrium angle and @f$ k_{ijk} @f$
 *  the bond angle force constant.
 *
 *  The derivative with respect to the angle is:
 *
 *  @f[
 *      \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *          = k_{ijk}\sin(\theta_{ijk} - \theta_{ijk}^0)
 *  @f]
 *
 *  resulting in the following angle force term:
 *
 *  @f{equation}{
 *      \label{eq:cosine-pot-angle-term}
 *      K(\theta_{ijk})
 *          = -k_{ijk}\frac{\sin(\theta_{ijk} - \theta_{ijk}^0)}
 *                         {\sin(\theta_{ijk})}
 *  @f}
 *
 *  which can lead to numerical instability at @f$ \theta_{ijk} = 0 @f$ and
 *  @f$ \theta_{ijk} = \pi @f$.
 *
 *
 *  @subsubsection bondedIA_angle_tab Tabulated potential
 *
 *  The tabulated potential and its derivative with respect to the angle are
 *  provided by the user. The angle force term takes the form:
 *
 *  @f{equation}{
 *      \label{eq:tabulated-pot-angle-term}
 *      K(\theta_{ijk})
 *          = \frac{-1}{\sin(\theta_{ijk})}
 *            \left(
 *                  \frac{\mathrm{d}U(\theta_{ijk})}{\mathrm{d}\theta_{ijk}}
 *            \right)
 *  @f}
 *
 *  which can lead to numerical instability at @f$ \theta_{ijk} = 0 @f$ and
 *  @f$ \theta_{ijk} = \pi @f$.
 *
 */
