Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2014-2017 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/PlumedMain.h" 26 : #include "core/ActionSet.h" 27 : #include "ClusteringBase.h" 28 : 29 : //+PLUMEDOC CONCOMP CLUSTER_WEIGHTS 30 : /* 31 : Setup a vector that has one for all the atoms that form part of the cluster of interest and that has zero for all other atoms. 32 : 33 : This method is designed to be used in tandem with the [DFSCLUSTERING](DFSCLUSTERING.md) action. An example input that uses this action and 34 : that calculates the average coordination number for the atoms in the largest cluster in the system is shown below. 35 : 36 : ```plumed 37 : # Calculate a contact matrix between the first 100 atoms in the configuration 38 : cm: CONTACT_MATRIX GROUP=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} 39 : # Evaluate the coordination numbers of the 100 atoms with themselves 40 : ones: ONES SIZE=100 41 : coord: MATRIX_VECTOR_PRODUCT ARG=cm,ones 42 : # Find the connected components from the contact matrix 43 : dfs: DFSCLUSTERING ARG=cm 44 : # Returns a 100-dimensional vector that is 1 if the correpsonding atom index is in the largest cluster and is zero otherwise 45 : c1: CLUSTER_WEIGHTS CLUSTERS=dfs CLUSTER=1 46 : # Now evaluate the sum of the coordination numbers of the atoms in the larget cluster 47 : numerv: CUSTOM ARG=c1,coord FUNC=x*y PERIODIC=NO 48 : numer: SUM ARG=numerv PERIODIC=NO 49 : # Evaluate the total number of atoms in the largest cluster 50 : denom: SUM ARG=c1 PERIODIC=NO 51 : # And finally calculate the average coordination number for the atoms in the largest cluster 52 : f: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO 53 : PRINT ARG=f FILE=colvar 54 : ``` 55 : 56 : */ 57 : //+ENDPLUMEDOC 58 : 59 : namespace PLMD { 60 : namespace clusters { 61 : 62 : class ClusterWeights : 63 : public ActionWithArguments, 64 : public ActionWithValue { 65 : private: 66 : /// The cluster we are looking for 67 : unsigned clustr; 68 : /// The forces 69 : std::vector<double> forcesToApply; 70 : public: 71 : /// Create manual 72 : static void registerKeywords( Keywords& keys ); 73 : /// Constructor 74 : explicit ClusterWeights(const ActionOptions&); 75 : /// The number of derivatives 76 : unsigned getNumberOfDerivatives() override ; 77 : /// Do the calculation 78 : void calculate() override ; 79 : /// 80 51 : void apply() override {} 81 : }; 82 : 83 : PLUMED_REGISTER_ACTION(ClusterWeights,"CLUSTER_WEIGHTS") 84 : 85 57 : void ClusterWeights::registerKeywords( Keywords& keys ) { 86 57 : Action::registerKeywords( keys ); 87 57 : ActionWithArguments::registerKeywords( keys ); 88 57 : ActionWithValue::registerKeywords( keys ); 89 57 : keys.remove("NUMERICAL_DERIVATIVES"); 90 114 : keys.addInputKeyword("compulsory","CLUSTERS","vector","the label of the action that does the clustering"); 91 57 : 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."); 92 57 : keys.addFlag("LOWMEM",false,"this flag does nothing and is present only to ensure back-compatibility"); 93 : // keys.add("hidden","FROM_PROPERTIES","indicates that this is created from CLUSTER_PROPERTIES shortcut"); 94 114 : keys.setValueDescription("vector","vector with elements that are one if the atom of interest is part of the required cluster and zero otherwise"); 95 57 : keys.addDOI("https://doi.org/10.1021/acs.jctc.6b01073"); 96 57 : } 97 : 98 29 : ClusterWeights::ClusterWeights(const ActionOptions&ao): 99 : Action(ao), 100 : ActionWithArguments(ao), 101 29 : ActionWithValue(ao) { 102 : bool lowmem; 103 29 : parseFlag("LOWMEM",lowmem); 104 29 : if( lowmem ) { 105 0 : warning("LOWMEM flag is deprecated and is no longer required for this action"); 106 : } 107 : // Read in the clustering object 108 : std::vector<Value*> clusters; 109 58 : parseArgumentList("CLUSTERS",clusters); 110 29 : if( clusters.size()!=1 ) { 111 0 : error("should pass only one matrix to clustering base"); 112 : } 113 29 : ClusteringBase* cc = dynamic_cast<ClusteringBase*>( clusters[0]->getPntrToAction() ); 114 29 : if( !cc ) { 115 0 : error("input to CLUSTERS keyword should be a clustering action"); 116 : } 117 : // Request the arguments 118 29 : requestArguments( clusters ); 119 : // Now create the value 120 29 : std::vector<unsigned> shape(1); 121 29 : shape[0]=clusters[0]->getShape()[0]; 122 29 : addValue( shape ); 123 29 : setNotPeriodic(); 124 29 : getPntrToComponent(0)->buildDataStore(); 125 : // Find out which cluster we want 126 29 : parse("CLUSTER",clustr); 127 29 : if( clustr<1 ) { 128 0 : error("cannot look for a cluster larger than the largest cluster"); 129 : } 130 29 : if( clustr>clusters[0]->getShape()[0] ) { 131 0 : error("cluster selected is invalid - too few atoms in system"); 132 : } 133 29 : log.printf(" atoms in %dth largest cluster calculated by %s are equal to one \n",clustr, cc->getLabel().c_str() ); 134 29 : } 135 : 136 24 : unsigned ClusterWeights::getNumberOfDerivatives() { 137 24 : return 0; 138 : } 139 : 140 51 : void ClusterWeights::calculate() { 141 51 : plumed_assert( getPntrToArgument(0)->valueHasBeenSet() ); 142 36627 : for(unsigned i=0; i<getPntrToArgument(0)->getShape()[0]; ++i) { 143 36576 : if( fabs(getPntrToArgument(0)->get(i)-clustr)<epsilon ) { 144 9826 : getPntrToComponent(0)->set( i, 1.0 ); 145 : } 146 : } 147 51 : } 148 : 149 : } 150 : }