Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2014-2020 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 : #include "ClusteringBase.h" 23 : #include "core/ActionRegister.h" 24 : 25 : #ifdef __PLUMED_HAS_BOOST_GRAPH 26 : #include <boost/graph/adjacency_list.hpp> 27 : #include <boost/graph/connected_components.hpp> 28 : #include <boost/graph/graph_utility.hpp> 29 : #endif 30 : 31 : //+PLUMEDOC MATRIXF DFSCLUSTERING 32 : /* 33 : Find the connected components of the matrix using the depth first search clustering algorithm. 34 : 35 : This action is useful if you are looking at a phenomenon such as nucleation where the aim is to detect the sizes of the crystalline nuclei that have formed 36 : in your simulation cell and is used in conjustion with tools from the adjmat module. The adjmat modlule contains a number of different methods that can be 37 : used to calculate adjacency matrices. An adjacency matrix is an $N \times N$ matrix 38 : in which the $i$th, $j$th element tells you whether or not the $i$th and $j$th atoms/molecules from a set of $N$ atoms/molecules are adjacent or not. The 39 : simplest of these adjcency matrix methods is the one for calculating a [CONTACT_MATRIX](CONTACT_MATRIX.md). All adjacency matrices provide a representation of a graph and can thus 40 : can be analyzed using tools from graph theory. This particular action thus performs 41 : [a depth first search clustering](https://en.wikipedia.org/wiki/Depth-first_search) to find the connected components of this graph. 42 : 43 : The input below calculates a CONTACT_MATRIX for 100 atoms. In the graph that is created from this CONTACT_MATRIX atoms are connected if they are within 44 : a distance of D_MAX of each other and are disconnected otherwise. The [DFSCLUSTERING](DFSCLUSTERING.md) method is used to find the connected components in this graph. This 45 : method outputs a 100-dimensional vector. The 1st element in this vector tells you which cluster the first atom is within, the second element tells you which 46 : cluster the second atom is in and so on. If an atom is in the largest cluster its corresponding element in the vector `dfs` will be one. We can thus print 47 : the positions of the atoms in the largest cluster by using a [DUMPATOMS](DUMPATOMS.md) command like the one shown below: 48 : 49 : ```plumed 50 : cm: CONTACT_MATRIX GROUP=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} 51 : dfs: DFSCLUSTERING ARG=cm 52 : DUMPATOMS FILE=cluster.xyz ATOMS=1-100 ARG=dfs LESS_THAN_OR_EQUAL=1.5 GREATER_THAN_OR_EQUAL=0.5 53 : ``` 54 : 55 : */ 56 : //+ENDPLUMEDOC 57 : 58 : namespace PLMD { 59 : namespace clusters { 60 : 61 : class DFSClustering : public ClusteringBase { 62 : private: 63 : #ifndef __PLUMED_HAS_BOOST_GRAPH 64 : /// The number of neighbors each atom has 65 : std::vector<unsigned> nneigh; 66 : /// The adjacency list 67 : Matrix<unsigned> adj_list; 68 : /// The color that tells us whether a node has been visited 69 : std::vector<unsigned> color; 70 : /// The recursive function at the heart of this method 71 : int explore( const unsigned& index ); 72 : #endif 73 : public: 74 : /// Create manual 75 : static void registerKeywords( Keywords& keys ); 76 : /// Constructor 77 : explicit DFSClustering(const ActionOptions&); 78 : /// Do the clustering 79 : void performClustering() override; 80 : }; 81 : 82 : PLUMED_REGISTER_ACTION(DFSClustering,"DFSCLUSTERING") 83 : 84 21 : void DFSClustering::registerKeywords( Keywords& keys ) { 85 21 : ClusteringBase::registerKeywords( keys ); 86 21 : keys.addFlag("LOWMEM",false,"this flag does nothing and is present only to ensure back-compatibility"); 87 21 : } 88 : 89 17 : DFSClustering::DFSClustering(const ActionOptions&ao): 90 : Action(ao), 91 17 : ClusteringBase(ao) { 92 : #ifndef __PLUMED_HAS_BOOST_GRAPH 93 17 : nneigh.resize( getNumberOfNodes() ); 94 17 : color.resize(getNumberOfNodes()); 95 : #endif 96 : bool lowmem; 97 17 : parseFlag("LOWMEM",lowmem); 98 17 : if( lowmem ) { 99 0 : warning("LOWMEM flag is deprecated and is no longer required for this action"); 100 : } 101 17 : } 102 : 103 38 : void DFSClustering::performClustering() { 104 : #ifdef __PLUMED_HAS_BOOST_GRAPH 105 : // Get the list of edges 106 : unsigned nedges=0; 107 : retrieveEdgeList( 0, nedges ); 108 : 109 : // Build the graph using boost 110 : boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS> sg(&pairs[0],&pairs[nedges],getNumberOfNodes()); 111 : 112 : // Find the connected components using boost (-1 here for compatibility with non-boost version) 113 : number_of_cluster=boost::connected_components(sg,&which_cluster[0]) - 1; 114 : 115 : // And work out the size of each cluster 116 : for(unsigned i=0; i<which_cluster.size(); ++i) { 117 : cluster_sizes[which_cluster[i]].first++; 118 : } 119 : #else 120 : // Get the adjacency matrix 121 38 : retrieveAdjacencyLists( nneigh, adj_list ); 122 : 123 : // Perform clustering 124 38 : number_of_cluster=-1; 125 38 : color.assign(color.size(),0); 126 20912 : for(unsigned i=0; i<getNumberOfNodes(); ++i) { 127 20874 : if( color[i]==0 ) { 128 11261 : number_of_cluster++; 129 11261 : color[i]=explore(i); 130 : } 131 : } 132 : #endif 133 38 : } 134 : 135 : #ifndef __PLUMED_HAS_BOOST_GRAPH 136 20874 : int DFSClustering::explore( const unsigned& index ) { 137 : 138 20874 : color[index]=1; 139 153802 : for(unsigned i=0; i<nneigh[index]; ++i) { 140 132928 : unsigned j=adj_list(index,i); 141 132928 : if( color[j]==0 ) { 142 9613 : color[j]=explore(j); 143 : } 144 : } 145 : 146 : // Count the size of the cluster 147 20874 : cluster_sizes[number_of_cluster].first++; 148 20874 : which_cluster[index] = number_of_cluster; 149 20874 : return color[index]; 150 : } 151 : #endif 152 : 153 : } 154 : }