pele
Python energy landscape explorer
|
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