Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2015-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 "core/ActionWithValue.h" 23 : #include "core/ActionWithArguments.h" 24 : #include "core/ActionRegister.h" 25 : #include "core/ActionShortcut.h" 26 : #include "core/PlumedMain.h" 27 : #include "multicolvar/MultiColvarShortcuts.h" 28 : #include "ClusteringBase.h" 29 : 30 : //+PLUMEDOC CONCOMP CLUSTER_DISTRIBUTION 31 : /* 32 : Calculate functions of the distribution of properties in your connected components. 33 : 34 : This collective variable was developed for looking at nucleation phenomena, where you are 35 : interested in using studying the behavior of atoms in small aggregates or nuclei. In these sorts of 36 : problems you might be interested in the distribution of the sizes of the clusters in your system. 37 : A detailed description of this CV can be found in \cite tribello-clustering. 38 : 39 : \par Examples 40 : 41 : The input provided below calculates the local q6 Steinhardt parameter on each atom. The coordination number 42 : that atoms with a high value for the local q6 Steinhardt parameter have with other atoms that have a high 43 : value for the local q6 Steinhardt parameter is then computed. A contact matrix is then computed that measures 44 : whether atoms atoms \f$i\f$ and \f$j\f$ have a high value for this coordination number and if they are within 45 : 3.6 nm of each other. The connected components of this matrix are then found using a depth first clustering 46 : algorithm on the corresponding graph. The number of components in this graph that contain more than 27 atoms is then computed. 47 : As discussed in \cite tribello-clustering an input similar to this one was used to analyze the formation of a polycrystal of GeTe from amorphous 48 : GeTe. 49 : 50 : \plumedfile 51 : q6: Q6 SPECIES=1-300 SWITCH={GAUSSIAN D_0=5.29 R_0=0.01 D_MAX=5.3} LOWMEM 52 : lq6: LOCAL_Q6 SPECIES=q6 SWITCH={GAUSSIAN D_0=5.29 R_0=0.01 D_MAX=5.3} LOWMEM 53 : flq6: MFILTER_MORE DATA=lq6 SWITCH={GAUSSIAN D_0=0.19 R_0=0.01 D_MAX=0.2} 54 : cc: COORDINATIONNUMBER SPECIES=flq6 SWITCH={GAUSSIAN D_0=3.59 R_0=0.01 D_MAX=3.6} 55 : fcc: MFILTER_MORE DATA=cc SWITCH={GAUSSIAN D_0=5.99 R_0=0.01 D_MAX=6.0} 56 : mat: CONTACT_MATRIX ATOMS=fcc SWITCH={GAUSSIAN D_0=3.59 R_0=0.01 D_MAX=3.6} 57 : dfs: DFSCLUSTERING MATRIX=mat 58 : nclust: CLUSTER_DISTRIBUTION CLUSTERS=dfs TRANSFORM={GAUSSIAN D_0=5.99 R_0=0.01 D_MAX=6.0} MORE_THAN={GAUSSIAN D_0=26.99 R_0=0.01 D_MAX=27} 59 : PRINT ARG=nclust.* FILE=colvar 60 : \endplumedfile 61 : 62 : */ 63 : //+ENDPLUMEDOC 64 : 65 : //+PLUMEDOC CONCOMP CLUSTER_DISTRIBUTION_CALC 66 : /* 67 : Calculate functions of the distribution of properties in your connected components. 68 : 69 : See \ref CLUSTER_DISTRIBUTION 70 : 71 : \par Examples 72 : 73 : */ 74 : //+ENDPLUMEDOC 75 : 76 : 77 : namespace PLMD { 78 : namespace clusters { 79 : 80 : class ClusterDistribution : 81 : public ActionWithArguments, 82 : public ActionWithValue { 83 : public: 84 : /// Create manual 85 : static void registerKeywords( Keywords& keys ); 86 : /// Constructor 87 : explicit ClusterDistribution(const ActionOptions&); 88 : /// The number of derivatives 89 : unsigned getNumberOfDerivatives() override ; 90 : /// Do the calculation 91 : void calculate() override; 92 : /// We can use ActionWithVessel to run all the calculation 93 2 : void apply() override {} 94 : }; 95 : 96 : PLUMED_REGISTER_ACTION(ClusterDistribution,"CLUSTER_DISTRIBUTION_CALC") 97 : 98 6 : void ClusterDistribution::registerKeywords( Keywords& keys ) { 99 6 : Action::registerKeywords( keys ); 100 6 : ActionWithArguments::registerKeywords( keys ); 101 6 : ActionWithValue::registerKeywords( keys ); keys.remove("NUMERICAL_DERIVATIVES"); 102 12 : keys.addInputKeyword("compulsory","CLUSTERS","vector","the label of the action that does the clustering"); keys.setDisplayName("CLUSTER_DISTRIBUTION"); 103 12 : keys.addInputKeyword("optional","WEIGHTS","vector","use the vector of values calculated by this action as weights rather than giving each atom a unit weight"); 104 12 : keys.setValueDescription("vector","a vector containing the sum of a atomic-cv that is calculated for each of the identified clusters"); 105 6 : } 106 : 107 2 : ClusterDistribution::ClusterDistribution(const ActionOptions&ao): 108 : Action(ao), 109 : ActionWithArguments(ao), 110 2 : ActionWithValue(ao) 111 : { 112 : // Read in the clustering object 113 4 : std::vector<Value*> clusters; parseArgumentList("CLUSTERS",clusters); 114 2 : if( clusters.size()!=1 ) error("should pass only one matrix to clustering base"); 115 2 : ClusteringBase* cc = dynamic_cast<ClusteringBase*>( clusters[0]->getPntrToAction() ); 116 2 : if( !cc ) error("input to CLUSTERS keyword should be a clustering action"); 117 4 : std::vector<Value*> weights; parseArgumentList("WEIGHTS",weights); 118 2 : if( weights.size()==0 ) { 119 1 : log.printf(" using unit weights in cluster distribution \n"); 120 1 : } else if( weights.size()==1 ) { 121 1 : if( weights[0]->getRank()!=1 ) error("input weights has wrong shape"); 122 1 : if( weights[0]->getShape()[0]!=clusters[0]->getShape()[0] ) error("mismatch between number of weights and number of atoms"); 123 1 : log.printf(" using weights from action with label %s in cluster distribution \n", weights[0]->getName().c_str() ); 124 1 : clusters.push_back( weights[0] ); 125 : } else { 126 0 : error("should have only one argument for weights \n"); 127 : } 128 : // Request the arguments 129 2 : requestArguments( clusters ); 130 2 : getPntrToArgument(0)->buildDataStore(); 131 2 : if( getNumberOfArguments()>1 ) getPntrToArgument(1)->buildDataStore(); 132 : // Now create the value 133 2 : std::vector<unsigned> shape(1); shape[0]=clusters[0]->getShape()[0]; 134 2 : addValue( shape ); setNotPeriodic(); getPntrToValue()->buildDataStore(); 135 2 : } 136 : 137 0 : unsigned ClusterDistribution::getNumberOfDerivatives() { 138 0 : return 0; 139 : } 140 : 141 2 : void ClusterDistribution::calculate() { 142 2 : plumed_assert( getPntrToArgument(0)->valueHasBeenSet() ); 143 2 : if( getNumberOfArguments()>1 ) plumed_assert( getPntrToArgument(1)->valueHasBeenSet() ); 144 2 : double csize = getPntrToArgument(0)->get(0); 145 12 : for(unsigned i=1; i<getPntrToArgument(0)->getShape()[0]; ++i) { 146 10 : if( getPntrToArgument(0)->get(i)>csize ) csize = getPntrToArgument(0)->get(i); 147 : } 148 2 : unsigned ntasks = static_cast<unsigned>( csize ); 149 8 : for(unsigned i=0; i<ntasks; ++i) { 150 42 : for(unsigned j=0; j<getPntrToArgument(0)->getShape()[0]; ++j) { 151 36 : if( fabs(getPntrToArgument(0)->get(j)-i)<epsilon ) { 152 10 : if( getNumberOfArguments()==2 ) getPntrToValue()->add( i, getPntrToArgument(1)->get(j) ); 153 5 : else getPntrToValue()->add( i, 1.0 ); 154 : } 155 : } 156 : } 157 2 : } 158 : 159 : class ClusterDistributionShortcut : public ActionShortcut { 160 : public: 161 : static void registerKeywords( Keywords& keys ); 162 : ClusterDistributionShortcut(const ActionOptions&); 163 : }; 164 : 165 : PLUMED_REGISTER_ACTION(ClusterDistributionShortcut,"CLUSTER_DISTRIBUTION") 166 : 167 6 : void ClusterDistributionShortcut::registerKeywords( Keywords& keys ) { 168 6 : ActionShortcut::registerKeywords( keys ); 169 12 : keys.add("compulsory","CLUSTERS","the label of the action that does the clustering"); 170 12 : keys.add("optional","WEIGHTS","use the vector of values calculated by this action as weights rather than giving each atom a unit weight"); 171 6 : multicolvar::MultiColvarShortcuts::shortcutKeywords( keys ); 172 6 : keys.addActionNameSuffix("_CALC"); 173 6 : } 174 : 175 2 : ClusterDistributionShortcut::ClusterDistributionShortcut(const ActionOptions&ao): 176 : Action(ao), 177 2 : ActionShortcut(ao) 178 : { 179 2 : std::map<std::string,std::string> keymap; multicolvar::MultiColvarShortcuts::readShortcutKeywords( keymap, this ); 180 4 : readInputLine( getShortcutLabel() + ": CLUSTER_DISTRIBUTION_CALC " + convertInputLineToString() ); 181 4 : multicolvar::MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel(), "", keymap, this ); 182 2 : } 183 : 184 : } 185 : }