Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2014-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 : #include "ClusterAnalysisBase.h" 23 : #include "AdjacencyMatrixVessel.h" 24 : #include "core/ActionRegister.h" 25 : 26 : //+PLUMEDOC CONCOMP CLUSTER_PROPERTIES 27 : /* 28 : Calculate properties of the distribution of some quantities that are part of a connected component 29 : 30 : This collective variable was developed for looking at nucleation phenomena, where you are 31 : interested in using studying the behavior of atoms in small aggregates or nuclei. In these sorts of 32 : problems you might be interested in the degree the atoms in a nucleus have adopted their crystalline 33 : structure or (in the case of heterogeneous nucleation of a solute from a solvent) you might be 34 : interested in how many atoms are present in the largest cluster \cite tribello-clustering. 35 : 36 : \par Examples 37 : 38 : The input below calculates the coordination numbers of atoms 1-100 and then computes the an adjacency 39 : matrix whose elements measures whether atoms \f$i\f$ and \f$j\f$ are within 0.55 nm of each other. The action 40 : labelled dfs then treats the elements of this matrix as zero or ones and thus thinks of the matrix as defining 41 : a graph. This dfs action then finds the largest connected component in this graph. The sum of the coordination 42 : numbers for the atoms in this largest connected component are then computed and this quantity is output to a colvar 43 : file. The way this input can be used is described in detail in \cite tribello-clustering. 44 : 45 : \plumedfile 46 : lq: COORDINATIONNUMBER SPECIES=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} LOWMEM 47 : cm: CONTACT_MATRIX ATOMS=lq SWITCH={CUBIC D_0=0.45 D_MAX=0.55} 48 : dfs: DFSCLUSTERING MATRIX=cm 49 : clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 SUM 50 : PRINT ARG=clust1.* FILE=colvar 51 : \endplumedfile 52 : 53 : */ 54 : //+ENDPLUMEDOC 55 : 56 : namespace PLMD { 57 : namespace adjmat { 58 : 59 : class ClusterProperties : public ClusterAnalysisBase { 60 : private: 61 : /// The cluster we are looking for 62 : unsigned clustr; 63 : public: 64 : /// Create manual 65 : static void registerKeywords( Keywords& keys ); 66 : /// Constructor 67 : explicit ClusterProperties(const ActionOptions&); 68 : /// Do the calculation 69 : void calculate() override; 70 : /// We can use ActionWithVessel to run all the calculation 71 : void performTask( const unsigned&, const unsigned&, MultiValue& ) const override; 72 : }; 73 : 74 13839 : PLUMED_REGISTER_ACTION(ClusterProperties,"CLUSTER_PROPERTIES") 75 : 76 31 : void ClusterProperties::registerKeywords( Keywords& keys ) { 77 31 : ClusterAnalysisBase::registerKeywords( keys ); 78 62 : keys.add("compulsory","CLUSTER","1","which cluster would you like to look at 1 is the largest cluster, 2 is the second largest, 3 is the the third largest and so on."); 79 31 : keys.use("MEAN"); 80 31 : keys.use("MORE_THAN"); 81 31 : keys.use("LESS_THAN"); 82 62 : if( keys.reserved("VMEAN") ) { 83 62 : keys.use("VMEAN"); 84 : } 85 62 : if( keys.reserved("VSUM") ) { 86 62 : keys.use("VSUM"); 87 : } 88 31 : keys.use("BETWEEN"); 89 31 : keys.use("HISTOGRAM"); 90 31 : keys.use("MOMENTS"); 91 31 : keys.use("ALT_MIN"); 92 31 : keys.use("MIN"); 93 31 : keys.use("MAX"); 94 31 : keys.use("SUM"); 95 31 : keys.use("LOWEST"); 96 31 : keys.use("HIGHEST"); 97 31 : } 98 : 99 27 : ClusterProperties::ClusterProperties(const ActionOptions&ao): 100 : Action(ao), 101 27 : ClusterAnalysisBase(ao) { 102 : // Find out which cluster we want 103 27 : parse("CLUSTER",clustr); 104 : 105 27 : if( clustr<1 ) { 106 0 : error("cannot look for a cluster larger than the largest cluster"); 107 : } 108 27 : if( clustr>getNumberOfNodes() ) { 109 0 : error("cluster selected is invalid - too few atoms in system"); 110 : } 111 : 112 : // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) 113 18214 : for(unsigned i=0; i<getNumberOfNodes(); ++i) { 114 18187 : addTaskToList(i); 115 : } 116 : 117 : // And now finish the setup of everything in the base 118 : std::vector<AtomNumber> fake_atoms; 119 27 : setupMultiColvarBase( fake_atoms ); 120 27 : } 121 : 122 34 : void ClusterProperties::calculate() { 123 : // Retrieve the atoms in the largest cluster 124 : std::vector<unsigned> myatoms; 125 34 : retrieveAtomsInCluster( clustr, myatoms ); 126 : // Activate the relevant tasks 127 34 : deactivateAllTasks(); 128 1373 : for(unsigned i=0; i<myatoms.size(); ++i) { 129 1339 : taskFlags[myatoms[i]]=1; 130 : } 131 34 : lockContributors(); 132 : // Now do the calculation 133 34 : runAllTasks(); 134 34 : } 135 : 136 1795 : void ClusterProperties::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { 137 1795 : std::vector<double> vals( myvals.getNumberOfValues() ); 138 1795 : getPropertiesOfNode( current, vals ); 139 1795 : if( !doNotCalculateDerivatives() ) { 140 1598 : getNodePropertyDerivatives( current, myvals ); 141 : } 142 5385 : for(unsigned k=0; k<vals.size(); ++k) { 143 : myvals.setValue( k, vals[k] ); 144 : } 145 1795 : } 146 : 147 : } 148 : }