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 : std::vector<Vector> positions; 56 : 57 : // remove atoms not in PDB file 58 : std::vector<AtomNumber> addtotree, addtoroot; 59 : std::vector<AtomNumber> newatoms; 60 2 : newatoms.reserve(atoms.size()); 61 2 : positions.reserve(atoms.size()); 62 2 : tree.reserve(atoms.size()); 63 2 : root_.reserve(atoms.size()); 64 2 : if(!moldat_->checkForAtom(atoms[0])) { 65 0 : plumed_merror("The first atom in the list should be present in the PDB file"); 66 : } 67 : // store first atom 68 2 : newatoms.push_back(atoms[0]); 69 2 : positions.push_back(moldat_->getPosition(atoms[0])); 70 245 : for(unsigned i=1; i<atoms.size(); ++i) { 71 243 : if(!moldat_->checkForAtom(atoms[i])) { 72 : // store this atom for later 73 61 : addtotree.push_back(atoms[i]); 74 : // along with its root (the previous atom) 75 61 : addtoroot.push_back(atoms[i-1]); 76 : } else { 77 182 : newatoms.push_back(atoms[i]); 78 364 : positions.push_back(moldat_->getPosition(atoms[i])); 79 : } 80 : } 81 : // reassign atoms 82 2 : atoms=newatoms; 83 : // start EMST 84 2 : std::vector<bool> intree(atoms.size(), false); 85 2 : std::vector<double> mindist(atoms.size(), std::numeric_limits<double>::max()); 86 : // initialize tree with first atom 87 2 : mindist[0] = 0.0; 88 : // loops 89 186 : for(unsigned i=0; i<atoms.size(); ++i) { 90 : int selected_vertex = -1; 91 19034 : for(unsigned j=0; j<atoms.size(); ++j) { 92 18850 : if( !intree[j] && (selected_vertex==-1 || mindist[j] < mindist[selected_vertex]) ) { 93 1078 : selected_vertex = j; 94 : } 95 : } 96 : // add to tree 97 184 : plumed_assert(selected_vertex>=0); 98 184 : tree.push_back(atoms[selected_vertex]); 99 : intree[selected_vertex] = true; 100 : // update distances 101 : double minroot = std::numeric_limits<double>::max(); 102 : int iroot = -1; 103 19034 : for(unsigned j=0; j<atoms.size(); ++j) { 104 18850 : double dist = delta(positions[selected_vertex], positions[j]).modulo2(); 105 18850 : if(dist < mindist[j]) { 106 4312 : mindist[j] = dist; 107 : } 108 22401 : if(dist < minroot && intree[j] && dist>0.0) { 109 : minroot = dist; 110 2822 : iroot = j; 111 : } 112 : } 113 : // add to root vector 114 184 : if(iroot>=0) { 115 182 : root_.push_back(atoms[iroot]); 116 : } 117 : } 118 : 119 : // now re-add atoms not present in the PDB 120 63 : for(unsigned i=0; i<addtotree.size(); ++i) { 121 61 : tree.push_back(addtotree[i]); 122 61 : root_.push_back(addtoroot[i]); 123 : } 124 : 125 : // return 126 2 : return tree; 127 : } 128 : 129 2 : std::vector<AtomNumber> Tree::getRoot() const { 130 2 : return root_; 131 : } 132 : 133 : }