Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2016-2019 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 "ActionWithAveraging.h" 23 : #include "analysis/DataCollectionObject.h" 24 : #include "analysis/ReadAnalysisFrames.h" 25 : #include "core/PlumedMain.h" 26 : #include "core/ActionSet.h" 27 : #include "bias/ReweightBase.h" 28 : 29 : namespace PLMD { 30 : namespace vesselbase { 31 : 32 74 : void ActionWithAveraging::registerKeywords( Keywords& keys ) { 33 74 : Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); 34 74 : ActionWithArguments::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionWithVessel::registerKeywords( keys ); 35 370 : keys.add("compulsory","STRIDE","1","the frequency with which the data should be collected and added to the quantity being averaged"); 36 : keys.add("compulsory","CLEAR","0","the frequency with which to clear all the accumulated data. The default value " 37 370 : "of 0 implies that all the data will be used and that the grid will never be cleared"); 38 296 : keys.add("optional","LOGWEIGHTS","list of actions that calculates log weights that should be used to weight configurations when calculating averages"); 39 370 : keys.add("compulsory","NORMALIZATION","true","This controls how the data is normalized it can be set equal to true, false or ndata. The differences between these options are explained in the manual page for \\ref HISTOGRAM"); 40 148 : keys.remove("NUMERICAL_DERIVATIVES"); 41 74 : } 42 : 43 64 : ActionWithAveraging::ActionWithAveraging( const ActionOptions& ao ): 44 : Action(ao), 45 : ActionPilot(ao), 46 : ActionAtomistic(ao), 47 : ActionWithArguments(ao), 48 : ActionWithValue(ao), 49 : ActionWithVessel(ao), 50 : myaverage(NULL), 51 : activated(false), 52 : my_analysis_object(NULL), 53 : normalization(t), 54 : useRunAllTasks(false), 55 : clearstride(0), 56 128 : lweight(0),cweight(0) 57 : { 58 128 : if( keywords.exists("CLEAR") ) { 59 106 : parse("CLEAR",clearstride); 60 53 : if( clearstride>0 ) { 61 12 : if( clearstride%getStride()!=0 ) error("CLEAR parameter must be a multiple of STRIDE"); 62 12 : log.printf(" clearing grid every %u steps \n",clearstride); 63 : } 64 : } 65 64 : if( getNumberOfArguments()>0 ) { 66 26 : my_analysis_object=dynamic_cast<analysis::AnalysisBase*>( getPntrToArgument(0)->getPntrToAction() ); 67 68 : for(unsigned i=1; i<getNumberOfArguments(); i++) { 68 8 : if( my_analysis_object && my_analysis_object->getLabel()!=(getPntrToArgument(i)->getPntrToAction())->getLabel() ) { 69 0 : error("all arguments should be from one single analysis object"); 70 : } 71 : } 72 26 : if( my_analysis_object ) { 73 7 : if( getStride()!=1 ) error("stride should not have been set when calculating average from analysis data"); 74 7 : setStride(0); addDependency( my_analysis_object ); 75 : } 76 : } 77 128 : if( keywords.exists("LOGWEIGHTS") ) { 78 106 : std::vector<std::string> wwstr; parseVector("LOGWEIGHTS",wwstr); 79 53 : if( wwstr.size()>0 ) log.printf(" reweighting using weights from "); 80 53 : std::vector<Value*> arg( getArguments() ); 81 67 : for(unsigned i=0; i<wwstr.size(); ++i) { 82 14 : ActionWithValue* val = plumed.getActionSet().selectWithLabel<ActionWithValue*>(wwstr[i]); 83 7 : if( !val ) error("could not find value named"); 84 7 : bias::ReweightBase* iswham=dynamic_cast<bias::ReweightBase*>( val ); 85 7 : if( iswham->buildsWeightStore() ) error("to use wham you must gather data using COLLECT_FRAMES"); 86 14 : weights.push_back( val->copyOutput(val->getLabel()) ); 87 14 : arg.push_back( val->copyOutput(val->getLabel()) ); 88 7 : log.printf("%s ",wwstr[i].c_str() ); 89 : } 90 53 : if( wwstr.size()>0 ) log.printf("\n"); 91 47 : else log.printf(" weights are all equal to one\n"); 92 106 : requestArguments( arg ); 93 : } 94 128 : if( keywords.exists("NORMALIZATION") ) { 95 106 : std::string normstr; parse("NORMALIZATION",normstr); 96 53 : if( normstr=="true" ) normalization=t; 97 31 : else if( normstr=="false" ) normalization=f; 98 22 : else if( normstr=="ndata" ) normalization=ndata; 99 0 : else error("invalid instruction for NORMALIZATION flag should be true, false, or ndata"); 100 : } 101 64 : } 102 : 103 59 : bool ActionWithAveraging::ignoreNormalization() const { 104 59 : if( normalization==f ) return true; 105 50 : return false; 106 : } 107 : 108 59 : void ActionWithAveraging::setAveragingAction( std::unique_ptr<AveragingVessel> av_vessel, const bool& usetasks ) { 109 59 : myaverage=av_vessel.get(); 110 118 : addVessel( std::move(av_vessel) ); 111 59 : useRunAllTasks=usetasks; resizeFunctions(); 112 59 : } 113 : 114 1185 : void ActionWithAveraging::lockRequests() { 115 : ActionAtomistic::lockRequests(); 116 : ActionWithArguments::lockRequests(); 117 1185 : } 118 : 119 1185 : void ActionWithAveraging::unlockRequests() { 120 : ActionAtomistic::unlockRequests(); 121 : ActionWithArguments::unlockRequests(); 122 1185 : } 123 : 124 206 : unsigned ActionWithAveraging::getNumberOfQuantities() const { 125 206 : if( my_analysis_object ) return getNumberOfArguments()+2; 126 : return 2; 127 : } 128 : 129 0 : void ActionWithAveraging::calculateNumericalDerivatives(PLMD::ActionWithValue*) { 130 0 : error("not possible to compute numerical derivatives for this action"); 131 0 : } 132 : 133 1199 : void ActionWithAveraging::update() { 134 1199 : if( (clearstride!=1 && getStep()==0) || (!onStep() && !my_analysis_object) ) return; 135 1123 : if( my_analysis_object ) { 136 7 : analysis::ReadAnalysisFrames* myfram = dynamic_cast<analysis::ReadAnalysisFrames*>( my_analysis_object ); 137 7 : if( !activated && !myfram && !onStep() ) return ; 138 7 : else if( !activated && !my_analysis_object->onStep() ) return ; 139 : } 140 : 141 : // Clear if it is time to reset 142 1123 : if( myaverage ) { 143 1122 : if( myaverage->wasreset() ) clearAverage(); 144 : } 145 : // Calculate the weight for all reweighting 146 1123 : if ( weights.size()>0 && !my_analysis_object ) { 147 7028 : double sum=0; for(unsigned i=0; i<weights.size(); ++i) sum+=weights[i]->get(); 148 1007 : lweight=sum; cweight = exp( sum ); 149 : } else { 150 116 : lweight=0; cweight=1.0; 151 : } 152 : // Prepare the task list for averaging 153 1123 : if( my_analysis_object ) { 154 7 : for(unsigned i=getFullNumberOfTasks(); i<my_analysis_object->getNumberOfDataPoints(); ++i) addTaskToList(i); 155 7 : deactivateAllTasks(); cweight=0; 156 2115 : for(unsigned i=0; i<my_analysis_object->getNumberOfDataPoints(); ++i) { 157 4216 : taskFlags[i]=1; cweight += my_analysis_object->getWeight(i); 158 : } 159 7 : lockContributors(); 160 : } 161 : // Prepare to do the averaging 162 1123 : prepareForAveraging(); 163 : // Run all the tasks (if required 164 1123 : if( my_analysis_object || useRunAllTasks ) runAllTasks(); 165 : // This the averaging if it is not done using task list 166 1028 : else performOperations( true ); 167 : // Update the norm 168 1123 : double normt = cweight; if( !my_analysis_object && normalization==ndata ) normt = 1; 169 1123 : if( myaverage && my_analysis_object ) myaverage->setNorm( normt ); 170 2231 : else if( myaverage ) myaverage->setNorm( normt + myaverage->getNorm() ); 171 : // Finish the averaging 172 1123 : finishAveraging(); 173 : // By resetting here we are ensuring that the grid will be cleared at the start of the next step 174 1123 : if( myaverage ) { 175 1122 : if( getStride()==0 || (clearstride>0 && getStep()%clearstride==0) ) myaverage->reset(); 176 : } 177 : } 178 : 179 50918 : void ActionWithAveraging::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { 180 50918 : if( my_analysis_object ) { 181 2108 : analysis::DataCollectionObject& mystore=my_analysis_object->getStoredData( current, false ); 182 8432 : for(unsigned i=0; i<getNumberOfArguments(); ++i) myvals.setValue( 1+i, mystore.getArgumentValue( ActionWithArguments::getArguments()[i]->getName() ) ); 183 2108 : myvals.setValue( 0, my_analysis_object->getWeight(current) ); 184 4216 : if( normalization==f ) myvals.setValue( 1+getNumberOfArguments(), 1.0 ); else myvals.setValue( 1+getNumberOfArguments(), 1.0 / cweight ); 185 2108 : accumulateAverage( myvals ); 186 : } else { 187 48810 : runTask( current, myvals ); 188 : } 189 50909 : } 190 : 191 93 : void ActionWithAveraging::clearAverage() { plumed_assert( myaverage->wasreset() ); myaverage->clear(); } 192 : 193 0 : void ActionWithAveraging::performOperations( const bool& from_update ) { plumed_error(); } 194 : 195 53 : void ActionWithAveraging::runFinalJobs() { 196 53 : if( my_analysis_object && getStride()==0 ) { activated=true; update(); } 197 53 : } 198 : 199 : } 200 5874 : }