Program Listing for File inversepower_hs.hpp#

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

#ifndef _PELE_INVERSEPOWER_HS_H
#define _PELE_INVERSEPOWER_HS_H

#include <iostream>
#include <memory>
#include <cmath>
#include <limits>

#include "atomlist_potential.hpp"
#include "base_interaction.hpp"
#include "cell_list_potential.hpp"
#include "distance.hpp"
#include "meta_pow.hpp"
#include "simple_pairwise_ilist.hpp"
#include "simple_pairwise_potential.hpp"

namespace pele {


struct InversePowerHS_interaction : BaseInteraction {
  double const _eps;
  double const _pow;
  double const _sca;
  double const _infty;

  InversePowerHS_interaction(double pow, double eps, double sca)
      : _eps(eps), _pow(pow), _sca(sca), _infty(std::numeric_limits<double>::infinity()) {}

  /* calculate energy from distance squared */
  double energy(double r2, const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      return 0.0;
    }
    const double r = std::sqrt(r2);
    return std::pow((1.0 - r / d_c), _pow) * _eps / _pow;
  }

  /* calculate energy and gradient from distance squared, gradient is in
   * -(dv/drij)/|rij| */
  double energy_gradient(double r2, double *gij,
                         const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      *gij = _infty;
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      *gij = 0.0;
      return 0.0;
    }
    const double r = std::sqrt(r2);
    const double factor = std::pow((1.0 - r / d_c), _pow) * _eps;
    *gij = -factor / ((r - d_c) * r);
    return factor / _pow;
  }

  double inline energy_gradient_hessian(double r2, double *gij, double *hij,
                                        const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      *gij = _infty;
      *hij = _infty;
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      *gij = 0.0;
      *hij = 0.0;
      return 0.0;
    }
    const double r = std::sqrt(r2);
    const double factor = std::pow((1.0 - r / d_c), _pow) * _eps;
    const double denom = 1.0 / (r - d_c);
    *gij = -factor * denom / r;
    *hij = (_pow - 1.0) * factor * denom * denom;
    return factor / _pow;
  }
};

template <int POW>
struct InverseIntPowerHS_interaction : BaseInteraction {
  double const _eps;
  double const _pow;
  double const _sca;
  double const _infty;

  InverseIntPowerHS_interaction(double eps, double sca)
      : _eps(eps), _pow(POW), _sca(sca), _infty(std::numeric_limits<double>::infinity()) {}

  /* calculate energy from distance squared */
  double energy(double r2, const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      return 0.0;
    }
    const double r = std::sqrt(r2);
    return pos_int_pow<POW>(1.0 - r / d_c) * _eps / _pow;
  }

  /* calculate energy and gradient from distance squared, gradient is in
   * -(dv/drij)/|rij| */
  double energy_gradient(double r2, double *gij,
                         const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      *gij = _infty;
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      *gij = 0.0;
      return 0.0;
    }
    const double r = std::sqrt(r2);
    const double factor = pos_int_pow<POW>(1.0 - r / d_c) * _eps;
    *gij = -factor / ((r - d_c) * r);
    return factor / _pow;
  }

  double inline energy_gradient_hessian(double r2, double *gij, double *hij,
                                        const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      *gij = _infty;
      *hij = _infty;
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      *gij = 0.0;
      *hij = 0.0;
      return 0.0;
    }
    const double r = std::sqrt(r2);
    const double factor = pos_int_pow<POW>(1.0 - r / d_c) * _eps;
    const double denom = 1.0 / (r - d_c);
    *gij = -factor * denom / r;
    *hij = (_pow - 1.0) * factor * denom * denom;
    return factor / _pow;
  }
};

template <int POW2>
struct InverseHalfIntPowerHS_interaction : BaseInteraction {
  double const _eps;
  double const _pow;
  double const _sca;
  double const _infty;

  InverseHalfIntPowerHS_interaction(double eps, double sca)
      : _eps(eps), _pow(0.5 * POW2), _sca(sca), _infty(std::numeric_limits<double>::infinity()) {}

  /* calculate energy from distance squared */
  double energy(double r2, const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      return 0.0;
    }
    const double r = std::sqrt(r2);
    return pos_half_int_pow<POW2>(1.0 - r / d_c) * _eps / _pow;
  }

  /* calculate energy and gradient from distance squared, gradient is in
   * -(dv/drij)/|rij| */
  double energy_gradient(double r2, double *gij,
                         const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      *gij = _infty;
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      *gij = 0.0;
      return 0.0;
    }
    const double r = std::sqrt(r2);
    const double factor = pos_half_int_pow<POW2>(1.0 - r / d_c) * _eps;
    *gij = -factor / ((r - d_c) * r);
    return factor / _pow;
  }

  double inline energy_gradient_hessian(double r2, double *gij, double *hij,
                                        const double dij_hs) const {
    const double d_hs2 = dij_hs * dij_hs;
    if (r2 <= d_hs2) {
      *gij = _infty;
      *hij = _infty;
      return _infty;
    }
    const double d_c = dij_hs * (1.0 + _sca);
    if (r2 >= d_c * d_c) {
      *gij = 0.0;
      *hij = 0.0;
      return 0.0;
    }
    const double r = std::sqrt(r2);
    const double factor = pos_half_int_pow<POW2>(1.0 - r / d_c) * _eps;
    const double denom = 1.0 / (r - d_c);
    *gij = -factor * denom / r;
    *hij = (_pow - 1.0) * factor * denom * denom;
    return factor / _pow;
  }
};

template <size_t ndim>
class InversePowerHS
    : public SimplePairwisePotential<InversePowerHS_interaction,
                                     cartesian_distance<ndim>> {
 public:
  InversePowerHS(double pow, double eps, double sca,
                 pele::Array<double> const radii, bool exact_sum = false,
                 double non_additivity = 0.0)
      : SimplePairwisePotential<InversePowerHS_interaction,
                                cartesian_distance<ndim>>(
            std::make_shared<InversePowerHS_interaction>(pow, eps, sca),
            radii, std::make_shared<cartesian_distance<ndim>>(), sca,
            exact_sum, non_additivity) {}
};

template <size_t ndim>
class InversePowerHSPeriodic
    : public SimplePairwisePotential<InversePowerHS_interaction,
                                     periodic_distance<ndim>> {
 public:
  InversePowerHSPeriodic(double pow, double eps, double sca,
                         pele::Array<double> const radii,
                         pele::Array<double> const boxvec,
                         bool exact_sum = false, double non_additivity = 0.0)
      : SimplePairwisePotential<InversePowerHS_interaction,
                                periodic_distance<ndim>>(
            std::make_shared<InversePowerHS_interaction>(pow, eps, sca),
            radii, std::make_shared<periodic_distance<ndim>>(boxvec), sca,
            exact_sum, non_additivity) {}
};

template <size_t ndim, int POW>
class InverseIntPowerHS
    : public SimplePairwisePotential<InverseIntPowerHS_interaction<POW>,
                                     cartesian_distance<ndim>> {
 public:
  InverseIntPowerHS(double eps, double sca, pele::Array<double> const radii,
                    bool exact_sum = false, double non_additivity = 0.0)
      : SimplePairwisePotential<InverseIntPowerHS_interaction<POW>,
                                cartesian_distance<ndim>>(
            std::make_shared<InverseIntPowerHS_interaction<POW>>(eps, sca),
            radii, std::make_shared<cartesian_distance<ndim>>(), sca,
            exact_sum, non_additivity) {}
};

template <size_t ndim, int POW>
class InverseIntPowerHSPeriodic
    : public SimplePairwisePotential<InverseIntPowerHS_interaction<POW>,
                                     periodic_distance<ndim>> {
 public:
  InverseIntPowerHSPeriodic(double eps, double sca,
                            pele::Array<double> const radii,
                            pele::Array<double> const boxvec,
                            bool exact_sum = false,
                            double non_additivity = 0.0)
      : SimplePairwisePotential<InverseIntPowerHS_interaction<POW>,
                                periodic_distance<ndim>>(
            std::make_shared<InverseIntPowerHS_interaction<POW>>(eps, sca),
            radii, std::make_shared<periodic_distance<ndim>>(boxvec), sca,
            exact_sum, non_additivity) {}
};

template <size_t ndim, int POW2>
class InverseHalfIntPowerHS
    : public SimplePairwisePotential<InverseHalfIntPowerHS_interaction<POW2>,
                                     cartesian_distance<ndim>> {
 public:
  InverseHalfIntPowerHS(double eps, double sca,
                        pele::Array<double> const radii,
                        bool exact_sum = false, double non_additivity = 0.0)
      : SimplePairwisePotential<InverseHalfIntPowerHS_interaction<POW2>,
                                cartesian_distance<ndim>>(
            std::make_shared<InverseHalfIntPowerHS_interaction<POW2>>(
                eps, sca),
            radii, std::make_shared<cartesian_distance<ndim>>(), sca,
            exact_sum, non_additivity) {}
};

template <size_t ndim, int POW2>
class InverseHalfIntPowerHSPeriodic
    : public SimplePairwisePotential<InverseHalfIntPowerHS_interaction<POW2>,
                                     periodic_distance<ndim>> {
 public:
  InverseHalfIntPowerHSPeriodic(double eps, double sca,
                                pele::Array<double> const radii,
                                pele::Array<double> const boxvec,
                                bool exact_sum = false,
                                double non_additivity = 0.0)
      : SimplePairwisePotential<InverseHalfIntPowerHS_interaction<POW2>,
                                periodic_distance<ndim>>(
            std::make_shared<InverseHalfIntPowerHS_interaction<POW2>>(
                eps, sca),
            radii, std::make_shared<periodic_distance<ndim>>(boxvec), sca,
            exact_sum, non_additivity) {}
};

template <size_t ndim>
class InversePowerHSPeriodicCellLists
    : public CellListPotential<InversePowerHS_interaction,
                               periodic_distance<ndim>> {
 public:
  InversePowerHSPeriodicCellLists(
      double pow, double eps, double sca, pele::Array<double> const radii,
      pele::Array<double> const boxvec, const double ncellx_scale = 1.0,
      bool exact_sum = false, double non_additivity = 0.0)
      : CellListPotential<InversePowerHS_interaction, periodic_distance<ndim>>(
            std::make_shared<InversePowerHS_interaction>(pow, eps, sca),
            std::make_shared<periodic_distance<ndim>>(boxvec), boxvec,
            (1.0 + sca) * 2.0 *
                (*std::max_element(radii.begin(), radii.end())),  // rcut
            ncellx_scale, radii, sca, true, exact_sum, non_additivity) {}
};

template <size_t ndim, int POW>
class InverseIntPowerHSPeriodicCellLists
    : public CellListPotential<InverseIntPowerHS_interaction<POW>,
                               periodic_distance<ndim>> {
 public:
  InverseIntPowerHSPeriodicCellLists(
      double eps, double sca, pele::Array<double> const radii,
      pele::Array<double> const boxvec, const double ncellx_scale = 1.0,
      bool exact_sum = false, double non_additivity = 0.0)
      : CellListPotential<InverseIntPowerHS_interaction<POW>,
                          periodic_distance<ndim>>(
            std::make_shared<InverseIntPowerHS_interaction<POW>>(eps, sca),
            std::make_shared<periodic_distance<ndim>>(boxvec), boxvec,
            (1.0 + sca) * 2.0 *
                (*std::max_element(
                    radii.begin(),
                    radii.end())),  // rcut, Note if boxvec or radii are of
                                    // size 0 this can lead to a segfault
            ncellx_scale, radii, sca, true, exact_sum, non_additivity) {}
};

template <size_t ndim, int POW2>
class InverseHalfIntPowerHSPeriodicCellLists
    : public CellListPotential<InverseHalfIntPowerHS_interaction<POW2>,
                               periodic_distance<ndim>> {
 public:
  InverseHalfIntPowerHSPeriodicCellLists(
      double eps, double sca, pele::Array<double> const radii,
      pele::Array<double> const boxvec, const double ncellx_scale = 1.0,
      bool exact_sum = false, double non_additivity = 0.0)
      : CellListPotential<InverseHalfIntPowerHS_interaction<POW2>,
                          periodic_distance<ndim>>(
            std::make_shared<InverseHalfIntPowerHS_interaction<POW2>>(
                eps, sca),
            std::make_shared<periodic_distance<ndim>>(boxvec), boxvec,
            (1.0 + sca) * 2.0 *
                (*std::max_element(radii.begin(), radii.end())),  // rcut,
            ncellx_scale, radii, sca, true, exact_sum, non_additivity) {}
};

}  // namespace pele

#endif  // #ifndef _PELE_INVERSEPOWER_HS_H