LCOV - code coverage report
Current view: top level - core - ActionWithVector.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 420 426 98.6 %
Date: 2024-10-18 14:00:25 Functions: 50 54 92.6 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-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 "ActionWithVector.h"
      23             : #include "PlumedMain.h"
      24             : #include "ActionSet.h"
      25             : #include "tools/OpenMP.h"
      26             : #include "tools/Communicator.h"
      27             : 
      28             : namespace PLMD {
      29             : 
      30        5380 : void ActionWithVector::registerKeywords( Keywords& keys ) {
      31        5380 :   Action::registerKeywords( keys );
      32        5380 :   ActionAtomistic::registerKeywords( keys );
      33        5380 :   ActionWithValue::registerKeywords( keys ); keys.remove("NUMERICAL_DERIVATIVES");
      34        5380 :   ActionWithArguments::registerKeywords( keys );
      35       10760 :   keys.addFlag("SERIAL",false,"do the calculation in serial.  Do not parallelize");
      36        5380 : }
      37             : 
      38        4916 : ActionWithVector::ActionWithVector(const ActionOptions&ao):
      39             :   Action(ao),
      40             :   ActionAtomistic(ao),
      41             :   ActionWithValue(ao),
      42             :   ActionWithArguments(ao),
      43        4916 :   serial(false),
      44        4916 :   action_to_do_before(NULL),
      45        4916 :   action_to_do_after(NULL),
      46        4916 :   never_reduce_tasks(false),
      47        4916 :   reduce_tasks(false),
      48        4916 :   atomsWereRetrieved(false),
      49        4916 :   done_in_chain(false)
      50             : {
      51       12272 :   if( keywords.exists("SERIAL") ) parseFlag("SERIAL",serial);
      52        4916 : }
      53             : 
      54        4916 : ActionWithVector::~ActionWithVector() {
      55        4916 :   if( action_to_do_before ) action_to_do_before->action_to_do_after=NULL;
      56        4916 : }
      57             : 
      58      273524 : void ActionWithVector::lockRequests() {
      59             :   ActionAtomistic::lockRequests();
      60             :   ActionWithArguments::lockRequests();
      61      273524 : }
      62             : 
      63      273524 : void ActionWithVector::unlockRequests() {
      64             :   ActionAtomistic::unlockRequests();
      65             :   ActionWithArguments::unlockRequests();
      66      273524 : }
      67             : 
      68           0 : void ActionWithVector::calculateNumericalDerivatives(ActionWithValue* av) {
      69           0 :   plumed_merror("cannot calculate numerical derivative for action " + getName() + " with label " + getLabel() );
      70             : }
      71             : 
      72      457632 : void ActionWithVector::clearDerivatives( const bool& force ) {
      73      457632 :   if( !force && actionInChain() ) return;
      74      338953 :   ActionWithValue::clearDerivatives();
      75      338953 :   if( action_to_do_after ) action_to_do_after->clearDerivatives( true );
      76             : }
      77             : 
      78      457632 : void ActionWithVector::clearInputForces( const bool& force ) {
      79      457632 :   if( !force && actionInChain() ) return;
      80      338953 :   ActionWithValue::clearInputForces();
      81      338953 :   if( action_to_do_after ) action_to_do_after->clearInputForces( true );
      82             : }
      83             : 
      84          46 : const ActionWithVector* ActionWithVector::getFirstActionInChain() const {
      85          46 :   if( !actionInChain() ) return this;
      86          46 :   return action_to_do_before->getFirstActionInChain();
      87             : }
      88             : 
      89   209535206 : ActionWithVector* ActionWithVector::getFirstActionInChain() {
      90   209535206 :   if( !actionInChain() ) return this;
      91   198646985 :   return action_to_do_before->getFirstActionInChain();
      92             : }
      93             : 
      94      456395 : void ActionWithVector::retrieveAtoms( const bool& force ) {
      95      456395 :   if( !force && actionInChain() || atomsWereRetrieved ) return;
      96      337377 :   ActionAtomistic::retrieveAtoms(); atomsWereRetrieved = !actionInChain();
      97      337377 :   if( action_to_do_after ) action_to_do_after->retrieveAtoms( true );
      98             : }
      99             : 
     100          46 : bool ActionWithVector::hasStoredArguments() const {
     101          46 :   std::string headstr=getFirstActionInChain()->getLabel();
     102         100 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     103          68 :     if( !getPntrToArgument(i)->ignoreStoredValue(headstr) ) return true;
     104             :   }
     105             :   return false;
     106             : }
     107             : 
     108         344 : bool ActionWithVector::argumentDependsOn( const std::string& headstr, ActionWithVector* faction, Value* thearg ) {
     109         826 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     110         488 :     if( this!=faction && thearg==getPntrToArgument(i) ) return true;
     111         485 :     ActionWithVector* av = dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     112         485 :     if( av && (av->getFirstActionInChain())->getLabel()==headstr ) {
     113         180 :       if( av->argumentDependsOn( headstr, faction, thearg ) ) return true;;
     114             :     }
     115             :   }
     116             :   return false;
     117             : }
     118             : 
     119        3401 : unsigned ActionWithVector::buildArgumentStore( const unsigned& argstart ) {
     120             :   // Don't use chains for grids
     121       10627 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     122        7608 :     if( getPntrToArgument(i)->isConstant() ) continue;
     123        6707 :     ActionWithVector* av=dynamic_cast<ActionWithVector*>(getPntrToArgument(i)->getPntrToAction());
     124        6707 :     if( !av || getPntrToArgument(i)->getRank()>0 && getPntrToArgument(i)->hasDerivatives() ) { done_in_chain=false; break; }
     125             :   }
     126        3401 :   if( done_in_chain ) {
     127             :     std::vector<std::string> alabels; std::vector<ActionWithVector*> f_actions;
     128        8623 :     for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     129        6200 :       bool found=false; std::string mylab = (getPntrToArgument(i)->getPntrToAction())->getLabel();
     130       12803 :       for(unsigned j=0; j<alabels.size(); ++j) {
     131        8749 :         if( alabels[j]==mylab ) { found=true; break; }
     132             :       }
     133        6200 :       if( !found ) alabels.push_back( mylab );
     134             : 
     135             :       // If this is calculated in setup we never need to add to chain
     136        6200 :       if( getPntrToArgument(i)->isConstant() ) continue;
     137             :       // Find the chain we need to add this to from the arguments
     138        5783 :       ActionWithVector* av=dynamic_cast<ActionWithVector*>(getPntrToArgument(i)->getPntrToAction()); plumed_assert( av );
     139        5783 :       found=false; ActionWithVector* myact = av->getFirstActionInChain();
     140        5783 :       if( getPntrToArgument(i)->getRank()==1 && getPntrToArgument(i)->storedata ) {
     141        5540 :         for(unsigned j=argstart; j<getNumberOfArguments(); ++j) {
     142        5252 :           ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getPntrToArgument(j)->getPntrToAction() );
     143        5252 :           if( !aarg || i==j ) continue;
     144       14182 :           for(unsigned k=0; k<aarg->getNumberOfArguments(); ++k) {
     145        9263 :             if( aarg->getPntrToArgument(k)==getPntrToArgument(i) ) { done_in_chain=false; return reallyBuildArgumentStore( argstart ); }
     146             :           }
     147             :         }
     148             :       }
     149        6129 :       for(unsigned j=0; j<f_actions.size(); ++j) {
     150        3320 :         if( f_actions[j]==myact ) { found=true; break; }
     151             :       }
     152        5763 :       if( !found ) {
     153        2809 :         if( f_actions.size()>0 ) {
     154         336 :           if( f_actions[0]->checkForDependency(myact) ) getPntrToArgument(i)->buildDataStore();
     155         336 :           if( myact->checkForDependency(f_actions[0]) ) error("cannot deal with arguments in this order. Try swapping argument order");
     156             :         }
     157        2809 :         if( !getPntrToArgument(i)->storedata && getPntrToArgument(i)->getRank()>0 ) f_actions.push_back( myact );
     158             :       }
     159             :     }
     160             :     // Now make sure that everything we need is in the chain
     161        2423 :     if( f_actions.size()>0 ) {
     162             :       // Check everything for later f_actions is done before f_actions[0]
     163        2448 :       for(unsigned i=1; i<f_actions.size(); ++i) {
     164         122 :         ActionWithArguments* aarg = dynamic_cast<ActionWithArguments*>( f_actions[i] );
     165         122 :         if( !aarg || aarg->getNumberOfArguments()==0 ) continue;
     166         179 :         for(unsigned j=0; j<aarg->getNumberOfArguments(); ++j) {
     167         134 :           if( (aarg->getPntrToArgument(j))->isConstant() ) continue ;
     168         123 :           bool found=false; std::string dep_argname = (aarg->getPntrToArgument(j))->getPntrToAction()->getLabel();
     169       17501 :           for(const auto & pp : plumed.getActionSet()) {
     170             :             Action* p(pp.get());
     171             :             // Check if this is the dependency
     172       17501 :             if( p->getLabel()==dep_argname ) { found=true; break; }
     173             :             // Check if this is the first of the arguments that will appear in this chain
     174       17389 :             else if( p->getLabel()==f_actions[0]->getLabel() ) break;
     175             :           }
     176         123 :           if( !found ) { done_in_chain=false; break; }
     177             :         }
     178             :         // Stop trying to add things in the chain if we cannot
     179          56 :         if( !done_in_chain ) return reallyBuildArgumentStore( argstart );
     180             :       }
     181        2326 :       std::vector<std::string> empty(1); empty[0] = f_actions[0]->getLabel();
     182        2437 :       for(unsigned i=1; i<f_actions.size(); ++i) f_actions[0]->addActionToChain( empty, f_actions[i] );
     183        2326 :     }
     184             :     // Now add this argument to the chain
     185             :     bool added=false;
     186        2461 :     for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     187             :       // Add this function to jobs to do in recursive loop in previous action
     188        2461 :       if( getPntrToArgument(i)->getRank()>0 && !getPntrToArgument(i)->isConstant() ) {
     189        2461 :         ActionWithVector* av=dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     190        2461 :         if( av && av->addActionToChain( alabels, this ) ) { added=true; break; }
     191             :       }
     192             :     }
     193        2412 :     plumed_massert(added, "could not add action " + getLabel() + " to chain of any of its arguments");
     194             :     // And get the number of derivatives
     195        2412 :     ActionWithVector* head=getFirstActionInChain();
     196        2412 :     unsigned nder=0; arg_deriv_starts.resize( getNumberOfArguments() );
     197        8565 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     198             :       // Ensures that we ignore the grid (first argument) if we are evaluating a function on a grid
     199        6153 :       if( i==0 && getName().find("EVALUATE_FUNCTION_FROM_GRID")!=std::string::npos ) continue ;
     200        6152 :       ActionWithVector* iaction=dynamic_cast<ActionWithVector*>(getPntrToArgument(i)->getPntrToAction());
     201        6152 :       if( actionInChain() && !getPntrToArgument(i)->ignoreStoredValue(head->getLabel()) ) {
     202         675 :         arg_deriv_starts[i] = 0; head->getNumberOfStreamedDerivatives( arg_deriv_starts[i], getPntrToArgument(i) );
     203        5477 :       } else if( iaction && iaction->isInSubChain(nder) ) {
     204        2255 :         arg_deriv_starts[i] = nder;
     205             :         // Add the total number of derivatives that we have by this point in the chain to nder
     206        2255 :         if( iaction ) { nder=0; head->getNumberOfStreamedDerivatives( nder, getPntrToArgument(i) ); }
     207             :       } else {
     208             :         // Check if we have already found this action
     209             :         int k=-1;
     210        3222 :         if( iaction ) {
     211        3222 :           ActionWithVector* ider_action=iaction->getActionWithDerivatives( iaction );
     212        3443 :           for(unsigned j=0; j<i; ++j) {
     213        1628 :             if( j==0 && getName().find("EVALUATE_FUNCTION_FROM_GRID")!=std::string::npos ) continue ;
     214        1627 :             ActionWithVector* jaction=dynamic_cast<ActionWithVector*>(getPntrToArgument(j)->getPntrToAction());
     215        1627 :             if( jaction->getActionWithDerivatives(jaction)==ider_action || jaction->checkForDependency(ider_action) ) { k=j; break; }
     216             :           }
     217        3222 :           if( k>=0 ) { arg_deriv_starts[i] = arg_deriv_starts[k]; continue; }
     218             :         }
     219             : 
     220        1815 :         if( i>0 ) {
     221             :           // This is a fudge so that inputs like this work:
     222             :           // c: CONTACT_MATRIX ATOMS=1-100
     223             :           // d: MATRIX_PRODUCT ARG=mat1,mat2
     224             :           // e: CUSTOM ARG=c,d
     225             :           // f: MATRIX_PRODUCT ARG=mat3,mat4
     226             :           // g: CUSTOM ARG=c,f
     227             :           // See symfunc rt-nbonds-q6 for an example
     228             :           // In this example when we set arg_deriv_starts[1] for f in g nder=number of derivatives of c
     229             :           // mder is equal to the number of derivatives by the time you get to f minus the number of derivatives for c
     230         136 :           unsigned mder=0;
     231         136 :           ActionWithVector* jaction=dynamic_cast<ActionWithVector*>(getPntrToArgument(i-1)->getPntrToAction());
     232         136 :           if( jaction->action_to_do_after && !(jaction->action_to_do_after)->getNumberOfStoredValues( getPntrToArgument(i-1), mder, i, getArguments() ) ) mder=0;
     233         136 :           if( mder>0 ) nder = nder + mder;
     234             :         }
     235             : 
     236        1815 :         arg_deriv_starts[i] = nder;
     237             :         // Add the total number of derivatives that we have by this point in the chain to nder
     238        1815 :         if( iaction ) {
     239        1815 :           nder=0;
     240        1815 :           if( (getPntrToArgument(i)->getPntrToAction())->getName().find("DIFFERENCE")!=std::string::npos ) {
     241           0 :             ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getPntrToArgument(i)->getPntrToAction() );
     242           0 :             plumed_assert( aarg && aarg->getNumberOfArguments()==2 );
     243           0 :             head->getNumberOfStreamedDerivatives( nder, aarg->getPntrToArgument(0) );
     244           0 :             nder += (aarg->getPntrToArgument(1))->getNumberOfValues();
     245        1815 :           } else head->getNumberOfStreamedDerivatives( nder, getPntrToArgument(i) );
     246             :         }
     247             :       }
     248             :     }
     249        2412 :     nder=0; head->getNumberOfStreamedDerivatives( nder, NULL );
     250        2412 :     return nder;
     251        2443 :   }
     252         958 :   return reallyBuildArgumentStore( argstart );
     253             : }
     254             : 
     255         989 : unsigned ActionWithVector::reallyBuildArgumentStore( const unsigned& argstart ) {
     256        2703 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) { if( getPntrToArgument(i)->getRank()>0 ) getPntrToArgument(i)->buildDataStore(); }
     257         989 :   unsigned nder=0; arg_deriv_starts.resize( getNumberOfArguments() );
     258        2703 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) { arg_deriv_starts[i] = nder; nder += getPntrToArgument(i)->getNumberOfValues(); }
     259         989 :   return nder;
     260             : }
     261             : 
     262       17691 : ActionWithVector* ActionWithVector::getActionWithDerivatives( ActionWithVector* depaction ) {
     263       17691 :   if( depaction==this || depaction->checkForDependency(this) ) {
     264       11635 :     if( getNumberOfAtoms()>0 ) return this;
     265        6786 :     std::string c=getFirstActionInChain()->getLabel();
     266       42648 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     267       36322 :       if( !getPntrToArgument(i)->ignoreStoredValue(c) && !getPntrToArgument(i)->isConstant() ) return this;
     268             :     }
     269             :   }
     270       12842 :   plumed_assert( action_to_do_before );
     271       12842 :   return action_to_do_before->getActionWithDerivatives(depaction);
     272             : }
     273             : 
     274       11762 : bool ActionWithVector::addActionToChain( const std::vector<std::string>& alabels, ActionWithVector* act ) {
     275       11762 :   if( action_to_do_after ) { bool state=action_to_do_after->addActionToChain( alabels, act ); return state; }
     276             :   // Check action is not already in chain
     277        2572 :   std::vector<std::string> mylabels; getFirstActionInChain()->getAllActionLabelsInChain( mylabels );
     278       21211 :   for(unsigned i=0; i<mylabels.size(); ++i) {
     279       18639 :     if( act->getLabel()==mylabels[i] ) return true;
     280             :   }
     281             : 
     282             :   // Check that everything that is required has been calculated
     283        6756 :   for(unsigned i=0; i<alabels.size(); ++i) {
     284             :     bool found=false;
     285       20767 :     for(unsigned j=0; j<mylabels.size(); ++j) {
     286       20037 :       if( alabels[i]==mylabels[j] ) { found=true; break; }
     287             :     }
     288        4233 :     if( !found ) {
     289         730 :       ActionWithValue* av=plumed.getActionSet().selectWithLabel<ActionWithValue*>( alabels[i] );
     290         730 :       plumed_massert( av, "could not cast " + alabels[i] ); bool storingall=true;
     291        1522 :       for(int j=0; j<av->getNumberOfComponents(); ++j) {
     292         792 :         if( !(av->getPntrToComponent(j))->storedata ) storingall=false;
     293             :       }
     294         730 :       if( !storingall ) return false;
     295             :     }
     296             :   }
     297             :   // This checks that there is nothing that will cause problems in the chain
     298        2523 :   mylabels.resize(0); getFirstActionInChain()->getAllActionLabelsInChain( mylabels );
     299       20709 :   for(unsigned i=0; i<mylabels.size(); ++i) {
     300       18186 :     ActionWithVector* av1=plumed.getActionSet().selectWithLabel<ActionWithVector*>( mylabels[i] );
     301      176648 :     for(unsigned j=0; j<i; ++j) {
     302      158462 :       ActionWithVector* av2=plumed.getActionSet().selectWithLabel<ActionWithVector*>( mylabels[j] );
     303      158462 :       if( !av1->canBeAfterInChain( av2 ) ) error("must calculate " + mylabels[j] + " before " + mylabels[i] );
     304             :     }
     305             :   }
     306        2523 :   action_to_do_after=act; act->action_to_do_before=this; updateTaskListReductionStatus();
     307        2523 :   ActionWithVector* head = getFirstActionInChain();
     308        2523 :   head->broadcastThatTasksAreReduced( head ); head->finishChainBuild( act );
     309             :   return true;
     310        2572 : }
     311             : 
     312        2674 : void ActionWithVector::updateTaskListReductionStatus() {
     313        2674 :   ActionWithVector* head = getFirstActionInChain();
     314        2674 :   std::vector<ActionWithVector*> task_reducing_actions; head->canReduceTasks( task_reducing_actions );
     315        2674 :   if( task_reducing_actions.size()>0 ) head->reduce_tasks=true;
     316        2674 : }
     317             : 
     318     3843518 : void ActionWithVector::broadcastThatTasksAreReduced( ActionWithVector* aselect ) {
     319     3843518 :   std::string c=getFirstActionInChain()->getLabel();
     320    18085391 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     321    14241873 :     if( !getPntrToArgument(i)->ignoreStoredValue(c) ) {
     322       71210 :       ActionWithVector* av = dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     323       71210 :       if( av ) {
     324             :         bool found=false;
     325       12111 :         ActionWithVector* av_head = av->getFirstActionInChain();
     326       17731 :         for(unsigned i=0; i<av_head->task_control_list.size(); ++i) {
     327       17268 :           if( aselect==av_head->task_control_list[i] ) { found=true; break; }
     328             :         }
     329       12111 :         if( !found ) av_head->task_control_list.insert( av_head->task_control_list.begin(), aselect );
     330             : 
     331       12111 :         av_head->reduce_tasks=true; av_head->updateTaskReductionFlag( av_head->reduce_tasks );
     332             :       }
     333             :     }
     334             :   }
     335     3843518 :   if( action_to_do_after ) action_to_do_after->broadcastThatTasksAreReduced( aselect );
     336     3843518 : }
     337             : 
     338      229464 : void ActionWithVector::updateTaskReductionFlag( bool& head_reduce_tasks ) {
     339      229464 :   if( actionInChain() ) {
     340      217353 :     plumed_assert( task_control_list.size()==0 );
     341             :   } else {
     342       30767 :     for(unsigned i=0; i<task_control_list.size(); ++i) {
     343       18656 :       if( !(task_control_list[i]->getFirstActionInChain())->reduce_tasks ) head_reduce_tasks=false;
     344             :     }
     345             :   }
     346      229464 :   broadcastThatTasksAreReduced( getFirstActionInChain() );
     347      229464 :   if( action_to_do_after ) action_to_do_after->updateTaskReductionFlag( head_reduce_tasks );
     348      229464 : }
     349             : 
     350       20916 : void ActionWithVector::canReduceTasks( std::vector<ActionWithVector*>& task_reducing_actions ) {
     351       20916 :   areAllTasksRequired( task_reducing_actions );
     352       20916 :   if( action_to_do_after ) action_to_do_after->canReduceTasks( task_reducing_actions );
     353       20916 : }
     354             : 
     355        3544 : void ActionWithVector::finishChainBuild( ActionWithVector* act ) {
     356        3544 :   if( action_to_do_after ) action_to_do_after->finishChainBuild( act );
     357        3544 : }
     358             : 
     359       36905 : void ActionWithVector::getAllActionLabelsInChain( std::vector<std::string>& mylabels ) const {
     360             :   bool found = false ;
     361      359315 :   for(unsigned i=0; i<mylabels.size(); ++i) {
     362      322410 :     if( getLabel()==mylabels[i] ) { found=true; }
     363             :   }
     364       36905 :   if( !found ) mylabels.push_back( getLabel() );
     365       36905 :   if( action_to_do_after ) action_to_do_after->getAllActionLabelsInChain( mylabels );
     366       36905 : }
     367             : 
     368     6793058 : void ActionWithVector::taskIsActive( const unsigned& current, int& flag ) const {
     369     6793058 :   if( isActive() ) flag = checkTaskStatus( current, flag );
     370     6793058 :   if( flag<=0 && action_to_do_after ) action_to_do_after->taskIsActive( current, flag );
     371     6793058 : }
     372             : 
     373        1309 : void ActionWithVector::getAdditionalTasksRequired( ActionWithVector* action, std::vector<unsigned>& atasks ) {
     374        1341 :   for(unsigned i=0; i<task_control_list.size(); ++i ) task_control_list[i]->getAdditionalTasksRequired( action, atasks );
     375        1309 : }
     376             : 
     377      274530 : void ActionWithVector::prepare() {
     378      274530 :   active_tasks.resize(0); atomsWereRetrieved=false;
     379      274530 : }
     380             : 
     381      144849 : std::vector<unsigned>& ActionWithVector::getListOfActiveTasks( ActionWithVector* action ) {
     382      144849 :   if( active_tasks.size()>0 ) return active_tasks;
     383      132859 :   unsigned ntasks=0; getNumberOfTasks( ntasks );
     384             : 
     385      132859 :   unsigned stride=comm.Get_size();
     386      132859 :   unsigned rank=comm.Get_rank();
     387      132859 :   if(serial) { stride=1; rank=0; }
     388             : 
     389             :   // Get number of threads for OpenMP
     390      132859 :   unsigned nt=OpenMP::getNumThreads();
     391      132859 :   if( nt*stride*10>ntasks ) nt=ntasks/stride/10;
     392             :   if( nt==0 ) nt=1;
     393             : 
     394      132859 :   if( !never_reduce_tasks && reduce_tasks ) {
     395        1493 :     if( task_control_list.size()>0 ) {
     396             :       // Get the list of tasks that are active in the action that uses the output of this action
     397         238 :       for(unsigned i=0; i<task_control_list.size(); ++i) {
     398         130 :         task_control_list[i]->retrieveAtoms();
     399         130 :         active_tasks = task_control_list[i]->getListOfActiveTasks( action );
     400             :       }
     401             :       // Now work out else we need from here to calculate the later action
     402         108 :       getAdditionalTasksRequired( action, active_tasks );
     403             :     } else {
     404        1385 :       std::vector<int> taskFlags( ntasks, -1 );
     405             : 
     406        1385 :       #pragma omp parallel num_threads(nt)
     407             :       {
     408             :         #pragma omp for nowait
     409             :         for(unsigned i=rank; i<ntasks; i+=stride ) {
     410             :           taskIsActive( i, taskFlags[i] );
     411             :         }
     412             :       }
     413     2492457 :       for(unsigned i=0; i<ntasks; ++i) taskFlags[i] = std::abs( taskFlags[i] );
     414        1385 :       if( !serial ) comm.Sum( taskFlags );
     415             : 
     416             :       unsigned nt=0;
     417     2492457 :       for(unsigned i=0; i<ntasks; ++i) {
     418     2491072 :         if( taskFlags[i]>=stride ) nt++;
     419             :       }
     420        1385 :       active_tasks.resize(nt); nt=0;
     421     2492457 :       for(unsigned i=0; i<ntasks; ++i) {
     422     2491072 :         if( taskFlags[i]>=stride ) { active_tasks[nt]=i; nt++; }
     423             :       }
     424        1385 :       getAdditionalTasksRequired( this, active_tasks );
     425             :     }
     426             :   } else {
     427      131366 :     active_tasks.resize( ntasks );
     428     5116683 :     for(unsigned i=0; i<ntasks; ++i) active_tasks[i]=i;
     429             :   }
     430      132859 :   return active_tasks;
     431             : }
     432             : 
     433      133004 : void ActionWithVector::runAllTasks() {
     434             : // Skip this if this is done elsewhere
     435      133004 :   if( action_to_do_before ) return;
     436             : 
     437      132969 :   unsigned stride=comm.Get_size();
     438      132969 :   unsigned rank=comm.Get_rank();
     439      132969 :   if(serial) { stride=1; rank=0; }
     440             : 
     441             :   // Get the list of active tasks
     442      132969 :   std::vector<unsigned> & partialTaskList( getListOfActiveTasks( this ) );
     443      132969 :   unsigned nactive_tasks=partialTaskList.size();
     444             : 
     445             :   // Get number of threads for OpenMP
     446      132969 :   unsigned nt=OpenMP::getNumThreads();
     447      132969 :   if( nt*stride*10>nactive_tasks ) nt=nactive_tasks/stride/10;
     448      132969 :   if( nt==0 ) nt=1;
     449             : 
     450             :   // Now do all preparations required to run all the tasks
     451             :   // prepareForTaskLoop();
     452             : 
     453             :   // Get the total number of streamed quantities that we need
     454      132969 :   unsigned nquants=0, nmatrices=0, maxcol=0, nbooks=0;
     455      132969 :   getNumberOfStreamedQuantities( getLabel(), nquants, nmatrices, maxcol, nbooks );
     456             :   // Get size for buffer
     457      132969 :   unsigned bufsize=0; getSizeOfBuffer( nactive_tasks, bufsize );
     458      132969 :   if( buffer.size()!=bufsize ) buffer.resize( bufsize );
     459             :   // Clear buffer
     460      132969 :   buffer.assign( buffer.size(), 0.0 );
     461             : 
     462             :   // Recover the number of derivatives we require
     463      132969 :   unsigned nderivatives = 0; bool gridsInStream=checkForGrids(nderivatives);
     464      132969 :   if( !doNotCalculateDerivatives() && !gridsInStream ) getNumberOfStreamedDerivatives( nderivatives, NULL );
     465             : 
     466      132969 :   #pragma omp parallel num_threads(nt)
     467             :   {
     468             :     std::vector<double> omp_buffer;
     469             :     if( nt>1 ) omp_buffer.resize( bufsize, 0.0 );
     470             :     MultiValue myvals( nquants, nderivatives, nmatrices, maxcol, nbooks );
     471             :     myvals.clearAll();
     472             : 
     473             :     #pragma omp for nowait
     474             :     for(unsigned i=rank; i<nactive_tasks; i+=stride) {
     475             :       // Calculate the stuff in the loop for this action
     476             :       runTask( partialTaskList[i], myvals );
     477             : 
     478             :       // Now transfer the data to the actions that accumulate values from the calculated quantities
     479             :       if( nt>1 ) gatherAccumulators( partialTaskList[i], myvals, omp_buffer );
     480             :       else gatherAccumulators( partialTaskList[i], myvals, buffer );
     481             : 
     482             :       // Clear the value
     483             :       myvals.clearAll();
     484             :     }
     485             :     #pragma omp critical
     486             :     gatherThreads( nt, bufsize, omp_buffer, buffer, myvals );
     487             :   }
     488             : 
     489             :   // MPI Gather everything
     490      132969 :   if( !serial && buffer.size()>0 ) gatherProcesses( buffer );
     491      132969 :   finishComputations( buffer );
     492             : }
     493             : 
     494      209939 : void ActionWithVector::gatherThreads( const unsigned& nt, const unsigned& bufsize, const std::vector<double>& omp_buffer, std::vector<double>& buffer, MultiValue& myvals ) {
     495   100317013 :   if( nt>1 ) for(unsigned i=0; i<bufsize; ++i) buffer[i]+=omp_buffer[i];
     496      209939 : }
     497             : 
     498      132962 : void ActionWithVector::gatherProcesses( std::vector<double>& buffer ) {
     499      132962 :   comm.Sum( buffer );
     500      132962 : }
     501             : 
     502      317683 : bool ActionWithVector::checkForGrids( unsigned& nder ) const {
     503      650581 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     504      341631 :     if( getConstPntrToComponent(i)->getRank()>0 && getConstPntrToComponent(i)->hasDerivatives() ) {
     505        8733 :       nder=getConstPntrToComponent(i)->getNumberOfGridDerivatives(); return true;
     506             :     }
     507             :   }
     508      308950 :   if( action_to_do_after ) return action_to_do_after->checkForGrids(nder);
     509             :   return false;
     510             : }
     511             : 
     512      314964 : void ActionWithVector::getNumberOfTasks( unsigned& ntasks ) {
     513      314964 :   if( ntasks==0 ) {
     514      130206 :     if( getNumberOfArguments()==1 && getNumberOfComponents()==1 && getPntrToComponent(0)->getRank()==0 ) {
     515        2285 :       if( !getPntrToArgument(0)->hasDerivatives() && getPntrToArgument(0)->getRank()==2 ) ntasks = getPntrToArgument(0)->getShape()[0];
     516        2268 :       else ntasks = getPntrToArgument(0)->getNumberOfValues();
     517             :     } else {
     518      127921 :       plumed_assert( getNumberOfComponents()>0 && getPntrToComponent(0)->getRank()>0 );
     519      127921 :       if( getPntrToComponent(0)->hasDerivatives() ) ntasks = getPntrToComponent(0)->getNumberOfValues();
     520      121860 :       else ntasks = getPntrToComponent(0)->getShape()[0];
     521             :     }
     522             :   }
     523      653872 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     524      338908 :     if( getPntrToComponent(i)->getRank()==0 ) {
     525       65937 :       if( getNumberOfArguments()!=1 ) error("mismatched numbers of tasks in streamed quantities");
     526       65937 :       if( getPntrToArgument(0)->hasDerivatives() && ntasks!=getPntrToArgument(0)->getNumberOfValues() ) error("mismatched numbers of tasks in streamed quantities");
     527       65937 :       else if ( !getPntrToArgument(0)->hasDerivatives() && ntasks!=getPntrToArgument(0)->getShape()[0] ) error("mismatched numbers of tasks in streamed quantities");
     528      272971 :     } else if( getPntrToComponent(i)->hasDerivatives() && ntasks!=getPntrToComponent(i)->getNumberOfValues() ) error("mismatched numbers of tasks in streamed quantities");
     529      272971 :     else if( !getPntrToComponent(i)->hasDerivatives() && ntasks!=getPntrToComponent(i)->getShape()[0] ) error("mismatched numbers of tasks in streamed quantities");
     530             :   }
     531      314964 :   if( action_to_do_after ) action_to_do_after->getNumberOfTasks( ntasks );
     532      314964 : }
     533             : 
     534      421278 : void ActionWithVector::setupStreamedComponents( const std::string& headstr, unsigned& nquants, unsigned& nmat, unsigned& maxcol, unsigned& nbookeeping ) {
     535     1075219 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     536      653941 :     if( !getPntrToArgument(i)->ignoreStoredValue(headstr) ) { getPntrToArgument(i)->streampos=nquants; nquants++; }
     537             :   }
     538      881595 :   for(int i=0; i<getNumberOfComponents(); ++i) { getPntrToComponent(i)->streampos=nquants; nquants++; }
     539      421278 : }
     540             : 
     541      421278 : void ActionWithVector::getNumberOfStreamedQuantities( const std::string& headstr, unsigned& nquants, unsigned& nmat, unsigned& maxcol, unsigned& nbookeeping ) {
     542      421278 :   setupStreamedComponents( headstr, nquants, nmat, maxcol, nbookeeping );
     543      421278 :   if( action_to_do_after ) action_to_do_after->getNumberOfStreamedQuantities( headstr, nquants, nmat, maxcol, nbookeeping );
     544      421278 : }
     545             : 
     546      317683 : void ActionWithVector::getSizeOfBuffer( const unsigned& nactive_tasks, unsigned& bufsize ) {
     547      659314 :   for(int i=0; i<getNumberOfComponents(); ++i) { getPntrToComponent(i)->bufstart=bufsize; bufsize += getPntrToComponent(i)->data.size(); }
     548      317683 :   if( action_to_do_after ) action_to_do_after->getSizeOfBuffer( nactive_tasks, bufsize );
     549      317683 : }
     550             : 
     551      424411 : void ActionWithVector::getNumberOfStreamedDerivatives( unsigned& nderivatives, Value* stopat ) {
     552      424411 :   std::string c=getFirstActionInChain()->getLabel();
     553     1144906 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     554      721170 :     if( !getPntrToArgument(i)->ignoreStoredValue(c) ) {
     555      385865 :       if( getPntrToArgument(i)==stopat ) return;
     556      385190 :       nderivatives += getPntrToArgument(i)->getNumberOfValues();
     557             :     }
     558             :   }
     559      423736 :   if( getNumberOfAtoms()>0 ) nderivatives += 3*getNumberOfAtoms() + 9;
     560             :   // Don't do the whole chain if we have been told to stop early
     561      423736 :   if( stopat && stopat->getPntrToAction()==this ) return;
     562             : 
     563      419562 :   if( action_to_do_after ) action_to_do_after->getNumberOfStreamedDerivatives( nderivatives, stopat );
     564             : }
     565             : 
     566         136 : bool ActionWithVector::getNumberOfStoredValues( Value* startat, unsigned& nvals, const unsigned& astart, const std::vector<Value*>& stopat ) {
     567         181 :   for(unsigned j=astart; j<stopat.size(); ++j) {
     568         151 :     if( stopat[j] && (stopat[j]->getPntrToAction()==this || (stopat[j]->getPntrToAction())->checkForDependency(this)) ) return true;
     569             :   }
     570             : 
     571          30 :   std::string c=getFirstActionInChain()->getLabel();
     572          77 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     573          47 :     if( !getPntrToArgument(i)->ignoreStoredValue(c) ) {
     574           4 :       for(unsigned j=astart; j<stopat.size(); ++j) {
     575           2 :         if( getPntrToArgument(i)==stopat[j] ) return true;
     576             :       }
     577           2 :       nvals += getPntrToArgument(i)->getNumberOfValues();
     578             :     }
     579             :   }
     580          30 :   if( startat->getPntrToAction()!=this && getNumberOfAtoms()>0 ) return false;
     581             : 
     582          30 :   if( action_to_do_after ) return action_to_do_after->getNumberOfStoredValues( startat, nvals, astart, stopat );
     583             :   return false;
     584             : }
     585             : 
     586    11340462 : void ActionWithVector::runTask( const unsigned& current, MultiValue& myvals ) const {
     587    11340462 :   if( isActive() ) {
     588    10224413 :     myvals.setTaskIndex(current); myvals.vector_call=true; performTask( current, myvals );
     589             :   }
     590    11340462 :   if( action_to_do_after ) action_to_do_after->runTask( current, myvals );
     591    11340462 : }
     592             : 
     593     9239280 : void ActionWithVector::gatherAccumulators( const unsigned& taskCode, const MultiValue& myvals, std::vector<double>& buffer ) const {
     594     9239280 :   if( isActive() ) {
     595    18562303 :     for(int i=0; i<getNumberOfComponents(); ++i) {
     596    10284069 :       unsigned bufstart = getConstPntrToComponent(i)->bufstart;
     597             :       // This looks after storing of scalars that are summed from vectors/matrices
     598    10284069 :       if( getConstPntrToComponent(i)->getRank()==0 ) {
     599             :         plumed_dbg_massert( bufstart<buffer.size(), "problem in " + getLabel() );
     600     1146054 :         unsigned sind = getConstPntrToComponent(i)->streampos; buffer[bufstart] += myvals.get(sind);
     601     1146054 :         if( getConstPntrToComponent(i)->hasDerivatives() ) {
     602    26904718 :           for(unsigned k=0; k<myvals.getNumberActive(sind); ++k) {
     603    25758664 :             unsigned kindex = myvals.getActiveIndex(sind,k);
     604             :             plumed_dbg_massert( bufstart+1+kindex<buffer.size(), "problem in " + getLabel()  );
     605    25758664 :             buffer[bufstart + 1 + kindex] += myvals.getDerivative(sind,kindex);
     606             :           }
     607             :         }
     608             :         // This looks after storing of vectors
     609     9138015 :       } else if( getConstPntrToComponent(i)->storedata ) gatherStoredValue( i, taskCode, myvals, bufstart, buffer );
     610             :     }
     611             :   }
     612     9239280 :   if( action_to_do_after ) action_to_do_after->gatherAccumulators( taskCode, myvals, buffer );
     613     9239280 : }
     614             : 
     615     3571815 : void ActionWithVector::gatherStoredValue( const unsigned& valindex, const unsigned& taskCode, const MultiValue& myvals,
     616             :     const unsigned& bufstart, std::vector<double>& buffer ) const {
     617             :   plumed_dbg_assert( getConstPntrToComponent(valindex)->getRank()==1 && !getConstPntrToComponent(valindex)->hasDeriv );
     618     3571815 :   unsigned vindex = getConstPntrToComponent(valindex)->bufstart + taskCode; plumed_dbg_massert( vindex<buffer.size(), "failing in " + getLabel() );
     619     3571815 :   buffer[vindex] += myvals.get(getConstPntrToComponent(valindex)->streampos);
     620     3571815 : }
     621             : 
     622      317683 : void ActionWithVector::finishComputations( const std::vector<double>& buf ) {
     623      317683 :   if( isActive() ) {
     624      527282 :     for(int i=0; i<getNumberOfComponents(); ++i) {
     625             :       // This gathers vectors and grids at the end of the calculation
     626      275615 :       unsigned bufstart = getPntrToComponent(i)->bufstart;
     627      275615 :       getPntrToComponent(i)->data.assign( getPntrToComponent(i)->data.size(), 0 );
     628      275615 :       if( (getPntrToComponent(i)->getRank()>0 && getPntrToComponent(i)->hasDerivatives()) || getPntrToComponent(i)->storedata ) {
     629      130918 :         unsigned sz_v = getPntrToComponent(i)->data.size();
     630    46583551 :         for(unsigned j=0; j<sz_v; ++j) {
     631             :           plumed_dbg_assert( bufstart+j<buf.size() );
     632    46452633 :           getPntrToComponent(i)->add( j, buf[bufstart+j] );
     633             :         }
     634             :         // Make sure single values are set
     635      144697 :       } else if( getPntrToComponent(i)->getRank()==0 ) getPntrToComponent(i)->set( buf[bufstart] );
     636             :       // This gathers derivatives of scalars
     637      275615 :       if( !doNotCalculateDerivatives() && getPntrToComponent(i)->hasDeriv && getPntrToComponent(i)->getRank()==0 ) {
     638    16229167 :         for(unsigned j=0; j<getPntrToComponent(i)->getNumberOfDerivatives(); ++j) getPntrToComponent(i)->setDerivative( j, buf[bufstart+1+j] );
     639             :       }
     640             :     }
     641             :   }
     642      317683 :   if( action_to_do_after ) action_to_do_after->finishComputations( buf );
     643      317683 : }
     644             : 
     645      292884 : bool ActionWithVector::checkChainForNonScalarForces() const {
     646      523180 :   for(unsigned i=0; i<getNumberOfComponents(); ++i) {
     647      305133 :     if( getConstPntrToComponent(i)->getRank()>0 && getConstPntrToComponent(i)->forcesWereAdded() ) return true;
     648             :   }
     649      218047 :   if( action_to_do_after ) return action_to_do_after->checkChainForNonScalarForces();
     650             :   return false;
     651             : }
     652             : 
     653      254422 : bool ActionWithVector::checkForForces() {
     654      254422 :   if( getPntrToComponent(0)->getRank()==0 ) return ActionWithValue::checkForForces();
     655      202650 :   else if( actionInChain() ) return false;
     656             : 
     657             :   // Check if there are any forces
     658      125264 :   if( !checkChainForNonScalarForces() ) return false;
     659             : 
     660             :   // Setup MPI parallel loop
     661       74837 :   unsigned stride=comm.Get_size();
     662       74837 :   unsigned rank=comm.Get_rank();
     663       74837 :   if(serial) { stride=1; rank=0; }
     664             : 
     665             :   // Get the number of tasks
     666       74837 :   std::vector<unsigned> force_tasks; getForceTasks( force_tasks );
     667       74837 :   Tools::removeDuplicates(force_tasks); unsigned nf_tasks=force_tasks.size();
     668             : 
     669             :   // Get number of threads for OpenMP
     670       74837 :   unsigned nt=OpenMP::getNumThreads();
     671       74837 :   if( nt*stride*10>nf_tasks ) nt=nf_tasks/stride/10;
     672             :   if( nt==0 ) nt=1;
     673             : 
     674             :   // Now determine how big the multivalue needs to be
     675       74837 :   unsigned nquants=0, nmatrices=0, maxcol=0, nbooks=0;
     676       74837 :   getNumberOfStreamedQuantities( getLabel(), nquants, nmatrices, maxcol, nbooks );
     677             :   // Recover the number of derivatives we require (this should be equal to the number of forces)
     678       74837 :   unsigned nderiv=0; getNumberOfStreamedDerivatives( nderiv, NULL );
     679       74837 :   if( forcesForApply.size()!=nderiv ) forcesForApply.resize( nderiv );
     680             :   // Clear force buffer
     681       74837 :   forcesForApply.assign( forcesForApply.size(), 0.0 );
     682             : 
     683       74837 :   #pragma omp parallel num_threads(nt)
     684             :   {
     685             :     std::vector<double> omp_forces;
     686             :     if( nt>1 ) omp_forces.resize( forcesForApply.size(), 0.0 );
     687             :     MultiValue myvals( nquants, nderiv, nmatrices, maxcol, nbooks );
     688             :     myvals.clearAll();
     689             : 
     690             :     #pragma omp for nowait
     691             :     for(unsigned i=rank; i<nf_tasks; i+=stride) {
     692             :       runTask( force_tasks[i], myvals );
     693             : 
     694             :       // Now get the forces
     695             :       if( nt>1 ) gatherForces( force_tasks[i], myvals, omp_forces );
     696             :       else gatherForces( force_tasks[i], myvals, forcesForApply );
     697             : 
     698             :       myvals.clearAll();
     699             :     }
     700             :     #pragma omp critical
     701             :     if(nt>1) for(unsigned i=0; i<forcesForApply.size(); ++i) forcesForApply[i]+=omp_forces[i];
     702             :   }
     703             :   // MPI Gather on forces
     704       74837 :   if( !serial ) comm.Sum( forcesForApply );
     705             :   return true;
     706             : }
     707             : 
     708     2039456 : bool ActionWithVector::checkComponentsForForce() const {
     709     2777915 :   for(unsigned i=0; i<values.size(); ++i) {
     710     2546733 :     if( getConstPntrToComponent(i)->forcesWereAdded() ) return true;
     711             :   }
     712             :   return false;
     713             : }
     714             : 
     715     5561312 : bool ActionWithVector::checkForTaskForce( const unsigned& itask, const Value* myval ) const {
     716             :   plumed_dbg_assert( !(myval->getRank()==2 && !myval->hasDerivatives()) );
     717     5561312 :   return fabs(myval->getForce(itask))>epsilon;
     718             : }
     719             : 
     720       90719 : void ActionWithVector::updateForceTasksFromValue( const Value* myval, std::vector<unsigned>& force_tasks ) const {
     721       90719 :   if( myval->getRank()>0 && myval->forcesWereAdded() ) {
     722       85478 :     unsigned nt = myval->getNumberOfValues();
     723       85478 :     if( !myval->hasDerivatives() ) nt = myval->getShape()[0];
     724     6149611 :     for(unsigned i=0; i<nt; ++i) {
     725     6064133 :       if( checkForTaskForce(i, myval) ) force_tasks.push_back( i );
     726             :     }
     727             :   }
     728       90719 : }
     729             : 
     730      103595 : void ActionWithVector::getForceTasks( std::vector<unsigned>& force_tasks ) const {
     731      103595 :   if( isActive() && checkComponentsForForce() ) {
     732      171577 :     for(unsigned k=0; k<values.size(); ++k) {
     733       91329 :       updateForceTasksFromValue( getConstPntrToComponent(k), force_tasks );
     734             :     }
     735             :   }
     736      103595 :   if( action_to_do_after ) action_to_do_after->getForceTasks( force_tasks );
     737      103595 : }
     738             : 
     739     1565796 : void ActionWithVector::gatherForcesOnStoredValue( const Value* myval, const unsigned& itask, const MultiValue& myvals, std::vector<double>& forces ) const {
     740             :   plumed_dbg_assert( myval->storedata && !(myval->getRank()==2 && !myval->hasDerivatives()) );
     741     1565796 :   double fforce = myval->getForce(itask);
     742             :   unsigned sspos = myval->getPositionInStream();
     743    20912845 :   for(unsigned j=0; j<myvals.getNumberActive(sspos); ++j) {
     744    19347049 :     unsigned jder=myvals.getActiveIndex(sspos, j); plumed_dbg_assert( jder<forces.size() );
     745    19347049 :     forces[jder] += fforce*myvals.getDerivative( sspos, jder );
     746             :   }
     747     1565796 : }
     748             : 
     749     2101182 : void ActionWithVector::gatherForces( const unsigned& itask, const MultiValue& myvals, std::vector<double>& forces ) const {
     750     2101182 :   if( isActive() && checkComponentsForForce() ) {
     751     3587802 :     for(unsigned k=0; k<getNumberOfComponents(); ++k) {
     752     1859776 :       const Value* myval=getConstPntrToComponent(k);
     753     1859776 :       if( myval->getRank()>0 && myval->forcesWereAdded() ) gatherForcesOnStoredValue( myval, itask, myvals, forces );
     754             :     }
     755             :   }
     756     2101182 :   if( action_to_do_after ) action_to_do_after->gatherForces( itask, myvals, forces );
     757     2101182 : }
     758             : 
     759      254422 : void ActionWithVector::apply() {
     760      254422 :   if( !checkForForces() ) return;
     761             :   // Find the top of the chain and add forces
     762      117831 :   unsigned ind=0; getFirstActionInChain()->addForcesToInput( getForcesToApply(), ind );
     763             : }
     764             : 
     765      186367 : void ActionWithVector::addForcesToInput( const std::vector<double>& forcesToApply, unsigned& ind ) {
     766      186367 :   if( ind>=forcesToApply.size() ) return;
     767      136821 :   addForcesOnArguments( 0, forcesToApply, ind, getFirstActionInChain()->getLabel() ); setForcesOnAtoms( forcesToApply, ind );
     768      136821 :   if( action_to_do_after ) action_to_do_after->addForcesToInput( forcesToApply, ind );
     769             : }
     770             : 
     771             : }

Generated by: LCOV version 1.16