Program Listing for File hs_pairwise_power.hpp#

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

#ifndef _PELE_HS_IP_H
#define _PELE_HS_IP_H

#include <algorithm>
#include <memory>

#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 {

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

  HS_halfint_pairwise_power_interaction(const double eps, const double sca)
      : _pow(0.5 * POW2), _eps(eps), _sca(sca), _infty(std::pow(10.0, 50)) {}

  /* calculate energy from distance squared, r0 is the hard core distance, r is
   * the distance between the centres */
  double inline energy(const double r2, const double dij) const {
    const double r02 = dij * dij;
    if (r2 <= r02) {
      return _infty;
    }
    const double coff =
        dij * (1.0 + _sca);  // distance at which the soft cores are at contact
    if (r2 > coff * coff) {
      return 0;
    }
    const double r = std::sqrt(r2);
    return pos_half_int_pow<POW2>(1 - r / dij) * _eps / _pow;
  }

  /* calculate energy and gradient from distance squared, gradient is in
   * g/|rij|, dij is the hard core distance, r is the distance between
   * the centres */
  double inline energy_gradient(const double r2, double *const gij,
                                const double dij) const {
    const double r02 = dij * dij;
    if (r2 <= r02) {
      *gij = _infty;
      return _infty;
    }
    const double coff =
        dij * (1.0 + _sca);  // distance at which the soft cores are at contact
    if (r2 > coff * coff) {
      *gij = 0.;
      return 0.;
    }
    const double r = std::sqrt(r2);
    const double factor = pos_half_int_pow<POW2>(1 - r / dij) * _eps;
    *gij = -factor / ((r - dij) * r);
    return factor / _pow;
  }

  double inline energy_gradient_hessian(const double r2, double *const gij,
                                        double *const hij,
                                        const double dij) const {
    const double r02 = dij * dij;
    if (r2 <= r02) {
      *gij = _infty;
      *hij = _infty;
      return _infty;
    }
    const double coff =
        dij * (1.0 + _sca);  // distance at which the soft cores are at contact
    if (r2 > coff * coff) {
      *gij = 0.;
      *hij = 0.;
      return 0.;
    }
    const double r = std::sqrt(r2);
    const double factor = pos_half_int_pow<POW2>(1 - r / dij) * _eps;
    const double denom = 1.0 / (r - dij);

    *gij = -factor * denom / r;
    *hij = (_pow - 1) * factor * denom * denom;
    return factor / _pow;
  }
};


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

template <size_t ndim, int POW2>
class HSHalfIntPairwisePowerPeriodic
    : public SimplePairwisePotential<
          HS_halfint_pairwise_power_interaction<POW2>,
          periodic_distance<ndim>> {
 public:
  HSHalfIntPairwisePowerPeriodic(double eps, pele::Array<double> const radii,
                                 pele::Array<double> const boxvec,
                                 bool exact_sum = false,
                                 double non_additivity = 0.0)
      : SimplePairwisePotential<HS_halfint_pairwise_power_interaction<POW2>,
                                periodic_distance<ndim>>(
            std::make_shared<HS_halfint_pairwise_power_interaction<POW2>>(eps),
            radii, std::make_shared<periodic_distance<ndim>>(boxvec), 0.0,
            exact_sum, non_additivity) {}
};
template <size_t ndim, int POW2>
class HSHalfIntPairwisePowerPeriodicCellLists
    : public CellListPotential<HS_halfint_pairwise_power_interaction<POW2>,
                               periodic_distance<ndim>> {
 public:
  HSHalfIntPairwisePowerPeriodicCellLists(double eps,
                                          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<HS_halfint_pairwise_power_interaction<POW2>,
                          periodic_distance<ndim>>(
            std::make_shared<HS_halfint_pairwise_power_interaction<POW2>>(eps),
            std::make_shared<periodic_distance<ndim>>(boxvec), boxvec,
            2.0 * (*std::max_element(radii.begin(), radii.end())),  // rcut,
            ncellx_scale, radii, 0.0, true, exact_sum, non_additivity) {}
};

}  // namespace pele

#endif  // _PELE_HS_IP_H