Program Listing for File inversepower.hpp#

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

#ifndef _PELE_INVERSEPOWER_H
#define _PELE_INVERSEPOWER_H

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


struct InversePower_interaction : BaseInteraction {
  double const _eps;
  double const _pow;

  InversePower_interaction(double pow, double eps) : _eps(eps), _pow(pow) {}

  /* calculate energy from distance squared */
  double energy(double r2, const double dij) const {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
    } else {
      // Sqrt moved into else, based on previous comment by CPG.
      const double r = std::sqrt(r2);
      E = std::pow((1 - r / dij), _pow) * _eps / _pow;
    }
    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 {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
      *gij = 0.;
    } else {
      const double r = std::sqrt(r2);
      const double factor = std::pow((1 - r / dij), _pow) * _eps;
      E = factor / _pow;
      *gij = -factor / ((r - dij) * r);
    }
    return E;
  }

  double inline energy_gradient_hessian(double r2, double *gij, double *hij,
                                        const double dij) const {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
      *gij = 0;
      *hij = 0;
    } else {
      const double r = std::sqrt(r2);
      const double factor = std::pow((1 - r / dij), _pow) * _eps;
      const double denom = 1.0 / (r - dij);
      E = factor / _pow;
      *gij = -factor * denom / r;
      *hij = (_pow - 1) * factor * denom * denom;
    }
    return E;
  }
};

template <int POW>
struct InverseIntPower_interaction : BaseInteraction {
  double const _eps;
  double const _pow;

  InverseIntPower_interaction(double eps) : _eps(eps), _pow(POW) {}

  /* calculate energy from distance squared */
  double energy(double r2, const double dij) const {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
    } else {
      const double r = std::sqrt(r2);
      E = pos_int_pow<POW>(1 - r / dij) * _eps / _pow;
    }
    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 {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
      *gij = 0;
    } else {
      const double r = std::sqrt(r2);
      const double factor = pos_int_pow<POW>(1 - r / dij) * _eps;
      E = factor / _pow;
      *gij = -factor / ((r - dij) * r);
    }
    return E;
  }

  double inline energy_gradient_hessian(double r2, double *gij, double *hij,
                                        const double dij) const {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
      *gij = 0;
      *hij = 0;
    } else {
      const double r = std::sqrt(r2);
      const double factor = pos_int_pow<POW>(1 - r / dij) * _eps;
      const double denom = 1.0 / (r - dij);
      E = factor / _pow;
      *gij = -factor * denom / r;
      *hij = (_pow - 1) * factor * denom * denom;
    }
    return E;
  }
};

template <int POW2>
struct InverseHalfIntPower_interaction : BaseInteraction {
  double const _eps;
  double const _pow;
  InverseHalfIntPower_interaction(double eps) : _eps(eps), _pow(0.5 * POW2) {}

  /* calculate energy from distance squared */
  double energy(double r2, const double dij) const {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
    } else {
      const double r = std::sqrt(r2);
      E = pos_half_int_pow<POW2>(1 - r / dij) * _eps / _pow;
    }
    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 {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
      *gij = 0;
    } else {
      const double r = std::sqrt(r2);
      const double factor = pos_half_int_pow<POW2>(1 - r / dij) * _eps;
      E = factor / _pow;
      *gij = -factor / ((r - dij) * r);
    }
    return E;
  }

  double inline energy_gradient_hessian(double r2, double *gij, double *hij,
                                        const double dij) const {
    double E;
    if (r2 >= dij * dij) {
      E = 0.;
      *gij = 0;
      *hij = 0;
    } else {
      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);
      E = factor / _pow;
      *gij = -factor * denom / r;
      *hij = (_pow - 1) * factor * denom * denom;
    }
    return E;
  }
};

//
// combine the components (interaction, looping method, distance function) into
// defined classes
//

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

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


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

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


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

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

/*
template <size_t ndim>
class InversePowerCellLists : public CellListPotential<
InversePower_interaction, cartesian_distance<ndim> > { public:
    InversePowerCellLists(double pow, double eps,
            pele::Array<double> const radii, pele::Array<double> const boxvec,
            const double rcut,
            const double ncellx_scale=1.0)
        : CellListPotential< InversePower_interaction, cartesian_distance<ndim>
>( std::make_shared<InversePower_interaction>(pow, eps),
                std::make_shared<cartesian_distance<ndim> >(),
                boxvec, rcut, ncellx_scale, radii)
    {}
};
*/

template <size_t ndim>
class InversePowerPeriodicCellLists
    : public CellListPotential<InversePower_interaction,
                               periodic_distance<ndim>> {
 public:
  InversePowerPeriodicCellLists(double pow, 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<InversePower_interaction, periodic_distance<ndim>>(
            std::make_shared<InversePower_interaction>(pow, 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) {}
};

template <size_t ndim, int POW>
class InverseIntPowerPeriodicCellLists
    : public CellListPotential<InverseIntPower_interaction<POW>,
                               periodic_distance<ndim>> {
 public:
  InverseIntPowerPeriodicCellLists(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<InverseIntPower_interaction<POW>,
                          periodic_distance<ndim>>(
            std::make_shared<InverseIntPower_interaction<POW>>(eps),
            std::make_shared<periodic_distance<ndim>>(boxvec), boxvec,
            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, 0.0, true, exact_sum, non_additivity) {}
};

template <size_t ndim, int POW2>
class InverseHalfIntPowerPeriodicCellLists
    : public CellListPotential<InverseHalfIntPower_interaction<POW2>,
                               periodic_distance<ndim>> {
 public:
  InverseHalfIntPowerPeriodicCellLists(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<InverseHalfIntPower_interaction<POW2>,
                          periodic_distance<ndim>>(
            std::make_shared<InverseHalfIntPower_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  //#ifndef _PELE_INVERSEPOWER_H