LCOV - code coverage report
Current view: top level - core - PlumedMain.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 699 790 88.5 %
Date: 2026-03-30 13:16:06 Functions: 39 42 92.9 %

          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 "PlumedMain.h"
      23             : #include "ActionAtomistic.h"
      24             : #include "ActionPilot.h"
      25             : #include "ActionRegister.h"
      26             : #include "ActionSet.h"
      27             : #include "ActionWithValue.h"
      28             : #include "ActionWithVirtualAtom.h"
      29             : #include "Atoms.h"
      30             : #include "CLToolMain.h"
      31             : #include "ExchangePatterns.h"
      32             : #include "GREX.h"
      33             : #include "config/Config.h"
      34             : #include "tools/Citations.h"
      35             : #include "tools/Communicator.h"
      36             : #include "tools/DLLoader.h"
      37             : #include "tools/Exception.h"
      38             : #include "tools/IFile.h"
      39             : #include "tools/Log.h"
      40             : #include "tools/OpenMP.h"
      41             : #include "tools/Tools.h"
      42             : #include "tools/Stopwatch.h"
      43             : #include "tools/TypesafePtr.h"
      44             : #include "lepton/Exception.h"
      45             : #include "DataFetchingObject.h"
      46             : #include <cstdlib>
      47             : #include <cstdio>
      48             : #include <cstring>
      49             : #include <set>
      50             : #include <unordered_map>
      51             : #include <exception>
      52             : #include <stdexcept>
      53             : #include <ios>
      54             : #include <new>
      55             : #include <typeinfo>
      56             : #include <iostream>
      57             : #include <algorithm>
      58             : #ifdef __PLUMED_LIBCXX11
      59             : #include <system_error>
      60             : #include <future>
      61             : #include <memory>
      62             : #include <functional>
      63             : #endif
      64             : 
      65             : 
      66             : namespace PLMD {
      67             : 
      68             : /// Small utility just used in this file to throw arbitrary exceptions
      69          38 : [[noreturn]] static void testThrow(const char* what) {
      70          76 :   auto words=Tools::getWords(what);
      71          38 :   plumed_assert(words.size()>0);
      72             : #define __PLUMED_THROW_NOMSG(type) if(words[0]==#type) throw type()
      73             : #define __PLUMED_THROW_MSG(type) if(words[0]==#type) throw type(what)
      74          39 :   __PLUMED_THROW_MSG(PLMD::ExceptionError);
      75          38 :   __PLUMED_THROW_MSG(PLMD::ExceptionDebug);
      76          37 :   __PLUMED_THROW_MSG(PLMD::Exception);
      77          36 :   __PLUMED_THROW_MSG(PLMD::lepton::Exception);
      78          34 :   __PLUMED_THROW_NOMSG(std::bad_exception);
      79             : #ifdef __PLUMED_LIBCXX11
      80          33 :   __PLUMED_THROW_NOMSG(std::bad_array_new_length);
      81             : #endif
      82          32 :   __PLUMED_THROW_NOMSG(std::bad_alloc);
      83             : #ifdef __PLUMED_LIBCXX11
      84          31 :   __PLUMED_THROW_NOMSG(std::bad_function_call);
      85          30 :   __PLUMED_THROW_NOMSG(std::bad_weak_ptr);
      86             : #endif
      87          29 :   __PLUMED_THROW_NOMSG(std::bad_cast);
      88          28 :   __PLUMED_THROW_NOMSG(std::bad_typeid);
      89          27 :   __PLUMED_THROW_MSG(std::underflow_error);
      90          26 :   __PLUMED_THROW_MSG(std::overflow_error);
      91          25 :   __PLUMED_THROW_MSG(std::range_error);
      92          24 :   __PLUMED_THROW_MSG(std::runtime_error);
      93          23 :   __PLUMED_THROW_MSG(std::out_of_range);
      94          22 :   __PLUMED_THROW_MSG(std::length_error);
      95          21 :   __PLUMED_THROW_MSG(std::domain_error);
      96          20 :   __PLUMED_THROW_MSG(std::invalid_argument);
      97          19 :   __PLUMED_THROW_MSG(std::logic_error);
      98             : 
      99             : #ifdef __PLUMED_LIBCXX11
     100          18 :   if(words[0]=="std::system_error") {
     101           4 :     plumed_assert(words.size()>2);
     102             :     int error_code;
     103           4 :     Tools::convert(words[2],error_code);
     104           4 :     if(words[1]=="std::generic_category") {
     105           1 :       throw std::system_error(error_code,std::generic_category(),what);
     106             :     }
     107           3 :     if(words[1]=="std::system_category") {
     108           1 :       throw std::system_error(error_code,std::system_category(),what);
     109             :     }
     110           2 :     if(words[1]=="std::iostream_category") {
     111           1 :       throw std::system_error(error_code,std::iostream_category(),what);
     112             :     }
     113           1 :     if(words[1]=="std::future_category") {
     114           1 :       throw std::system_error(error_code,std::future_category(),what);
     115             :     }
     116             :   }
     117             : #endif
     118             : 
     119          14 :   if(words[0]=="std::ios_base::failure") {
     120             : #ifdef __PLUMED_LIBCXX11
     121           1 :     int error_code=0;
     122           1 :     if(words.size()>2) {
     123           0 :       Tools::convert(words[2],error_code);
     124             :     }
     125           1 :     if(words.size()>1 && words[1]=="std::generic_category") {
     126           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::generic_category()));
     127             :     }
     128           1 :     if(words.size()>1 && words[1]=="std::system_category") {
     129           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::system_category()));
     130             :     }
     131           1 :     if(words.size()>1 && words[1]=="std::iostream_category") {
     132           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::iostream_category()));
     133             :     }
     134           1 :     if(words.size()>1 && words[1]=="std::future_category") {
     135           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::future_category()));
     136             :     }
     137             : #endif
     138           2 :     throw std::ios_base::failure(what);
     139             :   }
     140             : 
     141          13 :   if(words[0]=="int") {
     142           1 :     int value=0;
     143           1 :     if(words.size()>1) {
     144           0 :       Tools::convert(words[1],value);
     145             :     }
     146           1 :     throw value;
     147             :   }
     148             : 
     149          12 :   if(words[0]=="test_nested1") {
     150             :     try {
     151          12 :       throw Exception(std::string("inner ")+what);
     152           6 :     } catch(...) {
     153             :       try {
     154          18 :         std::throw_with_nested(Exception(std::string("middle ")+what));
     155           6 :       } catch(...) {
     156          18 :         std::throw_with_nested(Exception(std::string("outer ")+what));
     157           6 :       }
     158           6 :     }
     159             :   }
     160             : 
     161           6 :   if(words[0]=="test_nested2") {
     162             :     try {
     163           3 :       throw std::bad_alloc();
     164           3 :     } catch(...) {
     165             :       try {
     166           9 :         std::throw_with_nested(Exception(std::string("middle ")+what));
     167           3 :       } catch(...) {
     168           9 :         std::throw_with_nested(Exception(std::string("outer ")+what));
     169           3 :       }
     170           3 :     }
     171             :   }
     172             : 
     173           3 :   if(words[0]=="test_nested3") {
     174             :     try {
     175           2 :       throw "inner";
     176           2 :     } catch(...) {
     177             :       try {
     178           6 :         std::throw_with_nested(Exception(std::string("middle ")+what));
     179           2 :       } catch(...) {
     180           6 :         std::throw_with_nested(Exception(std::string("outer ")+what));
     181           2 :       }
     182           2 :     }
     183             :   }
     184             : 
     185           2 :   plumed_error() << "unknown exception " << what;
     186          38 : }
     187             : 
     188             : namespace {
     189             : // This is an internal tool used to count how many PlumedMain objects have been created
     190             : // and if they were correctly destroyed.
     191             : // When using debug options, it leads to a crash
     192             : // Otherwise, it just prints a message
     193             : class CountInstances {
     194             :   std::atomic<int> counter{};
     195             : public:
     196             :   void increase() noexcept {
     197             :     ++counter;
     198             :   }
     199             :   void decrease() noexcept {
     200             :     --counter;
     201             :   }
     202        4595 :   ~CountInstances() {
     203        4595 :     if(counter!=0) {
     204           0 :       std::cerr<<"WARNING: internal inconsistency in allocated PlumedMain instances (" <<counter<< ")\n";
     205             : #ifndef NDEBUG
     206             :       std::abort();
     207             : #endif
     208             :     }
     209        4595 :   }
     210             : };
     211             : static CountInstances countInstances;
     212             : }
     213             : 
     214             : 
     215      805723 : PlumedMain::PlumedMain():
     216      805723 :   initialized(false),
     217             : // automatically write on log in destructor
     218      805723 :   stopwatch_fwd(log),
     219      805723 :   step(0),
     220      805723 :   active(false),
     221      805723 :   mydatafetcher(DataFetchingObject::create(sizeof(double),*this)),
     222      805723 :   endPlumed(false),
     223      805723 :   atoms_fwd(*this),
     224      805723 :   actionSet_fwd(*this),
     225      805723 :   bias(0.0),
     226      805723 :   work(0.0),
     227      805723 :   exchangeStep(false),
     228      805723 :   restart(false),
     229      805723 :   doCheckPoint(false),
     230      805723 :   doParseOnly(false),
     231      805723 :   stopNow(false),
     232      805723 :   novirial(false),
     233      805723 :   detailedTimers(false),
     234     1611446 :   gpuDeviceId(-1) {
     235      805723 :   increaseReferenceCounter();
     236      805723 :   log.link(comm);
     237     1611446 :   log.setLinePrefix("PLUMED: ");
     238             :   // this is at last so as to avoid inconsistencies if an exception is thrown
     239             :   countInstances.increase(); // noexcept
     240      805723 : }
     241             : 
     242             : // destructor needed to delete forward declarated objects
     243     1610606 : PlumedMain::~PlumedMain() {
     244             :   countInstances.decrease();
     245     3222052 : }
     246             : 
     247             : /////////////////////////////////////////////////////////////
     248             : //  MAIN INTERPRETER
     249             : 
     250             : #define CHECK_INIT(ini,word) plumed_massert(ini,"cmd(\"" + word +"\") should be only used after plumed initialization")
     251             : #define CHECK_NOTINIT(ini,word) plumed_massert(!(ini),"cmd(\"" + word +"\") should be only used before plumed initialization")
     252             : #define CHECK_NOTNULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"" + word + "\")");
     253             : 
     254             : 
     255     1141613 : void PlumedMain::cmd(const std::string & word,const TypesafePtr & val) {
     256             : 
     257             : // Enumerate all possible commands:
     258             :   enum {
     259             : #include "PlumedMainEnum.inc"
     260             :   };
     261             : 
     262             : // Static object (initialized once) containing the map of commands:
     263             :   const static std::unordered_map<std::string, int> word_map = {
     264             : #include "PlumedMainMap.inc"
     265     1512107 :   };
     266             : 
     267             :   try {
     268             : 
     269     1141613 :     auto ss=stopwatch.startPause();
     270             : 
     271     1141613 :     std::vector<std::string> words=Tools::getWords(word);
     272     1141613 :     unsigned nw=words.size();
     273     1141613 :     if(nw==0) {
     274             :       // do nothing
     275             :     } else {
     276             :       int iword=-1;
     277             :       double d;
     278             :       const auto it=word_map.find(words[0]);
     279     1141613 :       if(it!=word_map.end()) {
     280     1141606 :         iword=it->second;
     281             :       }
     282     1141606 :       switch(iword) {
     283       53986 :       case cmd_setBox:
     284       53986 :         CHECK_INIT(initialized,word);
     285       53986 :         CHECK_NOTNULL(val,word);
     286       53986 :         atoms.setBox(val);
     287             :         break;
     288       58127 :       case cmd_setPositions:
     289       58127 :         CHECK_INIT(initialized,word);
     290       58127 :         atoms.setPositions(val);
     291             :         break;
     292       58131 :       case cmd_setMasses:
     293       58131 :         CHECK_INIT(initialized,word);
     294       58131 :         atoms.setMasses(val);
     295             :         break;
     296       48220 :       case cmd_setCharges:
     297       48220 :         CHECK_INIT(initialized,word);
     298       48220 :         atoms.setCharges(val);
     299             :         break;
     300           1 :       case cmd_setPositionsX:
     301           1 :         CHECK_INIT(initialized,word);
     302           1 :         atoms.setPositions(val,0);
     303             :         break;
     304           1 :       case cmd_setPositionsY:
     305           1 :         CHECK_INIT(initialized,word);
     306           1 :         atoms.setPositions(val,1);
     307             :         break;
     308           1 :       case cmd_setPositionsZ:
     309           1 :         CHECK_INIT(initialized,word);
     310           1 :         atoms.setPositions(val,2);
     311             :         break;
     312       48328 :       case cmd_setVirial:
     313       48328 :         CHECK_INIT(initialized,word);
     314       48328 :         CHECK_NOTNULL(val,word);
     315       48328 :         atoms.setVirial(val);
     316             :         break;
     317        9792 :       case cmd_setEnergy:
     318        9792 :         CHECK_INIT(initialized,word);
     319        9792 :         CHECK_NOTNULL(val,word);
     320        9792 :         atoms.setEnergy(val);
     321             :         break;
     322       58127 :       case cmd_setForces:
     323       58127 :         CHECK_INIT(initialized,word);
     324       58127 :         atoms.setForces(val);
     325             :         break;
     326           1 :       case cmd_setForcesX:
     327           1 :         CHECK_INIT(initialized,word);
     328           1 :         atoms.setForces(val,0);
     329             :         break;
     330           1 :       case cmd_setForcesY:
     331           1 :         CHECK_INIT(initialized,word);
     332           1 :         atoms.setForces(val,1);
     333             :         break;
     334           1 :       case cmd_setForcesZ:
     335           1 :         CHECK_INIT(initialized,word);
     336           1 :         atoms.setForces(val,2);
     337             :         break;
     338      256368 :       case cmd_calc:
     339      256368 :         CHECK_INIT(initialized,word);
     340      256368 :         calc();
     341             :         break;
     342          99 :       case cmd_prepareDependencies:
     343          99 :         CHECK_INIT(initialized,word);
     344          99 :         prepareDependencies();
     345             :         break;
     346          84 :       case cmd_shareData:
     347          84 :         CHECK_INIT(initialized,word);
     348          84 :         shareData();
     349             :         break;
     350        2070 :       case cmd_prepareCalc:
     351        2070 :         CHECK_INIT(initialized,word);
     352        2070 :         prepareCalc();
     353             :         break;
     354          10 :       case cmd_performCalc:
     355          10 :         CHECK_INIT(initialized,word);
     356          10 :         performCalc();
     357             :         break;
     358        2134 :       case cmd_performCalcNoUpdate:
     359        2134 :         CHECK_INIT(initialized,word);
     360        2134 :         performCalcNoUpdate();
     361             :         break;
     362          10 :       case cmd_performCalcNoForces:
     363          10 :         CHECK_INIT(initialized,word);
     364          10 :         performCalcNoForces();
     365             :         break;
     366          79 :       case cmd_update:
     367          79 :         CHECK_INIT(initialized,word);
     368          79 :         update();
     369             :         break;
     370        6092 :       case cmd_setStep:
     371        6092 :         CHECK_INIT(initialized,word);
     372        6098 :         CHECK_NOTNULL(val,word);
     373        6089 :         step=val.get<int>();
     374        6089 :         atoms.startStep();
     375             :         break;
     376           0 :       case cmd_setStepLong:
     377           0 :         CHECK_INIT(initialized,word);
     378           0 :         CHECK_NOTNULL(val,word);
     379           0 :         step=val.get<long int>();
     380           0 :         atoms.startStep();
     381             :         break;
     382      252394 :       case cmd_setStepLongLong:
     383      252394 :         CHECK_INIT(initialized,word);
     384      252394 :         CHECK_NOTNULL(val,word);
     385      252394 :         step=val.get<long long int>();
     386      252394 :         atoms.startStep();
     387             :         break;
     388             :       // words used less frequently:
     389        1142 :       case cmd_setAtomsNlocal:
     390        1142 :         CHECK_INIT(initialized,word);
     391        1142 :         CHECK_NOTNULL(val,word);
     392        1142 :         atoms.setAtomsNlocal(val.get<int>());
     393             :         break;
     394         988 :       case cmd_setAtomsGatindex:
     395         988 :         CHECK_INIT(initialized,word);
     396         988 :         atoms.setAtomsGatindex(val,false);
     397             :         break;
     398           2 :       case cmd_setAtomsFGatindex:
     399           2 :         CHECK_INIT(initialized,word);
     400           2 :         atoms.setAtomsGatindex(val,true);
     401             :         break;
     402         152 :       case cmd_setAtomsContiguous:
     403         152 :         CHECK_INIT(initialized,word);
     404         152 :         CHECK_NOTNULL(val,word);
     405         152 :         atoms.setAtomsContiguous(val.get<int>());
     406             :         break;
     407         116 :       case cmd_createFullList:
     408         116 :         CHECK_INIT(initialized,word);
     409         116 :         CHECK_NOTNULL(val,word);
     410         116 :         atoms.createFullList(val);
     411             :         break;
     412         116 :       case cmd_getFullList:
     413         116 :         CHECK_INIT(initialized,word);
     414         116 :         CHECK_NOTNULL(val,word);
     415         116 :         atoms.getFullList(val);
     416             :         break;
     417         116 :       case cmd_clearFullList:
     418         116 :         CHECK_INIT(initialized,word);
     419         116 :         atoms.clearFullList();
     420             :         break;
     421             :       /* ADDED WITH API==6 */
     422          64 :       case cmd_getDataRank:
     423          64 :         CHECK_INIT(initialized,words[0]);
     424          64 :         plumed_assert(nw==2 || nw==3);
     425          64 :         if( nw==2 ) {
     426         128 :           DataFetchingObject::get_rank( actionSet, words[1], "", val);
     427             :         } else {
     428           0 :           DataFetchingObject::get_rank( actionSet, words[1], words[2], val);
     429             :         }
     430             :         break;
     431             :       /* ADDED WITH API==6 */
     432           0 :       case cmd_getDataShape:
     433           0 :         CHECK_INIT(initialized,words[0]);
     434           0 :         plumed_assert(nw==2 || nw==3);
     435           0 :         if( nw==2 ) {
     436           0 :           DataFetchingObject::get_shape( actionSet, words[1], "", val );
     437             :         } else {
     438           0 :           DataFetchingObject::get_shape( actionSet, words[1], words[2], val );
     439             :         }
     440             :         break;
     441             :       /* ADDED WITH API==6 */
     442          64 :       case cmd_setMemoryForData:
     443          64 :         CHECK_INIT(initialized,words[0]);
     444          64 :         plumed_assert(nw==2 || nw==3);
     445          64 :         if( nw==2 ) {
     446         128 :           mydatafetcher->setData( words[1], "", val );
     447             :         } else {
     448           0 :           mydatafetcher->setData( words[1], words[2], val );
     449             :         }
     450             :         break;
     451             :       /* ADDED WITH API==6 */
     452             :       case cmd_setErrorHandler: {
     453           0 :         if(val) {
     454           0 :           error_handler=*static_cast<const plumed_error_handler*>(val.get<const void*>());
     455             :         } else {
     456           0 :           error_handler.handler=NULL;
     457             :         }
     458             :       }
     459             :       break;
     460           0 :       case cmd_read:
     461           0 :         CHECK_INIT(initialized,word);
     462           0 :         if(val) {
     463           0 :           readInputFile(val.get<const char*>());
     464             :         } else {
     465           0 :           readInputFile("plumed.dat");
     466             :         }
     467             :         break;
     468         276 :       case cmd_readInputLine:
     469         276 :         CHECK_INIT(initialized,word);
     470         276 :         CHECK_NOTNULL(val,word);
     471         276 :         readInputLine(val.get<const char*>());
     472         236 :         break;
     473           1 :       case cmd_readInputLines:
     474           1 :         CHECK_INIT(initialized,word);
     475           1 :         CHECK_NOTNULL(val,word);
     476           1 :         readInputLines(val.get<const char*>());
     477           1 :         break;
     478           1 :       case cmd_clear:
     479           1 :         CHECK_INIT(initialized,word);
     480           1 :         actionSet.clearDelete();
     481             :         break;
     482             :       case cmd_getApiVersion:
     483          42 :         CHECK_NOTNULL(val,word);
     484          42 :         val.set(int(10));
     485             :         break;
     486             :       // commands which can be used only before initialization:
     487        1036 :       case cmd_init:
     488        1036 :         CHECK_NOTINIT(initialized,word);
     489        1036 :         init();
     490             :         break;
     491         905 :       case cmd_setRealPrecision:
     492         905 :         CHECK_NOTINIT(initialized,word);
     493         905 :         CHECK_NOTNULL(val,word);
     494         905 :         atoms.setRealPrecision(val.get<int>());
     495        1808 :         mydatafetcher=DataFetchingObject::create(val.get<int>(),*this);
     496         904 :         break;
     497         837 :       case cmd_setMDLengthUnits:
     498         837 :         CHECK_NOTINIT(initialized,word);
     499         837 :         CHECK_NOTNULL(val,word);
     500         837 :         atoms.MD2double(val,d);
     501         837 :         atoms.setMDLengthUnits(d);
     502             :         break;
     503         837 :       case cmd_setMDChargeUnits:
     504         837 :         CHECK_NOTINIT(initialized,word);
     505         837 :         CHECK_NOTNULL(val,word);
     506         837 :         atoms.MD2double(val,d);
     507         837 :         atoms.setMDChargeUnits(d);
     508             :         break;
     509         837 :       case cmd_setMDMassUnits:
     510         837 :         CHECK_NOTINIT(initialized,word);
     511         837 :         CHECK_NOTNULL(val,word);
     512         837 :         atoms.MD2double(val,d);
     513         837 :         atoms.setMDMassUnits(d);
     514             :         break;
     515          45 :       case cmd_setMDEnergyUnits:
     516          45 :         CHECK_NOTINIT(initialized,word);
     517          45 :         CHECK_NOTNULL(val,word);
     518          45 :         atoms.MD2double(val,d);
     519          45 :         atoms.setMDEnergyUnits(d);
     520             :         break;
     521           6 :       case cmd_setMDTimeUnits:
     522           6 :         CHECK_NOTINIT(initialized,word);
     523           6 :         CHECK_NOTNULL(val,word);
     524           6 :         atoms.MD2double(val,d);
     525           6 :         atoms.setMDTimeUnits(d);
     526             :         break;
     527           0 :       case cmd_setNaturalUnits:
     528             :         // set the boltzman constant for MD in natural units (kb=1)
     529             :         // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...)
     530             :         // use as cmd("setNaturalUnits")
     531           0 :         CHECK_NOTINIT(initialized,word);
     532           0 :         atoms.setMDNaturalUnits(true);
     533             :         break;
     534          52 :       case cmd_setNoVirial:
     535          52 :         CHECK_NOTINIT(initialized,word);
     536          52 :         novirial=true;
     537          52 :         break;
     538         892 :       case cmd_setPlumedDat:
     539         892 :         CHECK_NOTINIT(initialized,word);
     540         892 :         CHECK_NOTNULL(val,word);
     541         892 :         plumedDat=val.get<const char*>();
     542             :         break;
     543         348 :       case cmd_setMPIComm:
     544         348 :         CHECK_NOTINIT(initialized,word);
     545         348 :         comm.Set_comm(val);
     546         348 :         atoms.setDomainDecomposition(comm);
     547             :         break;
     548           0 :       case cmd_setMPIFComm:
     549           0 :         CHECK_NOTINIT(initialized,word);
     550           0 :         comm.Set_fcomm(val);
     551           0 :         atoms.setDomainDecomposition(comm);
     552             :         break;
     553           0 :       case cmd_setMPImultiSimComm:
     554           0 :         CHECK_NOTINIT(initialized,word);
     555           0 :         multi_sim_comm.Set_comm(val);
     556             :         break;
     557        1019 :       case cmd_setNatoms:
     558        1019 :         CHECK_NOTINIT(initialized,word);
     559        1019 :         CHECK_NOTNULL(val,word);
     560        1019 :         atoms.setNatoms(val.get<int>());
     561             :         break;
     562         893 :       case cmd_setTimestep:
     563         893 :         CHECK_NOTINIT(initialized,word);
     564         893 :         CHECK_NOTNULL(val,word);
     565         893 :         atoms.setTimeStep(val);
     566             :         break;
     567             :       /* ADDED WITH API==2 */
     568          59 :       case cmd_setKbT:
     569          59 :         CHECK_NOTINIT(initialized,word);
     570          59 :         CHECK_NOTNULL(val,word);
     571          59 :         atoms.setKbT(val);
     572             :         break;
     573             :       /* ADDED WITH API==3 */
     574           8 :       case cmd_setRestart:
     575           8 :         CHECK_NOTINIT(initialized,word);
     576           8 :         CHECK_NOTNULL(val,word);
     577           8 :         if(val.get<int>()!=0) {
     578           2 :           restart=true;
     579             :         }
     580             :         break;
     581             :       /* ADDED WITH API==4 */
     582           0 :       case cmd_doCheckPoint:
     583           0 :         CHECK_INIT(initialized,word);
     584           0 :         CHECK_NOTNULL(val,word);
     585           0 :         doCheckPoint = false;
     586           0 :         if(val.get<int>()!=0) {
     587           0 :           doCheckPoint = true;
     588             :         }
     589             :         break;
     590             :       /* ADDED WITH API==6 */
     591             :       case cmd_setNumOMPthreads:
     592           0 :         CHECK_NOTNULL(val,word);
     593             :         {
     594           0 :           auto nt=val.get<unsigned>();
     595             :           if(nt==0) {
     596             :             nt=1;
     597             :           }
     598           0 :           OpenMP::setNumThreads(nt);
     599             :         }
     600             :         break;
     601             :       /* ADDED WITH API==10 */
     602             :       case cmd_setGpuDeviceId:
     603           0 :         CHECK_NOTNULL(val,word);
     604             :         {
     605           0 :           auto id=val.get<int>();
     606           0 :           if(id>=0) {
     607           0 :             gpuDeviceId=id;
     608             :           }
     609             :         }
     610             :         break;
     611             :       /* ADDED WITH API==6 */
     612             :       /* only used for testing */
     613             :       case cmd_throw:
     614          38 :         CHECK_NOTNULL(val,word);
     615          38 :         testThrow(val.get<const char*>());
     616             :       /* ADDED WITH API==10 */
     617             :       case cmd_setNestedExceptions:
     618          25 :         CHECK_NOTNULL(val,word);
     619          25 :         if(val.get<int>()!=0) {
     620          24 :           nestedExceptions=true;
     621             :         } else {
     622           1 :           nestedExceptions=false;
     623             :         }
     624             :         break;
     625             :       /* STOP API */
     626         890 :       case cmd_setMDEngine:
     627         890 :         CHECK_NOTINIT(initialized,word);
     628         890 :         CHECK_NOTNULL(val,word);
     629         890 :         MDEngine=val.get<const char*>();
     630             :         break;
     631         877 :       case cmd_setLog:
     632         877 :         CHECK_NOTINIT(initialized,word);
     633         877 :         log.link(val.get<FILE*>());
     634             :         break;
     635          53 :       case cmd_setLogFile:
     636          53 :         CHECK_NOTINIT(initialized,word);
     637          53 :         CHECK_NOTNULL(val,word);
     638         152 :         log.open(val.get<const char*>());
     639          53 :         break;
     640             :       // other commands that should be used after initialization:
     641      256293 :       case cmd_setStopFlag:
     642      256293 :         CHECK_INIT(initialized,word);
     643      256293 :         CHECK_NOTNULL(val,word);
     644      256293 :         val.get<int*>(); // just check type and discard pointer
     645      256292 :         stopFlag=val.copy();
     646      256292 :         break;
     647           0 :       case cmd_getExchangesFlag:
     648           0 :         CHECK_INIT(initialized,word);
     649           0 :         CHECK_NOTNULL(val,word);
     650           0 :         exchangePatterns.getFlag(*val.get<int*>()); // note: getFlag changes the value of the reference!
     651             :         break;
     652           0 :       case cmd_setExchangesSeed:
     653           0 :         CHECK_INIT(initialized,word);
     654           0 :         CHECK_NOTNULL(val,word);
     655           0 :         exchangePatterns.setSeed(val.get<int>());
     656             :         break;
     657           0 :       case cmd_setNumberOfReplicas:
     658           0 :         CHECK_INIT(initialized,word);
     659           0 :         CHECK_NOTNULL(val,word);
     660           0 :         exchangePatterns.setNofR(val.get<int>());
     661             :         break;
     662           0 :       case cmd_getExchangesList:
     663           0 :         CHECK_INIT(initialized,word);
     664           0 :         CHECK_NOTNULL(val,word);
     665           0 :         exchangePatterns.getList(val.get<int*>());
     666           0 :         break;
     667         840 :       case cmd_runFinalJobs:
     668         840 :         CHECK_INIT(initialized,word);
     669         840 :         runJobsAtEndOfCalculation();
     670             :         break;
     671          96 :       case cmd_isEnergyNeeded:
     672          96 :         CHECK_INIT(initialized,word);
     673          96 :         CHECK_NOTNULL(val,word);
     674          96 :         if(atoms.isEnergyNeeded()) {
     675           0 :           val.set(int(1));
     676             :         } else {
     677          96 :           val.set(int(0));
     678             :         }
     679             :         break;
     680        2172 :       case cmd_getBias:
     681        2172 :         CHECK_INIT(initialized,word);
     682        2172 :         CHECK_NOTNULL(val,word);
     683        2172 :         atoms.double2MD(getBias()/(atoms.getMDUnits().getEnergy()/atoms.getUnits().getEnergy()),val);
     684        2172 :         break;
     685             :       case cmd_checkAction:
     686           2 :         CHECK_NOTNULL(val,word);
     687           2 :         plumed_assert(nw==2);
     688           3 :         val.set(int(actionRegister().check(words[1]) ? 1:0));
     689             :         break;
     690             :       case cmd_setExtraCV:
     691          30 :         CHECK_NOTNULL(val,word);
     692          30 :         plumed_assert(nw==2);
     693          30 :         atoms.setExtraCV(words[1],val);
     694             :         break;
     695             :       case cmd_setExtraCVForce:
     696          30 :         CHECK_NOTNULL(val,word);
     697          30 :         plumed_assert(nw==2);
     698          30 :         atoms.setExtraCVForce(words[1],val);
     699             :         break;
     700             :       /* ADDED WITH API==10 */
     701             :       case cmd_isExtraCVNeeded:
     702          10 :         CHECK_NOTNULL(val,word);
     703          10 :         plumed_assert(nw==2);
     704          10 :         if(atoms.isExtraCVNeeded(words[1])) {
     705           4 :           val.set(int(1));
     706             :         } else {
     707           6 :           val.set(int(0));
     708             :         }
     709             :         break;
     710        1089 :       case cmd_GREX:
     711        1089 :         if(!grex) {
     712         208 :           grex=Tools::make_unique<GREX>(*this);
     713             :         }
     714        1089 :         plumed_massert(grex,"error allocating grex");
     715             :         {
     716        1089 :           std::string kk=words[1];
     717        1260 :           for(unsigned i=2; i<words.size(); i++) {
     718         342 :             kk+=" "+words[i];
     719             :           }
     720        2178 :           grex->cmd(kk.c_str(),val);
     721             :         }
     722        1089 :         break;
     723       14193 :       case cmd_CLTool:
     724       14193 :         CHECK_NOTINIT(initialized,word);
     725       14193 :         if(!cltool) {
     726        4643 :           cltool=Tools::make_unique<CLToolMain>();
     727             :         }
     728             :         {
     729       14193 :           std::string kk=words[1];
     730       14193 :           for(unsigned i=2; i<words.size(); i++) {
     731           0 :             kk+=" "+words[i];
     732             :           }
     733       28386 :           cltool->cmd(kk.c_str(),val);
     734             :         }
     735       14193 :         break;
     736             :       /* ADDED WITH API==7 */
     737             :       case cmd_convert: {
     738             :         double v;
     739          57 :         plumed_assert(words.size()==2);
     740          57 :         if(Tools::convertNoexcept(words[1],v)) {
     741          47 :           atoms.double2MD(v,val);
     742             :         }
     743             :       }
     744          57 :       break;
     745           7 :       default:
     746          21 :         plumed_merror("cannot interpret cmd(\"" + word + "\"). check plumed developers manual to see the available commands.");
     747             :         break;
     748             :       }
     749             :     }
     750             : 
     751     1141811 :   } catch (...) {
     752          99 :     if(log.isOpen()) {
     753             :       try {
     754          54 :         log<<"\n################################################################################\n";
     755          54 :         log<<Tools::concatenateExceptionMessages();
     756          54 :         log<<"\n################################################################################\n";
     757          54 :         log.flush();
     758           0 :       } catch(...) {
     759             :         // ignore errors here.
     760             :         // in any case, we are rethrowing this below
     761           0 :       }
     762             :     }
     763          99 :     throw;
     764          99 :   }
     765     1141514 : }
     766             : 
     767             : ////////////////////////////////////////////////////////////////////////
     768             : 
     769        1036 : void PlumedMain::init() {
     770             : // check that initialization just happens once
     771        1036 :   initialized=true;
     772        1036 :   atoms.init();
     773        1036 :   if(!log.isOpen()) {
     774         106 :     log.link(stdout);
     775             :   }
     776        1036 :   log<<"PLUMED is starting\n";
     777        3108 :   log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") "
     778        4144 :      <<"compiled on " <<config::getCompilationDate() << " at " << config::getCompilationTime() << "\n";
     779        1036 :   log<<"Please cite these papers when using PLUMED ";
     780        2072 :   log<<cite("The PLUMED consortium, Nat. Methods 16, 670 (2019)");
     781        2072 :   log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
     782        1036 :   log<<"\n";
     783        1036 :   log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
     784        1036 :   log<<"Root: "<<config::getPlumedRoot()<<"\n";
     785        2072 :   log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
     786        1036 :   log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
     787        1036 :   log.printf("Precision of reals: %d\n",atoms.getRealPrecision());
     788        1840 :   log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
     789        1036 :   log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
     790        1036 :   log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
     791        1036 :   log.printf("Number of atoms: %d\n",atoms.getNatoms());
     792        1036 :   if(grex) {
     793         208 :     log.printf("GROMACS-like replica exchange is on\n");
     794             :   }
     795        1036 :   log.printf("File suffix: %s\n",getSuffix().c_str());
     796        1036 :   if(plumedDat.length()>0) {
     797         892 :     readInputFile(plumedDat);
     798             :     plumedDat="";
     799             :   }
     800        1036 :   atoms.updateUnits();
     801        1036 :   log.printf("Timestep: %f\n",atoms.getTimeStep());
     802        1036 :   if(atoms.getKbT()>0.0) {
     803          53 :     log.printf("KbT: %f\n",atoms.getKbT());
     804             :   } else {
     805         983 :     log.printf("KbT has not been set by the MD engine\n");
     806         983 :     log.printf("It should be set by hand where needed\n");
     807             :   }
     808        1036 :   log<<"Relevant bibliography:\n";
     809        1036 :   log<<citations;
     810        1036 :   log<<"Please read and cite where appropriate!\n";
     811        1036 :   log<<"Finished setup\n";
     812        1036 : }
     813             : 
     814         910 : void PlumedMain::readInputFile(const std::string & str) {
     815         910 :   plumed_assert(initialized);
     816         910 :   log<<"FILE: "<<str<<"\n";
     817         910 :   IFile ifile;
     818         910 :   ifile.link(*this);
     819         910 :   ifile.open(str);
     820         910 :   ifile.allowNoEOL();
     821         910 :   readInputFile(ifile);
     822         910 :   log<<"END FILE: "<<str<<"\n";
     823         910 :   log.flush();
     824             : 
     825         910 : }
     826             : 
     827         911 : void PlumedMain::readInputFile(IFile & ifile) {
     828             :   std::vector<std::string> words;
     829       15236 :   while(Tools::getParsedLine(ifile,words) && !endPlumed) {
     830       14325 :     readInputWords(words);
     831             :   }
     832         911 :   endPlumed=false;
     833         911 :   pilots=actionSet.select<ActionPilot*>();
     834         911 : }
     835             : 
     836         360 : void PlumedMain::readInputLine(const std::string & str) {
     837         360 :   plumed_assert(initialized);
     838         360 :   if(str.empty()) {
     839           0 :     return;
     840             :   }
     841         360 :   std::vector<std::string> words=Tools::getWords(str);
     842         360 :   citations.clear();
     843         360 :   readInputWords(words);
     844         320 :   if(!citations.empty()) {
     845           2 :     log<<"Relevant bibliography:\n";
     846           2 :     log<<citations;
     847           2 :     log<<"Please read and cite where appropriate!\n";
     848             :   }
     849         360 : }
     850             : 
     851           1 : void PlumedMain::readInputLines(const std::string & str) {
     852           1 :   plumed_assert(initialized);
     853           1 :   if(str.empty()) {
     854           0 :     return;
     855             :   }
     856             : 
     857           1 :   log<<"FILE: (temporary)\n";
     858             : 
     859             :   // Open a temporary file
     860           1 :   auto fp=std::tmpfile();
     861           1 :   plumed_assert(fp);
     862             : 
     863             :   // make sure file is closed (and thus deleted) also if an exception occurs
     864             :   auto deleter=[](FILE* fp) {
     865           1 :     std::fclose(fp);
     866             :   };
     867             :   std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
     868             : 
     869           1 :   auto ret=std::fputs(str.c_str(),fp);
     870           1 :   plumed_assert(ret!=EOF);
     871             : 
     872           1 :   std::rewind(fp);
     873             : 
     874           1 :   IFile ifile;
     875           1 :   ifile.link(*this);
     876           1 :   ifile.link(fp);
     877           1 :   ifile.allowNoEOL();
     878             : 
     879           1 :   readInputFile(ifile);
     880           1 :   log<<"END FILE: (temporary)\n";
     881           1 : }
     882             : 
     883       14711 : void PlumedMain::readInputWords(const std::vector<std::string> & words) {
     884       14711 :   plumed_assert(initialized);
     885       14711 :   if(words.empty()) {
     886             :     return;
     887       14555 :   } else if(words[0]=="_SET_SUFFIX") {
     888           3 :     plumed_assert(words.size()==2);
     889             :     setSuffix(words[1]);
     890             :   } else {
     891       14552 :     std::vector<std::string> interpreted(words);
     892       14552 :     Tools::interpretLabel(interpreted);
     893       29066 :     auto action=actionRegister().create(ActionOptions(*this,interpreted));
     894       14514 :     if(!action) {
     895             :       std::string msg;
     896             :       msg ="ERROR\nI cannot understand line:";
     897           8 :       for(unsigned i=0; i<interpreted.size(); ++i) {
     898          14 :         msg+=" "+interpreted[i];
     899             :       }
     900             :       msg+="\nMaybe a missing space or a typo?";
     901           2 :       log << msg;
     902           2 :       log.flush();
     903           4 :       plumed_merror(msg);
     904             :     }
     905       14512 :     action->checkRead();
     906       14512 :     actionSet.emplace_back(std::move(action));
     907       14554 :   };
     908             : 
     909       29030 :   pilots=actionSet.select<ActionPilot*>();
     910             : }
     911             : 
     912             : ////////////////////////////////////////////////////////////////////////
     913             : 
     914           0 : void PlumedMain::exit(int c) {
     915           0 :   comm.Abort(c);
     916           0 : }
     917             : 
     918       14550 : Log& PlumedMain::getLog() {
     919       14550 :   return log;
     920             : }
     921             : 
     922      256368 : void PlumedMain::calc() {
     923      256368 :   prepareCalc();
     924      256368 :   performCalc();
     925      256368 : }
     926             : 
     927      258438 : void PlumedMain::prepareCalc() {
     928      258438 :   prepareDependencies();
     929      258438 :   shareData();
     930      258438 : }
     931             : 
     932             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     933             : // here we have the main steps in "calc()"
     934             : // they can be called individually, but the standard thing is to
     935             : // traverse them in this order:
     936      258765 : void PlumedMain::prepareDependencies() {
     937             : 
     938             : // Stopwatch is stopped when sw goes out of scope
     939      258765 :   auto sw=stopwatch.startStop("1 Prepare dependencies");
     940             : 
     941             : // activate all the actions which are on step
     942             : // activation is recursive and enables also the dependencies
     943             : // before doing that, the prepare() method is called to see if there is some
     944             : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
     945             : // which can be dynamically changed).
     946             : 
     947             : // First switch off all actions
     948     2109359 :   for(const auto & p : actionSet) {
     949     1850594 :     p->deactivate();
     950             :   }
     951             : 
     952             : // for optimization, an "active" flag remains false if no action at all is active
     953      258765 :   active=mydatafetcher->activate();
     954     1615751 :   for(unsigned i=0; i<pilots.size(); ++i) {
     955     1356986 :     if(pilots[i]->onStep()) {
     956     1286891 :       pilots[i]->activate();
     957     1286891 :       active=true;
     958             :     }
     959             :   };
     960             : 
     961             : // also, if one of them is the total energy, tell to atoms that energy should be collected
     962     2109359 :   for(const auto & p : actionSet) {
     963     1850594 :     if(p->isActive()) {
     964     1665305 :       if(p->checkNeedsGradients()) {
     965         172 :         p->setOption("GRADIENTS");
     966             :       }
     967             :     }
     968             :   }
     969             : 
     970      258765 : }
     971             : 
     972      258522 : void PlumedMain::shareData() {
     973             : // atom positions are shared (but only if there is something to do)
     974      258522 :   if(!active) {
     975        1648 :     return;
     976             :   }
     977             : // Stopwatch is stopped when sw goes out of scope
     978      256874 :   auto sw=stopwatch.startStop("2 Sharing data");
     979      256874 :   if(atoms.getNatoms()>0) {
     980       56534 :     atoms.share();
     981             :   }
     982      256874 : }
     983             : 
     984        2134 : void PlumedMain::performCalcNoUpdate() {
     985        2134 :   waitData();
     986        2134 :   justCalculate();
     987        2134 :   backwardPropagate();
     988        2134 : }
     989             : 
     990          10 : void PlumedMain::performCalcNoForces() {
     991          10 :   waitData();
     992          10 :   justCalculate();
     993          10 : }
     994             : 
     995      256378 : void PlumedMain::performCalc() {
     996      256378 :   waitData();
     997      256378 :   justCalculate();
     998      256378 :   backwardPropagate();
     999      256378 :   update();
    1000      256378 :   mydatafetcher->finishDataGrab();
    1001      256378 : }
    1002             : 
    1003      258636 : void PlumedMain::waitData() {
    1004      258636 :   if(!active) {
    1005        1648 :     return;
    1006             :   }
    1007             : // Stopwatch is stopped when sw goes out of scope
    1008      256988 :   auto sw=stopwatch.startStop("3 Waiting for data");
    1009      256988 :   if(atoms.getNatoms()>0) {
    1010       56648 :     atoms.wait();
    1011             :   }
    1012      256988 : }
    1013             : 
    1014      258636 : void PlumedMain::justCalculate() {
    1015      258636 :   if(!active) {
    1016        1648 :     return;
    1017             :   }
    1018             : // Stopwatch is stopped when sw goes out of scope
    1019      256988 :   auto sw=stopwatch.startStop("4 Calculating (forward loop)");
    1020      256988 :   bias=0.0;
    1021      256988 :   work=0.0;
    1022             : 
    1023      256988 :   int iaction=0;
    1024             : // calculate the active actions in order (assuming *backward* dependence)
    1025     2097206 :   for(const auto & pp : actionSet) {
    1026             :     Action* p(pp.get());
    1027             :     try {
    1028     1840218 :       if(p->isActive()) {
    1029             : // Stopwatch is stopped when sw goes out of scope.
    1030             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1031     1664441 :         Stopwatch::Handler sw;
    1032     1664441 :         if(detailedTimers) {
    1033             :           std::string actionNumberLabel;
    1034        1690 :           Tools::convert(iaction,actionNumberLabel);
    1035        1690 :           const unsigned m=actionSet.size();
    1036             :           unsigned k=0;
    1037             :           unsigned n=1;
    1038        5070 :           while(n<m) {
    1039        3380 :             n*=10;
    1040        3380 :             k++;
    1041             :           }
    1042        1690 :           const int pad=k-actionNumberLabel.length();
    1043        2815 :           for(int i=0; i<pad; i++) {
    1044        2250 :             actionNumberLabel=" "+actionNumberLabel;
    1045             :           }
    1046        1690 :           sw=stopwatch.startStop("4A "+actionNumberLabel+" "+p->getLabel());
    1047             :         }
    1048     1664441 :         ActionWithValue*av=dynamic_cast<ActionWithValue*>(p);
    1049     1664441 :         ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(p);
    1050             :         {
    1051     1664441 :           if(av) {
    1052     1397729 :             av->clearInputForces();
    1053             :           }
    1054     1664441 :           if(av) {
    1055     1397729 :             av->clearDerivatives();
    1056             :           }
    1057             :         }
    1058             :         {
    1059     1664441 :           if(aa) {
    1060      174709 :             aa->clearOutputForces();
    1061             :           }
    1062     1664441 :           if(aa)
    1063      174709 :             if(aa->isActive()) {
    1064      174709 :               aa->retrieveAtoms();
    1065             :             }
    1066             :         }
    1067     1664441 :         if(p->checkNumericalDerivatives()) {
    1068         568 :           p->calculateNumericalDerivatives();
    1069             :         } else {
    1070     1663873 :           p->calculate();
    1071             :         }
    1072             :         // This retrieves components called bias
    1073     1664441 :         if(av) {
    1074     1397729 :           bias+=av->getOutputQuantity("bias");
    1075     1397729 :           work+=av->getOutputQuantity("work");
    1076     1397729 :           av->setGradientsIfNeeded();
    1077             :         }
    1078     1664441 :         ActionWithVirtualAtom*avv=dynamic_cast<ActionWithVirtualAtom*>(p);
    1079     1664441 :         if(avv) {
    1080       14422 :           avv->setGradientsIfNeeded();
    1081             :         }
    1082     1664441 :       }
    1083           0 :     } catch(...) {
    1084           0 :       plumed_error_nested() << "An error happened while calculating " << p->getLabel();
    1085           0 :     }
    1086     1840218 :     iaction++;
    1087             :   }
    1088      256988 : }
    1089             : 
    1090           0 : void PlumedMain::justApply() {
    1091           0 :   backwardPropagate();
    1092           0 :   update();
    1093           0 : }
    1094             : 
    1095      258512 : void PlumedMain::backwardPropagate() {
    1096      258512 :   if(!active) {
    1097        1648 :     return;
    1098             :   }
    1099      256864 :   int iaction=0;
    1100             : // Stopwatch is stopped when sw goes out of scope
    1101      256864 :   auto sw=stopwatch.startStop("5 Applying (backward loop)");
    1102             : // apply them in reverse order
    1103     2096128 :   for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
    1104             :     const auto & p(pp->get());
    1105     1839264 :     if(p->isActive()) {
    1106             : 
    1107             : // Stopwatch is stopped when sw goes out of scope.
    1108             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1109     1663679 :       Stopwatch::Handler sw;
    1110     1663679 :       if(detailedTimers) {
    1111             :         std::string actionNumberLabel;
    1112        1690 :         Tools::convert(iaction,actionNumberLabel);
    1113        1690 :         const unsigned m=actionSet.size();
    1114             :         unsigned k=0;
    1115             :         unsigned n=1;
    1116        5070 :         while(n<m) {
    1117        3380 :           n*=10;
    1118        3380 :           k++;
    1119             :         }
    1120        1690 :         const int pad=k-actionNumberLabel.length();
    1121        2815 :         for(int i=0; i<pad; i++) {
    1122        2250 :           actionNumberLabel=" "+actionNumberLabel;
    1123             :         }
    1124        1690 :         sw=stopwatch.startStop("5A "+actionNumberLabel+" "+p->getLabel());
    1125             :       }
    1126             : 
    1127     1663679 :       p->apply();
    1128     1663679 :       ActionAtomistic*a=dynamic_cast<ActionAtomistic*>(p);
    1129             : // still ActionAtomistic has a special treatment, since they may need to add forces on atoms
    1130     1663679 :       if(a) {
    1131      174225 :         a->applyForces();
    1132             :       }
    1133             : 
    1134     1663679 :     }
    1135     1839264 :     iaction++;
    1136             :   }
    1137             : 
    1138             : // Stopwatch is stopped when sw goes out of scope.
    1139             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1140      256864 :   Stopwatch::Handler sw1;
    1141      256864 :   if(detailedTimers) {
    1142         113 :     sw1=stopwatch.startStop("5B Update forces");
    1143             :   }
    1144             : // this is updating the MD copy of the forces
    1145      256864 :   if(atoms.getNatoms()>0) {
    1146       56524 :     atoms.updateForces();
    1147             :   }
    1148      256864 : }
    1149             : 
    1150      256457 : void PlumedMain::update() {
    1151      256457 :   if(!active) {
    1152        1648 :     return;
    1153             :   }
    1154             : 
    1155             : // Stopwatch is stopped when sw goes out of scope
    1156      254809 :   auto sw=stopwatch.startStop("6 Update");
    1157             : 
    1158             : // update step (for statistics, etc)
    1159      254809 :   updateFlags.push(true);
    1160     2087586 :   for(const auto & p : actionSet) {
    1161     1832777 :     p->beforeUpdate();
    1162     3489611 :     if(p->isActive() && p->checkUpdate() && updateFlagsTop()) {
    1163     1656814 :       p->update();
    1164             :     }
    1165             :   }
    1166      509622 :   while(!updateFlags.empty()) {
    1167             :     updateFlags.pop();
    1168             :   }
    1169             :   if(!updateFlags.empty()) {
    1170             :     plumed_merror("non matching changes in the update flags");
    1171             :   }
    1172             : // Check that no action has told the calculation to stop
    1173      254809 :   if(stopNow) {
    1174          65 :     if(stopFlag) {
    1175          65 :       stopFlag.set(int(1));
    1176             :     } else {
    1177           0 :       plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
    1178             :     }
    1179             :   }
    1180             : 
    1181             : // flush by default every 10000 steps
    1182             : // hopefully will not affect performance
    1183             : // also if receive checkpointing signal
    1184      254809 :   if(step%10000==0||doCheckPoint) {
    1185        1005 :     fflush();
    1186        1005 :     log.flush();
    1187       15927 :     for(const auto & p : actionSet) {
    1188       14922 :       p->fflush();
    1189             :     }
    1190             :   }
    1191      254809 : }
    1192             : 
    1193           2 : void PlumedMain::load(const std::string& ss) {
    1194           2 :   if(DLLoader::installed()) {
    1195           2 :     std::string s=ss;
    1196           2 :     size_t n=s.find_last_of(".");
    1197           3 :     std::string extension="";
    1198           2 :     std::string base=s;
    1199           2 :     if(n!=std::string::npos && n<s.length()-1) {
    1200           4 :       extension=s.substr(n+1);
    1201             :     }
    1202           2 :     if(n!=std::string::npos && n<s.length()) {
    1203           4 :       base=s.substr(0,n);
    1204             :     }
    1205           2 :     if(extension=="cpp") {
    1206             : // full path command, including environment setup
    1207             : // this will work even if plumed is not in the execution path or if it has been
    1208             : // installed with a name different from "plumed"
    1209           4 :       std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh "+s;
    1210           2 :       log<<"Executing: "<<cmd;
    1211           2 :       if(comm.Get_size()>0) {
    1212           2 :         log<<" (only on master node)";
    1213             :       }
    1214           2 :       log<<"\n";
    1215           2 :       if(comm.Get_rank()==0) {
    1216           2 :         int ret=std::system(cmd.c_str());
    1217           2 :         if(ret!=0) {
    1218           2 :           plumed_error() <<"An error happened while executing command "<<cmd<<"\n";
    1219             :         }
    1220             :       }
    1221           1 :       comm.Barrier();
    1222           2 :       base="./"+base;
    1223             :     }
    1224           2 :     s=base+"."+config::getSoExt();
    1225           1 :     void *p=dlloader.load(s);
    1226           1 :     if(!p) {
    1227           0 :       plumed_error()<<"I cannot load library " << ss << " " << dlloader.error();
    1228             :     }
    1229           2 :     log<<"Loading shared library "<<s.c_str()<<"\n";
    1230           1 :     log<<"Here is the new list of available actions\n";
    1231           1 :     log<<actionRegister();
    1232             :   } else {
    1233           0 :     plumed_error()<<"While loading library "<< ss << " loading was not enabled, please check if dlopen was found at configure time";
    1234             :   }
    1235           1 : }
    1236             : 
    1237        2805 : double PlumedMain::getBias() const {
    1238        2805 :   return bias;
    1239             : }
    1240             : 
    1241         450 : double PlumedMain::getWork() const {
    1242         450 :   return work;
    1243             : }
    1244             : 
    1245          73 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
    1246          73 :   std::string mmode(mode);
    1247          73 :   std::string ppath(path);
    1248          73 :   std::string suffix(getSuffix());
    1249          73 :   std::string ppathsuf=ppath+suffix;
    1250          73 :   FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
    1251          73 :   if(!fp) {
    1252           0 :     fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
    1253             :   }
    1254          73 :   plumed_massert(fp,"file " + ppath + " cannot be found");
    1255          73 :   return fp;
    1256             : }
    1257             : 
    1258          91 : int PlumedMain::fclose(FILE*fp) {
    1259          91 :   return std::fclose(fp);
    1260             : }
    1261             : 
    1262        4005 : std::string PlumedMain::cite(const std::string&item) {
    1263        4005 :   return citations.cite(item);
    1264             : }
    1265             : 
    1266        1566 : void PlumedMain::fflush() {
    1267        4919 :   for(const auto  & p : files) {
    1268        3353 :     p->flush();
    1269             :   }
    1270        1566 : }
    1271             : 
    1272        4671 : void PlumedMain::insertFile(FileBase&f) {
    1273        4671 :   files.insert(&f);
    1274        4671 : }
    1275             : 
    1276        4989 : void PlumedMain::eraseFile(FileBase&f) {
    1277        4989 :   files.erase(&f);
    1278        4989 : }
    1279             : 
    1280          65 : void PlumedMain::stop() {
    1281          65 :   stopNow=true;
    1282          65 : }
    1283             : 
    1284         840 : void PlumedMain::runJobsAtEndOfCalculation() {
    1285       14834 :   for(const auto & p : actionSet) {
    1286       13994 :     p->runFinalJobs();
    1287             :   }
    1288         840 : }
    1289             : 
    1290     8805798 : unsigned PlumedMain::increaseReferenceCounter() noexcept {
    1291     8805798 :   return ++referenceCounter;
    1292             : }
    1293             : 
    1294     8804856 : unsigned PlumedMain::decreaseReferenceCounter() noexcept {
    1295     8804856 :   return --referenceCounter;
    1296             : }
    1297             : 
    1298          42 : unsigned PlumedMain::useCountReferenceCounter() const noexcept {
    1299          42 :   return referenceCounter;
    1300             : }
    1301             : 
    1302           0 : void PlumedMain::activateParseOnlyMode() {
    1303           0 :   doParseOnly=true;
    1304           0 : }
    1305             : 
    1306        1915 : bool PlumedMain::parseOnlyMode() const {
    1307        1915 :   return doParseOnly;
    1308             : }
    1309             : 
    1310             : #ifdef __PLUMED_HAS_PYTHON
    1311             : // This is here to stop cppcheck throwing an error
    1312             : #endif
    1313             : 
    1314             : }
    1315             : 
    1316             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.16