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_) { 38 0 : plumed_merror("MOLINFO DATA not found"); 39 : } 40 : // check if reference structure is whole 41 2 : if(!moldat_->isWhole()) { 42 0 : plumed_merror("Check that reference structure in PDB file is not broken by pbc and set WHOLE in MOLINFO line"); 43 : } 44 2 : } 45 : 46 2 : std::vector<AtomNumber> Tree::getTree(std::vector<AtomNumber> atoms) { 47 : // Implementation inspired from: 48 : // https://mayanknatani.wordpress.com/2013/05/31/euclidean-minimummaximum-spanning-tree-emst/ 49 : // 50 : // list of AtomNumbers ordered by proximity in PDB file 51 : std::vector<AtomNumber> tree; 52 : // clear root_ vector 53 2 : root_.clear(); 54 : 55 : // remove atoms not in PDB file 56 : std::vector<AtomNumber> addtotree, addtoroot; 57 : std::vector<AtomNumber> newatoms; 58 2 : newatoms.reserve(atoms.size()); 59 2 : if(!moldat_->checkForAtom(atoms[0])) { 60 0 : plumed_merror("The first atom in the list should be present in the PDB file"); 61 : } 62 : // store first atom 63 2 : newatoms.push_back(atoms[0]); 64 245 : for(unsigned i=1; i<atoms.size(); ++i) { 65 243 : if(!moldat_->checkForAtom(atoms[i])) { 66 : // store this atom for later 67 61 : addtotree.push_back(atoms[i]); 68 : // along with its root (the previous atom) 69 61 : addtoroot.push_back(atoms[i-1]); 70 : } else { 71 182 : newatoms.push_back(atoms[i]); 72 : } 73 : } 74 : // reassign atoms 75 2 : atoms=newatoms; 76 : // start EMST 77 2 : std::vector<bool> intree(atoms.size(), false); 78 2 : std::vector<double> mindist(atoms.size(), std::numeric_limits<double>::max()); 79 : // initialize tree with first atom 80 2 : mindist[0] = 0.0; 81 : // loops 82 186 : for(unsigned i=0; i<atoms.size(); ++i) { 83 : int selected_vertex = -1; 84 19034 : for(unsigned j=0; j<atoms.size(); ++j) { 85 18850 : if( !intree[j] && (selected_vertex==-1 || mindist[j] < mindist[selected_vertex]) ) { 86 1078 : selected_vertex = j; 87 : } 88 : } 89 : // add to tree 90 184 : plumed_assert(selected_vertex>=0); 91 184 : tree.push_back(atoms[selected_vertex]); 92 : intree[selected_vertex] = true; 93 : // update distances 94 : double minroot = std::numeric_limits<double>::max(); 95 : int iroot = -1; 96 19034 : for(unsigned j=0; j<atoms.size(); ++j) { 97 18850 : double dist = delta(moldat_->getPosition(atoms[selected_vertex]), moldat_->getPosition(atoms[j])).modulo2(); 98 18850 : if(dist < mindist[j]) { 99 4312 : mindist[j] = dist; 100 : } 101 22401 : if(dist < minroot && intree[j] && dist>0.0) { 102 : minroot = dist; 103 2822 : iroot = j; 104 : } 105 : } 106 : // add to root vector 107 184 : if(iroot>=0) { 108 182 : root_.push_back(atoms[iroot]); 109 : } 110 : } 111 : 112 : // now re-add atoms not present in the PDB 113 63 : for(unsigned i=0; i<addtotree.size(); ++i) { 114 61 : tree.push_back(addtotree[i]); 115 61 : root_.push_back(addtoroot[i]); 116 : } 117 : 118 : // return 119 2 : return tree; 120 : } 121 : 122 2 : std::vector<AtomNumber> Tree::getRoot() const { 123 2 : return root_; 124 : } 125 : 126 : }