pele
Python energy landscape explorer
/home/js850/projects/pele/source/pele/harmonic.h
00001 #ifndef _PELE_HARMONIC_H
00002 #define _PELE_HARMONIC_H
00003 
00004 #include <algorithm>
00005 #include <functional>
00006 
00007 #include "atomlist_potential.h"
00008 #include "base_potential.h"
00009 #include "distance.h"
00010 #include "simple_pairwise_ilist.h"
00011 
00012 namespace pele {
00013 
00014 class BaseHarmonic : public BasePotential {
00015 protected:
00016     virtual void _get_distance(const pele::Array<double>& x)=0;
00017     pele::Array<double> _origin;
00018     pele::Array<double> _distance;
00019     double _k;
00020     const size_t _ndim;
00021     const size_t _nparticles;
00022     BaseHarmonic(const pele::Array<double> origin, const double k, const size_t ndim)
00023         : _origin(origin.copy()),
00024           _distance(origin.size()),
00025           _k(k),
00026           _ndim(ndim),
00027           _nparticles(origin.size() / _ndim)
00028     {}
00029 public:
00030     virtual ~BaseHarmonic() {}
00031     virtual double inline get_energy(pele::Array<double> x);
00032     virtual double inline get_energy_gradient(pele::Array<double> x, pele::Array<double> grad);
00033     void set_k(double newk) { _k = newk; }
00034     double get_k() { return _k; }
00035 };
00036 
00037 
00038 /* calculate energy from distance squared, r0 is the hard core distance, r is the distance between the centres */
00039 double inline BaseHarmonic::get_energy(pele::Array<double> x) 
00040 {
00041     this->_get_distance(x);
00042     return 0.5 * _k * dot(_distance, _distance);
00043 }
00044 
00045 /* calculate energy and gradient from distance squared, gradient is in g/|rij|, r0 is the hard core distance, r is the distance between the centres */
00046 // It seems that there the gradient is not returned as -g/r, as in other places?
00047 double inline BaseHarmonic::get_energy_gradient(pele::Array<double> x, pele::Array<double> grad) 
00048 {
00049     assert(grad.size() == _origin.size());
00050     this->_get_distance(x);
00051     for (size_t i = 0; i < x.size(); ++i) {
00052         grad[i] = _k * _distance[i];
00053     }
00054     return 0.5 * _k * dot(_distance, _distance);
00055 }
00056 
00060 class Harmonic : public BaseHarmonic{
00061 public:
00062     Harmonic(pele::Array<double> origin, double k, size_t ndim)
00063         : BaseHarmonic(origin, k, ndim)
00064     {}
00065     virtual void inline _get_distance(const pele::Array<double>& x)
00066     {
00067         assert(x.size() == _origin.size());
00068         for (size_t i = 0; i < x.size(); ++i) {
00069             _distance[i] = x[i] - _origin[i];
00070         }
00071     }
00072 };
00073 
00077 class HarmonicCOM : public BaseHarmonic{
00078 public:
00079     HarmonicCOM(pele::Array<double> origin, double k, size_t ndim)
00080         : BaseHarmonic(origin, k, ndim)
00081     {}
00082     virtual void inline _get_distance(const pele::Array<double>& x)
00083     {
00084         assert(x.size() == _origin.size());
00085         pele::Array<double> delta_com(_ndim, 0);
00086 
00087         for (size_t i = 0; i < _nparticles; ++i) {
00088             const size_t i1 = i * _ndim;
00089             for (size_t j = 0; j < _ndim; ++j) {
00090                 const double d = x[i1 + j] - _origin[i1 + j];
00091                 _distance[i1 + j] = d;
00092                 delta_com[j] += d;
00093             }
00094         }
00095 
00096         delta_com /= _nparticles;
00097 
00098         for (size_t i = 0; i < _nparticles; ++i) {
00099             const size_t i1 = i * _ndim;
00100             for (size_t j = 0; j < _ndim; ++j) {
00101                 _distance[i1 + j] -= delta_com[j];
00102             }
00103         }
00104     }
00105 };
00106 
00107 
00108 /*
00109  * redo the harmonic potential in the pair potential framework
00110  */
00111 
00112 struct harmonic_interaction {
00113     double const m_k;
00114     harmonic_interaction(double k)
00115         : m_k(k)
00116     {}
00117 
00118     /* calculate energy from distance squared */
00119     double inline energy(double r2, size_t atom_i, size_t atom_j) const
00120     {
00121         return 0.5 * m_k * r2;
00122     }
00123 
00124     /* calculate energy and gradient from distance squared, gradient is in g/|rij| */
00125     double inline energy_gradient(double r2, double *gij, size_t atom_i, size_t atom_j) const
00126     {
00127         *gij = -m_k;
00128         return 0.5 * m_k * r2;
00129     }
00130 
00131     double inline energy_gradient_hessian(double r2, double *gij, double *hij,
00132             size_t atom_i, size_t atom_j) const
00133     {
00134         *gij = -m_k;
00135         *hij = 1.;
00136         return 0.5 * m_k * r2;
00137     }
00138 };
00139 
00143 class HarmonicAtomList : public AtomListPotential<harmonic_interaction, cartesian_distance<3> > {
00144 public:
00145     HarmonicAtomList(double k, Array<size_t> atoms1, Array<size_t> atoms2)
00146         : AtomListPotential<harmonic_interaction, cartesian_distance<3> >(
00147                 std::make_shared<harmonic_interaction>(k),
00148                 std::make_shared<cartesian_distance<3>>(), atoms1, atoms2)
00149     {}
00150 
00151     HarmonicAtomList(double k, Array<size_t> atoms1)
00152         : AtomListPotential<harmonic_interaction, cartesian_distance<3> >(
00153                 std::make_shared<harmonic_interaction>(k),
00154                 std::make_shared<cartesian_distance<3>>(), atoms1)
00155     {}
00156 };
00157 
00161 class HarmonicNeighborList : public SimplePairwiseNeighborList<harmonic_interaction> {
00162 public:
00163     HarmonicNeighborList(double k, Array<size_t> ilist)
00164         :  SimplePairwiseNeighborList<harmonic_interaction>(
00165                 std::make_shared<harmonic_interaction>(k), ilist)
00166     {}
00167 };
00168 
00169 } // namespace pele
00170 
00171 #endif // #ifndef _PELE_HARMONIC_H
 All Classes Namespaces Functions Variables Typedefs