Program Listing for File inversepower_stillinger_cut.hpp#

↰ Return to documentation for file (source/pele/inversepower_stillinger_cut.hpp)

#ifndef _PELE_INVERSEPOWER_STILLIGNER_CUT_H
#define _PELE_INVERSEPOWER_STILLIGNER_CUT_H

#include "base_interaction.hpp"
#include "pele/cell_list_potential.hpp"
#include "pele/simple_pairwise_potential.hpp"

namespace pele {

struct InversePowerStillinger_cut_interaction : BaseInteraction {
  // Inverse power law potential, see JCP 83, 4767 (1984),
  // http://dx.doi.org/10.1063/1.449840
  const double m_pow, m_rcut, m_rcut2, m_q0, m_q1, m_q2;
  InversePowerStillinger_cut_interaction(const size_t pow, const double rcut)
      : m_pow(pow),
        m_rcut(rcut),
        m_rcut2(m_rcut * m_rcut),
        m_q0(-0.5 * (m_pow + 1) * (m_pow + 2) / std::pow(m_rcut, m_pow)),
        m_q1(m_pow * (m_pow + 2) / std::pow(m_rcut, m_pow + 1)),
        m_q2(-0.5 * m_pow * (m_pow + 1) / std::pow(m_rcut, m_pow + 2)) {}
  double energy(double r2, const double dij) const {
    if (r2 > m_rcut2) {
      return 0.;
    }
    const double an = power_inp2(dij * dij, m_pow);
    const double irn = 1. / power_inp2(r2, m_pow);
    const double E = an * (irn + m_q0 + m_q1 * std::sqrt(r2) + m_q2 * r2);
    return E;
  }
  // calculate energy and gradient from distance squared, gradient is in
  // -(dv/drij)/|rij|
  double energy_gradient(double r2, double *gij, const double dij) const {
    if (r2 > m_rcut2) {
      *gij = 0;
      return 0.;
    }
    const double an = power_inp2(dij * dij, m_pow);
    const double r = std::sqrt(r2);
    const double irn = 1. / this->power(r, m_pow);
    const double E = an * (irn + m_q0 + m_q1 * r + m_q2 * r2);
    *gij = an * (m_pow * irn / r2 - m_q1 / r - 2 * m_q2);
    return E;
  }
  double energy_gradient_hessian(double r2, double *gij, double *hij,
                                 const double dij) const {
    if (r2 > m_rcut2) {
      *gij = 0;
      *hij = 0;
      return 0.;
    }
    const double an = power_inp2(dij * dij, m_pow);
    const double r = std::sqrt(r2);
    const double irn = 1. / this->power(r, m_pow);
    const double E = an * (irn + m_q0 + m_q1 * r + m_q2 * r2);
    *gij = an * (m_pow * irn / r2 - m_q1 / r - 2 * m_q2);
    *hij = an * (m_pow * (m_pow + 1) * irn / r2 + 2 * m_q2);
    return E;
  }

  // Compute inp ** n.
  // See Skiena, p. 48.
  template <class T>
  T power(const T inp, const size_t n) const {
    if (n == 0) {
      return 1;
    }
    const T x = power(inp, n / 2);
    if (n % 2) {
      return inp * x * x;
    } else {
      return x * x;
    }
  }
  // Compute inp ** n, given inp ** 2.
  template <class T>
  T power_inp2(const T inp2, const size_t n) const {
    const T x = power(inp2, n / 2);
    if (n % 2) {
      return std::sqrt(inp2) * x;
    } else {
      return x;
    }
  }
};

template <size_t ndim>
class InversePowerStillingerCut
    : public SimplePairwisePotential<InversePowerStillinger_cut_interaction,
                                     cartesian_distance<ndim>> {
 public:
  InversePowerStillingerCut(const size_t pow, const pele::Array<double> radii,
                            double rcut)
      : SimplePairwisePotential<InversePowerStillinger_cut_interaction,
                                cartesian_distance<ndim>>(
            std::make_shared<InversePowerStillinger_cut_interaction>(pow, rcut),
            radii, std::make_shared<cartesian_distance<ndim>>()) {}
};

template <size_t ndim>
class InversePowerStillingerCutPeriodic
    : public SimplePairwisePotential<InversePowerStillinger_cut_interaction,
                                     periodic_distance<ndim>> {
 public:
  InversePowerStillingerCutPeriodic(const size_t pow,
                                    const pele::Array<double> radii,
                                    double rcut,
                                    const pele::Array<double> boxvec)
      : SimplePairwisePotential<InversePowerStillinger_cut_interaction,
                                periodic_distance<ndim>>(
            std::make_shared<InversePowerStillinger_cut_interaction>(pow, rcut),
            radii, std::make_shared<periodic_distance<ndim>>(boxvec)) {}
};

template <size_t ndim>
class InversePowerStillingerCutPeriodicCellLists
    : public CellListPotential<InversePowerStillinger_cut_interaction,
                               periodic_distance<ndim>> {
 public:
  InversePowerStillingerCutPeriodicCellLists(const size_t pow,
                                             const pele::Array<double> radii,
                                             double rcut,
                                             const pele::Array<double> boxvec,
                                             double ncellx_scale)
      : CellListPotential<InversePowerStillinger_cut_interaction,
                          periodic_distance<ndim>>(
            std::make_shared<InversePowerStillinger_cut_interaction>(pow, rcut),
            std::make_shared<periodic_distance<ndim>>(boxvec), boxvec, rcut,
            ncellx_scale, radii) {}
};

}  // namespace pele

#endif  // #ifndef _PELE_INVERSEPOWER_STILLIGNER_CUT_H