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 corresponding 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 62 : void apply() override {} 81 : }; 82 : 83 : PLUMED_REGISTER_ACTION(ClusterWeights,"CLUSTER_WEIGHTS") 84 : 85 69 : void ClusterWeights::registerKeywords( Keywords& keys ) { 86 69 : Action::registerKeywords( keys ); 87 69 : ActionWithArguments::registerKeywords( keys ); 88 69 : ActionWithValue::registerKeywords( keys ); 89 69 : keys.remove("NUMERICAL_DERIVATIVES"); 90 138 : keys.addInputKeyword("compulsory","CLUSTERS","vector","the label of the action that does the clustering"); 91 69 : 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 third largest and so on."); 92 138 : keys.addDeprecatedFlag("LOWMEM",""); 93 138 : keys.setValueDescription("vector","vector with elements that are one if the atom of interest is part of the required cluster and zero otherwise"); 94 69 : keys.addDOI("https://doi.org/10.1021/acs.jctc.6b01073"); 95 69 : } 96 : 97 34 : ClusterWeights::ClusterWeights(const ActionOptions&ao): 98 : Action(ao), 99 : ActionWithArguments(ao), 100 34 : ActionWithValue(ao) { 101 : bool lowmem; 102 34 : parseFlag("LOWMEM",lowmem); 103 34 : if( lowmem ) { 104 0 : warning("LOWMEM flag is deprecated and is no longer required for this action"); 105 : } 106 : // Read in the clustering object 107 34 : std::vector<Value*> clusters; 108 68 : parseArgumentList("CLUSTERS",clusters); 109 34 : if( clusters.size()!=1 ) { 110 0 : error("should pass only one matrix to clustering base"); 111 : } 112 34 : ClusteringBase* cc = dynamic_cast<ClusteringBase*>( clusters[0]->getPntrToAction() ); 113 34 : if( !cc ) { 114 0 : error("input to CLUSTERS keyword should be a clustering action"); 115 : } 116 : // Request the arguments 117 34 : requestArguments( clusters ); 118 : // Now create the value 119 34 : std::vector<std::size_t> shape(1); 120 34 : shape[0]=clusters[0]->getShape()[0]; 121 34 : addValue( shape ); 122 34 : setNotPeriodic(); 123 : // Find out which cluster we want 124 34 : parse("CLUSTER",clustr); 125 34 : if( clustr<1 ) { 126 0 : error("cannot look for a cluster larger than the largest cluster"); 127 : } 128 34 : if( clustr>clusters[0]->getShape()[0] ) { 129 0 : error("cluster selected is invalid - too few atoms in system"); 130 : } 131 34 : log.printf(" atoms in %dth largest cluster calculated by %s are equal to one \n",clustr, cc->getLabel().c_str() ); 132 68 : } 133 : 134 24 : unsigned ClusterWeights::getNumberOfDerivatives() { 135 24 : return 0; 136 : } 137 : 138 62 : void ClusterWeights::calculate() { 139 62 : plumed_assert( getPntrToArgument(0)->valueHasBeenSet() ); 140 37136 : for(unsigned i=0; i<getPntrToArgument(0)->getShape()[0]; ++i) { 141 37074 : if( fabs(getPntrToArgument(0)->get(i)-clustr)<epsilon ) { 142 10039 : getPntrToComponent(0)->set( i, 1.0 ); 143 : } 144 : } 145 62 : } 146 : 147 : } 148 : }