LCOV - code coverage report
Current view: top level - core - ActionWithVector.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 541 555 97.5 %
Date: 2026-11-12 10:48:31 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        5614 : void ActionWithVector::registerKeywords( Keywords& keys ) {
      31        5614 :   Action::registerKeywords( keys );
      32        5614 :   ActionAtomistic::registerKeywords( keys );
      33        5614 :   ActionWithValue::registerKeywords( keys );
      34        5614 :   keys.remove("NUMERICAL_DERIVATIVES");
      35        5614 :   ActionWithArguments::registerKeywords( keys );
      36       11228 :   keys.addFlag("SERIAL",false,"do the calculation in serial.  Do not parallelize");
      37        5614 : }
      38             : 
      39        5001 : ActionWithVector::ActionWithVector(const ActionOptions&ao):
      40             :   Action(ao),
      41             :   ActionAtomistic(ao),
      42             :   ActionWithValue(ao),
      43             :   ActionWithArguments(ao),
      44        5001 :   serial(false),
      45        5001 :   action_to_do_before(NULL),
      46        5001 :   action_to_do_after(NULL),
      47        5001 :   never_reduce_tasks(false),
      48        5001 :   reduce_tasks(false),
      49        5001 :   atomsWereRetrieved(false),
      50        5001 :   done_in_chain(false) {
      51       10002 :   if( keywords.exists("SERIAL") ) {
      52        4956 :     parseFlag("SERIAL",serial);
      53             :   }
      54        5001 :   warning("you will likely obtain superior performance for this action if you update to version 2.11 or higher");
      55        5001 : }
      56             : 
      57        5001 : ActionWithVector::~ActionWithVector() {
      58        5001 :   if( action_to_do_before ) {
      59        2485 :     action_to_do_before->action_to_do_after=NULL;
      60             :   }
      61        5001 : }
      62             : 
      63      288992 : void ActionWithVector::lockRequests() {
      64             :   ActionAtomistic::lockRequests();
      65             :   ActionWithArguments::lockRequests();
      66      288992 : }
      67             : 
      68      288992 : void ActionWithVector::unlockRequests() {
      69             :   ActionAtomistic::unlockRequests();
      70             :   ActionWithArguments::unlockRequests();
      71      288992 : }
      72             : 
      73           0 : void ActionWithVector::calculateNumericalDerivatives(ActionWithValue* av) {
      74           0 :   plumed_merror("cannot calculate numerical derivative for action " + getName() + " with label " + getLabel() );
      75             : }
      76             : 
      77      473345 : void ActionWithVector::clearDerivatives( const bool& force ) {
      78      473345 :   if( !force && actionInChain() ) {
      79             :     return;
      80             :   }
      81      354357 :   ActionWithValue::clearDerivatives();
      82      354357 :   if( action_to_do_after ) {
      83      184956 :     action_to_do_after->clearDerivatives( true );
      84             :   }
      85             : }
      86             : 
      87      473345 : void ActionWithVector::clearInputForces( const bool& force ) {
      88      473345 :   if( !force && actionInChain() ) {
      89             :     return;
      90             :   }
      91      354357 :   ActionWithValue::clearInputForces();
      92      354357 :   if( action_to_do_after ) {
      93      184956 :     action_to_do_after->clearInputForces( true );
      94             :   }
      95             : }
      96             : 
      97          46 : const ActionWithVector* ActionWithVector::getFirstActionInChain() const {
      98          46 :   if( !actionInChain() ) {
      99             :     return this;
     100             :   }
     101          46 :   return action_to_do_before->getFirstActionInChain();
     102             : }
     103             : 
     104   209474253 : ActionWithVector* ActionWithVector::getFirstActionInChain() {
     105   209474253 :   if( !actionInChain() ) {
     106             :     return this;
     107             :   }
     108   198584362 :   return action_to_do_before->getFirstActionInChain();
     109             : }
     110             : 
     111      472099 : void ActionWithVector::retrieveAtoms( const bool& force ) {
     112      472099 :   if( !force && actionInChain() || atomsWereRetrieved ) {
     113             :     return;
     114             :   }
     115      352781 :   ActionAtomistic::retrieveAtoms();
     116      352781 :   atomsWereRetrieved = !actionInChain();
     117      352781 :   if( action_to_do_after ) {
     118      184942 :     action_to_do_after->retrieveAtoms( true );
     119             :   }
     120             : }
     121             : 
     122          46 : bool ActionWithVector::hasStoredArguments() const {
     123          46 :   std::string headstr=getFirstActionInChain()->getLabel();
     124         100 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     125          68 :     if( !getPntrToArgument(i)->ignoreStoredValue(headstr) ) {
     126             :       return true;
     127             :     }
     128             :   }
     129             :   return false;
     130             : }
     131             : 
     132         346 : bool ActionWithVector::argumentDependsOn( const std::string& headstr, ActionWithVector* faction, Value* thearg ) {
     133         830 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     134         490 :     if( this!=faction && thearg==getPntrToArgument(i) ) {
     135             :       return true;
     136             :     }
     137         487 :     ActionWithVector* av = dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     138         487 :     if( av && (av->getFirstActionInChain())->getLabel()==headstr ) {
     139         180 :       if( av->argumentDependsOn( headstr, faction, thearg ) ) {
     140             :         return true;
     141             :       };
     142             :     }
     143             :   }
     144             :   return false;
     145             : }
     146             : 
     147        3452 : unsigned ActionWithVector::buildArgumentStore( const unsigned& argstart ) {
     148             :   // Don't use chains for grids
     149       10729 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     150        7667 :     if( getPntrToArgument(i)->isConstant() ) {
     151         911 :       continue;
     152             :     }
     153        6756 :     ActionWithVector* av=dynamic_cast<ActionWithVector*>(getPntrToArgument(i)->getPntrToAction());
     154        6756 :     if( !av || getPntrToArgument(i)->getRank()>0 && getPntrToArgument(i)->hasDerivatives() ) {
     155         390 :       done_in_chain=false;
     156         390 :       break;
     157             :     }
     158             :   }
     159        3452 :   if( done_in_chain ) {
     160             :     std::vector<std::string> alabels;
     161             :     std::vector<ActionWithVector*> f_actions;
     162        8582 :     for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     163             :       bool found=false;
     164        6163 :       std::string mylab = (getPntrToArgument(i)->getPntrToAction())->getLabel();
     165       12731 :       for(unsigned j=0; j<alabels.size(); ++j) {
     166        8717 :         if( alabels[j]==mylab ) {
     167             :           found=true;
     168             :           break;
     169             :         }
     170             :       }
     171        6163 :       if( !found ) {
     172        4014 :         alabels.push_back( mylab );
     173             :       }
     174             : 
     175             :       // If this is calculated in setup we never need to add to chain
     176        6163 :       if( getPntrToArgument(i)->isConstant() ) {
     177             :         continue;
     178             :       }
     179             :       // Find the chain we need to add this to from the arguments
     180        5744 :       ActionWithVector* av=dynamic_cast<ActionWithVector*>(getPntrToArgument(i)->getPntrToAction());
     181        5744 :       plumed_assert( av );
     182             :       found=false;
     183        5744 :       ActionWithVector* myact = av->getFirstActionInChain();
     184        5744 :       if( getPntrToArgument(i)->getRank()==1 && getPntrToArgument(i)->storedata ) {
     185        5601 :         for(unsigned j=argstart; j<getNumberOfArguments(); ++j) {
     186        5282 :           ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getPntrToArgument(j)->getPntrToAction() );
     187        5282 :           if( !aarg || i==j ) {
     188         344 :             continue;
     189             :           }
     190       14180 :           for(unsigned k=0; k<aarg->getNumberOfArguments(); ++k) {
     191        9261 :             if( aarg->getPntrToArgument(k)==getPntrToArgument(i) ) {
     192          19 :               done_in_chain=false;
     193          19 :               return reallyBuildArgumentStore( argstart );
     194             :             }
     195             :           }
     196             :         }
     197             :       }
     198        6053 :       for(unsigned j=0; j<f_actions.size(); ++j) {
     199        3287 :         if( f_actions[j]==myact ) {
     200             :           found=true;
     201             :           break;
     202             :         }
     203             :       }
     204        5725 :       if( !found ) {
     205        2766 :         if( f_actions.size()>0 ) {
     206         298 :           if( f_actions[0]->checkForDependency(myact) ) {
     207          13 :             getPntrToArgument(i)->buildDataStore();
     208             :           }
     209         298 :           if( myact->checkForDependency(f_actions[0]) ) {
     210           0 :             error("cannot deal with arguments in this order. Try swapping argument order");
     211             :           }
     212             :         }
     213        2766 :         if( !getPntrToArgument(i)->storedata && getPntrToArgument(i)->getRank()>0 ) {
     214        2391 :           f_actions.push_back( myact );
     215             :         }
     216             :       }
     217             :     }
     218             :     // Now make sure that everything we need is in the chain
     219        2419 :     if( f_actions.size()>0 ) {
     220             :       // Check everything for later f_actions is done before f_actions[0]
     221        2377 :       for(unsigned i=1; i<f_actions.size(); ++i) {
     222          84 :         ActionWithArguments* aarg = dynamic_cast<ActionWithArguments*>( f_actions[i] );
     223          84 :         if( !aarg || aarg->getNumberOfArguments()==0 ) {
     224          30 :           continue;
     225             :         }
     226         175 :         for(unsigned j=0; j<aarg->getNumberOfArguments(); ++j) {
     227         130 :           if( (aarg->getPntrToArgument(j))->isConstant() ) {
     228           9 :             continue ;
     229             :           }
     230             :           bool found=false;
     231         121 :           std::string dep_argname = (aarg->getPntrToArgument(j))->getPntrToAction()->getLabel();
     232       17436 :           for(const auto & pp : plumed.getActionSet()) {
     233             :             Action* p(pp.get());
     234             :             // Check if this is the dependency
     235       17436 :             if( p->getLabel()==dep_argname ) {
     236             :               found=true;
     237             :               break;
     238             :             }
     239             :             // Check if this is the first of the arguments that will appear in this chain
     240       17324 :             else if( p->getLabel()==f_actions[0]->getLabel() ) {
     241             :               break;
     242             :             }
     243             :           }
     244         121 :           if( !found ) {
     245           9 :             done_in_chain=false;
     246             :             break;
     247             :           }
     248             :         }
     249             :         // Stop trying to add things in the chain if we cannot
     250          54 :         if( !done_in_chain ) {
     251           9 :           return reallyBuildArgumentStore( argstart );
     252             :         }
     253             :       }
     254        2293 :       std::vector<std::string> empty(1);
     255        2293 :       empty[0] = f_actions[0]->getLabel();
     256        2368 :       for(unsigned i=1; i<f_actions.size(); ++i) {
     257          75 :         f_actions[0]->addActionToChain( empty, f_actions[i] );
     258             :       }
     259        2293 :     }
     260             :     // Now add this argument to the chain
     261             :     bool added=false;
     262        2459 :     for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     263             :       // Add this function to jobs to do in recursive loop in previous action
     264        2459 :       if( getPntrToArgument(i)->getRank()>0 && !getPntrToArgument(i)->isConstant() ) {
     265        2459 :         ActionWithVector* av=dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     266        2459 :         if( av && av->addActionToChain( alabels, this ) ) {
     267             :           added=true;
     268             :           break;
     269             :         }
     270             :       }
     271             :     }
     272        2410 :     plumed_massert(added, "could not add action " + getLabel() + " to chain of any of its arguments");
     273             :     // And get the number of derivatives
     274        2410 :     ActionWithVector* head=getFirstActionInChain();
     275        2410 :     unsigned nder=0;
     276        2410 :     arg_deriv_starts.resize( getNumberOfArguments() );
     277        8532 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     278             :       // Ensures that we ignore the grid (first argument) if we are evaluating a function on a grid
     279        6122 :       if( i==0 && getName().find("EVALUATE_FUNCTION_FROM_GRID")!=std::string::npos ) {
     280           1 :         continue ;
     281             :       }
     282        6121 :       ActionWithVector* iaction=dynamic_cast<ActionWithVector*>(getPntrToArgument(i)->getPntrToAction());
     283        6121 :       if( actionInChain() && !getPntrToArgument(i)->ignoreStoredValue(head->getLabel()) ) {
     284         677 :         arg_deriv_starts[i] = 0;
     285         677 :         head->getNumberOfStreamedDerivatives( arg_deriv_starts[i], getPntrToArgument(i) );
     286        5444 :       } else if( iaction && iaction->isInSubChain(nder) ) {
     287        2183 :         arg_deriv_starts[i] = nder;
     288             :         // Add the total number of derivatives that we have by this point in the chain to nder
     289             :         if( iaction ) {
     290        2183 :           nder=0;
     291        2183 :           head->getNumberOfStreamedDerivatives( nder, getPntrToArgument(i) );
     292             :         }
     293             :       } else {
     294             :         // Check if we have already found this action
     295             :         int k=-1;
     296        3261 :         if( iaction ) {
     297        3261 :           ActionWithVector* ider_action=iaction->getActionWithDerivatives( iaction );
     298        3482 :           for(unsigned j=0; j<i; ++j) {
     299        1633 :             if( j==0 && getName().find("EVALUATE_FUNCTION_FROM_GRID")!=std::string::npos ) {
     300           1 :               continue ;
     301             :             }
     302        1632 :             ActionWithVector* jaction=dynamic_cast<ActionWithVector*>(getPntrToArgument(j)->getPntrToAction());
     303        1632 :             if( jaction->getActionWithDerivatives(jaction)==ider_action || jaction->checkForDependency(ider_action) ) {
     304        1412 :               k=j;
     305        1412 :               break;
     306             :             }
     307             :           }
     308        3261 :           if( k>=0 ) {
     309        1412 :             arg_deriv_starts[i] = arg_deriv_starts[k];
     310        1412 :             continue;
     311             :           }
     312             :         }
     313             : 
     314        1849 :         if( i>0 ) {
     315             :           // This is a fudge so that inputs like this work:
     316             :           // c: CONTACT_MATRIX ATOMS=1-100
     317             :           // d: MATRIX_PRODUCT ARG=mat1,mat2
     318             :           // e: CUSTOM ARG=c,d
     319             :           // f: MATRIX_PRODUCT ARG=mat3,mat4
     320             :           // g: CUSTOM ARG=c,f
     321             :           // See symfunc rt-nbonds-q6 for an example
     322             :           // In this example when we set arg_deriv_starts[1] for f in g nder=number of derivatives of c
     323             :           // mder is equal to the number of derivatives by the time you get to f minus the number of derivatives for c
     324         136 :           unsigned mder=0;
     325         136 :           ActionWithVector* jaction=dynamic_cast<ActionWithVector*>(getPntrToArgument(i-1)->getPntrToAction());
     326         136 :           if( jaction->action_to_do_after && !(jaction->action_to_do_after)->getNumberOfStoredValues( getPntrToArgument(i-1), mder, i, getArguments() ) ) {
     327           0 :             mder=0;
     328             :           }
     329         136 :           if( mder>0 ) {
     330           1 :             nder = nder + mder;
     331             :           }
     332             :         }
     333             : 
     334        1849 :         arg_deriv_starts[i] = nder;
     335             :         // Add the total number of derivatives that we have by this point in the chain to nder
     336        1849 :         if( iaction ) {
     337        1849 :           nder=0;
     338        1849 :           if( (getPntrToArgument(i)->getPntrToAction())->getName().find("DIFFERENCE")!=std::string::npos ) {
     339           0 :             ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getPntrToArgument(i)->getPntrToAction() );
     340           0 :             plumed_assert( aarg && aarg->getNumberOfArguments()==2 );
     341           0 :             head->getNumberOfStreamedDerivatives( nder, aarg->getPntrToArgument(0) );
     342           0 :             nder += (aarg->getPntrToArgument(1))->getNumberOfValues();
     343             :           } else {
     344        1849 :             head->getNumberOfStreamedDerivatives( nder, getPntrToArgument(i) );
     345             :           }
     346             :         }
     347             :       }
     348             :     }
     349        2410 :     nder=0;
     350        2410 :     head->getNumberOfStreamedDerivatives( nder, NULL );
     351        2410 :     return nder;
     352        2438 :   }
     353        1014 :   return reallyBuildArgumentStore( argstart );
     354             : }
     355             : 
     356        1042 : unsigned ActionWithVector::reallyBuildArgumentStore( const unsigned& argstart ) {
     357        2846 :   for(unsigned i=argstart; i<getNumberOfArguments(); ++i) {
     358        1804 :     if( getPntrToArgument(i)->getRank()>0 ) {
     359        1558 :       getPntrToArgument(i)->buildDataStore();
     360             :     }
     361             :   }
     362             :   unsigned nder=0;
     363        1042 :   arg_deriv_starts.resize( getNumberOfArguments() );
     364        2846 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     365        1804 :     arg_deriv_starts[i] = nder;
     366        1804 :     nder += getPntrToArgument(i)->getNumberOfValues();
     367             :   }
     368        1042 :   return nder;
     369             : }
     370             : 
     371       17841 : ActionWithVector* ActionWithVector::getActionWithDerivatives( ActionWithVector* depaction ) {
     372       17841 :   if( depaction==this || depaction->checkForDependency(this) ) {
     373       11247 :     if( getNumberOfAtoms()>0 ) {
     374        4893 :       return this;
     375             :     }
     376        6851 :     std::string c=getFirstActionInChain()->getLabel();
     377       42713 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     378       36359 :       if( !getPntrToArgument(i)->ignoreStoredValue(c) && !getPntrToArgument(i)->isConstant() ) {
     379             :         return this;
     380             :       }
     381             :     }
     382             :   }
     383       12948 :   plumed_assert( action_to_do_before );
     384       12948 :   return action_to_do_before->getActionWithDerivatives(depaction);
     385             : }
     386             : 
     387       10495 : bool ActionWithVector::addActionToChain( const std::vector<std::string>& alabels, ActionWithVector* act ) {
     388       10495 :   if( action_to_do_after ) {
     389        7961 :     bool state=action_to_do_after->addActionToChain( alabels, act );
     390        7961 :     return state;
     391             :   }
     392             :   // Check action is not already in chain
     393             :   std::vector<std::string> mylabels;
     394        2534 :   getFirstActionInChain()->getAllActionLabelsInChain( mylabels );
     395       19308 :   for(unsigned i=0; i<mylabels.size(); ++i) {
     396       16774 :     if( act->getLabel()==mylabels[i] ) {
     397             :       return true;
     398             :     }
     399             :   }
     400             : 
     401             :   // Check that everything that is required has been calculated
     402        6648 :   for(unsigned i=0; i<alabels.size(); ++i) {
     403             :     bool found=false;
     404       19801 :     for(unsigned j=0; j<mylabels.size(); ++j) {
     405       19069 :       if( alabels[i]==mylabels[j] ) {
     406             :         found=true;
     407             :         break;
     408             :       }
     409             :     }
     410        4163 :     if( !found ) {
     411         732 :       ActionWithValue* av=plumed.getActionSet().selectWithLabel<ActionWithValue*>( alabels[i] );
     412         732 :       plumed_massert( av, "could not cast " + alabels[i] );
     413             :       bool storingall=true;
     414        1526 :       for(int j=0; j<av->getNumberOfComponents(); ++j) {
     415         794 :         if( !(av->getPntrToComponent(j))->storedata ) {
     416             :           storingall=false;
     417             :         }
     418             :       }
     419         732 :       if( !storingall ) {
     420             :         return false;
     421             :       }
     422             :     }
     423             :   }
     424             :   // This checks that there is nothing that will cause problems in the chain
     425        2485 :   mylabels.resize(0);
     426        2485 :   getFirstActionInChain()->getAllActionLabelsInChain( mylabels );
     427       18806 :   for(unsigned i=0; i<mylabels.size(); ++i) {
     428       16321 :     ActionWithVector* av1=plumed.getActionSet().selectWithLabel<ActionWithVector*>( mylabels[i] );
     429      153887 :     for(unsigned j=0; j<i; ++j) {
     430      137566 :       ActionWithVector* av2=plumed.getActionSet().selectWithLabel<ActionWithVector*>( mylabels[j] );
     431      137566 :       if( !av1->canBeAfterInChain( av2 ) ) {
     432           0 :         error("must calculate " + mylabels[j] + " before " + mylabels[i] );
     433             :       }
     434             :     }
     435             :   }
     436        2485 :   action_to_do_after=act;
     437        2485 :   act->action_to_do_before=this;
     438        2485 :   updateTaskListReductionStatus();
     439        2485 :   ActionWithVector* head = getFirstActionInChain();
     440        2485 :   head->broadcastThatTasksAreReduced( head );
     441        2485 :   head->finishChainBuild( act );
     442             :   return true;
     443        2534 : }
     444             : 
     445        2640 : void ActionWithVector::updateTaskListReductionStatus() {
     446        2640 :   ActionWithVector* head = getFirstActionInChain();
     447             :   std::vector<ActionWithVector*> task_reducing_actions;
     448        2640 :   head->canReduceTasks( task_reducing_actions );
     449        2640 :   if( task_reducing_actions.size()>0 ) {
     450         319 :     head->reduce_tasks=true;
     451             :   }
     452        2640 : }
     453             : 
     454     3841714 : void ActionWithVector::broadcastThatTasksAreReduced( ActionWithVector* aselect ) {
     455     3841714 :   std::string c=getFirstActionInChain()->getLabel();
     456    18080207 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     457    14238493 :     if( !getPntrToArgument(i)->ignoreStoredValue(c) ) {
     458       71083 :       ActionWithVector* av = dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     459       71083 :       if( av ) {
     460             :         bool found=false;
     461       12049 :         ActionWithVector* av_head = av->getFirstActionInChain();
     462       17754 :         for(unsigned i=0; i<av_head->task_control_list.size(); ++i) {
     463       17217 :           if( aselect==av_head->task_control_list[i] ) {
     464             :             found=true;
     465             :             break;
     466             :           }
     467             :         }
     468       12049 :         if( !found ) {
     469         537 :           av_head->task_control_list.insert( av_head->task_control_list.begin(), aselect );
     470             :         }
     471             : 
     472       12049 :         av_head->reduce_tasks=true;
     473       12049 :         av_head->updateTaskReductionFlag( av_head->reduce_tasks );
     474             :       }
     475             :     }
     476             :   }
     477     3841714 :   if( action_to_do_after ) {
     478     3609739 :     action_to_do_after->broadcastThatTasksAreReduced( aselect );
     479             :   }
     480     3841714 : }
     481             : 
     482      229490 : void ActionWithVector::updateTaskReductionFlag( bool& head_reduce_tasks ) {
     483      229490 :   if( actionInChain() ) {
     484      217441 :     plumed_assert( task_control_list.size()==0 );
     485             :   } else {
     486       30600 :     for(unsigned i=0; i<task_control_list.size(); ++i) {
     487       18551 :       if( !(task_control_list[i]->getFirstActionInChain())->reduce_tasks ) {
     488       17359 :         head_reduce_tasks=false;
     489             :       }
     490             :     }
     491             :   }
     492      229490 :   broadcastThatTasksAreReduced( getFirstActionInChain() );
     493      229490 :   if( action_to_do_after ) {
     494      217441 :     action_to_do_after->updateTaskReductionFlag( head_reduce_tasks );
     495             :   }
     496      229490 : }
     497             : 
     498       19013 : void ActionWithVector::canReduceTasks( std::vector<ActionWithVector*>& task_reducing_actions ) {
     499       19013 :   areAllTasksRequired( task_reducing_actions );
     500       19013 :   if( action_to_do_after ) {
     501       16373 :     action_to_do_after->canReduceTasks( task_reducing_actions );
     502             :   }
     503       19013 : }
     504             : 
     505        3874 : void ActionWithVector::finishChainBuild( ActionWithVector* act ) {
     506        3874 :   if( action_to_do_after ) {
     507        3187 :     action_to_do_after->finishChainBuild( act );
     508             :   }
     509        3874 : }
     510             : 
     511       33175 : void ActionWithVector::getAllActionLabelsInChain( std::vector<std::string>& mylabels ) const {
     512             :   bool found = false ;
     513      313793 :   for(unsigned i=0; i<mylabels.size(); ++i) {
     514      280618 :     if( getLabel()==mylabels[i] ) {
     515             :       found=true;
     516             :     }
     517             :   }
     518       33175 :   if( !found ) {
     519       33175 :     mylabels.push_back( getLabel() );
     520             :   }
     521       33175 :   if( action_to_do_after ) {
     522       28145 :     action_to_do_after->getAllActionLabelsInChain( mylabels );
     523             :   }
     524       33175 : }
     525             : 
     526     6014383 : void ActionWithVector::taskIsActive( const unsigned& current, int& flag ) const {
     527     6014383 :   if( isActive() ) {
     528     6014383 :     flag = checkTaskStatus( current, flag );
     529             :   }
     530     6014383 :   if( flag<=0 && action_to_do_after ) {
     531     3732005 :     action_to_do_after->taskIsActive( current, flag );
     532             :   }
     533     6014383 : }
     534             : 
     535        1400 : void ActionWithVector::getAdditionalTasksRequired( ActionWithVector* action, std::vector<unsigned>& atasks ) {
     536        1445 :   for(unsigned i=0; i<task_control_list.size(); ++i ) {
     537          45 :     task_control_list[i]->getAdditionalTasksRequired( action, atasks );
     538             :   }
     539        1400 : }
     540             : 
     541      289998 : void ActionWithVector::prepare() {
     542      289998 :   active_tasks.resize(0);
     543      289998 :   atomsWereRetrieved=false;
     544      289998 : }
     545             : 
     546      147420 : std::vector<unsigned>& ActionWithVector::getListOfActiveTasks( ActionWithVector* action ) {
     547      147420 :   if( active_tasks.size()>0 ) {
     548       11971 :     return active_tasks;
     549             :   }
     550      135449 :   unsigned ntasks=0;
     551      135449 :   getNumberOfTasks( ntasks );
     552             : 
     553      135449 :   unsigned stride=comm.Get_size();
     554      135449 :   unsigned rank=comm.Get_rank();
     555      135449 :   if(serial) {
     556             :     stride=1;
     557             :     rank=0;
     558             :   }
     559             : 
     560             :   // Get number of threads for OpenMP
     561      135449 :   unsigned nt=OpenMP::getNumThreads();
     562      135449 :   if( nt*stride*10>ntasks ) {
     563       58134 :     nt=ntasks/stride/10;
     564             :   }
     565             :   if( nt==0 ) {
     566             :     nt=1;
     567             :   }
     568             : 
     569      135449 :   if( !never_reduce_tasks && reduce_tasks ) {
     570        1450 :     if( task_control_list.size()>0 ) {
     571             :       // Get the list of tasks that are active in the action that uses the output of this action
     572         220 :       for(unsigned i=0; i<task_control_list.size(); ++i) {
     573         121 :         task_control_list[i]->retrieveAtoms();
     574         121 :         active_tasks = task_control_list[i]->getListOfActiveTasks( action );
     575             :       }
     576             :       // Now work out else we need from here to calculate the later action
     577          99 :       getAdditionalTasksRequired( action, active_tasks );
     578             :     } else {
     579        1351 :       std::vector<int> taskFlags( ntasks, -1 );
     580             : 
     581        1351 :       #pragma omp parallel num_threads(nt)
     582             :       {
     583             :         #pragma omp for nowait
     584             :         for(unsigned i=rank; i<ntasks; i+=stride ) {
     585             :           taskIsActive( i, taskFlags[i] );
     586             :         }
     587             :       }
     588     2482527 :       for(unsigned i=0; i<ntasks; ++i) {
     589     2481176 :         taskFlags[i] = std::abs( taskFlags[i] );
     590             :       }
     591        1351 :       if( !serial ) {
     592        1351 :         comm.Sum( taskFlags );
     593             :       }
     594             : 
     595             :       unsigned nt=0;
     596     2482527 :       for(unsigned i=0; i<ntasks; ++i) {
     597     2481176 :         if( taskFlags[i]>=stride ) {
     598      261189 :           nt++;
     599             :         }
     600             :       }
     601        1351 :       active_tasks.resize(nt);
     602             :       nt=0;
     603     2482527 :       for(unsigned i=0; i<ntasks; ++i) {
     604     2481176 :         if( taskFlags[i]>=stride ) {
     605      261189 :           active_tasks[nt]=i;
     606      261189 :           nt++;
     607             :         }
     608             :       }
     609        1351 :       getAdditionalTasksRequired( this, active_tasks );
     610             :     }
     611             :   } else {
     612      133999 :     active_tasks.resize( ntasks );
     613     5870454 :     for(unsigned i=0; i<ntasks; ++i) {
     614     5736455 :       active_tasks[i]=i;
     615             :     }
     616             :   }
     617      135449 :   return active_tasks;
     618             : }
     619             : 
     620      135604 : void ActionWithVector::runAllTasks() {
     621             : // Skip this if this is done elsewhere
     622      135604 :   if( action_to_do_before ) {
     623          35 :     return;
     624             :   }
     625             : 
     626      135569 :   unsigned stride=comm.Get_size();
     627      135569 :   unsigned rank=comm.Get_rank();
     628      135569 :   if(serial) {
     629             :     stride=1;
     630             :     rank=0;
     631             :   }
     632             : 
     633             :   // Get the list of active tasks
     634      135569 :   std::vector<unsigned> & partialTaskList( getListOfActiveTasks( this ) );
     635      135569 :   unsigned nactive_tasks=partialTaskList.size();
     636             : 
     637             :   // Get number of threads for OpenMP
     638      135569 :   unsigned nt=OpenMP::getNumThreads();
     639      135569 :   if( nt*stride*10>nactive_tasks ) {
     640       58325 :     nt=nactive_tasks/stride/10;
     641             :   }
     642      135569 :   if( nt==0 ) {
     643       20063 :     nt=1;
     644             :   }
     645             : 
     646             :   // Now do all preparations required to run all the tasks
     647             :   // prepareForTaskLoop();
     648             : 
     649             :   // Get the total number of streamed quantities that we need
     650      135569 :   unsigned nquants=0, nmatrices=0, maxcol=0, nbooks=0;
     651      135569 :   getNumberOfStreamedQuantities( getLabel(), nquants, nmatrices, maxcol, nbooks );
     652             :   // Get size for buffer
     653      135569 :   unsigned bufsize=0;
     654      135569 :   getSizeOfBuffer( nactive_tasks, bufsize );
     655      135569 :   if( buffer.size()!=bufsize ) {
     656        2347 :     buffer.resize( bufsize );
     657             :   }
     658             :   // Clear buffer
     659      135569 :   buffer.assign( buffer.size(), 0.0 );
     660             : 
     661             :   // Recover the number of derivatives we require
     662      135569 :   unsigned nderivatives = 0;
     663      135569 :   bool gridsInStream=checkForGrids(nderivatives);
     664      135569 :   if( !doNotCalculateDerivatives() && !gridsInStream ) {
     665      105507 :     getNumberOfStreamedDerivatives( nderivatives, NULL );
     666             :   }
     667             : 
     668      135569 :   #pragma omp parallel num_threads(nt)
     669             :   {
     670             :     std::vector<double> omp_buffer;
     671             :     if( nt>1 ) {
     672             :       omp_buffer.resize( bufsize, 0.0 );
     673             :     }
     674             :     MultiValue myvals( nquants, nderivatives, nmatrices, maxcol, nbooks );
     675             :     myvals.clearAll();
     676             : 
     677             :     #pragma omp for nowait
     678             :     for(unsigned i=rank; i<nactive_tasks; i+=stride) {
     679             :       // Calculate the stuff in the loop for this action
     680             :       runTask( partialTaskList[i], myvals );
     681             : 
     682             :       // Now transfer the data to the actions that accumulate values from the calculated quantities
     683             :       if( nt>1 ) {
     684             :         gatherAccumulators( partialTaskList[i], myvals, omp_buffer );
     685             :       } else {
     686             :         gatherAccumulators( partialTaskList[i], myvals, buffer );
     687             :       }
     688             : 
     689             :       // Clear the value
     690             :       myvals.clearAll();
     691             :     }
     692             :     #pragma omp critical
     693             :     gatherThreads( nt, bufsize, omp_buffer, buffer, myvals );
     694             :   }
     695             : 
     696             :   // MPI Gather everything
     697      135569 :   if( !serial && buffer.size()>0 ) {
     698      135562 :     gatherProcesses( buffer );
     699             :   }
     700      135569 :   finishComputations( buffer );
     701             : }
     702             : 
     703      212813 : void ActionWithVector::gatherThreads( const unsigned& nt, const unsigned& bufsize, const std::vector<double>& omp_buffer, std::vector<double>& buffer, MultiValue& myvals ) {
     704      212813 :   if( nt>1 )
     705    98748328 :     for(unsigned i=0; i<bufsize; ++i) {
     706    98593840 :       buffer[i]+=omp_buffer[i];
     707             :     }
     708      212813 : }
     709             : 
     710      135562 : void ActionWithVector::gatherProcesses( std::vector<double>& buffer ) {
     711      135562 :   comm.Sum( buffer );
     712      135562 : }
     713             : 
     714      320544 : bool ActionWithVector::checkForGrids( unsigned& nder ) const {
     715      659569 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     716      347786 :     if( getConstPntrToComponent(i)->getRank()>0 && getConstPntrToComponent(i)->hasDerivatives() ) {
     717        8761 :       nder=getConstPntrToComponent(i)->getNumberOfGridDerivatives();
     718        8761 :       return true;
     719             :     }
     720             :   }
     721      311783 :   if( action_to_do_after ) {
     722      184975 :     return action_to_do_after->checkForGrids(nder);
     723             :   }
     724             :   return false;
     725             : }
     726             : 
     727      317763 : void ActionWithVector::getNumberOfTasks( unsigned& ntasks ) {
     728      317763 :   if( ntasks==0 ) {
     729      132784 :     if( getNumberOfArguments()==1 && getNumberOfComponents()==1 && getPntrToComponent(0)->getRank()==0 ) {
     730        2293 :       if( !getPntrToArgument(0)->hasDerivatives() && getPntrToArgument(0)->getRank()==2 ) {
     731          19 :         ntasks = getPntrToArgument(0)->getShape()[0];
     732             :       } else {
     733        2274 :         ntasks = getPntrToArgument(0)->getNumberOfValues();
     734             :       }
     735             :     } else {
     736      130491 :       plumed_assert( getNumberOfComponents()>0 && getPntrToComponent(0)->getRank()>0 );
     737      130491 :       if( getPntrToComponent(0)->hasDerivatives() ) {
     738        6077 :         ntasks = getPntrToComponent(0)->getNumberOfValues();
     739             :       } else {
     740      124414 :         ntasks = getPntrToComponent(0)->getShape()[0];
     741             :       }
     742             :     }
     743             :   }
     744      662764 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     745      345001 :     if( getPntrToComponent(i)->getRank()==0 ) {
     746       66066 :       if( getNumberOfArguments()!=1 ) {
     747           0 :         error("mismatched numbers of tasks in streamed quantities");
     748             :       }
     749       66066 :       if( getPntrToArgument(0)->hasDerivatives() && ntasks!=getPntrToArgument(0)->getNumberOfValues() ) {
     750           0 :         error("mismatched numbers of tasks in streamed quantities");
     751       66066 :       } else if ( !getPntrToArgument(0)->hasDerivatives() && ntasks!=getPntrToArgument(0)->getShape()[0] ) {
     752           0 :         error("mismatched numbers of tasks in streamed quantities");
     753             :       }
     754      278935 :     } else if( getPntrToComponent(i)->hasDerivatives() && ntasks!=getPntrToComponent(i)->getNumberOfValues() ) {
     755           0 :       error("mismatched numbers of tasks in streamed quantities");
     756      278935 :     } else if( !getPntrToComponent(i)->hasDerivatives() && ntasks!=getPntrToComponent(i)->getShape()[0] ) {
     757           0 :       error("mismatched numbers of tasks in streamed quantities");
     758             :     }
     759             :   }
     760      317763 :   if( action_to_do_after ) {
     761      184979 :     action_to_do_after->getNumberOfTasks( ntasks );
     762             :   }
     763      317763 : }
     764             : 
     765      424565 : void ActionWithVector::setupStreamedComponents( const std::string& headstr, unsigned& nquants, unsigned& nmat, unsigned& maxcol, unsigned& nbookeeping ) {
     766     1081840 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     767      657275 :     if( !getPntrToArgument(i)->ignoreStoredValue(headstr) ) {
     768      415109 :       getPntrToArgument(i)->streampos=nquants;
     769      415109 :       nquants++;
     770             :     }
     771             :   }
     772      891463 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     773      466898 :     getPntrToComponent(i)->streampos=nquants;
     774      466898 :     nquants++;
     775             :   }
     776      424565 : }
     777             : 
     778      424565 : void ActionWithVector::getNumberOfStreamedQuantities( const std::string& headstr, unsigned& nquants, unsigned& nmat, unsigned& maxcol, unsigned& nbookeeping ) {
     779      424565 :   setupStreamedComponents( headstr, nquants, nmat, maxcol, nbookeeping );
     780      424565 :   if( action_to_do_after ) {
     781      213997 :     action_to_do_after->getNumberOfStreamedQuantities( headstr, nquants, nmat, maxcol, nbookeeping );
     782             :   }
     783      424565 : }
     784             : 
     785      320544 : void ActionWithVector::getSizeOfBuffer( const unsigned& nactive_tasks, unsigned& bufsize ) {
     786      668330 :   for(int i=0; i<getNumberOfComponents(); ++i) {
     787      347786 :     getPntrToComponent(i)->bufstart=bufsize;
     788      347786 :     bufsize += getPntrToComponent(i)->data.size();
     789             :   }
     790      320544 :   if( action_to_do_after ) {
     791      184975 :     action_to_do_after->getSizeOfBuffer( nactive_tasks, bufsize );
     792             :   }
     793      320544 : }
     794             : 
     795      422811 : void ActionWithVector::getNumberOfStreamedDerivatives( unsigned& nderivatives, Value* stopat ) {
     796      422811 :   std::string c=getFirstActionInChain()->getLabel();
     797     1140863 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     798      718729 :     if( !getPntrToArgument(i)->ignoreStoredValue(c) ) {
     799      385417 :       if( getPntrToArgument(i)==stopat ) {
     800             :         return;
     801             :       }
     802      384740 :       nderivatives += getPntrToArgument(i)->getNumberOfValues();
     803             :     }
     804             :   }
     805      422134 :   if( getNumberOfAtoms()>0 ) {
     806       53871 :     nderivatives += 3*getNumberOfAtoms() + 9;
     807             :   }
     808             :   // Don't do the whole chain if we have been told to stop early
     809      422134 :   if( stopat && stopat->getPntrToAction()==this ) {
     810             :     return;
     811             :   }
     812             : 
     813      417928 :   if( action_to_do_after ) {
     814      235012 :     action_to_do_after->getNumberOfStreamedDerivatives( nderivatives, stopat );
     815             :   }
     816             : }
     817             : 
     818         136 : bool ActionWithVector::getNumberOfStoredValues( Value* startat, unsigned& nvals, const unsigned& astart, const std::vector<Value*>& stopat ) {
     819         181 :   for(unsigned j=astart; j<stopat.size(); ++j) {
     820         151 :     if( stopat[j] && (stopat[j]->getPntrToAction()==this || (stopat[j]->getPntrToAction())->checkForDependency(this)) ) {
     821         106 :       return true;
     822             :     }
     823             :   }
     824             : 
     825          30 :   std::string c=getFirstActionInChain()->getLabel();
     826          77 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     827          47 :     if( !getPntrToArgument(i)->ignoreStoredValue(c) ) {
     828           4 :       for(unsigned j=astart; j<stopat.size(); ++j) {
     829           2 :         if( getPntrToArgument(i)==stopat[j] ) {
     830             :           return true;
     831             :         }
     832             :       }
     833           2 :       nvals += getPntrToArgument(i)->getNumberOfValues();
     834             :     }
     835             :   }
     836          30 :   if( startat->getPntrToAction()!=this && getNumberOfAtoms()>0 ) {
     837             :     return false;
     838             :   }
     839             : 
     840          30 :   if( action_to_do_after ) {
     841          30 :     return action_to_do_after->getNumberOfStoredValues( startat, nvals, astart, stopat );
     842             :   }
     843             :   return false;
     844             : }
     845             : 
     846    13555748 : void ActionWithVector::runTask( const unsigned& current, MultiValue& myvals ) const {
     847    13555748 :   if( isActive() ) {
     848    12021026 :     myvals.setTaskIndex(current);
     849    12021026 :     myvals.vector_call=true;
     850    12021026 :     performTask( current, myvals );
     851             :   }
     852    13555748 :   if( action_to_do_after ) {
     853     6301873 :     action_to_do_after->runTask( current, myvals );
     854             :   }
     855    13555748 : }
     856             : 
     857    11442823 : void ActionWithVector::gatherAccumulators( const unsigned& taskCode, const MultiValue& myvals, std::vector<double>& buffer ) const {
     858    11442823 :   if( isActive() ) {
     859    26584722 :     for(int i=0; i<getNumberOfComponents(); ++i) {
     860    16520398 :       unsigned bufstart = getConstPntrToComponent(i)->bufstart;
     861             :       // This looks after storing of scalars that are summed from vectors/matrices
     862    16520398 :       if( getConstPntrToComponent(i)->getRank()==0 ) {
     863             :         plumed_dbg_massert( bufstart<buffer.size(), "problem in " + getLabel() );
     864     1336426 :         unsigned sind = getConstPntrToComponent(i)->streampos;
     865     1336426 :         buffer[bufstart] += myvals.get(sind);
     866     1336426 :         if( getConstPntrToComponent(i)->hasDerivatives() ) {
     867    26205534 :           for(unsigned k=0; k<myvals.getNumberActive(sind); ++k) {
     868    24869108 :             unsigned kindex = myvals.getActiveIndex(sind,k);
     869             :             plumed_dbg_massert( bufstart+1+kindex<buffer.size(), "problem in " + getLabel()  );
     870    24869108 :             buffer[bufstart + 1 + kindex] += myvals.getDerivative(sind,kindex);
     871             :           }
     872             :         }
     873             :         // This looks after storing of vectors
     874    15183972 :       } else if( getConstPntrToComponent(i)->storedata ) {
     875     5738668 :         gatherStoredValue( i, taskCode, myvals, bufstart, buffer );
     876             :       }
     877             :     }
     878             :   }
     879    11442823 :   if( action_to_do_after ) {
     880     5614243 :     action_to_do_after->gatherAccumulators( taskCode, myvals, buffer );
     881             :   }
     882    11442823 : }
     883             : 
     884     4071938 : void ActionWithVector::gatherStoredValue( const unsigned& valindex, const unsigned& taskCode, const MultiValue& myvals,
     885             :     const unsigned& bufstart, std::vector<double>& buffer ) const {
     886             :   plumed_dbg_assert( getConstPntrToComponent(valindex)->getRank()==1 && !getConstPntrToComponent(valindex)->hasDeriv );
     887     4071938 :   unsigned vindex = getConstPntrToComponent(valindex)->bufstart + taskCode;
     888             :   plumed_dbg_massert( vindex<buffer.size(), "failing in " + getLabel() );
     889     4071938 :   buffer[vindex] += myvals.get(getConstPntrToComponent(valindex)->streampos);
     890     4071938 : }
     891             : 
     892      320544 : void ActionWithVector::finishComputations( const std::vector<double>& buf ) {
     893      320544 :   if( isActive() ) {
     894      536394 :     for(int i=0; i<getNumberOfComponents(); ++i) {
     895             :       // This gathers vectors and grids at the end of the calculation
     896      281818 :       unsigned bufstart = getPntrToComponent(i)->bufstart;
     897      281818 :       getPntrToComponent(i)->data.assign( getPntrToComponent(i)->data.size(), 0 );
     898      281818 :       if( (getPntrToComponent(i)->getRank()>0 && getPntrToComponent(i)->hasDerivatives()) || getPntrToComponent(i)->storedata ) {
     899      136650 :         unsigned sz_v = getPntrToComponent(i)->data.size();
     900    47392382 :         for(unsigned j=0; j<sz_v; ++j) {
     901             :           plumed_dbg_assert( bufstart+j<buf.size() );
     902    47255732 :           getPntrToComponent(i)->add( j, buf[bufstart+j] );
     903             :         }
     904             :         // Make sure single values are set
     905      145168 :       } else if( getPntrToComponent(i)->getRank()==0 ) {
     906       43628 :         getPntrToComponent(i)->set( buf[bufstart] );
     907             :       }
     908             :       // This gathers derivatives of scalars
     909      281818 :       if( !doNotCalculateDerivatives() && getPntrToComponent(i)->hasDeriv && getPntrToComponent(i)->getRank()==0 ) {
     910    10216614 :         for(unsigned j=0; j<getPntrToComponent(i)->getNumberOfDerivatives(); ++j) {
     911    10180276 :           getPntrToComponent(i)->setDerivative( j, buf[bufstart+1+j] );
     912             :         }
     913             :       }
     914             :     }
     915             :   }
     916      320544 :   if( action_to_do_after ) {
     917      184975 :     action_to_do_after->finishComputations( buf );
     918             :   }
     919      320544 : }
     920             : 
     921      294478 : bool ActionWithVector::checkChainForNonScalarForces() const {
     922      528408 :   for(unsigned i=0; i<getNumberOfComponents(); ++i) {
     923      308929 :     if( getConstPntrToComponent(i)->getRank()>0 && getConstPntrToComponent(i)->forcesWereAdded() ) {
     924             :       return true;
     925             :     }
     926             :   }
     927      219479 :   if( action_to_do_after ) {
     928      167738 :     return action_to_do_after->checkChainForNonScalarForces();
     929             :   }
     930             :   return false;
     931             : }
     932             : 
     933      257303 : bool ActionWithVector::checkForForces() {
     934      257303 :   if( getPntrToComponent(0)->getRank()==0 ) {
     935       53033 :     return ActionWithValue::checkForForces();
     936      204270 :   } else if( actionInChain() ) {
     937             :     return false;
     938             :   }
     939             : 
     940             :   // Check if there are any forces
     941      126740 :   if( !checkChainForNonScalarForces() ) {
     942             :     return false;
     943             :   }
     944             : 
     945             :   // Setup MPI parallel loop
     946       74999 :   unsigned stride=comm.Get_size();
     947       74999 :   unsigned rank=comm.Get_rank();
     948       74999 :   if(serial) {
     949             :     stride=1;
     950             :     rank=0;
     951             :   }
     952             : 
     953             :   // Get the number of tasks
     954             :   std::vector<unsigned> force_tasks;
     955       74999 :   getForceTasks( force_tasks );
     956       74999 :   Tools::removeDuplicates(force_tasks);
     957       74999 :   unsigned nf_tasks=force_tasks.size();
     958             : 
     959             :   // Get number of threads for OpenMP
     960       74999 :   unsigned nt=OpenMP::getNumThreads();
     961       74999 :   if( nt*stride*10>nf_tasks ) {
     962       42369 :     nt=nf_tasks/stride/10;
     963             :   }
     964             :   if( nt==0 ) {
     965             :     nt=1;
     966             :   }
     967             : 
     968             :   // Now determine how big the multivalue needs to be
     969       74999 :   unsigned nquants=0, nmatrices=0, maxcol=0, nbooks=0;
     970       74999 :   getNumberOfStreamedQuantities( getLabel(), nquants, nmatrices, maxcol, nbooks );
     971             :   // Recover the number of derivatives we require (this should be equal to the number of forces)
     972       74999 :   unsigned nderiv=0;
     973       74999 :   getNumberOfStreamedDerivatives( nderiv, NULL );
     974       74999 :   if( forcesForApply.size()!=nderiv ) {
     975         381 :     forcesForApply.resize( nderiv );
     976             :   }
     977             :   // Clear force buffer
     978       74999 :   forcesForApply.assign( forcesForApply.size(), 0.0 );
     979             : 
     980       74999 :   #pragma omp parallel num_threads(nt)
     981             :   {
     982             :     std::vector<double> omp_forces;
     983             :     if( nt>1 ) {
     984             :       omp_forces.resize( forcesForApply.size(), 0.0 );
     985             :     }
     986             :     MultiValue myvals( nquants, nderiv, nmatrices, maxcol, nbooks );
     987             :     myvals.clearAll();
     988             : 
     989             :     #pragma omp for nowait
     990             :     for(unsigned i=rank; i<nf_tasks; i+=stride) {
     991             :       runTask( force_tasks[i], myvals );
     992             : 
     993             :       // Now get the forces
     994             :       if( nt>1 ) {
     995             :         gatherForces( force_tasks[i], myvals, omp_forces );
     996             :       } else {
     997             :         gatherForces( force_tasks[i], myvals, forcesForApply );
     998             :       }
     999             : 
    1000             :       myvals.clearAll();
    1001             :     }
    1002             :     #pragma omp critical
    1003             :     if(nt>1)
    1004             :       for(unsigned i=0; i<forcesForApply.size(); ++i) {
    1005             :         forcesForApply[i]+=omp_forces[i];
    1006             :       }
    1007             :   }
    1008             :   // MPI Gather on forces
    1009       74999 :   if( !serial ) {
    1010       74999 :     comm.Sum( forcesForApply );
    1011             :   }
    1012             :   return true;
    1013             : }
    1014             : 
    1015     2050310 : bool ActionWithVector::checkComponentsForForce() const {
    1016     2793497 :   for(unsigned i=0; i<values.size(); ++i) {
    1017     2557587 :     if( getConstPntrToComponent(i)->forcesWereAdded() ) {
    1018             :       return true;
    1019             :     }
    1020             :   }
    1021             :   return false;
    1022             : }
    1023             : 
    1024     5921624 : bool ActionWithVector::checkForTaskForce( const unsigned& itask, const Value* myval ) const {
    1025             :   plumed_dbg_assert( !(myval->getRank()==2 && !myval->hasDerivatives()) );
    1026     5921624 :   return fabs(myval->getForce(itask))>epsilon;
    1027             : }
    1028             : 
    1029       90929 : void ActionWithVector::updateForceTasksFromValue( const Value* myval, std::vector<unsigned>& force_tasks ) const {
    1030       90929 :   if( myval->getRank()>0 && myval->forcesWereAdded() ) {
    1031       85640 :     unsigned nt = myval->getNumberOfValues();
    1032       85640 :     if( !myval->hasDerivatives() ) {
    1033       85171 :       nt = myval->getShape()[0];
    1034             :     }
    1035     6510085 :     for(unsigned i=0; i<nt; ++i) {
    1036     6424445 :       if( checkForTaskForce(i, myval) ) {
    1037     2079412 :         force_tasks.push_back( i );
    1038             :       }
    1039             :     }
    1040             :   }
    1041       90929 : }
    1042             : 
    1043      104021 : void ActionWithVector::getForceTasks( std::vector<unsigned>& force_tasks ) const {
    1044      104021 :   if( isActive() && checkComponentsForForce() ) {
    1045      171997 :     for(unsigned k=0; k<values.size(); ++k) {
    1046       91539 :       updateForceTasksFromValue( getConstPntrToComponent(k), force_tasks );
    1047             :     }
    1048             :   }
    1049      104021 :   if( action_to_do_after ) {
    1050       29022 :     action_to_do_after->getForceTasks( force_tasks );
    1051             :   }
    1052      104021 : }
    1053             : 
    1054     1570301 : void ActionWithVector::gatherForcesOnStoredValue( const Value* myval, const unsigned& itask, const MultiValue& myvals, std::vector<double>& forces ) const {
    1055             :   plumed_dbg_assert( myval->storedata && !(myval->getRank()==2 && !myval->hasDerivatives()) );
    1056     1570301 :   double fforce = myval->getForce(itask);
    1057             :   unsigned sspos = myval->getPositionInStream();
    1058    22066949 :   for(unsigned j=0; j<myvals.getNumberActive(sspos); ++j) {
    1059    20496648 :     unsigned jder=myvals.getActiveIndex(sspos, j);
    1060             :     plumed_dbg_assert( jder<forces.size() );
    1061    20496648 :     forces[jder] += fforce*myvals.getDerivative( sspos, jder );
    1062             :   }
    1063     1570301 : }
    1064             : 
    1065     2112925 : void ActionWithVector::gatherForces( const unsigned& itask, const MultiValue& myvals, std::vector<double>& forces ) const {
    1066     2112925 :   if( isActive() && checkComponentsForForce() ) {
    1067     3599634 :     for(unsigned k=0; k<getNumberOfComponents(); ++k) {
    1068     1865692 :       const Value* myval=getConstPntrToComponent(k);
    1069     1865692 :       if( myval->getRank()>0 && myval->forcesWereAdded() ) {
    1070     1699333 :         gatherForcesOnStoredValue( myval, itask, myvals, forces );
    1071             :       }
    1072             :     }
    1073             :   }
    1074     2112925 :   if( action_to_do_after ) {
    1075      687630 :     action_to_do_after->gatherForces( itask, myvals, forces );
    1076             :   }
    1077     2112925 : }
    1078             : 
    1079      257303 : void ActionWithVector::apply() {
    1080      257303 :   if( !checkForForces() ) {
    1081      139205 :     return;
    1082             :   }
    1083             :   // Find the top of the chain and add forces
    1084      118098 :   unsigned ind=0;
    1085      118098 :   getFirstActionInChain()->addForcesToInput( getForcesToApply(), ind );
    1086             : }
    1087             : 
    1088      185112 : void ActionWithVector::addForcesToInput( const std::vector<double>& forcesToApply, unsigned& ind ) {
    1089      185112 :   if( ind>=forcesToApply.size() ) {
    1090             :     return;
    1091             :   }
    1092      135354 :   addForcesOnArguments( 0, forcesToApply, ind, getFirstActionInChain()->getLabel() );
    1093      135354 :   setForcesOnAtoms( forcesToApply, ind );
    1094      135354 :   if( action_to_do_after ) {
    1095       67014 :     action_to_do_after->addForcesToInput( forcesToApply, ind );
    1096             :   }
    1097             : }
    1098             : 
    1099             : }

Generated by: LCOV version 1.16