LCOV - code coverage report
Current view: top level - vesselbase - ActionWithAveraging.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 136 147 92.5 %
Date: 2026-03-30 13:16:06 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-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 "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         113 : void ActionWithAveraging::registerKeywords( Keywords& keys ) {
      33         113 :   Action::registerKeywords( keys );
      34         113 :   ActionPilot::registerKeywords( keys );
      35         113 :   ActionAtomistic::registerKeywords( keys );
      36         113 :   ActionWithArguments::registerKeywords( keys );
      37         113 :   ActionWithValue::registerKeywords( keys );
      38         113 :   ActionWithVessel::registerKeywords( keys );
      39         226 :   keys.add("compulsory","STRIDE","1","the frequency with which the data should be collected and added to the quantity being averaged");
      40         226 :   keys.add("compulsory","CLEAR","0","the frequency with which to clear all the accumulated data.  The default value "
      41             :            "of 0 implies that all the data will be used and that the grid will never be cleared");
      42         226 :   keys.add("optional","LOGWEIGHTS","list of actions that calculates log weights that should be used to weight configurations when calculating averages");
      43         226 :   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");
      44         113 :   keys.remove("NUMERICAL_DERIVATIVES");
      45         113 : }
      46             : 
      47          73 : ActionWithAveraging::ActionWithAveraging( const ActionOptions& ao ):
      48             :   Action(ao),
      49             :   ActionPilot(ao),
      50             :   ActionAtomistic(ao),
      51             :   ActionWithArguments(ao),
      52             :   ActionWithValue(ao),
      53             :   ActionWithVessel(ao),
      54          73 :   myaverage(NULL),
      55          73 :   activated(false),
      56          73 :   my_analysis_object(NULL),
      57          73 :   normalization(t),
      58          73 :   useRunAllTasks(false),
      59          73 :   clearstride(0),
      60          73 :   lweight(0),cweight(0) {
      61         146 :   if( keywords.exists("CLEAR") ) {
      62          58 :     parse("CLEAR",clearstride);
      63          58 :     if( clearstride>0 ) {
      64          12 :       if( clearstride%getStride()!=0 ) {
      65           0 :         error("CLEAR parameter must be a multiple of STRIDE");
      66             :       }
      67          12 :       log.printf("  clearing grid every %u steps \n",clearstride);
      68             :     }
      69             :   }
      70          73 :   if( ActionWithAveraging::getNumberOfArguments()>0 ) {
      71          29 :     my_analysis_object=dynamic_cast<analysis::AnalysisBase*>( getPntrToArgument(0)->getPntrToAction() );
      72          38 :     for(unsigned i=1; i<ActionWithAveraging::getNumberOfArguments(); i++) {
      73           9 :       if( my_analysis_object && my_analysis_object->getLabel()!=(getPntrToArgument(i)->getPntrToAction())->getLabel() ) {
      74           0 :         error("all arguments should be from one single analysis object");
      75             :       }
      76             :     }
      77          29 :     if( my_analysis_object ) {
      78           7 :       if( getStride()!=1 ) {
      79           0 :         error("stride should not have been set when calculating average from analysis data");
      80             :       }
      81           7 :       setStride(0);
      82           7 :       addDependency( my_analysis_object );
      83             :     }
      84             :   }
      85         146 :   if( keywords.exists("LOGWEIGHTS") ) {
      86             :     std::vector<std::string> wwstr;
      87         116 :     parseVector("LOGWEIGHTS",wwstr);
      88          58 :     if( wwstr.size()>0 ) {
      89           7 :       log.printf("  reweighting using weights from ");
      90             :     }
      91          58 :     std::vector<Value*> arg( getArguments() );
      92          66 :     for(unsigned i=0; i<wwstr.size(); ++i) {
      93           8 :       ActionWithValue* val = plumed.getActionSet().selectWithLabel<ActionWithValue*>(wwstr[i]);
      94           8 :       if( !val ) {
      95           0 :         error("could not find value named");
      96             :       }
      97           8 :       bias::ReweightBase* iswham=dynamic_cast<bias::ReweightBase*>( val );
      98           8 :       if( iswham && iswham->buildsWeightStore() ) {
      99           0 :         error("to use wham you must gather data using COLLECT_FRAMES");
     100             :       }
     101           8 :       weights.push_back( val->copyOutput(val->getLabel()) );
     102           8 :       arg.push_back( val->copyOutput(val->getLabel()) );
     103           8 :       log.printf("%s ",wwstr[i].c_str() );
     104             :     }
     105          58 :     if( wwstr.size()>0 ) {
     106           7 :       log.printf("\n");
     107             :     } else {
     108          51 :       log.printf("  weights are all equal to one\n");
     109             :     }
     110          58 :     requestArguments( arg );
     111          58 :   }
     112         146 :   if( keywords.exists("NORMALIZATION") ) {
     113             :     std::string normstr;
     114         116 :     parse("NORMALIZATION",normstr);
     115          58 :     if( normstr=="true" ) {
     116          23 :       normalization=t;
     117          35 :     } else if( normstr=="false" ) {
     118           9 :       normalization=f;
     119          26 :     } else if( normstr=="ndata" ) {
     120          26 :       normalization=ndata;
     121             :     } else {
     122           0 :       error("invalid instruction for NORMALIZATION flag should be true, false, or ndata");
     123             :     }
     124             :   }
     125          73 : }
     126             : 
     127          53 : bool ActionWithAveraging::ignoreNormalization() const {
     128          53 :   if( normalization==f ) {
     129           9 :     return true;
     130             :   }
     131             :   return false;
     132             : }
     133             : 
     134          68 : void ActionWithAveraging::setAveragingAction( std::unique_ptr<AveragingVessel> av_vessel, const bool& usetasks ) {
     135             :   // cppcheck-suppress danglingLifetime
     136          68 :   myaverage=av_vessel.get();
     137          68 :   addVessel( std::move(av_vessel) );
     138          68 :   useRunAllTasks=usetasks;
     139          68 :   resizeFunctions();
     140          68 : }
     141             : 
     142        1240 : void ActionWithAveraging::lockRequests() {
     143             :   ActionAtomistic::lockRequests();
     144             :   ActionWithArguments::lockRequests();
     145        1240 : }
     146             : 
     147        1240 : void ActionWithAveraging::unlockRequests() {
     148             :   ActionAtomistic::unlockRequests();
     149             :   ActionWithArguments::unlockRequests();
     150        1240 : }
     151             : 
     152         374 : unsigned ActionWithAveraging::getNumberOfQuantities() const {
     153         374 :   if( my_analysis_object ) {
     154          26 :     return getNumberOfArguments()+2;
     155             :   }
     156             :   return 2;
     157             : }
     158             : 
     159           0 : void ActionWithAveraging::calculateNumericalDerivatives(PLMD::ActionWithValue*) {
     160           0 :   error("not possible to compute numerical derivatives for this action");
     161             : }
     162             : 
     163        1258 : void ActionWithAveraging::update() {
     164        1258 :   if( (clearstride!=1 && getStep()==0) || (!onStep() && !my_analysis_object) ) {
     165          81 :     return;
     166             :   }
     167        1177 :   if( my_analysis_object ) {
     168           7 :     analysis::ReadAnalysisFrames* myfram = dynamic_cast<analysis::ReadAnalysisFrames*>( my_analysis_object );
     169           7 :     if( !activated && !myfram && !onStep() ) {
     170             :       return ;
     171           7 :     } else if( !activated && !my_analysis_object->onStep() ) {
     172             :       return ;
     173             :     }
     174             :   }
     175             : 
     176             :   // Clear if it is time to reset
     177        1177 :   if( myaverage ) {
     178        1176 :     if( myaverage->wasreset() ) {
     179          82 :       clearAverage();
     180             :     }
     181             :   }
     182             :   // Calculate the weight for all reweighting
     183        1177 :   if ( weights.size()>0 && !my_analysis_object ) {
     184             :     double sum=0;
     185        3018 :     for(unsigned i=0; i<weights.size(); ++i) {
     186        2009 :       sum+=weights[i]->get();
     187             :     }
     188        1009 :     lweight=sum;
     189        1009 :     cweight = exp( sum );
     190             :   } else {
     191         168 :     lweight=0;
     192         168 :     cweight=1.0;
     193             :   }
     194             :   // Prepare the task list for averaging
     195        1177 :   if( my_analysis_object ) {
     196        2115 :     for(unsigned i=getFullNumberOfTasks(); i<my_analysis_object->getNumberOfDataPoints(); ++i) {
     197        2108 :       addTaskToList(i);
     198             :     }
     199           7 :     deactivateAllTasks();
     200           7 :     cweight=0;
     201        2115 :     for(unsigned i=0; i<my_analysis_object->getNumberOfDataPoints(); ++i) {
     202        2108 :       taskFlags[i]=1;
     203        2108 :       cweight += my_analysis_object->getWeight(i);
     204             :     }
     205           7 :     lockContributors();
     206             :   }
     207             :   // Prepare to do the averaging
     208        1177 :   prepareForAveraging();
     209             :   // Run all the tasks (if required
     210        1177 :   if( my_analysis_object || useRunAllTasks ) {
     211         145 :     runAllTasks();
     212             :   }
     213             :   // This the averaging if it is not done using task list
     214             :   else {
     215        1032 :     performOperations( true );
     216             :   }
     217             :   // Update the norm
     218        1177 :   double normt = cweight;
     219        1177 :   if( !my_analysis_object && normalization==ndata ) {
     220             :     normt = 1;
     221             :   }
     222        1177 :   if( myaverage && my_analysis_object ) {
     223             :     myaverage->setNorm( normt );
     224        1170 :   } else if( myaverage ) {
     225        1169 :     myaverage->setNorm( normt + myaverage->getNorm() );
     226             :   }
     227             :   // Finish the averaging
     228        1177 :   finishAveraging();
     229             :   // By resetting here we are ensuring that the grid will be cleared at the start of the next step
     230        1177 :   if( myaverage ) {
     231        1176 :     if( getStride()==0 || (clearstride>0 && getStep()%clearstride==0) ) {
     232          49 :       myaverage->reset();
     233             :     }
     234             :   }
     235             : }
     236             : 
     237       60010 : void ActionWithAveraging::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const {
     238       60010 :   if( my_analysis_object ) {
     239        2108 :     const analysis::DataCollectionObject& mystore=my_analysis_object->getStoredData( current, false );
     240        4216 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     241        2108 :       myvals.setValue( 1+i, mystore.getArgumentValue( ActionWithArguments::getArguments()[i]->getName() ) );
     242             :     }
     243        2108 :     myvals.setValue( 0, my_analysis_object->getWeight(current) );
     244        2108 :     if( normalization==f ) {
     245           0 :       myvals.setValue( 1+getNumberOfArguments(), 1.0 );
     246             :     } else {
     247        2108 :       myvals.setValue( 1+getNumberOfArguments(), 1.0 / cweight );
     248             :     }
     249        2108 :     accumulateAverage( myvals );
     250             :   } else {
     251       57902 :     runTask( current, myvals );
     252             :   }
     253       60010 : }
     254             : 
     255         102 : void ActionWithAveraging::clearAverage() {
     256         102 :   plumed_assert( myaverage->wasreset() );
     257         102 :   myaverage->clear();
     258         102 : }
     259             : 
     260           0 : void ActionWithAveraging::performOperations( const bool& from_update ) {
     261           0 :   plumed_error();
     262             : }
     263             : 
     264          58 : void ActionWithAveraging::runFinalJobs() {
     265          58 :   if( my_analysis_object && getStride()==0 ) {
     266           7 :     activated=true;
     267           7 :     update();
     268             :   }
     269          58 : }
     270             : 
     271             : }
     272             : }

Generated by: LCOV version 1.16