text:
# Copyright (c) 2009-2022 The Regents of the University of Michigan.
# Part of HOOMD-blue, released under the BSD 3-Clause License.

"""Pair forces."""

import copy
import warnings

import hoomd
from hoomd.md import _md
from hoomd.md import force
from hoomd.data.parameterdicts import ParameterDict, TypeParameterDict
from hoomd.data.typeparam import TypeParameter
import numpy as np
from hoomd.data.typeconverter import OnlyFrom, nonnegative_real

class Pair(force.Force):
    r"""Base class pair force.

    Note:
        :py:class:`Pair` is the base class for all pair forces. Users should
        not instantiate this class directly.

    .. py:attribute:: r_cut

        Cuttoff radius beyond which the energy and force are 0
        :math:`[\mathrm{length}]`. *Optional*: defaults to the value
        ``default_r_cut`` specified on construction.

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `float`])

    .. py:attribute:: r_on

        Radius at which the smoothing modification to the potential starts
        :math:`[\mathrm{length}]`.  *Optional*: defaults to the value
        ``default_r_on`` specified on construction.

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `float`])

    .. py:attribute:: mode

        *mode*, *optional*: defaults to ``"none"``.
        Possible values: ``"none"``, ``"shift"``, ``"xplor"``

        Type: `str`

    .. py:attribute:: nlist

        Neighbor list used to compute the pair force.

        Type: `hoomd.md.nlist.NeighborList`
    """

    # The accepted modes for the potential. Should be reset by subclasses with
    # restricted modes.
    _accepted_modes = ("none", "shift", "xplor")

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__()
        tp_r_cut = TypeParameter(
            'r_cut', 'particle_types',
            TypeParameterDict(nonnegative_real, len_keys=2))
        if default_r_cut is not None:
            tp_r_cut.default = default_r_cut
        tp_r_on = TypeParameter('r_on', 'particle_types',
                                TypeParameterDict(nonnegative_real, len_keys=2))
        if default_r_on is not None:
            tp_r_on.default = default_r_on

        type_params = [tp_r_cut]
        if 'xplor' in self._accepted_modes:
            type_params.append(tp_r_on)

        self._extend_typeparam(type_params)
        self._param_dict.update(
            ParameterDict(mode=OnlyFrom(self._accepted_modes),
                          nlist=hoomd.md.nlist.NeighborList))
        self.mode = mode
        self.nlist = nlist

    def compute_energy(self, tags1, tags2):
        r"""Compute the energy between two sets of particles.

        Args:
            tags1 (``ndarray<int32>``): a numpy array of particle tags in the
                first group.
            tags2 (``ndarray<int32>``): a numpy array of particle tags in the
                second group.

        .. math::

            U = \sum_{i \in \mathrm{tags1}, j \in \mathrm{tags2}} V_{ij}(r)

        where :math:`V_{ij}(r)` is the pairwise energy between two particles
        :math:`i` and :math:`j`.

        Assumed properties of the sets *tags1* and *tags2* are:

        - *tags1* and *tags2* are disjoint
        - all elements in *tags1* and *tags2* are unique
        - *tags1* and *tags2* are contiguous numpy arrays of dtype int32

        None of these properties are validated.

        Examples::

            tags=numpy.linspace(0,N-1,1, dtype=numpy.int32)
            # computes the energy between even and odd particles
            U = mypair.compute_energy(tags1=numpy.array(tags[0:N:2]),
                                      tags2=numpy.array(tags[1:N:2]))

        """
        # TODO future versions could use np functions to test the assumptions
        # above and raise an error if they occur.
        return self._cpp_obj.computeEnergyBetweenSets(tags1, tags2)

    def _add(self, simulation):
        super()._add(simulation)
        self._add_nlist()

    def _add_nlist(self):
        nlist = self.nlist
        deepcopy = False
        if not isinstance(self._simulation, hoomd.Simulation):
            if nlist._added:
                deepcopy = True
            else:
                return
        # We need to check if the force is added since if it is not then this is
        # being called by a SyncedList object and a disagreement between the
        # simulation and nlist._simulation is an error. If the force is added
        # then the nlist is compatible. We cannot just check the nlist's _added
        # property because _add is also called when the SyncedList is synced.
        if deepcopy or nlist._added and nlist._simulation != self._simulation:
            warnings.warn(
                f"{self} object is creating a new equivalent neighbor list."
                f" This is happending since the force is moving to a new "
                f"simulation. Set a new nlist to suppress this warning.",
                RuntimeWarning)
            self.nlist = copy.deepcopy(nlist)
        self.nlist._add(self._simulation)
        # This is ideopotent, but we need to ensure that if we change
        # neighbor list when not attached we handle correctly.
        self._add_dependency(self.nlist)

    def _attach(self):
        # This should never happen, but leaving it in case the logic for adding
        # missed some edge case.
        if self._simulation != self.nlist._simulation:
            raise RuntimeError("{} object's neighbor list is used in a "
                               "different simulation.".format(type(self)))
        self.nlist._attach()
        if isinstance(self._simulation.device, hoomd.device.CPU):
            cls = getattr(_md, self._cpp_class_name)
            self.nlist._cpp_obj.setStorageMode(
                _md.NeighborList.storageMode.half)
        else:
            cls = getattr(_md, self._cpp_class_name + "GPU")
            self.nlist._cpp_obj.setStorageMode(
                _md.NeighborList.storageMode.full)
        self._cpp_obj = cls(self._simulation.state._cpp_sys_def,
                            self.nlist._cpp_obj)

        super()._attach()

    def _setattr_param(self, attr, value):
        if attr == "nlist":
            self._nlist_setter(value)
            return
        super()._setattr_param(attr, value)

    def _nlist_setter(self, new_nlist):
        if self._attached:
            raise RuntimeError("nlist cannot be set after scheduling.")
        old_nlist = self.nlist
        self._param_dict._dict["nlist"] = new_nlist
        if self._added:
            self._add_nlist()
            old_nlist._remove_dependent(self)

class LJ(Pair):
    r"""Lennard-Jones pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.
        tail_correction (bool): Whether to apply the isotropic integrated long
            range tail correction.

    `LJ` computes the Lennard-Jones pair force on every particle in the
    simulation state.

    .. math::
        U(r) = 4 \varepsilon \left[ \left(
        \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r}
        \right)^{6} \right]

    Example::

        nl = nlist.Cell()
        lj = pair.LJ(nl, default_r_cut=3.0)
        lj.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0}
        lj.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The LJ potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) -
          energy parameter :math:`\varepsilon` :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) -
          particle size :math:`\sigma` :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`

    .. py:attribute:: tail_correction

        Whether to apply the isotropic integrated long range tail correction.

        Type: `bool`
    """
    _cpp_class_name = "PotentialPairLJ"

    def __init__(self,
                 nlist,
                 default_r_cut=None,
                 default_r_on=0.,
                 mode='none',
                 tail_correction=False):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float, sigma=float, len_keys=2))
        self._add_typeparam(params)
        self._param_dict.update(
            ParameterDict(tail_correction=bool(tail_correction)))

class Gauss(Pair):
    r"""Gaussian pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Gauss` computes the Gaussian pair force should on every particle in the
    simulation state:

    .. math::
        U(r) = \varepsilon \exp \left( -\frac{1}{2}
               \left( \frac{r}{\sigma} \right)^2 \right)

    Example::

        nl = nlist.Cell()
        gauss = pair.Gauss(default_r_cut=3.0, nlist=nl)
        gauss.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0)
        gauss.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The Gauss potential parameters. The dictionary has the following
        keys:

        * ``epsilon`` (`float`, **required**) - energy parameter
          :math:`\varepsilon` :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) - particle size :math:`\sigma`
          :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairGauss"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float, sigma=float, len_keys=2))
        self._add_typeparam(params)

class ExpandedLJ(Pair):
    r"""Expanded Lennard-Jones pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting mode.

    `ExpandedLJ` computes the radially-shifted Lennard-Jones pair force on every
    particle in the simulation state:

    .. math::
        U(r) = 4 \varepsilon \left[ \left(
               \frac{\sigma}{r - \Delta} \right)^{12} -
               \left( \frac{\sigma}{r - \Delta}
               \right)^{6} \right]

    Note:
        To replicate the behavior of the SLJ potential in HOOMD-blue v2, set
        `hoomd.md.pair.Pair.r_cut` to ``r_cut_unshifted + delta``.

    Example::

        nl = nlist.Cell()
        expanded_lj = pair.ExpandedLJ(default_r_cut=3.0, nlist=nl)
        expanded_lj.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0, delta=1.0)
        expanded_lj.params[('A', 'B')] = dict(
                                             epsilon=2.0,
                                             sigma=1.0,
                                             delta=0.75)
        expanded_lj.params[('B', 'B')] = dict(epsilon=1.0, sigma=1.0, delta=0.5)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) - energy parameter
          :math:`\varepsilon` :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) - particle size :math:`\sigma`
          :math:`[\mathrm{length}]`
        * ``delta`` (`float`, **required**) - radial shift
          :math:`\Delta` :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = 'PotentialPairExpandedLJ'

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float,
                              sigma=float,
                              delta=float,
                              len_keys=2))
        self._add_typeparam(params)
        self.mode = mode

class Yukawa(Pair):
    r"""Yukawa pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Yukawa` computes the Yukawa pair force son every particle in the simulation
    state:

    .. math::

        U(r) = \varepsilon \frac{ \exp \left(
               -\kappa r \right) }{r}

    Example::

        nl = nlist.Cell()
        yukawa = pair.Yukawa(default_r_cut=3.0, nlist=nl)
        yukawa.params[('A', 'A')] = dict(epsilon=1.0, kappa=1.0)
        yukawa.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The Yukawa potential parameters. The dictionary has the following
        keys:

        * ``epsilon`` (`float`, **required**) - energy parameter
          :math:`\varepsilon` :math:`[\mathrm{energy}]`
        * ``kappa`` (`float`, **required**) - scaling parameter
          :math:`\kappa` :math:`[\mathrm{length}^{-1}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairYukawa"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(kappa=float, epsilon=float, len_keys=2))
        self._add_typeparam(params)

class Ewald(Pair):
    r"""Ewald pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.

    `Ewald` computes the Ewald pair force on every particle in the simulation
    state:

    .. math::

        U(r) = q_i q_j \left[\mathrm{erfc}\left(\kappa
               r + \frac{\alpha}{2\kappa}\right)
               \exp(\alpha r)
               + \mathrm{erfc}\left(\kappa r -
               \frac{\alpha}{2 \kappa}\right)
               \exp(-\alpha r)\right]

    Call `md.long_range.pppm.make_pppm_coulomb_forces` to create an instance
    of `Ewald` and `md.long_range.pppm.Coulomb` that together implement the PPPM
    method for electrostatics.

    Example::

        nl = nlist.Cell()
        ewald = pair.Ewald(default_r_cut=3.0, nlist=nl)
        ewald.params[('A', 'A')] = dict(kappa=1.0, alpha=1.5)
        ewald.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The Ewald potential parameters. The dictionary has the following keys:

        * ``kappa`` (`float`, **required**) - Splitting parameter
          :math:`\kappa` :math:`[\mathrm{length}^{-1}]`
        * ``alpha`` (`float`, **required**) - Debye screening length
          :math:`\alpha` :math:`[\mathrm{length}^{-1}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairEwald"
    _accepted_modes = ("none",)

    def __init__(self, nlist, default_r_cut=None):
        super().__init__(nlist=nlist,
                         default_r_cut=default_r_cut,
                         default_r_on=0,
                         mode='none')
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(kappa=float, alpha=0.0, len_keys=2))

        self._add_typeparam(params)

class Table(Pair):
    """Tabulated pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list
        default_r_cut (float): Default cutoff radius :math:`[\\mathrm{length}]`.

    `Table` computes the tabulated pair force on every particle in the
    simulation state.

    The force :math:`\\vec{F}` is:

    .. math::

        \\vec{F}(\\vec{r}) =
        \\begin{cases}
        0 & r < r_{\\mathrm{min}} \\\\
        F_\\mathrm{table}(r)\\hat{r} &
        r_{\\mathrm{min}} \\le r < r_{\\mathrm{cut}} \\\\
        0 & r \\ge r_{\\mathrm{cut}} \\\\
        \\end{cases}

    and the potential :math:`U(r)` is:

    .. math::

        U(r) =
        \\begin{cases}
        0 & r < r_{\\mathrm{min}} \\\\
        U_\\mathrm{table}(r)
        & r_{\\mathrm{min}} \\le r < r_{\\mathrm{cut}} \\\\
        0 & r \\ge r_{\\mathrm{cut}} \\\\
        \\end{cases}

    where :math:`\\vec{r}` is the vector pointing from one particle to the other
    in the pair, ``r_min`` is defined in `params`, and ``r_cut`` is defined in
    `Pair.r_cut`.

    Provide :math:`F_\\mathrm{table}(r)` and :math:`U_\\mathrm{table}(r)` on
    evenly spaced grid points points between :math:`r_{\\mathrm{min}}` and
    :math:`r_{\\mathrm{cut}}`. `Table` linearly interpolates values when
    :math:`r` lies between grid points and between the last grid point and
    :math:`r=r_{\\mathrm{cut}}`.  The force must be specificed commensurate with
    the potential: :math:`F = -\\frac{\\partial U}{\\partial r}`.

    `Table` does not support energy shifting or smoothing modes.

    Note:
        For potentials that diverge near r=0, to set *r_min* to a non-zero
        value.

    Note:
        The implicitly defined :math:`r` values are those that would be returned
        by ``numpy.linspace(r_min, r_cut, len(V), endpoint=False)``.

    Tip:
        Define non-interacting potentials with::

            table.params[(type1, type2)] = dict(r_min=0, V=[0], F=[0])
            table.r_cut[(type1, type2)] = 0

        There must be at least one element in V and F, and the ``r_cut`` value
        of 0 disables the interaction entirely.

    Attributes:
        params (`TypeParameter` [\
          `tuple` [``particle_type``, ``particle_type``],\
          `dict`]):
          The potential parameters. The dictionary has the following keys:

          * ``r_min`` (`float`, **required**) - the minimum distance to apply
            the tabulated potential, corresponding to the first element of the
            energy and force arrays :math:`[\\mathrm{length}]`.

          * ``U`` ((*N*,) `numpy.ndarray` of `float`, **required**) -
            the tabulated energy values :math:`[\\mathrm{energy}]`.

          * ``F`` ((*N*,) `numpy.ndarray` of `float`, **required**) -
            the tabulated force values :math:`[\\mathrm{force}]`. Must have the
            same length as ``V``.

        mode (str): Energy shifting/smoothing mode: ``"none"``.
    """
    _cpp_class_name = "PotentialPairTable"
    _accepted_modes = ("none",)

    def __init__(self, nlist, default_r_cut=None):
        super().__init__(nlist,
                         default_r_cut=default_r_cut,
                         default_r_on=0,
                         mode='none')
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(
                r_min=float,
                U=hoomd.data.typeconverter.NDArrayValidator(np.float64),
                F=hoomd.data.typeconverter.NDArrayValidator(np.float64),
                len_keys=2))
        self._add_typeparam(params)

class Morse(Pair):
    r"""Morse pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Morse` computes the Morse pair force on every particle in the simulation
    state:

    .. math::
        U(r) = D_0 \left[ \exp \left(-2\alpha\left(
            r-r_0\right)\right) -2\exp \left(-\alpha\left(r-r_0\right)
            \right) \right]

    Example::

        nl = nlist.Cell()
        morse = pair.Morse(default_r_cut=3.0, nlist=nl)
        morse.params[('A', 'A')] = dict(D0=1.0, alpha=3.0, r0=1.0)
        morse.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``D0`` (`float`, **required**) - depth of the potential at its
          minimum :math:`D_0` :math:`[\mathrm{energy}]`
        * ``alpha`` (`float`, **required**) - the width of the potential well
          :math:`\alpha` :math:`[\mathrm{length}^{-1}]`
        * ``r0`` (`float`, **required**) - position of the minimum
          :math:`r_0` :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """

    _cpp_class_name = "PotentialPairMorse"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(D0=float, alpha=float, r0=float, len_keys=2))
        self._add_typeparam(params)

class DPD(Pair):
    r"""Dissipative Particle Dynamics.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list
        kT (`hoomd.variant` or `float`): Temperature of
            thermostat :math:`[\mathrm{energy}]`.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.

    `DPD` computes the DPD pair force on every particle in the simulation state.
    DPD includes a an interaction potential, pairwise drag force, and pairwise
    random force. See `Groot and Warren 1997
    <http://dx.doi.org/10.1063/1.474784>`_:

    .. math::

        F = F_{\mathrm{C}}(r) + F_{\mathrm{R,ij}}(r_{ij}) +
        F_{\mathrm{D,ij}}(v_{ij})

    where

    .. math::
        F_{\mathrm{C}}(r) &= A \cdot  w(r_{ij}), \\
        F_{\mathrm{R, ij}}(r_{ij}) &= - \theta_{ij}\sqrt{3}
        \sqrt{\frac{2k_b\gamma T}{\Delta t}}\cdot w(r_{ij}),  \\
        F_{\mathrm{D, ij}}(r_{ij}) &= - \gamma w^2(r_{ij})\left(
        \hat r_{ij} \circ v_{ij} \right), \\
        w(r_{ij}) &=
        \begin{cases}
        \left( 1 - r/r_{\mathrm{cut}} \right)
        & r < r_{\mathrm{cut}} \\
        0 & r \ge r_{\mathrm{cut}} \\
        \end{cases},

    :math:`\hat r_{ij}` is a normalized vector from particle i to
    particle j, :math:`v_{ij} = v_i - v_j`, and :math:`\theta_{ij}` is a
    uniformly distributed random number in the range :math:`[-1, 1]`.

    `C. L. Phillips et. al. 2011 <http://dx.doi.org/10.1016/j.jcp.2011.05.021>`_
    describes the DPD implementation details. Cite it if you utilize the DPD
    functionality in your work.

    `DPD` does not implement any energy shift / smoothing modes due to the
    function of the force.

    To use the DPD thermostat, apply the `hoomd.md.methods.NVE` integration
    method along with `DPD` forces.  Use of the DPD thermostat pair force with
    other integrators will result in nonphysical behavior. To use `DPD` with a
    different conservative potential than :math:`F_C`, set A to zero and define
    the conservative pair force separately.

    Example::

        nl = nlist.Cell()
        dpd = pair.DPD(nlist=nl, kT=1.0, default_r_cut=1.0)
        dpd.params[('A', 'A')] = dict(A=25.0, gamma=4.5)
        dpd.params[('A', 'B')] = dict(A=40.0, gamma=4.5)
        dpd.params[('B', 'B')] = dict(A=25.0, gamma=4.5)
        dpd.params[(['A', 'B'], ['C', 'D'])] = dict(A=40.0, gamma=4.5)

    .. py:attribute:: params

        The force parameters. The dictionary has the following keys:

        * ``A`` (`float`, **required**) - :math:`A` :math:`[\mathrm{force}]`
        * ``gamma`` (`float`, **required**) - :math:`\gamma`
          :math:`[\mathrm{mass} \cdot \mathrm{time}^{-1}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairDPDThermoDPD"
    _accepted_modes = ("none",)

    def __init__(
        self,
        nlist,
        kT,
        default_r_cut=None,
    ):
        super().__init__(nlist=nlist,
                         default_r_cut=default_r_cut,
                         default_r_on=0,
                         mode='none')
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(A=float, gamma=float, len_keys=2))
        self._add_typeparam(params)
        param_dict = ParameterDict(kT=hoomd.variant.Variant)
        param_dict["kT"] = kT
        self._param_dict.update(param_dict)

    def _add(self, simulation):
        """Add the operation to a simulation.

        DPD uses RNGs. Warn the user if they did not set the seed.
        """
        if isinstance(simulation, hoomd.Simulation):
            simulation._warn_if_seed_unset()

        super()._add(simulation)

class DPDConservative(Pair):
    r"""DPD Conservative pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.

    `DPDConservative` computes the conservative part of the `DPD` pair force on
    every particle in the simulation state with:

    .. math::
        U(r) = A \cdot \left( r_{\mathrm{cut}} - r
          \right) - \frac{1}{2} \cdot \frac{A}{r_{\mathrm{cut}}} \cdot
          \left(r_{\mathrm{cut}}^2 - r^2 \right).

    `DPDConservative` does not implement any energy shift / smoothing modes due
    to the function of the force.

    Example::

        nl = nlist.Cell()
        dpdc = pair.DPDConservative(nlist=nl, default_r_cut=3.0)
        dpdc.params[('A', 'A')] = dict(A=1.0)
        dpdc.params[('A', 'B')] = dict(A=2.0, r_cut = 1.0)
        dpdc.params[(['A', 'B'], ['C', 'D'])] = dict(A=3.0)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``A`` (`float`, **required**) - :math:`A` :math:`[\mathrm{force}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairDPD"
    _accepted_modes = ("none",)

    def __init__(self, nlist, default_r_cut=None):
        # initialize the base class
        super().__init__(nlist=nlist,
                         default_r_cut=default_r_cut,
                         default_r_on=0,
                         mode='none')
        params = TypeParameter('params', 'particle_types',
                               TypeParameterDict(A=float, len_keys=2))
        self._add_typeparam(params)

class DPDLJ(Pair):
    r"""Dissipative Particle Dynamics with the LJ conservative force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        kT (`hoomd.variant` or `float`): Temperature of
            thermostat :math:`[\mathrm{energy}]`.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting mode.

    `DPDLJ` computes the `DPD` thermostat combined with the `LJ` pair force
    on every particle in the simulation state with:

    .. math::
        F &= F_{\mathrm{C}}(r) + F_{\mathrm{R,ij}}(r_{ij}) +
            F_{\mathrm{D,ij}}(v_{ij}), \\
        F_{\mathrm{C}}(r) &= \partial U / \partial r, \\
        F_{\mathrm{R, ij}}(r_{ij}) &= - \theta_{ij}\sqrt{3}
            \sqrt{\frac{2k_b\gamma T}{\Delta t}}\cdot w(r_{ij}), \\
        F_{\mathrm{D, ij}}(r_{ij}) &= - \gamma w^2(r_{ij})
            \left( \hat r_{ij} \circ v_{ij} \right), \\
        U(r) &= 4 \varepsilon \left[ \left(
               \frac{\sigma}{r} \right)^{12} -
               \left( \frac{\sigma}{r} \right)^{6} \right], \\
        w(r_{ij}) &=
        \begin{cases}
        \left( 1 - r/r_{\mathrm{cut}} \right)
        & r < r_{\mathrm{cut}} \\
        0 & r \ge r_{\mathrm{cut}} \\
        \end{cases},

    :math:`\hat r_{ij}` is a normalized vector from particle i to
    particle j, :math:`v_{ij} = v_i - v_j`, and :math:`\theta_{ij}` is a
    uniformly distributed random number in the range [-1, 1].

    `C. L. Phillips et. al. 2011 <http://dx.doi.org/10.1016/j.jcp.2011.05.021>`_
    describes the DPD implementation details. Cite it if you utilize the DPD
    functionality in your work.

    To use the DPD thermostat, apply the `hoomd.md.methods.NVE` integration
    method along with `DPD` forces.  Use of the DPD thermostat pair force with
    other integrators will result in nonphysical behavior.

    Example::

        nl = nlist.Cell()
        dpdlj = pair.DPDLJ(nlist=nl, kT=1.0, default_r_cut=2.5)
        dpdlj.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0, gamma=4.5)
        dpdlj.params[(['A', 'B'], ['C', 'D'])] = dict(
            epsilon=3.0, sigma=1.0, gamma=1.2)
        dpdlj.r_cut[('B', 'B')] = 2.0**(1.0/6.0)

    .. py:attribute:: params

        The DPDLJ potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) - :math:`\varepsilon`
          :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) - :math:`\sigma`
          :math:`[\mathrm{length}]`
        * ``gamma`` (`float`, **required**) - :math:`\gamma`
          :math:`[\mathrm{mass} \cdot \mathrm{time}^{-1}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"`` or ``"shift"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairDPDLJThermoDPD"
    _accepted_modes = ("none", "shift")

    def __init__(self, nlist, kT, default_r_cut=None, mode='none'):

        super().__init__(nlist=nlist,
                         default_r_cut=default_r_cut,
                         default_r_on=0,
                         mode=mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float,
                              sigma=float,
                              gamma=float,
                              len_keys=2))
        self._add_typeparam(params)

        d = ParameterDict(kT=hoomd.variant.Variant)
        self._param_dict.update(d)

        self.kT = kT

    def _add(self, simulation):
        """Add the operation to a simulation.

        DPDLJ uses RNGs. Warn the user if they did not set the seed.
        """
        if isinstance(simulation, hoomd.Simulation):
            simulation._warn_if_seed_unset()

        super()._add(simulation)

class ForceShiftedLJ(Pair):
    r"""Force-shifted Lennard-Jones pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `ForceShiftedLJ` computes the modified Lennard-Jones pair force on every
    particle in the simulation state.

    .. math::
        U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r}
          \right)^{12} - \left( \frac{\sigma}{r} \right)^{6}
          \right] + \Delta V(r)

    .. math::

        \Delta V(r) = -(r - r_{\mathrm{cut}}) \frac{\partial
          V_{\mathrm{LJ}}}{\partial r}(r_{\mathrm{cut}})

    The force differs from the one calculated by  `LJ` by the subtraction of the
    value of the force at :math:`r_{\mathrm{cut}}`, such that the force smoothly
    goes to zero at the cut-off. The potential is modified by a linear function.
    See `Toxvaerd et. al. 2011 <http://dx.doi.org/10.1063/1.3558787>`_ for a
    discussion of this potential.

    Example::

        nl = nlist.Cell()
        fslj = pair.ForceShiftedLJ(nlist=nl, default_r_cut=1.5)
        fslj.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) - :math:`\varepsilon`
          :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) - :math:`\sigma`
          :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairForceShiftedLJ"
    _accepted_modes = ("none",)

    def __init__(self, nlist, default_r_cut=None):
        super().__init__(nlist=nlist,
                         default_r_cut=default_r_cut,
                         default_r_on=0,
                         mode='none')

        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float, sigma=float, len_keys=2))
        self._add_typeparam(params)

class Moliere(Pair):
    r"""Moliere pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Moliere` computes the Moliere pair force on every particle in the
    simulation state:

    .. math::
        U(r) = \frac{Z_i Z_j e^2}{4 \pi \epsilon_0 r_{ij}} \left[ 0.35 \exp
          \left( -0.3 \frac{r_{ij}}{a_F} \right) + \\
          0.55 \exp \left( -1.2 \frac{r_{ij}}{a_F} \right) + 0.10 \exp
          \left( -6.0 \frac{r_{ij}}{a_F} \right) \right]

    Where each parameter is defined as:

    - :math:`Z_i` - *Z_i* - Atomic number of species i
      :math:`[\mathrm{dimensionless}]`
    - :math:`Z_j` - *Z_j* - Atomic number of species j
      :math:`[\mathrm{dimensionless}]`
    - :math:`e` - *elementary_charge* - The elementary charge
      :math:`[\mathrm{charge}]`
    - :math:`a_F = \frac{0.8853 a_0}{\left( \sqrt{Z_i} + \sqrt{Z_j}
      \right)^{2/3}}`, where :math:`a_0` is the Bohr radius
      :math:`[\mathrm{length}]`

    Example::

        nl = nlist.Cell()
        moliere = pair.Moliere(default_r_cut = 3.0, nlist=nl)

        Zi = 54
        Zj = 7
        e = 1
        a0 = 1
        aF = 0.8853 * a0 / (np.sqrt(Zi) + np.sqrt(Zj))**(2/3)

        moliere.params[('A', 'B')] = dict(qi=Zi*e, qj=Zj*e, aF=aF)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``qi`` (`float`, **required**) -
          :math:`q_i = Z_i \frac{e}{\sqrt{4 \pi \epsilon_0}}`
          :math:`[\mathrm{charge}]`
        * ``qj`` (`float`, **required**) -
          :math:`q_j = Z_j \frac{e}{\sqrt{4 \pi \epsilon_0}}`
          :math:`[\mathrm{charge}]`

        * ``aF`` (`float`, **required**) -
          :math:`a_F = \frac{0.8853 a_0}{\left( \sqrt{Z_i} + \sqrt{Z_j}
          \right)^{2/3}}` :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairMoliere"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(qi=float, qj=float, aF=float, len_keys=2))
        self._add_typeparam(params)

class ZBL(Pair):
    r"""ZBL pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.

    `ZBL` computes the Ziegler-Biersack-Littmark pair force on every particle in
    the simulation state:

    .. math::
        U(r) =
          \frac{Z_i Z_j e^2}{4 \pi \epsilon_0 r_{ij}} \left[ 0.1818
          \exp \left( -3.2 \frac{r_{ij}}{a_F} \right) \right. \\
          + 0.5099 \exp \left( -0.9423 \frac{r_{ij}}{a_F} \right) \\
          + 0.2802 \exp \left( -0.4029 \frac{r_{ij}}{a_F} \right) \\
          + \left. 0.02817 \exp \left( -0.2016 \frac{r_{ij}}{a_F} \right)
          \right]

    Where each parameter is defined as:

    - :math:`Z_i` - *Z_i* - Atomic number of species i
      :math:`[\mathrm{dimensionless}]`
    - :math:`Z_j` - *Z_j* - Atomic number of species j
      :math:`[\mathrm{dimensionless}]`
    - :math:`e` - *elementary_charge* - The elementary charge
      :math:`[\mathrm{charge}]`
    - :math:`a_F = \frac{0.8853 a_0}{ Z_i^{0.23} + Z_j^{0.23} }`, where
      :math:`a_0` is the Bohr radius :math:`[\mathrm{length}]`

    Example::

        nl = nlist.Cell()
        zbl = pair.ZBL(default_r_cut=3.0, nlist=nl)

        Zi = 54
        Zj = 7
        e = 1
        a0 = 1
        aF = 0.8853 * a0 / (Zi**(0.23) + Zj**(0.23))

        zbl.params[('A', 'B')] = dict(qi=Zi*e, qj=Zj*e, aF=aF)

    .. py:attribute:: params

        The ZBL potential parameters. The dictionary has the following keys:

        * ``q_i`` (`float`, **required**) - :math:`q_i=Z_i \frac{e}{\sqrt{4
          \pi \epsilon_0}}` :math:`[\mathrm{charge}]`
        * ``q_j`` (`float`, **required**) - :math:`q_j=Z_j \frac{e}{\sqrt{4
          \pi \epsilon_0}}` :math:`[\mathrm{charge}]`
        * ``a_F`` (`float`, **required**) -
          :math:`a_F = \frac{0.8853 a_0}{ Z_i^{0.23} + Z_j^{0.23} }`
          :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairZBL"
    _accepted_modes = ("none",)

    def __init__(self, nlist, default_r_cut=None, default_r_on=0.):

        super().__init__(nlist, default_r_cut, default_r_on, 'none')
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(qi=float, qj=float, aF=float, len_keys=2))
        self._add_typeparam(params)

class Mie(Pair):
    r"""Mie pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Mie` computes the Mie pair force on every particle in the simulation state.

    .. math::
        U(r) = \left( \frac{n}{n-m} \right) {\left( \frac{n}{m}
          \right)}^{\frac{m}{n-m}} \varepsilon \left[ \left(
          \frac{\sigma}{r} \right)^{n} - \left( \frac{\sigma}{r}
          \right)^{m} \right]

    Example::

        nl = nlist.Cell()
        mie = pair.Mie(nlist=nl, default_r_cut=3.0)
        mie.params[('A', 'A')] = dict(epsilon=1.0, sigma=1.0, n=12, m=6)
        mie.r_cut[('A', 'A')] = 2**(1.0/6.0)
        mie.r_on[('A', 'A')] = 2.0
        mie.params[(['A', 'B'], ['C', 'D'])] = dict(epsilon=1.5, sigma=2.0)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) - :math:`\varepsilon`
          :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) - :math:`\sigma`
          :math:`[\mathrm{length}]`
        * ``n`` (`float`, **required**) - :math:`n`
          :math:`[\mathrm{dimensionless}]`
        * ``m`` (`float`, **required**) - :math:`m`
          :math:`[\mathrm{dimensionless}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairMie"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):

        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float,
                              sigma=float,
                              n=float,
                              m=float,
                              len_keys=2))

        self._add_typeparam(params)

class ExpandedMie(Pair):
    """Expanded Mie pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius (in distance units).
        default_r_on (float): Default turn-on radius (in distance units).
        mode (str): Energy shifting/smoothing mode.

    `ExpandedMie` computes the radially shifted Mie pair force on every particle
    in the simulation state:

    .. math::
        U(r) = \\left( \\frac{n}{n-m} \\right) {\\left( \\frac{n}{m}
          \\right)}^{\\frac{m}{n-m}} \\varepsilon \\left[ \\left(
          \\frac{\\sigma}{r-\\Delta} \\right)^{n} - \\left( \\frac
          {\\sigma}{r-\\Delta}
          \\right)^{m} \\right]

    Example::

        nl = nlist.Cell()
        expanded_mie = pair.ExpandedMie(nlist=nl, default_r_cut=3.0)
        mie.params[('A', 'B')] = {
            "epsilon": 1.0, "sigma": 1.0, "n": 12, "m": 6,
            "delta": 0.5}
        expanded_mie.r_cut[('A', 'B')] = 2**(1.0 / 6.0)
        expanded_mie.params[(['A', 'B'], ['C', 'D'])] = {
            "epsilon": 1.5, "sigma": 2.0, "n": 12, "m": 6,
            "delta": 0.5}

    .. py:attribute:: params

        The Expanded Mie potential parameters.
        The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) -
          :math:`\\epsilon` :math:`[\\mathrm{energy}]`.
        * ``sigma`` (`float`, **required**) -
          :math:`\\sigma` :math:`[\\mathrm{length}]`.
        * ``n`` (`float`, **required**) -
          :math:`n` :math:`[\\mathrm{dimensionless}]`.
        * ``m`` (`float`, **required**) -
          :math:`m` :math:`[\\mathrm{dimensionless}]`.
        * ``delta`` (`float`, **required**) -
          :math:`\\Delta` :math:`[\\mathrm{length}]`.

        Type: `TypeParameter` [ `tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairExpandedMie"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):

        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float,
                              sigma=float,
                              n=float,
                              m=float,
                              delta=float,
                              len_keys=2))

        self._add_typeparam(params)

class ReactionField(Pair):
    r"""Onsager reaction field pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `ReactionField` computes the Onsager reaction field pair force
    on all particles in the simulation state.

    Reaction field electrostatics is an approximation to the screened
    electrostatic interaction, which assumes that the medium can be treated as
    an electrostatic continuum of dielectric constant :math:`\epsilon_{RF}`
    outside the cutoff sphere of radius :math:`r_{\mathrm{cut}}`. See: `Barker
    et. al. 1973 <http://dx.doi.org/10.1080/00268977300102101>`_.

    By default (``use_charge=False``), the reaction field potential ignores the
    particle charges. Two parameters, :math:`\varepsilon` and
    :math:`\epsilon_{RF}` are needed. If :math:`\epsilon_{RF}` is specified as
    zero, it will represent infinity:

    .. math::

       U(r) = \varepsilon \left[ \frac{1}{r} +
           \frac{(\epsilon_{RF}-1) r^2}{(2 \epsilon_{RF} + 1) r_c^3} \right]

    When *use_charge* is set to `True`, the following formula is evaluated
    instead:

    .. math::

        U(r) = q_i q_j \varepsilon \left[ \frac{1}{r} +
          \frac{(\epsilon_{RF}-1) r^2}{(2 \epsilon_{RF} + 1) r_c^3} \right]

    where :math:`q_i` and :math:`q_j` are the charges of the particle pair.

    Example::

        nl = nlist.Cell()
        reaction_field = pair.reaction_field(nl, default_r_cut=3.0)
        reaction_field.params[('A', 'B')] = dict(epsilon=1.0, eps_rf=1.0)
        reaction_field.params[('B', 'B')] = dict(
            epsilon=1.0, eps_rf=0.0, use_charge=True)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) - :math:`\varepsilon`
          :math:`[\mathrm{energy} \cdot \mathrm{length}]`
        * ``eps_rf`` (`float`, **required**) - :math:`\epsilon_{RF}`
          :math:`[\mathrm{dimensionless}]`
        * ``use_charge`` (`bool`, **optional**) - evaluate pair force
          using particle charges (*default*: False)

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairReactionField"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float,
                              eps_rf=float,
                              use_charge=False,
                              len_keys=2))

        self._add_typeparam(params)

class DLVO(Pair):
    r"""DLVO colloidal interaction.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        name (str): Name of the force instance.
        mode (str): Energy shifting mode.

    `DLVO` computes the DLVO dispersion and electrostatic interaction pair force
    on every particle in the simulation state with:

    .. math::
        V_{\mathrm{DLVO}}(r) = &- \frac{A}{6} \left[
            \frac{2a_1a_2}{r^2 - (a_1+a_2)^2} +
            \frac{2a_1a_2}{r^2 - (a_1-a_2)^2} \\
            + \log \left(
            \frac{r^2 - (a_1+a_2)^2}{r^2 - (a_1-a_2)^2} \right) \right] \\
            & + \frac{a_1 a_2}{a_1+a_2} Z e^{-\kappa(r - (a_1+a_2))}

    where :math:`a_1` is the radius of first particle in the pair, :math:`a_2`
    is the radius of second particle in the pair, :math:`A` is the Hamaker
    constant, :math:`Z` is proportional to the surface electric potential,
    and :math:`\kappa` is the screening parameter.

    The first term corresponds to the attractive van der Waals interaction with
    and the second term to the repulsive double-layer interaction between two
    spherical surfaces. See "Intermolecular and Surface Forces" Israelachvili
    2011, pp. 317.

    Example::

        nl = hoomd.md.nlist.Cell()
        dlvo = hoomd.md.pair.DLVO(nlist=nl)
        dlvo.params[('A', 'A')] = dict(A=1.0, kappa=1.0, Z=2, a1=1, a2=1)
        dlvo.params[('A', 'B')] = dict(A=2.0, kappa=0.5, Z=3, a1=1, a2=3)
        dlvo.params[('B', 'B')] = dict(A=2.0, kappa=0.5, Z=3, a1=3, a2=3)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``A`` (`float`, **required**) - Hamaker constant :math:`A`
          :math:`[\mathrm{energy}]`
        * ``a1`` (`float`, **required**) - Radius of first particle :math:`a_1`
          :math:`[\mathrm{length}]`
        * ``a2`` (`float`, **required**) - Radius of second particle :math:`a_2`
          :math:`[\mathrm{length}]`
        * ``kappa`` (`float`, **required**) - screening parameter
          :math:`\kappa` :math:`[\mathrm{length}^{-1}]`
        * ``Z`` surface electric potential (`float`, **required**) - :math:`Z`
          :math:`[\mathrm{energy} \cdot \mathrm{length}^{-1}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"`` or ``"shift"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairDLVO"
    _accepted_modes = ("none", "shift")

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        if mode == 'xplor':
            raise ValueError("xplor is not a valid mode for the DLVO potential")

        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(
                kappa=float,
                Z=float,
                A=float,
                a1=float,
                a2=float,
                len_keys=2,
            ))
        self._add_typeparam(params)

class Buckingham(Pair):
    r"""Buckingham pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Buckingham` computes the Buckingham pair force on every particle in the
    simulation state with:

    .. math::
        U(r) = A \exp\left(-\frac{r}{\rho}\right) - \frac{C}{r^6}

    Example::

        nl = nlist.Cell()
        buck = pair.Buckingham(nl, default_r_cut=3.0)
        buck.params[('A', 'A')] = {'A': 2.0, 'rho'=0.5, 'C': 1.0}
        buck.params[('A', 'B')] = dict(A=1.0, rho=1.0, C=1.0)
        buck.params[('B', 'B')] = dict(A=2.0, rho=2.0, C=2.0)

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``A`` (`float`, **required**) - :math:`A` :math:`[\mathrm{energy}]`
        * ``rho`` (`float`, **required**) - :math:`\rho`
          :math:`[\mathrm{length}]`
        * ``C`` (`float`, **required**) - :math:`C` :math:`[\mathrm{energy}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """

    _cpp_class_name = "PotentialPairBuckingham"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(A=float, rho=float, C=float, len_keys=2))
        self._add_typeparam(params)

class LJ1208(Pair):
    r"""Lennard-Jones 12-8 pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `LJ1208` computes the Lennard-Jones 12-8 pair force on every particle
    in the simulation state.

    Example::

        nl = nlist.Cell()
        lj1208 = pair.LJ1208(nl, default_r_cut=3.0)
        lj1208.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0}
        lj1208.params[('A', 'B')] = dict(epsilon=2.0, sigma=1.0)

    .. math::
        U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} -
          \left( \frac{\sigma}{r} \right)^{8} \right]

    .. py:attribute:: params

        The potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) - energy parameter
          :math:`\varepsilon` :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) - particle size :math:`\sigma`
          :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairLJ1208"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float, sigma=float, len_keys=2))
        self._add_typeparam(params)

class LJ0804(Pair):
    r"""Lennard-Jones 8-4 pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `LJ0804` computes the Lennard-Jones 8-4 pair force on every particle in the
    simulation state:

    .. math::
        U(r) = 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{8} -
          \left( \frac{\sigma}{r} \right)^{4} \right]

    Example::

        nl = nlist.Cell()
        lj0804 = pair.LJ0804(nl, default_r_cut=3.0)
        lj0804.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0}
        lj0804.params[('A', 'B')] = dict(epsilon=2.0, sigma=1.0)
        lj0804.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The LJ potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) -
          energy parameter :math:`\varepsilon` :math:`[\mathrm{energy}]`
        * ``sigma`` (`float`, **required**) -
          particle size :math:`\sigma` :math:`[\mathrm{length}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairLJ0804"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float, sigma=float, len_keys=2))
        self._add_typeparam(params)

class Fourier(Pair):
    r"""Fourier pair force.

    Args:
        nlist (`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `Fourier` computes the  Fourier pair force on every particle in the
    simulation state:

    .. math::
        U(r) = \frac{1}{r^{12}} + \frac{1}{r^2}\sum_{n=1}^4
          \left[ a_n cos \left( \frac{n \pi r}{r_{cut}} \right) +
          b_n sin \left( \frac{n \pi r}{r_{cut}} \right) \right]

    where

    .. math::

        a_1 &= \sum_{n=2}^4 (-1)^n a_n \\
        b_1 &= \sum_{n=2}^4 n (-1)^n b_n \\

    enforce :math:`U(r_\mathrm{cut}) = 0`.

    Example::

        nl = nlist.Cell()
        fourier = pair.Fourier(default_r_cut=3.0, nlist=nl)
        fourier.params[('A', 'A')] = dict(a=[a2,a3,a4], b=[b2,b3,b4])

    .. py:attribute:: params

        The Fourier potential parameters. The dictionary has the following
        keys:

        * ``a`` (`float`, **required**) - array of 3 values corresponding to
          a2, a3 and a4 in the Fourier series :math:`[\mathrm{dimensionless}]`
        * ``b`` (`float`, **required**) - array of 3 values corresponding to
          b2, b3 and b4 in the Fourier series :math:`[\mathrm{dimensionless}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairFourier"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(a=(float, float, float),
                              b=(float, float, float),
                              len_keys=2))
        self._add_typeparam(params)

class OPP(Pair):
    r"""Oscillating pair force.

    Args:
        nlist (:py:mod:`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius :math:`[\mathrm{length}]`.
        default_r_on (float): Default turn-on radius :math:`[\mathrm{length}]`.
        mode (str): Energy shifting/smoothing mode.

    `OPP` computes the oscillating pair force on all particles in the simulation
    state:

    .. math::
        U(r) = C_1 r^{-\eta_1}
              + C_2 r^{-\eta_2} \cos{\left(k r - \phi\right)}

    The potential was introduced in `Marek Mihalkovič and C. L. Henley 2012`_.

    .. _Marek Mihalkovič and C. L. Henley 2012:
       https://dx.doi.org/10.1103/PhysRevB.85.092102

    Example::

        nl = nlist.Cell()
        opp = pair.OPP(nl, default_r_cut=3.0)
        opp.params[('A', 'A')] = {
            'C1': 1., 'C2': 1., 'eta1': 15,
            'eta2': 3, 'k': 1.0, 'phi': 3.14}
        opp.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The OPP potential parameters. The dictionary has the following keys:

        * ``C1`` (`float`, **required**) -
          Energy scale of the first term :math:`C_1`
          :math:`[\mathrm{energy}]`
        * ``C2`` (`float`, **required**) -
          Energy scale of the second term :math:`C_2`
          :math:`[\mathrm{energy}]`
        * ``eta1`` (`float`, **required**) -
          The inverse power to take :math:`r` to in the first term,
          :math:`\eta_1` :math:`[\mathrm{dimensionless}]`.
        * ``eta2`` (`float`, **required**) -
          The inverse power to take :math:`r` to in the second term
          :math:`\eta_2` :math:`[\mathrm{dimensionless}]`.
        * ``k`` (`float`, **required**) -
          oscillation frequency :math:`k` :math:`[\mathrm{length}^{-1}]`
        * ``phi`` (`float`, **required**) -
          potential phase shift :math:`\phi` :math:`[\mathrm{dimensionless}]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairOPP"

    def __init__(self, nlist, default_r_cut=None, default_r_on=0., mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(C1=float,
                              C2=float,
                              eta1=float,
                              eta2=float,
                              k=float,
                              phi=float,
                              len_keys=2))
        self._add_typeparam(params)

class TWF(Pair):
    r"""Pair potential model for globular proteins.

    Args:
        nlist (:py:mod:`hoomd.md.nlist.NeighborList`): Neighbor list.
        default_r_cut (float): Default cutoff radius (in distance units).
        default_r_on (float): Default turn-on radius (in distance units).
        mode (str): Energy shifting/smoothing mode.

    `TWF` computes the Ten-wolde Frenkel potential on all particles in the
    simulation state:

    .. math::
        U(r) = \frac{4 \epsilon}{\alpha^2} {\left[
        {\left(\frac{\sigma^2}{r^2} - 1 \right)}^6 -
        \alpha {\left(\frac{\sigma^2}{r^2} - 1 \right)}^3\right]}

    The potential was introdcued in `Pieter Rein ten Wolde and Daan Frenkel
    1997`_.

    .. _Pieter Rein ten Wolde and Daan Frenkel 1997:
       https://dx.doi.org/10.1126/science.277.5334.1975

    Example::

        nl = nlist.Cell()
        twf = hoomd.md.pair.TWF(nl, default_r_cut=3.0)
        twf.params[('A', 'A')] = {'sigma': 1.0, 'epsilon': 1.0, 'alpha': 50.0}
        twf.r_cut[('A', 'B')] = 3.0

    .. py:attribute:: params

        The LJ potential parameters. The dictionary has the following keys:

        * ``epsilon`` (`float`, **required**) -
          energy parameter :math:`\varepsilon` :math:`[energy]`
        * ``sigma`` (`float`, **required**) -
          particle size :math:`\sigma` :math:`[length]`
        * ``alpha`` (`float`, **required**) -
          controls well-width :math:`\alpha` :math:`[dimensionless]`

        Type: `TypeParameter` [`tuple` [``particle_type``, ``particle_type``],
        `dict`]

    .. py:attribute:: mode

        Energy shifting/smoothing mode: ``"none"``, ``"shift"``, or ``"xplor"``.

        Type: `str`
    """
    _cpp_class_name = "PotentialPairTWF"

    def __init__(self,
                 nlist,
                 default_r_cut=None,
                 default_r_on=0.0,
                 mode='none'):
        super().__init__(nlist, default_r_cut, default_r_on, mode)
        params = TypeParameter(
            'params', 'particle_types',
            TypeParameterDict(epsilon=float,
                              sigma=float,
                              alpha=float,
                              len_keys=2))
        self._add_typeparam(params)

max_stars_repo_name: wouterel/hoomd-blue

max_issues_repo_name: wouterel/hoomd-blue

max_forks_repo_name: wouterel/hoomd-blue


text:
# TatamiRacer Test for Steering Servo and Motor

import pigpio
import tkinter as tk
from tkinter import messagebox
import numpy as np
import os
import re
import time
import threading

pi = pigpio.pi()
gpio_pin0 = 13 #Motor1
gpio_pin1 = 19 #Motor2
gpio_pin2 = 14 #Servo
fname = os.getcwd()+r'/myconfig.py' #for Donkey Car parameter file

#Variable
class cfg: #parameter
    pass
root = tk.Tk()
motor = tk.IntVar()
servo = tk.IntVar()
servo_center = tk.IntVar()
servo_limit = tk.IntVar()
servo_limit_flag = tk.BooleanVar()
throttle_boost_enable_flag = tk.BooleanVar()
throttle = tk.DoubleVar()
steering = tk.DoubleVar()

throttle_start_boost = tk.DoubleVar()
throttle_start_boost_time = tk.DoubleVar()
throttle_upper_limit = tk.DoubleVar()
throttle_lower_limit = tk.DoubleVar()
throttle_steering_boost = tk.DoubleVar()
steering_feel = tk.DoubleVar()
steering_balance = tk.DoubleVar()

throttle_start_boost_time0 = 0.0
throttle_start_boost_val = 0.0
throttle_deadzone=0.01

timer_enable = True
def timer100ms():
    global throttle_start_boost_val,throttle_start_boost_time0
    if not timer_enable:
        return

    throttle_abs = np.abs(throttle.get())
    t_current = time.time()
    if throttle_abs<=throttle_deadzone:
        throttle_start_boost_time0 = t_current
    #Throttle Boost
    t = t_current-throttle_start_boost_time0
    if(t <= throttle_start_boost_time.get()):
        throttle_start_boost_val = throttle_start_boost.get() #Boost mode
    else:
        throttle_start_boost_val = 0.0
        set_throttle(0)

    t = threading.Timer(0.1, timer100ms)
    t.start()

def set_timer():
    t = threading.Thread(target=timer100ms)
    t.start()
    return t

def set_config():
    servo_max= cfg.TATAMI_STEERING_LEFT_PWM
    servo_min= cfg.TATAMI_STEERING_RIGHT_PWM
    tmp=int(servo_max-servo_min)/2
    servo_limit.set(tmp)
    servo_limit_flag.set(True)
    throttle_boost_enable_flag.set(True)
    servo_center.set(servo_min+tmp)
    servo.set(servo_center.get())
    motor.set(0)
    throttle.set(0)
    steering.set(0)
    set_motor(0)
    set_servo(0)

    steering_feel.set(cfg.TATAMI_STEERING_FEEL)
    steering_balance.set(cfg.TATAMI_STEERING_BALANCE)
    throttle_start_boost_time.set(cfg.TATAMI_THROTTLE_START_BOOST_TIME)
    throttle_start_boost.set(cfg.TATAMI_THROTTLE_START_BOOST)
    throttle_upper_limit.set(cfg.TATAMI_THROTTLE_UPPER_LIMIT)
    throttle_lower_limit.set(cfg.TATAMI_THROTTLE_LOWER_LIMIT)
    throttle_steering_boost.set(cfg.TATAMI_THROTTLE_STEERING_BOOST)
    status()
    status2()
    disable_button()

def load_config():
    f=open(fname)
    datalist=f.readlines()
    f.close()
    i=0
    for s in datalist:
        tmp = re.match(r'^(TATAMI_[A-z_0-9]+\s*[=].+)#',s)
        if tmp:
            exec('cfg.'+tmp.groups()[0])
        i=i+1
    set_config()

def save_config():
    ret = messagebox.askyesno('Write configuration','Write myconfig.py?')
    if not ret:return
    f = open(fname)
    datalist=f.readlines()
    f.close()
    servo_max = servo_center.get()+servo_limit.get()
    servo_min = servo_center.get()-servo_limit.get()
    cfg.TATAMI_STEERING_LEFT_PWM = servo_max
    cfg.TATAMI_STEERING_RIGHT_PWM = servo_min
    cfg.TATAMI_STEERING_FEEL=steering_feel.get()
    cfg.TATAMI_STEERING_BALANCE=steering_balance.get()
    cfg.TATAMI_THROTTLE_START_BOOST_TIME=throttle_start_boost_time.get()
    cfg.TATAMI_THROTTLE_START_BOOST=throttle_start_boost.get()
    cfg.TATAMI_THROTTLE_UPPER_LIMIT=throttle_upper_limit.get()
    cfg.TATAMI_THROTTLE_LOWER_LIMIT=throttle_lower_limit.get()
    cfg.TATAMI_THROTTLE_STEERING_BOOST=throttle_steering_boost.get()

    print('Write Parameter into:' + fname)
    i = 0
    for s in datalist:
        tmp = re.match(r'^(TATAMI_[A-z_0-9]+)\s*[=].+(#.+$)',s)
        if tmp:
            varname =tmp.groups()[0]
            val = str( eval('cfg.'+varname) )
            comment = tmp.groups()[1]
            d = varname+" = "+val+" "+comment
            datalist[i] = d+"\n"
            print(d)
        i = i + 1
    f=open(fname,'w')
    f.writelines(datalist)
    f.close()

def init_config():
    load_config()
    set_config()

def set_motor(motor_level):
    motor_v=int(motor_level)
    if motor_v > 0:
        pi.set_PWM_range(gpio_pin0, 100)  # Set PWM range
        pi.set_PWM_dutycycle(gpio_pin0,   motor_v) # Set PWM duty
        pi.set_PWM_frequency(gpio_pin0,490)
        pi.set_PWM_dutycycle(gpio_pin1,   0) # PWM off
    else:
        pi.set_PWM_range(gpio_pin1, 100)  # Set PWM range
        pi.set_PWM_dutycycle(gpio_pin1,   -motor_v) # Set PWM duty
        pi.set_PWM_frequency(gpio_pin1,490)
        pi.set_PWM_dutycycle(gpio_pin0,   0) # PWM off

def set_servo(x):
    servo_v = servo.get()
    servo_max = servo_center.get()+servo_limit.get()
    servo_min = servo_center.get()-servo_limit.get()
    if servo_limit_flag.get() and servo_v > servo_max:
        servo_v = servo_max
    elif servo_limit_flag.get() and servo_v < servo_min:
        servo_v = servo_min
    pi.set_mode(gpio_pin2, pigpio.OUTPUT)
    pi.set_servo_pulsewidth(gpio_pin2, servo_v )
    servo.set(servo_v)
    status()

def set_throttle(x):
    global throttle_start_boost_val
    th_in = throttle.get()
    throttle_abs = np.abs(th_in)

    #Steering Boost
    angle_adjust = throttle_lower_limit.get()+np.abs(steering.get())*(throttle_steering_boost.get()-throttle_lower_limit.get())

    #Feeling
    if throttle_abs < throttle_lower_limit.get():
        throttle_feel = throttle_lower_limit.get()
    elif throttle_abs > throttle_upper_limit.get():
        throttle_feel = throttle_upper_limit.get()
    else:
        slope = throttle_upper_limit.get()-throttle_lower_limit.get()
        throttle_feel = throttle_lower_limit.get() + throttle_abs*slope

    if throttle_abs > throttle_deadzone:
        if throttle_boost_enable_flag.get():
            th = np.sign(th_in)*max(throttle_start_boost_val,angle_adjust,throttle_feel)
        else:
            th = th_in
    else:
        th=0
    s1.set(th*100)

def set_steering(x):
    angle = steering.get()
    #Steering Feeling Adjustment
    ang_abs=np.abs(angle)
    steering_half=0.5
    if ang_abs < steering_half:
        slope = steering_feel.get()/steering_half
        angle = np.sign(angle)*ang_abs*slope
    else:
        slope = (1.0-steering_feel.get())/(1.0-steering_half)
        angle = np.sign(angle)* (steering_feel.get()+(ang_abs-steering_half)*slope)

    #Steering Balance Adjustment
    if angle>0:
        angle =  angle * (1.0+steering_balance.get())
    else:
        angle =  angle * (1.0-steering_balance.get())

    v = servo_center.get()-servo_limit.get()*angle
    s2.set(v)
    set_throttle(0)

def status():
    servo_offset = servo.get()-servo_center.get()
    servo_max = servo_center.get()+servo_limit.get()
    servo_min = servo_center.get()-servo_limit.get()
    s = ' Servo:'+str(servo_offset)
    s = s+' Limit:'+str(servo_limit.get())
    s = s+' (Min:'+str(servo_min)
    s = s+ ' Center:'+str(servo_center.get())
    s = s+' Max:'+str(servo_max)+')'
    l1.config(text=s)

def status2():
    s = 'Start Boost:'+str(throttle_start_boost.get())
    s = s + ' Steering Boost:'+str(throttle_steering_boost.get())
    s = s + ' Lower Limit:'+str(throttle_lower_limit.get())
    s = s + ' Upper Limit:'+str(throttle_upper_limit.get())
    l2.config(text=s)

def disable_button():
    if servo_limit_flag.get():
        b3.config(state=tk.DISABLED)
        b4.config(state=tk.DISABLED)
    else:
        b3.config(state=tk.NORMAL)
        b4.config(state=tk.NORMAL)

    if throttle_boost_enable_flag.get():
        b12.config(state=tk.DISABLED)
        b11.config(state=tk.DISABLED)
        b9.config(state=tk.DISABLED)
        b8.config(state=tk.DISABLED)
    else:
        b12.config(state=tk.NORMAL)
        b11.config(state=tk.NORMAL)
        b9.config(state=tk.NORMAL)
        b8.config(state=tk.NORMAL)

#GUI
root.title('TatamiRacer Test')
root.minsize(width=640, height=480)

#Make GUI
f1=tk.Frame(root)
f1.pack(fill = tk.BOTH)

f3=tk.Frame(root)
f3.pack(fill = tk.BOTH)
f4=tk.Frame(root)
f4.pack(fill = tk.BOTH)
f7=tk.Frame(root)
f7.pack(fill = tk.BOTH)
f6=tk.Frame(root)
f6.pack(fill = tk.BOTH)
f5=tk.Frame(root)
f5.pack(fill = tk.BOTH)
f2=tk.Frame(root)
f2.pack(fill = tk.BOTH)

s1 = tk.Scale(f1, label = 'Motor PWM: ', orient = 'h', from_ = -100.0,
              to = 100.0, variable = motor, command = set_motor)
s1.pack(fill = tk.BOTH)
b1 = tk.Button(f1, text= 'Off', command = lambda :s1.set(0) )
b1.pack()
s2 = tk.Scale(f1, label = 'Servo PWM: ', orient = 'h',
              from_ = 500.0, to = 2500.0,  variable = servo, command =set_servo)
s2.pack(fill=tk.BOTH)
l1 = tk.Label(f3, width=100, text='')
l1.pack(fill=tk.BOTH)
b2 = tk.Button(f1, text= 'Center', command = lambda :[s2.set(servo_center.get()),status()])
b2.pack()
l1.pack(fill=tk.BOTH)
b2.pack()
c1 = tk.Checkbutton(f1, text= 'Enable Servo Limit' ,variable = servo_limit_flag,
                    command = lambda :[s2.set(servo_center.get()),disable_button()] )
c1.pack(side=tk.RIGHT)
b4 = tk.Button(f1, text= 'Set Servo Limit',
               command = lambda :[servo_limit.set( np.abs(servo.get()-servo_center.get() )),status()])
b4.pack(side=tk.RIGHT)
b3 = tk.Button(f1, text= 'Set Servo Center',
               command = lambda:[servo_center.set(servo.get()),status()])
b3.pack(side=tk.RIGHT)
s3 = tk.Scale(f4, label = 'Throttle Level: ', orient = 'h',
              from_ = -1.0, to = 1.0, resolution=0.01,  variable = throttle, command= set_throttle)
s3.pack(fill=tk.BOTH)
b10 = tk.Button(f7, text= 'Forward >', command = lambda:s3.set(0.1) )
b10.pack(side=tk.RIGHT,ipadx=120)
b15 = tk.Button(f7, text= 'Stop', command = lambda:s3.set(0) )
b15.pack(side=tk.RIGHT,ipadx=120)
b16 = tk.Button(f7, text= '< Backward', command = lambda:s3.set(-0.1) )
b16.pack(side=tk.RIGHT,ipadx=120)

c2 = tk.Checkbutton(f4, text= 'Enable Boost&Limit' ,variable = throttle_boost_enable_flag,
                    command = lambda :[disable_button(),s3.set(0)] )
c2.pack(side=tk.RIGHT)
b12 = tk.Button(f4, text= 'Set Upper Limit',
                command = lambda: [throttle_upper_limit.set(s3.get()),status2()] )
b12.pack(side=tk.RIGHT)
b11 = tk.Button(f4, text= 'Set Lower Limit',
                command = lambda: [throttle_lower_limit.set(s3.get()),status2()] )
b11.pack(side=tk.RIGHT)
b9 = tk.Button(f4, text= 'Set Steering Boost',
               command = lambda:[throttle_steering_boost.set(s3.get()),status2()] )
b9.pack(side=tk.RIGHT)
b8 = tk.Button(f4, text= 'Set Start Boost',
               command = lambda:[throttle_start_boost.set(s3.get()),status2()] )
b8.pack(side=tk.RIGHT)

s4 = tk.Scale(f5, label = 'Steering Level: ', orient = 'h',
              from_ = -1.0, to = 1.0, resolution=0.01,  variable = steering, command = set_steering)
s4.pack(fill=tk.BOTH)
b13 = tk.Button(f5, text= 'Center', command = lambda:s4.set(0) )
b13.pack()

s5 = tk.Scale(f5, label = 'Steering Feel:', orient = 'h',length=320,
              from_ = 0.1, to = 0.9, resolution=0.01, variable = steering_feel )
s5.pack(side=tk.RIGHT)
s6 = tk.Scale(f5, label = 'Steering Balance:', orient = 'h',length=320,
              from_ = -0.9, to = 0.9, resolution=0.01, variable = steering_balance )
s6.pack(side=tk.RIGHT)
s7 = tk.Scale(f5, label = 'Start Boost Time:', orient = 'h',length=320,
              from_ = 0.0, to = 3.0, resolution=0.1, variable = throttle_start_boost_time )
s7.pack(side=tk.RIGHT)
l2 = tk.Label(f6, width=100, text='-')
l2.pack(fill=tk.BOTH)

b14 = tk.Button(f2, text= 'Close', command = lambda :root.destroy() )
b14.pack(side=tk.RIGHT)
b5 = tk.Button(f2, text= 'Write myconfig.py', command = save_config )
b5.pack(side=tk.RIGHT)
b7 = tk.Button(f2, text= 'Load myconfig.py',
               command = lambda :[load_config(),s2.set(servo_center.get()),status(),status2()] )
b7.pack(side=tk.RIGHT)

#Start
init_config()
status()
disable_button()
timer_thread=set_timer()
root.mainloop()

#Exit
timer_enable = False
pi.set_mode(gpio_pin0, pigpio.INPUT)
pi.set_mode(gpio_pin1, pigpio.INPUT)
pi.set_mode(gpio_pin2, pigpio.INPUT)
pi.stop()
time.sleep(1)
print('TatamiRacer Test End')

ext: py

max_stars_repo_name: covao/TatamiRacer

max_issues_repo_name: covao/TatamiRacer

max_forks_repo_name: covao/TatamiRacer

reason: import numpy


text:
import os
import nni
import GPUtil
import numpy as np

from UCTB.dataset import NodeTrafficLoader
from UCTB.model import ST_MGCN
from UCTB.evaluation import metric
from UCTB.preprocess import SplitData
from UCTB.preprocess.time_utils import is_work_day_china, is_work_day_america

def stmeta_param_parser():
    import argparse
    parser = argparse.ArgumentParser(description="Argument Parser")
    # data source
    parser.add_argument('--Dataset', default='Metro')
    parser.add_argument('--City', default='Shanghai')
    # network parameter
    parser.add_argument('--CT', default='6', type=int)
    parser.add_argument('--PT', default='7', type=int)
    parser.add_argument('--TT', default='4', type=int)
    parser.add_argument('--K', default='1', type=int)
    parser.add_argument('--L', default='1', type=int)
    parser.add_argument('--Graph', default='Distance-Correlation-Line')
    parser.add_argument('--LSTMUnits', default='128', type=int)
    parser.add_argument('--LSTMLayers', default='3', type=int)
    # Training data parameters
    parser.add_argument('--DataRange', default='All')
    parser.add_argument('--TrainDays', default='365')
    parser.add_argument('--test_ratio', default=0.1, type=float)
    # Graph parameter
    parser.add_argument('--TC', default='0', type=float)
    parser.add_argument('--TD', default='1000', type=float)
    parser.add_argument('--TI', default='500', type=float)
    # training parameters
    parser.add_argument('--Epoch', default='20000', type=int)
    parser.add_argument('--Train', default='True')
    parser.add_argument('--lr', default='5e-4', type=float)
    parser.add_argument('--ESlength', default='50', type=int)
    parser.add_argument('--patience', default='0.1', type=float)
    parser.add_argument('--BatchSize', default='32', type=int)
    # graph parameter
    parser.add_argument('--threshold_distance', default=5000, type=float)
    parser.add_argument('--threshold_correlation', default=0.7, type=float)
    parser.add_argument('--threshold_interaction', default=30, type=float)
    # version control
    parser.add_argument('--CodeVersion', default='V')
    # Merge parameter
    parser.add_argument('--MergeIndex', default=1, type=int)
    parser.add_argument('--MergeWay', default='sum', type=str)
    # external features
    parser.add_argument('--external_method', default="not-not-not", type=str)
    parser.add_argument('--external_use', default="weather-holiday-tp", type=str)
    parser.add_argument('--external_lstm_len', default=5, type=int)
    parser.add_argument('--embedding_dim', default=[8,1,8,8], type=str)
    parser.add_argument('--poi_distance', default=5000, type=int)
    return parser

parser = stmeta_param_parser()
args = vars(parser.parse_args())

model_dir = os.path.join('model_dir', args['City'])
code_version = 'ST_MMGCN_{}_K{}L{}_{}_F{}'.format(''.join([e[0] for e in args['Graph'].split('-')]),
                                              args['K'], args['L'], args['CodeVersion'],int(args['MergeIndex']))

if isinstance(args["embedding_dim"],str):
    args["embedding_dim"] = [int(item) for item in args["embedding_dim"].replace("[","").replace("]","").split(",")]
print(args["embedding_dim"],type(args["embedding_dim"]))

print("external_method:",args["external_method"])
print("external_use:",args["external_use"])

# Config data loader
data_loader = NodeTrafficLoader(dataset=args['Dataset'], city=args['City'],
                                test_ratio=float(args['test_ratio']),
                                data_range=args['DataRange'],
                                train_data_length=args['TrainDays'],
                                closeness_len=int(args['CT']),
                                period_len=int(args['PT']),
                                trend_len=int(args['TT']),
                                external_method=args['external_method'],
                                external_lstm_len=args['external_lstm_len'],
                                threshold_distance=args['threshold_distance'],
                                threshold_correlation=args['threshold_correlation'],
                                threshold_interaction=args['threshold_interaction'],
                                normalize=True,
                                graph=args['Graph'],
                                with_lm=True,
                                workday_parser=is_work_day_america if args['Dataset'] == 'Bike' else is_work_day_china,
                                external_use=args['external_use'],
                                poi_distance=args['poi_distance'],
                                MergeIndex=args['MergeIndex'],
                                MergeWay=args["MergeWay"])

# split data
train_closeness, val_closeness = SplitData.split_data(data_loader.train_closeness, [0.9, 0.1])
train_period, val_period = SplitData.split_data(data_loader.train_period, [0.9, 0.1])
train_trend, val_trend = SplitData.split_data(data_loader.train_trend, [0.9, 0.1])
if data_loader.external_dim > 0:
    train_ef_closeness, val_ef_closeness = SplitData.split_data(data_loader.train_ef_closeness, [0.9, 0.1])
    train_ef_period, val_ef_period= SplitData.split_data(data_loader.train_ef_period, [0.9, 0.1])
    train_ef_trend, val_ef_trend = SplitData.split_data(data_loader.train_ef_trend, [0.9, 0.1])
    train_ef, val_ef = SplitData.split_data(data_loader.train_ef, [0.9, 0.1])
    train_lstm_ef, val_lstm_ef = SplitData.split_data(data_loader.train_lstm_ef, [0.9, 0.1])
if data_loader.poi_dim is not None and data_loader.poi_dim > 0:
    train_poi,val_poi = SplitData.split_data(data_loader.poi_feature_train, [0.9, 0.1])

train_y, val_y = SplitData.split_data(data_loader.train_y, [0.9, 0.1])

de_normalizer =  data_loader.normalizer.min_max_denormal

# GPU device
deviceIDs = GPUtil.getAvailable(order='memory', limit=2, maxLoad=1, maxMemory=0.7,
                                includeNan=False, excludeID=[], excludeUUID=[])

if len(deviceIDs) == 0:
    current_device = '-1'
else:
    current_device = str(deviceIDs[0])

ST_MGCN_Obj = ST_MGCN(num_node=data_loader.station_number,
                      T=int(args['CT']) + int(args['PT']) + int(args['TT']),
                      input_dim=1,
                      external_dim=data_loader.external_dim,
                      closeness_len=int(args['CT']),
                      period_len=int(args['PT']),
                      trend_len=int(args['TT']),
                      external_lstm_len=args['external_lstm_len'],
                      num_graph=data_loader.LM.shape[0],
                      gcl_k=args['K'],
                      gcl_l=args['L'],
                      lstm_units=args['LSTMUnits'],
                      lstm_layers=args['LSTMLayers'],
                      lr=args['lr'],
                      code_version=code_version,
                      model_dir=model_dir,
                      gpu_device=current_device,
                      external_method=args['external_method'],
                      embedding_dim=args['embedding_dim'],
                      poi_dim=data_loader.poi_dim,
                      classified_external_feature_dim=data_loader.external_onehot_dim if "multi" in args['external_method'] or args['external_method'] == "lstm" else [])

ST_MGCN_Obj.build()

print(args['Dataset'], args['City'], code_version)
print(ST_MGCN_Obj.trainable_vars)

# Training
if args['Train'] == 'True':
    ST_MGCN_Obj.fit(traffic_flow=np.concatenate((np.transpose(data_loader.train_closeness, [0, 2, 1, 3]),
                                                 np.transpose(data_loader.train_period, [0, 2, 1, 3]),
                                                 np.transpose(data_loader.train_trend, [0, 2, 1, 3])), axis=1),
                    poi_feature = data_loader.poi_feature_train,
                    external_closeness=data_loader.train_ef_closeness,
                    external_period=data_loader.train_ef_period,
                    external_trend=data_loader.train_ef_trend,
                    external_lstm_hidden=data_loader.train_lstm_ef,
                    laplace_matrix=data_loader.LM,
                    target=data_loader.train_y,
                    external_feature=data_loader.train_ef,
                    output_names=('loss', ),
                    evaluate_loss_name='loss',
                    early_stop_method='t-test',
                    early_stop_length=int(args['ESlength']),
                    early_stop_patience=float(args['patience']),
                    sequence_length=data_loader.train_sequence_len,
                    save_model=True,
                    batch_size=int(args['BatchSize']),
                    max_epoch=int(args['Epoch']))

ST_MGCN_Obj.load(code_version)

# Evaluate
prediction = ST_MGCN_Obj.predict(traffic_flow=np.concatenate((np.transpose(data_loader.test_closeness, [0, 2, 1, 3]),
                                                              np.transpose(data_loader.test_period, [0, 2, 1, 3]),
                                                              np.transpose(data_loader.test_trend, [0, 2, 1, 3])), axis=1),
                                 poi_feature=data_loader.poi_feature_test,
                                 external_closeness=data_loader.test_ef_closeness if data_loader.external_dim > 0 else None,
                                 external_period=data_loader.test_ef_period if data_loader.external_dim > 0 else None,
                                 external_trend=data_loader.test_ef_trend if data_loader.external_dim > 0 else None,
                                 external_lstm_hidden=data_loader.test_lstm_ef if data_loader.external_dim > 0 else None,
                                 laplace_matrix=data_loader.LM,
                                 external_feature=data_loader.test_ef if data_loader.external_dim > 0 else None,
                                 sequence_length=data_loader.test_sequence_len,
                                 output_names=['prediction'],
                                 cache_volume=int(args['BatchSize']))

test_rmse = metric.rmse(prediction=data_loader.normalizer.min_max_denormal(prediction['prediction']),
                        target=data_loader.normalizer.min_max_denormal(data_loader.test_y),
                        threshold=0)

test_mae = metric.mae(prediction=data_loader.normalizer.min_max_denormal(prediction['prediction']),
                        target=data_loader.normalizer.min_max_denormal(data_loader.test_y),
                        threshold=0)

# Evaluate
prediction = ST_MGCN_Obj.predict(traffic_flow=np.concatenate((np.transpose(val_closeness, [0, 2, 1, 3]),
                                                             np.transpose(val_period, [0, 2, 1, 3]),
                                                             np.transpose(val_trend, [0, 2, 1, 3])), axis=1),
                                 poi_feature=val_poi if data_loader.poi_dim is not None and data_loader.poi_dim > 0 else None,
                                 external_closeness=val_ef_closeness if data_loader.external_dim > 0 else None,
                                 external_period=val_ef_period if data_loader.external_dim > 0 else None,
                                 external_trend=val_ef_trend if data_loader.external_dim > 0 else None,
                                 external_lstm_hidden=val_lstm_ef if data_loader.external_dim > 0 else None,
                                 laplace_matrix=data_loader.LM,
                                 external_feature=val_ef if data_loader.external_dim > 0 else None,
                                 sequence_length=max((len(val_closeness), len(val_period), len(val_trend))),
                                 output_names=['prediction'],
                                 cache_volume=int(args['BatchSize']))

val_rmse = metric.rmse(prediction=data_loader.normalizer.min_max_denormal(prediction['prediction']),
                        target=data_loader.normalizer.min_max_denormal(val_y),
                        threshold=0)
val_mae = metric.mae(prediction=data_loader.normalizer.min_max_denormal(prediction['prediction']),
                        target=data_loader.normalizer.min_max_denormal(val_y),
                        threshold=0)

print('Val RMSE', val_rmse)
print('Test RMSE', test_rmse)
print('Val MAE', val_mae)
print('Test MAE', test_mae)

val_loss = ST_MGCN_Obj.load_event_scalar('val_loss')

time_consumption = [val_loss[e][0] - val_loss[e-1][0] for e in range(1, len(val_loss))]
time_consumption = sum([e for e in time_consumption if e < (min(time_consumption) * 10)]) / 3600
print('Converged using %.2f hour / %s epochs' % (time_consumption, ST_MGCN_Obj._global_step))


text:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
data_proc.py
ChE696 class project
Minh Hoang Nguyen
"""

from __future__ import print_function
import sys
import os
import argparse
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

CURRENT_DIR = os.path.dirname(__file__)
MAIN_DIR = os.path.join(CURRENT_DIR, '..')
DATA_DIR = os.path.join(CURRENT_DIR, 'data')
RES_DIR = os.path.join(CURRENT_DIR, 'results')
DEFAULT_DATA_FN = os.path.join(DATA_DIR, 'sample_data.csv')

MODULUS_0_AVG = 7539.0
MODULUS_0_STDDEV = 2.2
BASELINE = [0, MODULUS_0_AVG, MODULUS_0_STDDEV]

def warning(*objs):  # =====================================================================================
    """Writes a message to stderr."""
    print("WARNING: ", *objs, file=sys.stderr)

def data_analysis(df, alignment, archi, value_type):  # ====================================================
    """
        - Filtering
        - Convert to Numpy Array
        - Convert std. dev. from % to real values
    """

    # FILTERING -----------
    df = df.loc[df['Defect_alignment'] == alignment]
    df = df.loc[df['Defect_architecture'] == archi]
    df = df.drop(columns=["Defect_alignment", "Defect_architecture"])

    # CONVERTING ----------
    a = df.values
    a = np.vstack([BASELINE, a])
    a[:, 2] = np.multiply(a[:, 1], a[:, 2])/100

    if value_type:
        a[:, 1] = a[:, 1] / MODULUS_0_AVG
        a[:, 2] = a[:, 2] / MODULUS_0_AVG

    return a

def plot_data(a, alignment, archi, value_type, base_out_fname):  # =============================================
    """
        Plotting error bars
        https://matplotlib.org/1.2.1/examples/pylab_examples/errorbar_demo.html
    """

    if value_type:
        ylimit = 1.3
        ylabel_text = value_type + ' modulus (-)'
    else:
        ylimit = 8500
        ylabel_text = ' modulus (ksi)'

    plt.plot([0, 5.5], [a[0, 1], a[0, 1]], 'b--')
    plt.plot(a[:, 0], a[:, 1], 'r.')
    plt.errorbar(a[:, 0], a[:, 1], yerr=a[:, 2], fmt='o', capsize=5)
    plt.title('Modulus of Defect Specimens (' + alignment + archi + ')')
    plt.xlabel('defect size (in)')
    plt.ylabel(ylabel_text)
    plt.axis([0, 0.55, 0, ylimit])
    plt.grid(True)
    # plt.show()
    plt.savefig(RES_DIR + '\\' + base_out_fname + ".png")
    plt.clf()

def parse_cmdline(argv):  # ================================================================================
    """
        Returns the parsed argument list and return code.
        `argv` is a list of arguments, or `None` for ``sys.argv[1:]``.
    """
    if argv is None:
        argv = sys.argv[1:]

    # initialize the parser object:
    parser = argparse.ArgumentParser(description='Read in a csv (no header) of'
                                                 ' experimental data and plots results.')
    parser.add_argument("-c", "--csv_data_file", help="Directory and name of the csv file with data to analyzed.",
                        default=DEFAULT_DATA_FN)
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-r", "--real_values", help="Plotting real values", action="store_true", default=True)
    group.add_argument("-n", "--normalized_values", help="Plotting normalized values", action="store_true", default=False)

    args = None
    try:
        args = parser.parse_args(argv)
        # args.csv_data = np.loadtxt(fname=args.csv_data_file, delimiter=',')
        args.csv_data = pd.read_csv(args.csv_data_file)
    except IOError as e:
        warning("Problems reading file:", e)
        parser.print_help()
        return args, 1

    return args, 0

def main(argv=None):  # =====================================================================================
    """
    print(CURRENT_DIR)
    print(MAIN_DIR)
    print(DATA_DIR)
    print(DEFAULT_DATA_FN)
    """
    args, ret = parse_cmdline(argv)
    if ret != 0:
        return ret

    value_type = ''
    if args.normalized_values:
        value_type = 'Normalized'
    print(value_type)

    configs = np.array([['A', '-'], ['A', '+'], ['S', '-'], ['S', '+']])
    for i in range(4):
        base_out_fname = os.path.basename(args.csv_data_file)
        base_out_fname = os.path.splitext(base_out_fname)[0]
        base_out_fname = base_out_fname + '_plot_' + configs[i, 0] + configs[i, 1]
        a = data_analysis(args.csv_data, configs[i, 0], configs[i, 1], value_type)
        np.savetxt(RES_DIR + '\\' + base_out_fname + ".csv",
                   a, delimiter=",")

        print("Results written to file " + base_out_fname + ".csv")
        plot_data(a, configs[i, 0], configs[i, 1], value_type, base_out_fname)

    return 0  # success

if __name__ == "__main__":
    status = main()
    sys.exit(status)


text:
import numpy as np
from sklearn import tree
from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
from warnings import filterwarnings
from time import perf_counter

# todo: put back!!
#from DatasetsEvaluator.DatasetsEvaluator import DatasetsTester

import sys
sys.path.insert(0, 'C:\python_projects\DatasetsEvaluator_project\DatasetsEvaluator')
import DatasetsEvaluator as de

def run_single_process(datasets_tester, estimators_arr):
	print("Running a single process...")
	start_time = perf_counter()
	summary_df, _ = datasets_tester.run_tests(estimators_arr)
	end_time = perf_counter()
	print(f"Total Time: {end_time-start_time}")

def run_multiple_processes(datasets_tester, estimators_arr):
	print("\n\nRunning multiple processes...")
	start_time = perf_counter()
	summary_df, _ = datasets_tester.run_tests(estimators_arr, run_parallel=True)
	end_time = perf_counter()
	print(f"Total Time: {end_time-start_time}")

def main():
	filterwarnings('ignore')

	cache_folder = "c:\\dataset_cache"

	datasets_tester = de.DatasetsTester(
		problem_type="classification",
		path_local_cache=cache_folder)

	matching_datasets = datasets_tester.find_datasets(
		min_num_classes=2,
		max_num_classes=20,
		min_num_minority_class=5,
		max_num_minority_class=np.inf,
		min_num_features=0,
		max_num_features=np.inf,
		min_num_instances=500,
		max_num_instances=5_000,
		min_num_numeric_features=2,
		max_num_numeric_features=50,
		min_num_categorical_features=0,
		max_num_categorical_features=50)

	print(f"Number matching datasets found: {len(matching_datasets)}")

	datasets_tester.collect_data(
		max_num_datasets_used=20,
		method_pick_sets='pick_first',
		preview_data=False,
		save_local_cache=True,
		check_local_cache=True)

	dt_1 = tree.DecisionTreeClassifier(min_samples_split=50, max_depth=6, random_state=0)
	dt_2 = tree.DecisionTreeClassifier(min_samples_split=25, max_depth=5, random_state=0)
	knn_1 = KNeighborsClassifier(n_neighbors=5)
	knn_2 = KNeighborsClassifier(n_neighbors=10)

	estimators_arr = [
		("Decision Tree", "Original Features", "min_samples_split=50, max_depth=6", dt_1),
		("Decision Tree", "Original Features", "min_samples_split=25, max_depth=5", dt_2),
		("kNN", "Original Features", "n_neighbors=5", knn_1),
		("kNN", "Original Features", "n_neighbors=10", knn_2)]

	run_single_process(datasets_tester, estimators_arr)
	run_multiple_processes(datasets_tester, estimators_arr)

if __name__ == "__main__":
	main()

max_stars_repo_name: Brett-Kennedy/DatasetsEvaluator

max_issues_repo_name: Brett-Kennedy/DatasetsEvaluator

max_forks_repo_name: Brett-Kennedy/DatasetsEvaluator


text:
import numpy as num
n, m = map(int, input().split())
array = num.array([input().split() for _ in range(n)], int)
print (array.transpose())
print (array.flatten())


text:
#--------------------------------------------------------------------
# Name:        svm.py
#
# Purpose:     Train an svm
#
# Author:      Willie Boag
#--------------------------------------------------------------------

import os
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.svm import LinearSVC

label_names = ['positive', 'negative', 'neutral']
label2ind = { label:ind for ind,label in enumerate(label_names) }

def main():

   # Get data from notes
   train_tweets = []
   train_labels = []
   train_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'twitter-train-gold-B.tsv')
   with open(train_file, 'r') as f:
       for line in f.readlines():
           tid,uid,label,text = line.strip().split('\t')
           if text == 'Not Available':
               continue                #print 'tid:   [%s]' % tid
           #print 'uid:   [%s]' % uid
           #print 'label: [%s]' % label
           #print 'text:  [%s]' % text
           #print
           train_tweets.append(text)
           train_labels.append(label)

   # Data -> features (encoded as sparse feature dictionaries)
   train_feats = extract_features(train_tweets)

   # feature dictionary -> sparse numpy vector
   vectorizer = DictVectorizer()
   train_X = vectorizer.fit_transform(train_feats)

   # e.g. 'positive' -> 0
   train_Y = np.array( [label2ind[label] for label in train_labels] )

   # Fit model (AKA learn model parameters)
   classifier = LinearSVC(C=0.1)
   classifier.fit(train_X, train_Y)

   # Predict on test data
   test_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'twitter-test-gold-B.tsv')
   test_tweets = []
   test_labels = []
   with open(test_file, 'r') as f:
       for line in f.readlines():
           tid,uid,label,text = line.strip().split('\t')
           if text == 'Not Available':
               continue
           test_tweets.append(text)
           test_labels.append(label)
   test_feats =  extract_features(test_tweets)
   test_X = vectorizer.transform(test_feats)
   test_Y = np.array( [label2ind[label] for label in test_labels] )
   test_predictions = classifier.predict(test_X)

   # display a couple results
   print
   print 'references:  ', test_Y[:5]
   print 'predictions: ', test_predictions[:5]
   print

   # compute confusion matrix (rows=predictions, columns=reference)
   confusion = np.zeros((3,3))
   for pred,ref in zip(test_predictions,test_Y):
       confusion[pred][ref] += 1
   print ' '.join(label_names)
   print confusion
   print

   # compute P, R, and F1 of each class
   for label in label_names:
       ind = label2ind[label]

       tp         = confusion[ind,ind]
       tp_plus_fn = confusion[:,ind].sum()
       tp_plus_fp = confusion[ind,:].sum()

       precision = float(tp)/tp_plus_fp
       recall    = float(tp)/tp_plus_fn
       f1        = (2*precision*recall) / (precision+recall+1e-9)

       print label
       print '\tprecision: ', precision
       print '\trecall:    ', recall
       print '\tf1:        ', f1
       print

def extract_features(tweets):
   features_list = []
   for tweet in tweets:
       feats = {}
       for word in tweet.split():
           featurename = ('unigram',word) # tuple format not required
           featureval  = 1                # indicate this feature is "on"
           feats[featurename] = featureval
       features_list.append(feats)
   return features_list

if __name__ == '__main__':
   main()