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 0 : Tree::Tree(GenericMolInfo* moldat) { 34 : // initialize class 35 0 : moldat_ = moldat; 36 : // check if molinfo present 37 0 : if(!moldat_) plumed_merror("MOLINFO DATA not found"); 38 : // check if reference structure is whole 39 0 : if(!moldat_->isWhole()) plumed_merror("Check that reference structure in PDB file is not broken by pbc and set WHOLE in MOLINFO line"); 40 0 : } 41 : 42 0 : 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 0 : root_.clear(); 51 : 52 : // remove atoms not in PDB file 53 : std::vector<AtomNumber> addtotree, addtoroot; 54 : std::vector<AtomNumber> newatoms; 55 0 : newatoms.reserve(atoms.size()); 56 0 : if(!moldat_->checkForAtom(atoms[0])) plumed_merror("The first atom in the list should be present in the PDB file"); 57 : // store first atom 58 0 : newatoms.push_back(atoms[0]); 59 0 : for(unsigned i=1; i<atoms.size(); ++i) { 60 0 : if(!moldat_->checkForAtom(atoms[i])) { 61 : // store this atom for later 62 0 : addtotree.push_back(atoms[i]); 63 : // along with its root (the previous atom) 64 0 : addtoroot.push_back(atoms[i-1]); 65 : } else { 66 0 : newatoms.push_back(atoms[i]); 67 : } 68 : } 69 : // reassign atoms 70 0 : atoms=newatoms; 71 : // start EMST 72 0 : std::vector<bool> intree(atoms.size(), false); 73 0 : std::vector<double> mindist(atoms.size(), std::numeric_limits<double>::max()); 74 : // initialize tree with first atom 75 0 : mindist[0] = 0.0; 76 : // loops 77 0 : for(unsigned i=0; i<atoms.size(); ++i) { 78 : int selected_vertex = -1; 79 0 : for(unsigned j=0; j<atoms.size(); ++j) { 80 0 : if( !intree[j] && (selected_vertex==-1 || mindist[j] < mindist[selected_vertex]) ) 81 0 : selected_vertex = j; 82 : } 83 : // add to tree 84 0 : plumed_assert(selected_vertex>=0); 85 0 : tree.push_back(atoms[selected_vertex]); 86 : intree[selected_vertex] = true; 87 : // update distances 88 : double minroot = std::numeric_limits<double>::max(); 89 : int iroot = -1; 90 0 : for(unsigned j=0; j<atoms.size(); ++j) { 91 0 : double dist = delta(moldat_->getPosition(atoms[selected_vertex]), moldat_->getPosition(atoms[j])).modulo2(); 92 0 : if(dist < mindist[j]) mindist[j] = dist; 93 0 : if(dist < minroot && intree[j] && dist>0.0) { 94 : minroot = dist; 95 0 : iroot = j; 96 : } 97 : } 98 : // add to root vector 99 0 : if(iroot>=0) root_.push_back(atoms[iroot]); 100 : } 101 : 102 : // now re-add atoms not present in the PDB 103 0 : for(unsigned i=0; i<addtotree.size(); ++i) { 104 0 : tree.push_back(addtotree[i]); 105 0 : root_.push_back(addtoroot[i]); 106 : } 107 : 108 : // return 109 0 : return tree; 110 : } 111 : 112 0 : std::vector<AtomNumber> Tree::getRoot() const 113 : { 114 0 : return root_; 115 : } 116 : 117 : }