Program Listing for File simple_pairwise_ilist.hpp#

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

#ifndef PYGMIN_SIMPLE_PAIRWISE_ILIST_H
#define PYGMIN_SIMPLE_PAIRWISE_ILIST_H

#include <assert.h>
#include <iostream>
#include <memory>
#include <vector>

#include "array.hpp"
#include "distance.hpp"
#include "pairwise_potential_interface.hpp"

namespace pele {
template <typename pairwise_interaction,
          typename distance_policy = cartesian_distance<3>>
class SimplePairwiseNeighborList : public PairwisePotentialInterface {
 protected:
  std::shared_ptr<pairwise_interaction> _interaction;
  std::shared_ptr<distance_policy> _dist;
  std::vector<size_t> const _neighbor_list;
  static const size_t _ndim = distance_policy::_ndim;

  SimplePairwiseNeighborList(std::shared_ptr<pairwise_interaction> interaction,
                             Array<size_t> const &neighbor_list,
                             const Array<double> radii,
                             std::shared_ptr<distance_policy> dist = NULL)
      : PairwisePotentialInterface(radii),
        _interaction(interaction),
        _dist(dist),
        _neighbor_list(neighbor_list.begin(), neighbor_list.end()) {
    if (_dist == NULL) _dist = std::make_shared<distance_policy>();
  }

  SimplePairwiseNeighborList(std::shared_ptr<pairwise_interaction> interaction,
                             Array<size_t> const &neighbor_list,
                             std::shared_ptr<distance_policy> dist = NULL)
      : _interaction(interaction),
        _dist(dist),
        _neighbor_list(neighbor_list.begin(), neighbor_list.end()) {
    if (_dist == NULL) _dist = std::make_shared<distance_policy>();
  }

 public:
  virtual ~SimplePairwiseNeighborList() {}

  virtual double get_energy(Array<double> const &x);
  virtual double get_energy_gradient(Array<double> const &x,
                                     Array<double> &grad) {
    grad.assign(0);
    return add_energy_gradient(x, grad);
  }
  //    virtual double get_energy_gradient_hessian(Array<double> const & x,
  //    Array<double> & grad, Array<double> & hess)
  //    {
  //        grad.assign(0);
  //        hess.assign(0);
  //        return add_energy_gradient_hessian(x, grad, hess);
  //    }
  virtual double add_energy_gradient(Array<double> const &x,
                                     Array<double> &grad);
  //    virtual double add_energy_gradient_hessian(Array<double> const & x,
  //    Array<double> & grad, Array<double> & hess);
};

template <typename pairwise_interaction, typename distance_policy>
inline double SimplePairwiseNeighborList<
    pairwise_interaction,
    distance_policy>::add_energy_gradient(Array<double> const &x,
                                          Array<double> &grad) {
  double e = 0.;
  double gij, dr[_ndim];
  const size_t nlist = _neighbor_list.size();
  assert(x.size() == grad.size());

  //    grad.assign(0.);

#ifndef NDEBUG
  const size_t natoms = x.size() / _ndim;
  for (size_t i = 0; i < nlist; ++i) {
    assert(_neighbor_list[i] < natoms);
  }
#endif

  for (size_t i = 0; i < nlist; i += 2) {
    size_t atom1 = _neighbor_list[i];
    size_t atom2 = _neighbor_list[i + 1];
    size_t i1 = _ndim * atom1;
    size_t i2 = _ndim * atom2;

    for (size_t k = 0; k < _ndim; ++k) {
      dr[k] = x[i1 + k] - x[i2 + k];
    }

    double r2 = 0;
    for (size_t k = 0; k < _ndim; ++k) {
      r2 += dr[k] * dr[k];
    }

    e += _interaction->energy_gradient(r2, &gij,
                                       get_non_additive_cutoff(atom1, atom2));
    for (size_t k = 0; k < _ndim; ++k) {
      grad[i1 + k] -= gij * dr[k];
    }
    for (size_t k = 0; k < _ndim; ++k) {
      grad[i2 + k] += gij * dr[k];
    }
  }

  return e;
}

template <typename pairwise_interaction, typename distance_policy>
inline double
SimplePairwiseNeighborList<pairwise_interaction, distance_policy>::get_energy(
    Array<double> const &x) {
  double e = 0.;
  size_t const nlist = _neighbor_list.size();

  for (size_t i = 0; i < nlist; i += 2) {
    size_t atom1 = _neighbor_list[i];
    size_t atom2 = _neighbor_list[i + 1];
    size_t i1 = _ndim * atom1;
    size_t i2 = _ndim * atom2;
    double dr[_ndim];
    for (size_t k = 0; k < _ndim; ++k) {
      dr[k] = x[i1 + k] - x[i2 + k];
    }
    double r2 = 0;
    for (size_t k = 0; k < _ndim; ++k) {
      r2 += dr[k] * dr[k];
    }
    e += _interaction->energy(r2, get_non_additive_cutoff(atom1, atom2));
  }

  return e;
}
}  // namespace pele

#endif