pele
Python energy landscape explorer
/home/js850/projects/pele/source/pele/aatopology.h
00001 
00007 #ifndef _PELE_AATOPOLOGY_H_
00008 #define _PELE_AATOPOLOGY_H_
00009 
00010 #include <string>
00011 #include <list>
00012 #include <cmath>
00013 #include <stdexcept>
00014 
00015 #include "pele/array.h"
00016 #include "pele/rotations.h"
00017 #include "pele/base_potential.h"
00018 #include "pele/vecn.h"
00019 #include "pele/lowest_eig_potential.h"
00020 #include "pele/matrix.h"
00021 #include "pele/distance.h"
00022 
00023 namespace pele{
00024 
00025 
00026 
00027 
00038 class CoordsAdaptor {
00039     size_t _nrigid;  
00040     size_t _natoms;  
00041     pele::Array<double> _coords;
00042     static const size_t _ndim = 3;
00043 
00044 public:
00045     CoordsAdaptor(size_t nrigid, size_t natoms, pele::Array<double> coords)
00046         : _nrigid(nrigid),
00047           _natoms(natoms),
00048           _coords(coords)
00049     {
00050         if (coords.size() != (6*_nrigid + 3*_natoms)) {
00051             throw std::invalid_argument(std::string("coords has the wrong size ") + std::to_string(coords.size()));
00052         }
00053         if (natoms != 0)
00054             throw std::runtime_error("coords adaptor doesn't support free atoms yet");
00055     }
00056 
00060     pele::Array<double> get_coords() { return _coords; }
00061 
00065     pele::Array<double> get_rb_positions()
00066     {
00067         if (_nrigid == 0) {
00068             // return empty array
00069             return pele::Array<double>();
00070         }
00071         return _coords.view(0, 3*_nrigid);
00072     }
00073 
00077     pele::Array<double> get_rb_position(size_t isite)
00078     {
00079         if (_nrigid == 0) {
00080             // return empty array
00081             return pele::Array<double>();
00082         }
00083         if (isite > _nrigid) {
00084             throw std::invalid_argument("isite must be less than nrigid");
00085         }
00086         size_t const istart = 3*isite;
00087         return _coords.view(istart, istart+3);
00088     }
00089 
00093     pele::Array<double> get_rb_rotations()
00094     {
00095         if (_nrigid == 0) {
00096             // return empty array
00097             return pele::Array<double>();
00098         }
00099         return _coords.view(3*_nrigid, 6*_nrigid);
00100     }
00101 
00105    pele::Array<double> get_rb_rotation(size_t isite)
00106     {
00107         if (_nrigid == 0) {
00108             // return empty array
00109             return pele::Array<double>();
00110         }
00111         if (isite > _nrigid) {
00112             throw std::invalid_argument("isite must be less than nrigid");
00113         }
00114         size_t const istart = 3*_nrigid + 3*isite;
00115         return _coords.view(istart, istart+3);
00116     }
00117 
00118     pele::Array<double> get_atom_positions()
00119     {
00120         if (_natoms == 0) {
00121             // return empty array
00122             return pele::Array<double>();
00123         }
00124 
00125         return _coords.view(6*_nrigid, 6*_nrigid + 3*_natoms);
00126     }
00127 
00128 };
00129 
00130 // forward definition of RBTopology needed for TrasnformAACluster
00131 class RBTopology;
00132 
00136 class TransformPolicy {
00137 public:
00138 //    void translate(self, X, d) {
00139 //        ''' translate the coordinates '''
00140 //    }
00141     virtual ~TransformPolicy() {}
00142 
00146     virtual void rotate(pele::Array<double> x, pele::MatrixNM<3,3> const & mx) = 0;
00147 
00148 //    def can_invert(self):
00149 //        ''' returns True or False if an inversion can be performed'''
00150 //
00151 //    def invert(self, X):
00152 //        ''' perform an inversion at the origin '''
00153 //
00154 //    def permute(self, X, perm):
00155 //        ''' returns the permuted coordinates '''
00156 
00157 };
00158 
00162 class TransformAACluster : public TransformPolicy {
00163 public:
00164     pele::RBTopology * m_topology;
00165     TransformAACluster(pele::RBTopology * topology)
00166         : m_topology(topology)
00167     { }
00168     virtual ~TransformAACluster() {}
00169 
00173     void rotate(pele::Array<double> x, pele::MatrixNM<3,3> const & mx);
00174 //    inline void rotate(pele::Array<double> x, pele::Array<double> mx)
00175 //    {
00176 //        return rotate(x, pele::MatrixNM<3,3>(mx));
00177 //    }
00178 };
00179 
00180 class MeasureAngleAxisCluster {
00181 public:
00182     pele::RBTopology * m_topology;
00183     MeasureAngleAxisCluster(pele::RBTopology * topology)
00184         : m_topology(topology)
00185     { }
00186 
00190     void align(pele::Array<double> const x1, pele::Array<double> x2);
00191 
00192 
00193 };
00194 
00195 
00199 class RigidFragment {
00200     static const size_t _ndim = 3;
00201     pele::Array<double> _atom_positions;
00202     pele::MatrixAdapter<double> _atom_positions_matrix;
00203     size_t _natoms;
00204 
00205     std::shared_ptr<DistanceInterface> m_distance_function;
00206 
00207     double m_M; // total mass of the angle axis site
00208     double m_W; // sum of all weights
00209     pele::VecN<3> m_cog; // center of gravity
00210     pele::MatrixNM<3,3> m_S; // weighted tensor of gyration S_ij = \sum m_i x_i x_j
00211     pele::MatrixNM<3,3> m_inversion; // matrix that applies the appropriate inversion
00212     bool m_can_invert;
00213 
00214     // a list of rotations that leave the rigid body unchanged.
00215     std::vector<pele::MatrixNM<3,3> > m_symmetry_rotations;
00216 
00217 
00218 public:
00219     RigidFragment(pele::Array<double> atom_positions,
00220             Array<double> cog,
00221             double M,
00222             double W,
00223             Array<double> S,
00224             Array<double> inversion, bool can_invert,
00225             std::shared_ptr<DistanceInterface> distance_function
00226             )
00227     : _atom_positions(atom_positions.copy()),
00228       _atom_positions_matrix(_atom_positions, _ndim),
00229       _natoms(_atom_positions.size() / _ndim),
00230       m_distance_function(distance_function),
00231       m_M(M),
00232       m_W(W),
00233       m_cog(cog),
00234       m_S(S),
00235       m_inversion(inversion),
00236       m_can_invert(can_invert)
00237     {
00238         if (_atom_positions.size() == 0 ) {
00239             throw std::invalid_argument("the atom positions must not have zero size");
00240         }
00241         if (_atom_positions.size() != _natoms * _ndim ) {
00242             throw std::invalid_argument("the length of atom_positions must be divisible by 3");
00243         }
00244     }
00245 
00249     inline size_t natoms() const { return _natoms; }
00250 
00254     inline void add_symmetry_rotation(pele::Array<double> R)
00255     {
00256         m_symmetry_rotations.push_back(R);
00257     }
00258 
00262     inline std::vector<pele::MatrixNM<3,3> > const & get_symmetry_rotations() const
00263     {
00264         return m_symmetry_rotations;
00265     }
00266 
00270     pele::Array<double> to_atomistic(pele::Array<double> const com,
00271             pele::VecN<3> const & p);
00272 
00277     void transform_grad(
00278             pele::VecN<3> const & p,
00279             pele::Array<double> const g,
00280             pele::VecN<3> & g_com,
00281             pele::VecN<3> & g_rot
00282             );
00283 
00291     void transform_grad(
00292             pele::Array<double> const p,
00293             pele::Array<double> const g,
00294             pele::Array<double> g_com,
00295             pele::Array<double> g_rot
00296             )
00297     {
00298         pele::VecN<3> p_vec = p;
00299         pele::VecN<3> g_com_vec = g_com;
00300         pele::VecN<3> g_rot_vec = g_rot;
00301         transform_grad(p_vec, g, g_com_vec, g_rot_vec);
00305         for (size_t i = 0; i<3; ++i) {
00306             g_com[i] = g_com_vec[i];
00307             g_rot[i] = g_rot_vec[i];
00308         }
00309 
00310     }
00311 
00317     inline pele::VecN<3> get_smallest_rij(pele::VecN<3> const & com1, pele::VecN<3> const & com2) const
00318     {
00319         pele::VecN<3> distance;
00320         m_distance_function->get_rij(distance.data(), com2.data(), com1.data());
00321         return distance;
00322     }
00323 
00327     double distance_squared(pele::VecN<3> const & com1, pele::VecN<3> const & p1,
00328             pele::VecN<3> const & com2, pele::VecN<3> const & p2) const;
00329 
00330     void distance_squared_grad(pele::VecN<3> const & com1, pele::VecN<3> const & p1,
00331             pele::VecN<3> const & com2, pele::VecN<3> const & p2,
00332             VecN<3> & g_M, VecN<3> & g_P
00333             ) const;
00334 };
00335 
00337 // * Angle axis topology
00338 // *
00339 // * An angle axis topology stores all topology information for an angle axis
00340 // * system. The AATopology is composed of several angle axis sites,
00341 // * which describe the shape of the angle axis site and each site carries a
00342 // * position and orientation. Therefore, the length of the coordinate array
00343 // * must be 6*number_of_sites.
00344 // */
00345 //class AATopology {
00346 //};
00347 
00351 class RBTopology {
00352     std::vector<RigidFragment> _sites;
00353     size_t _natoms_total;
00354 
00355 public:
00356     RBTopology()
00357         : _natoms_total(0)
00358     {}
00359 
00360     void add_site(RigidFragment const & site)
00361     {
00362         _sites.push_back(site);
00363         _natoms_total += site.natoms();
00364     }
00365 
00369     std::vector<RigidFragment> const & get_sites() const { return _sites; };
00370 
00374     size_t nrigid() const { return _sites.size(); }
00375 
00379     size_t natoms_total() const { return _natoms_total; }
00380 
00381     size_t number_of_non_rigid_atoms() const { return 0; }
00382 
00386     CoordsAdaptor get_coords_adaptor(pele::Array<double> x) const
00387     {
00388         return CoordsAdaptor(nrigid(), number_of_non_rigid_atoms(), x);
00389     }
00390 
00394     Array<double> to_atomistic(Array<double> rbcoords);
00395 
00399     void transform_gradient(pele::Array<double> rbcoords,
00400             pele::Array<double> grad, pele::Array<double> rbgrad);
00401 
00407     pele::VecN<3> align_angle_axis_vectors(pele::VecN<3> const & p1,
00408             pele::VecN<3> const & p2in);
00409 
00415     void align_all_angle_axis_vectors(pele::Array<double> x1,
00416             pele::Array<double> x2);
00417 
00423     void align_path(std::list<pele::Array<double> > path);
00424 
00431     void get_zero_modes(pele::Array<double> const x,
00432             std::vector<pele::Array<double> > & zev)
00433     {
00434         auto ca = get_coords_adaptor(x);
00435         pele::Array<double> v(x.size(), 0);
00436         auto cv = get_coords_adaptor(v);
00437 
00438         // get the zero eigenvectors corresponding to translation
00439         std::vector<pele::Array<double> > zev_t;
00440         pele::zero_modes_translational(zev_t, nrigid(), 3);
00441 
00442         for (auto const & v : zev_t) {
00443             cv.get_rb_positions().assign(v);
00444             zev.push_back(cv.get_coords().copy());
00445         }
00446 
00447         // get the zero eigenvectors corresponding to rotation
00448         TransformAACluster transform(this);
00449         double d = 1e-5;
00450         pele::VecN<3> v3;
00451         pele::Array<double> delta(x.size());
00452 
00453         // do rotations around the x y and z axes
00454         for (size_t i = 0; i < 3; ++i) {
00455             delta.assign(x);
00456             v3.assign(0);
00457             v3[i] = d;
00458             transform.rotate(delta, pele::aa_to_rot_mat(v3));
00459             align_all_angle_axis_vectors(x, delta);
00460             delta -= x;
00461             delta /= norm(delta);
00462             zev.push_back(delta.copy());
00463         }
00464     }
00465 
00469     double distance_squared(pele::Array<double> const x1, pele::Array<double> const x2) const
00470     {
00471         double d_sq = 0;
00472         auto ca1 = get_coords_adaptor(x1);
00473         auto ca2 = get_coords_adaptor(x2);
00474         for (size_t isite = 0; isite < nrigid(); ++isite) {
00475             d_sq += _sites[isite].distance_squared(
00476                     ca1.get_rb_position(isite),
00477                     ca1.get_rb_rotation(isite),
00478                     ca2.get_rb_position(isite),
00479                     ca2.get_rb_rotation(isite)
00480                 );
00481         }
00482         return d_sq;
00483     }
00484 
00490     void distance_squared_grad(pele::Array<double> const x1, pele::Array<double> const x2,
00491             pele::Array<double> grad
00492             ) const
00493     {
00494         if (grad.size() != x1.size()) {
00495             throw std::runtime_error("grad has the wrong size");
00496         }
00497         grad.assign(0);
00498         auto ca1 = get_coords_adaptor(x1);
00499         auto ca2 = get_coords_adaptor(x2);
00500         auto ca_spring = get_coords_adaptor(grad);
00501 
00502         // first distance for sites only
00503         for (size_t isite=0; isite<nrigid(); ++isite) {
00504             pele::VecN<3> g_M, g_P;
00505             _sites[isite].distance_squared_grad(
00506                     ca1.get_rb_position(isite),
00507                     ca1.get_rb_rotation(isite),
00508                     ca2.get_rb_position(isite),
00509                     ca2.get_rb_rotation(isite),
00510                     g_M, g_P);
00511             auto spring_com = ca_spring.get_rb_position(isite);
00512             std::copy(g_M.begin(), g_M.end(), spring_com.begin());
00513             auto spring_rot = ca_spring.get_rb_rotation(isite);
00514             std::copy(g_P.begin(), g_P.end(), spring_rot.begin());
00515         }
00516     }
00517 };
00518 
00526 class RBPotentialWrapper : public BasePotential {
00527     std::shared_ptr<BasePotential> potential_;
00528     std::shared_ptr<RBTopology> topology_;
00529 public:
00530 
00531     RBPotentialWrapper(std::shared_ptr<BasePotential> potential,
00532             std::shared_ptr<RBTopology> top)
00533         : potential_(potential),
00534           topology_(top)
00535 
00536     {}
00537 
00538     inline double get_energy(pele::Array<double> rbcoords)
00539     {
00540         auto x = topology_->to_atomistic(rbcoords);
00541         return potential_->get_energy(x);
00542     }
00543 
00544     inline double get_energy_gradient(pele::Array<double> rbcoords,
00545             pele::Array<double> rbgrad)
00546     {
00547         auto x = topology_->to_atomistic(rbcoords);
00548         pele::Array<double> grad_atomistic(topology_->natoms_total() * 3);
00549         double e = potential_->get_energy_gradient(x, grad_atomistic);
00550         topology_->transform_gradient(rbcoords, grad_atomistic, rbgrad);
00551         return e;
00552     }
00553 };
00554 
00555 }
00556 
00557 #endif
 All Classes Namespaces Functions Variables Typedefs