mcpele
1.0.0
The Monte Carlo Python Energy Landscape Explorer
|
00001 #ifndef _PELE_LOWEST_EIG_POTENTIAL_H 00002 #define _PELE_LOWEST_EIG_POTENTIAL_H 00003 00004 #include "base_potential.h" 00005 #include "array.h" 00006 #include <algorithm> 00007 #include <vector> 00008 #include <cmath> 00009 #include <memory> 00010 00011 namespace pele { 00012 00013 inline void zero_modes_translational(std::vector<pele::Array<double> > & zev, 00014 size_t natoms, size_t bdim) 00015 { 00016 double v = 1 / sqrt(natoms); 00017 size_t N = natoms * bdim; 00018 for(size_t i=0; i<bdim; ++i) { 00019 pele::Array<double> evec(N, 0); //initialize array of zeros 00020 for(size_t j=i; j<N; j+=bdim) { 00021 evec[j] = v; 00022 } 00023 zev.push_back(evec); 00024 } 00025 } 00026 00027 class Orthogonalize{ 00028 public: 00029 virtual ~Orthogonalize(){}; 00030 virtual void orthogonalize(Array<double>& coords, Array<double>& vector) =0; 00031 }; 00032 00033 class OrthogonalizeTranslational : public Orthogonalize{ 00034 protected: 00035 std::vector<pele::Array<double>> _tr_evec; 00036 size_t _natoms, _bdim, _ndim; 00037 double _d, _tol; 00038 public: 00039 00040 //OrthogonalizeTranslational(size_t natoms, size_t bdim, double tol=1e-6); 00041 OrthogonalizeTranslational(size_t natoms, size_t bdim, double tol=1e-6) 00042 : _natoms(natoms), _bdim(bdim), _ndim(bdim*natoms), _tol(tol) 00043 { 00044 /*initialize translational eigenvectors to canonical orthonormal basis*/ 00045 zero_modes_translational(_tr_evec, _natoms, _bdim); 00046 } 00047 00048 virtual ~OrthogonalizeTranslational() {} 00049 00050 //virtual inline void orthogonalize(Array<double>& coords, Array<double>& vector); 00051 virtual inline void orthogonalize(Array<double>& coords, Array<double>& vector) 00052 { 00053 bool success = true; 00054 pele::Array<double> dot_prod(_bdim); 00055 vector /= norm(vector); 00056 //generally in this loop success will be set to false 00057 for (size_t i=0; i<_bdim;++i) { 00058 dot_prod[i] = dot(_tr_evec[i],vector); 00059 if(std::abs(dot_prod[i]) > _tol){success = false;}; 00060 } 00061 00062 while (success == false) { 00063 success = true; 00064 for (size_t i=0; i<_bdim;++i) { 00065 for(size_t j=0;j<_ndim;++j) { 00066 vector[j] -= dot_prod[i]*_tr_evec[i][j]; 00067 } 00068 } 00069 vector /= norm(vector); 00070 for (size_t i=0; i<_bdim;++i) { 00071 dot_prod[i] = dot(_tr_evec[i],vector); 00072 if (std::abs(dot_prod[i]) > _tol) { 00073 success = false; 00074 }; 00075 } 00076 } 00077 } 00078 00079 }; //class OrthogonalizeTranslational 00080 00081 /* 00082 * Lowest Eigenvalue Potential: 00083 * gd = g(x+d) 00084 * _v: normal unit vector in arbitrary direction 00085 * _d: finite difference step 00086 * */ 00087 00088 class LowestEigPotential : public BasePotential { 00089 protected: 00090 std::shared_ptr<pele::BasePotential> _potential; 00091 pele::Array<double> _coords, _coordsd, _g, _gd; 00092 size_t _bdim, _natoms; 00093 double _d; 00094 OrthogonalizeTranslational _orthog; 00095 public: 00096 00097 //LowestEigPotential(std::shared_ptr<pele::BasePotential> potential, pele::Array<double> 00098 // coords, size_t bdim, double d=1e-6); 00099 /*constructor*/ 00100 LowestEigPotential(std::shared_ptr<pele::BasePotential> potential, pele::Array<double>coords, 00101 size_t bdim, double d=1e-6) 00102 : _potential(potential), _coords(coords), _coordsd(coords.size()), 00103 _g(_coords.size()), _gd(_coords.size()), _bdim(bdim), 00104 _natoms(_coords.size()/_bdim), _d(d), _orthog(_natoms,_bdim) 00105 { 00106 _potential->get_energy_gradient(_coords,_g); 00107 } 00108 00109 00110 virtual ~LowestEigPotential(){} 00111 00112 00113 //virtual double inline get_energy(pele::Array<double> x); 00114 /* calculate energy from distance squared, r0 is the hard core distance, r is the distance between the centres */ 00115 virtual double inline get_energy(pele::Array<double> x) 00116 { 00117 _orthog.orthogonalize(_coords, x); //takes care of orthogonalizing and normalizing x 00118 00119 for (size_t i=0;i<x.size();++i) { 00120 _coordsd[i] = _coords[i] + _d*x[i]; 00121 } 00122 00123 _potential->get_energy_gradient(_coordsd,_gd); 00124 _gd -= _g; 00125 double mu = dot(_gd,x)/_d; 00126 00127 return mu; 00128 } 00129 00130 //virtual double inline get_energy_gradient(pele::Array<double> x, 00131 // pele::Array<double> grad); 00132 /* 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 */ 00133 virtual double inline get_energy_gradient(pele::Array<double> x, pele::Array<double> grad) 00134 { 00135 _orthog.orthogonalize(_coords, x); //takes care of orthogonalizing and normalizing x 00136 00137 for (size_t i=0;i<x.size();++i) { 00138 _coordsd[i] = _coords[i] + _d*x[i]; 00139 } 00140 00141 _potential->get_energy_gradient(_coordsd,_gd); 00142 _gd -= _g; 00143 double mu = dot(_gd,x)/_d; 00144 for (size_t i=0;i<x.size();++i) { 00145 grad[i] = 2*_gd[i]/_d - 2*mu*x[i]; 00146 } 00147 00148 return mu; 00149 } 00150 00151 //void reset_coords(pele::Array<double> new_coords); 00152 void reset_coords(pele::Array<double> new_coords) 00153 { 00154 _coords.assign(new_coords); 00155 _potential->get_energy_gradient(_coords,_g); 00156 } 00157 00158 00159 }; 00160 00161 }//namespace pele 00162 00163 #endif//#ifndef _PELE_LOWEST_EIG_POTENTIAL_H