Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2021-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : 23 : #include "Tree.h" 24 : #include "Tools.h" 25 : #include "Vector.h" 26 : #include "AtomNumber.h" 27 : #include "core/GenericMolInfo.h" 28 : #include <vector> 29 : #include <limits> 30 : 31 : namespace PLMD { 32 : 33 2 : Tree::Tree(GenericMolInfo* moldat) { 34 : // initialize class 35 2 : moldat_ = moldat; 36 : // check if molinfo present 37 2 : if(!moldat_) plumed_merror("MOLINFO DATA not found"); 38 : // check if reference structure is whole 39 2 : if(!moldat_->isWhole()) plumed_merror("Check that reference structure in PDB file is not broken by pbc and set WHOLE in MOLINFO line"); 40 2 : } 41 : 42 2 : std::vector<AtomNumber> Tree::getTree(std::vector<AtomNumber> atoms) 43 : { 44 : // Implementation inspired from: 45 : // https://mayanknatani.wordpress.com/2013/05/31/euclidean-minimummaximum-spanning-tree-emst/ 46 : // 47 : // list of AtomNumbers ordered by proximity in PDB file 48 : std::vector<AtomNumber> tree; 49 : // clear root_ vector 50 2 : root_.clear(); 51 : 52 : std::vector<Vector> positions; 53 : 54 : // remove atoms not in PDB file 55 : std::vector<AtomNumber> addtotree, addtoroot; 56 : std::vector<AtomNumber> newatoms; 57 2 : newatoms.reserve(atoms.size()); 58 2 : positions.reserve(atoms.size()); 59 2 : tree.reserve(atoms.size()); 60 2 : root_.reserve(atoms.size()); 61 2 : if(!moldat_->checkForAtom(atoms[0])) plumed_merror("The first atom in the list should be present in the PDB file"); 62 : // store first atom 63 2 : newatoms.push_back(atoms[0]); 64 2 : positions.push_back(moldat_->getPosition(atoms[0])); 65 245 : for(unsigned i=1; i<atoms.size(); ++i) { 66 243 : if(!moldat_->checkForAtom(atoms[i])) { 67 : // store this atom for later 68 61 : addtotree.push_back(atoms[i]); 69 : // along with its root (the previous atom) 70 61 : addtoroot.push_back(atoms[i-1]); 71 : } else { 72 182 : newatoms.push_back(atoms[i]); 73 364 : positions.push_back(moldat_->getPosition(atoms[i])); 74 : } 75 : } 76 : // reassign atoms 77 2 : atoms=newatoms; 78 : // start EMST 79 2 : std::vector<bool> intree(atoms.size(), false); 80 2 : std::vector<double> mindist(atoms.size(), std::numeric_limits<double>::max()); 81 : // initialize tree with first atom 82 2 : mindist[0] = 0.0; 83 : // loops 84 186 : for(unsigned i=0; i<atoms.size(); ++i) { 85 : int selected_vertex = -1; 86 19034 : for(unsigned j=0; j<atoms.size(); ++j) { 87 9517 : if( !intree[j] && (selected_vertex==-1 || mindist[j] < mindist[selected_vertex]) ) 88 1078 : selected_vertex = j; 89 : } 90 : // add to tree 91 184 : plumed_assert(selected_vertex>=0); 92 184 : tree.push_back(atoms[selected_vertex]); 93 : intree[selected_vertex] = true; 94 : // update distances 95 : double minroot = std::numeric_limits<double>::max(); 96 : int iroot = -1; 97 19034 : for(unsigned j=0; j<atoms.size(); ++j) { 98 18850 : double dist = delta(positions[selected_vertex], positions[j]).modulo2(); 99 18850 : if(dist < mindist[j]) mindist[j] = dist; 100 22401 : if(dist < minroot && intree[j] && dist>0.0) { 101 : minroot = dist; 102 2822 : iroot = j; 103 : } 104 : } 105 : // add to root vector 106 184 : if(iroot>=0) root_.push_back(atoms[iroot]); 107 : } 108 : 109 : // now re-add atoms not present in the PDB 110 63 : for(unsigned i=0; i<addtotree.size(); ++i) { 111 61 : tree.push_back(addtotree[i]); 112 61 : root_.push_back(addtoroot[i]); 113 : } 114 : 115 : // return 116 2 : return tree; 117 : } 118 : 119 2 : std::vector<AtomNumber> Tree::getRoot() const 120 : { 121 2 : return root_; 122 : } 123 : 124 : }