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 : As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the 36 : so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether 37 : or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. As detailed in \cite tribello-clustering 38 : these matrices provide a representation of a graph and can thus can be analyzed using tools from graph theory. This particular action performs 39 : a depth first search clustering to find the connected components of this graph. You can read more about depth first search here: 40 : 41 : https://en.wikipedia.org/wiki/Depth-first_search 42 : 43 : 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 44 : in your simulation cell. 45 : 46 : \par Examples 47 : 48 : The input below calculates the coordination numbers of atoms 1-100 and then computes the an adjacency 49 : matrix whose elements measures whether atoms \f$i\f$ and \f$j\f$ are within 0.55 nm of each other. The action 50 : labelled dfs then treats the elements of this matrix as zero or ones and thus thinks of the matrix as defining 51 : a graph. This dfs action then finds the largest connected component in this graph. The sum of the coordination 52 : numbers for the atoms in this largest connected component are then computed and this quantity is output to a colvar 53 : file. The way this input can be used is described in detail in \cite tribello-clustering. 54 : 55 : \plumedfile 56 : lq: COORDINATIONNUMBER SPECIES=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} LOWMEM 57 : cm: CONTACT_MATRIX ATOMS=lq SWITCH={CUBIC D_0=0.45 D_MAX=0.55} 58 : dfs: DFSCLUSTERING MATRIX=cm 59 : clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 SUM 60 : PRINT ARG=clust1.* FILE=colvar 61 : \endplumedfile 62 : 63 : */ 64 : //+ENDPLUMEDOC 65 : 66 : namespace PLMD { 67 : namespace clusters { 68 : 69 : class DFSClustering : public ClusteringBase { 70 : private: 71 : #ifndef __PLUMED_HAS_BOOST_GRAPH 72 : /// The number of neighbors each atom has 73 : std::vector<unsigned> nneigh; 74 : /// The adjacency list 75 : Matrix<unsigned> adj_list; 76 : /// The color that tells us whether a node has been visited 77 : std::vector<unsigned> color; 78 : /// The recursive function at the heart of this method 79 : int explore( const unsigned& index ); 80 : #endif 81 : public: 82 : /// Create manual 83 : static void registerKeywords( Keywords& keys ); 84 : /// Constructor 85 : explicit DFSClustering(const ActionOptions&); 86 : /// Do the clustering 87 : void performClustering() override; 88 : }; 89 : 90 : PLUMED_REGISTER_ACTION(DFSClustering,"DFSCLUSTERING") 91 : 92 21 : void DFSClustering::registerKeywords( Keywords& keys ) { 93 21 : ClusteringBase::registerKeywords( keys ); 94 42 : keys.addFlag("LOWMEM",false,"this flag does nothing and is present only to ensure back-compatibility"); 95 21 : } 96 : 97 17 : DFSClustering::DFSClustering(const ActionOptions&ao): 98 : Action(ao), 99 17 : ClusteringBase(ao) { 100 : #ifndef __PLUMED_HAS_BOOST_GRAPH 101 17 : nneigh.resize( getNumberOfNodes() ); 102 17 : color.resize(getNumberOfNodes()); 103 : #endif 104 : bool lowmem; 105 17 : parseFlag("LOWMEM",lowmem); 106 17 : if( lowmem ) { 107 0 : warning("LOWMEM flag is deprecated and is no longer required for this action"); 108 : } 109 17 : } 110 : 111 38 : void DFSClustering::performClustering() { 112 : #ifdef __PLUMED_HAS_BOOST_GRAPH 113 : // Get the list of edges 114 : unsigned nedges=0; 115 : retrieveEdgeList( 0, nedges ); 116 : 117 : // Build the graph using boost 118 : boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS> sg(&pairs[0],&pairs[nedges],getNumberOfNodes()); 119 : 120 : // Find the connected components using boost (-1 here for compatibility with non-boost version) 121 : number_of_cluster=boost::connected_components(sg,&which_cluster[0]) - 1; 122 : 123 : // And work out the size of each cluster 124 : for(unsigned i=0; i<which_cluster.size(); ++i) { 125 : cluster_sizes[which_cluster[i]].first++; 126 : } 127 : #else 128 : // Get the adjacency matrix 129 38 : retrieveAdjacencyLists( nneigh, adj_list ); 130 : 131 : // Perform clustering 132 38 : number_of_cluster=-1; 133 38 : color.assign(color.size(),0); 134 20912 : for(unsigned i=0; i<getNumberOfNodes(); ++i) { 135 20874 : if( color[i]==0 ) { 136 11261 : number_of_cluster++; 137 11261 : color[i]=explore(i); 138 : } 139 : } 140 : #endif 141 38 : } 142 : 143 : #ifndef __PLUMED_HAS_BOOST_GRAPH 144 20874 : int DFSClustering::explore( const unsigned& index ) { 145 : 146 20874 : color[index]=1; 147 153802 : for(unsigned i=0; i<nneigh[index]; ++i) { 148 132928 : unsigned j=adj_list(index,i); 149 132928 : if( color[j]==0 ) { 150 9613 : color[j]=explore(j); 151 : } 152 : } 153 : 154 : // Count the size of the cluster 155 20874 : cluster_sizes[number_of_cluster].first++; 156 20874 : which_cluster[index] = number_of_cluster; 157 20874 : return color[index]; 158 : } 159 : #endif 160 : 161 : } 162 : }