pele
Python energy landscape explorer
/home/js850/projects/pele/source/pele/frozen_atoms.h
00001 #ifndef _PELE_FROZEN_ATOMS_H
00002 #define _PELE_FROZEN_ATOMS_H
00003 
00004 #include <vector>
00005 #include <algorithm>
00006 #include <set>
00007 #include <assert.h>
00008 #include <iostream>
00009 #include <memory>
00010 
00011 #include "array.h"
00012 #include "base_potential.h"
00013 
00014 namespace pele{
00021 class FrozenCoordsConverter
00022 {
00023 private:
00024     std::vector<double> const _reference_coords;
00025     std::vector<size_t> _frozen_dof;
00026     std::vector<size_t> _mobile_dof;
00027 public:
00028     FrozenCoordsConverter(Array<double> const & reference_coords, 
00029             Array<size_t> const & frozen_dof) :
00030         _reference_coords(reference_coords.begin(), reference_coords.end())
00031     {
00032         //populate _frozen_dof after removing duplicates and sorting
00033         std::set<size_t> frozenset(frozen_dof.begin(), frozen_dof.end());
00034         _frozen_dof = std::vector<size_t>(frozenset.begin(), frozenset.end());
00035         std::sort(_frozen_dof.begin(), _frozen_dof.end());
00036 
00037         // do a sanity check
00038         if (_frozen_dof.size() > 0){
00039             if (_frozen_dof[_frozen_dof.size()-1] >= (size_t)ndof()) {
00040                 throw std::runtime_error("index of frozen degree of freedom is out of bounds");
00041             }
00042         }
00043 
00044         //populate _mobile_dof
00045         _mobile_dof = std::vector<size_t>(ndof() - ndof_frozen());
00046         size_t imobile = 0;
00047         for (size_t i=0; i<_reference_coords.size(); ++i){
00048             // if degree of freedom i is not in frozen, add it to _mobile_dof
00049             if (frozenset.count(i) == 0){
00050                 _mobile_dof[imobile] = i;
00051                 ++imobile;
00052             }
00053         }
00054         assert(imobile == _mobile_dof.size());
00055 
00056     }
00057 
00058     size_t ndof() const { return _reference_coords.size(); }
00059     size_t ndof_frozen() const { return _frozen_dof.size(); }
00060     size_t ndof_mobile() const { return _mobile_dof.size(); }
00061 
00066     Array<double> get_reduced_coords(Array<double> const &full_coords){
00067         if (full_coords.size() != ndof()) {
00068             std::invalid_argument("full_coords has the wrong size");
00069         }
00070         Array<double> reduced_coords(ndof_mobile());
00071         for (size_t i=0; i < ndof_mobile(); ++i){
00072             reduced_coords[i] = full_coords[_mobile_dof[i]];
00073         }
00074         return reduced_coords;
00075     }
00076 
00081     Array<double> get_full_coords(Array<double> const &reduced_coords)
00082     {
00083         if (reduced_coords.size() != ndof_mobile()) {
00084             std::invalid_argument("reduced_coords has the wrong size");
00085         }
00086         // make a new array full_coords as a copy of _reference_coords.
00087         //Array<double> const a(_reference_coords); //wrap _reference_coords in an Array (returns error due to _reference_coords being const)
00089         Array<double> full_coords(ndof());
00090         for (size_t i=0; i < ndof(); ++i){
00091             full_coords[i] = _reference_coords[i];
00092         }
00093         // replace the mobile degrees of freedom with those in reduced_coords
00094         for (size_t i=0; i < _mobile_dof.size(); ++i){
00095             full_coords[_mobile_dof[i]] = reduced_coords[i];
00096         }
00097         return full_coords;
00098     }
00099 
00104     Array<double> get_full_grad(Array<double> const &reduced_grad)
00105     {
00106         if (reduced_grad.size() != ndof_mobile()) {
00107             std::invalid_argument("reduced_grad has the wrong size");
00108         }
00109         Array<double> full_grad(ndof(), 0.);
00110         // replace the mobile degrees of freedom with those in reduced_grad
00111         for (size_t i=0; i < _mobile_dof.size(); ++i){
00112             full_grad[_mobile_dof[i]] = reduced_grad[i];
00113         }
00114         return full_grad;
00115     }
00116 
00120     Array<double> get_reduced_hessian(Array<double> const full_hess)
00121     {
00122         if (full_hess.size() != ndof()*ndof()) {
00123             std::invalid_argument("full_hessian has the wrong size");
00124         }
00125         Array<double> reduced_hess(ndof_mobile() * ndof_mobile());
00126 //                size_t const N = ndof_mobile();
00127         for (size_t i=0; i < ndof_mobile(); ++i){
00128             for (size_t j=0; j < ndof_mobile(); ++j){
00129                 size_t k_red = i * ndof_mobile() + j;
00130                 size_t k_full = _mobile_dof[i] * ndof() + _mobile_dof[j];
00131                 reduced_hess[k_red] = full_hess[k_full];
00132             }
00133         }
00134         return reduced_hess;
00135     }
00136 
00137 };
00138 
00139 
00140 template<typename PotentialType>
00141 class FrozenPotentialWrapper : public BasePotential
00142 {
00143 public:
00144     FrozenCoordsConverter coords_converter;
00145 protected:
00146     std::shared_ptr<PotentialType> _underlying_potential;
00147 
00148     FrozenPotentialWrapper(std::shared_ptr<PotentialType> potential,
00149             Array<double> const &reference_coords,
00150             Array<size_t> const & frozen_dof) :
00151         coords_converter(reference_coords, frozen_dof),
00152         _underlying_potential(potential)
00153     {}
00154 
00155 public:
00156     ~FrozenPotentialWrapper() {}
00157 
00158 //            inline size_t ndof() const { return coords_converter.ndof(); }
00159 //            inline size_t ndof_frozen() const { return coords_converter.ndof_frozen(); }
00160 //            inline size_t ndof_mobile() const { return coords_converter.ndof_mobile(); }
00161 //            inline Array<double> get_reduced_coords(Array<double> const &full_coords){
00162 //                return coords_converter.get_reduced_coords(full_coords);
00163 //            }
00164 //            Array<double> get_full_coords(Array<double> const &reduced_coords){
00165 //                return coords_converter.get_full_coords(reduced_coords);
00166 //            }
00167 
00168     inline double get_energy(Array<double> reduced_coords) 
00169     {
00170         if (reduced_coords.size() != coords_converter.ndof_mobile()){
00171             throw std::runtime_error("reduced coords does not have the right size");
00172         }
00173         Array<double> full_coords(coords_converter.get_full_coords(reduced_coords));
00174         return _underlying_potential->get_energy(full_coords);
00175     }
00176 
00177     inline double get_energy_gradient(Array<double> reduced_coords, Array<double> reduced_grad) 
00178     {
00179         if (reduced_coords.size() != coords_converter.ndof_mobile()){
00180             throw std::runtime_error("reduced coords does not have the right size");
00181         }
00182         if (reduced_grad.size() != coords_converter.ndof_mobile()) {
00183             throw std::invalid_argument("reduced_grad has the wrong size");
00184         }
00185         
00186         Array<double> full_coords(coords_converter.get_full_coords(reduced_coords));
00187         Array<double> gfull(coords_converter.ndof());
00188         double energy = _underlying_potential->get_energy_gradient(full_coords, gfull);
00189         Array<double> gred = coords_converter.get_reduced_coords(gfull);
00190         for (size_t i = 0; i < gred.size(); ++i){
00191             reduced_grad[i] = gred[i];
00192         }
00193         return energy;
00194     }
00195 
00196     inline double get_energy_gradient_hessian(Array<double> reduced_coords,
00197             Array<double> reduced_grad, Array<double> reduced_hess)
00198     {
00199         if (reduced_coords.size() != coords_converter.ndof_mobile()){
00200             throw std::runtime_error("reduced coords does not have the right size");
00201         }
00202         if (reduced_grad.size() != coords_converter.ndof_mobile()) {
00203             throw std::invalid_argument("reduced_grad has the wrong size");
00204         }
00205         if (reduced_hess.size() != coords_converter.ndof_mobile()*coords_converter.ndof_mobile()){
00206             throw std::invalid_argument("reduced_hess has the wrong size");
00207         }
00208         Array<double> full_coords(coords_converter.get_full_coords(reduced_coords));
00209         Array<double> gfull(coords_converter.ndof());
00210         Array<double> hfull(coords_converter.ndof()*coords_converter.ndof());
00211         const double energy = _underlying_potential->get_energy_gradient_hessian(full_coords, gfull, hfull);
00212         Array<double> gred = coords_converter.get_reduced_coords(gfull);
00213         Array<double> hred = coords_converter.get_reduced_hessian(hfull);
00214         reduced_grad.assign(gred);
00215         reduced_hess.assign(hred);
00216         return energy;
00217     }
00218 };
00219 }
00220 
00221 #endif
 All Classes Namespaces Functions Variables Typedefs