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