LCOV - code coverage report
Current view: top level - core - PlumedMain.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 597 657 90.9 %
Date: 2024-10-11 08:09:47 Functions: 34 36 94.4 %

          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          26 : [[noreturn]] static void testThrow(const char* what) {
      70          52 :   auto words=Tools::getWords(what);
      71          26 :   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          27 :   __PLUMED_THROW_MSG(PLMD::ExceptionError);
      75          26 :   __PLUMED_THROW_MSG(PLMD::ExceptionDebug);
      76          25 :   __PLUMED_THROW_MSG(PLMD::Exception);
      77          24 :   __PLUMED_THROW_MSG(PLMD::lepton::Exception);
      78          22 :   __PLUMED_THROW_NOMSG(std::bad_exception);
      79             : #ifdef __PLUMED_LIBCXX11
      80          21 :   __PLUMED_THROW_NOMSG(std::bad_array_new_length);
      81             : #endif
      82          20 :   __PLUMED_THROW_NOMSG(std::bad_alloc);
      83             : #ifdef __PLUMED_LIBCXX11
      84          19 :   __PLUMED_THROW_NOMSG(std::bad_function_call);
      85          18 :   __PLUMED_THROW_NOMSG(std::bad_weak_ptr);
      86             : #endif
      87          17 :   __PLUMED_THROW_NOMSG(std::bad_cast);
      88          16 :   __PLUMED_THROW_NOMSG(std::bad_typeid);
      89          15 :   __PLUMED_THROW_MSG(std::underflow_error);
      90          14 :   __PLUMED_THROW_MSG(std::overflow_error);
      91          13 :   __PLUMED_THROW_MSG(std::range_error);
      92          12 :   __PLUMED_THROW_MSG(std::runtime_error);
      93          11 :   __PLUMED_THROW_MSG(std::out_of_range);
      94          10 :   __PLUMED_THROW_MSG(std::length_error);
      95           9 :   __PLUMED_THROW_MSG(std::domain_error);
      96           8 :   __PLUMED_THROW_MSG(std::invalid_argument);
      97           7 :   __PLUMED_THROW_MSG(std::logic_error);
      98             : 
      99             : #ifdef __PLUMED_LIBCXX11
     100           6 :   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") throw std::system_error(error_code,std::generic_category(),what);
     105           3 :     if(words[1]=="std::system_category") throw std::system_error(error_code,std::system_category(),what);
     106           2 :     if(words[1]=="std::iostream_category") throw std::system_error(error_code,std::iostream_category(),what);
     107           1 :     if(words[1]=="std::future_category") throw std::system_error(error_code,std::future_category(),what);
     108             :   }
     109             : #endif
     110             : 
     111           2 :   if(words[0]=="std::ios_base::failure") {
     112             : #ifdef __PLUMED_LIBCXX11
     113           1 :     int error_code=0;
     114           1 :     if(words.size()>2) Tools::convert(words[2],error_code);
     115           1 :     if(words.size()>1 && words[1]=="std::generic_category") throw std::ios_base::failure(what,std::error_code(error_code,std::generic_category()));
     116           1 :     if(words.size()>1 && words[1]=="std::system_category") throw std::ios_base::failure(what,std::error_code(error_code,std::system_category()));
     117           1 :     if(words.size()>1 && words[1]=="std::iostream_category") throw std::ios_base::failure(what,std::error_code(error_code,std::iostream_category()));
     118           1 :     if(words.size()>1 && words[1]=="std::future_category") throw std::ios_base::failure(what,std::error_code(error_code,std::future_category()));
     119             : #endif
     120           2 :     throw std::ios_base::failure(what);
     121             :   }
     122             : 
     123           2 :   plumed_error() << "unknown exception " << what;
     124          26 : }
     125             : 
     126             : #if 0
     127             : // this is temporarily commented out since it makes
     128             : // multithread calculations fail
     129             : namespace {
     130             : class Register {
     131             :   std::vector<PlumedMain*> instances;
     132             : public:
     133             :   void add(PlumedMain* instance) {
     134             :     instances.push_back(instance);
     135             :   }
     136             :   void remove(PlumedMain* instance) {
     137             :     auto it = std::find(instances.begin(), instances.end(), instance);
     138             :     if(it==instances.end()) {
     139             :       std::cerr<<"WARNING: internal inconsistency in allocated PlumedMain instances\n";
     140             :     } else {
     141             :       instances.erase(it);
     142             :     }
     143             :   }
     144             :   ~Register() {
     145             :     if(instances.size()>0) std::cerr<<"PLUMED instances was not properly deallocated in your code: "<<instances.size()<<"\n";
     146             :   }
     147             : };
     148             : 
     149             : static Register myregister;
     150             : 
     151             : }
     152             : #endif
     153             : 
     154      404395 : PlumedMain::PlumedMain():
     155      404395 :   initialized(false),
     156             : // automatically write on log in destructor
     157      404395 :   stopwatch_fwd(log),
     158      404395 :   step(0),
     159      404395 :   active(false),
     160      404395 :   mydatafetcher(DataFetchingObject::create(sizeof(double),*this)),
     161      404395 :   endPlumed(false),
     162      404395 :   atoms_fwd(*this),
     163      404395 :   actionSet_fwd(*this),
     164      404395 :   bias(0.0),
     165      404395 :   work(0.0),
     166      404395 :   exchangeStep(false),
     167      404395 :   restart(false),
     168      404395 :   doCheckPoint(false),
     169      404395 :   stopNow(false),
     170      404395 :   novirial(false),
     171      808790 :   detailedTimers(false)
     172             : {
     173      404395 :   log.link(comm);
     174      404395 :   log.setLinePrefix("PLUMED: ");
     175             :   //myregister.add(this);
     176      404395 : }
     177             : 
     178             : // destructor needed to delete forward declarated objects
     179      808069 : PlumedMain::~PlumedMain() {
     180             :   //myregister.remove(this);
     181     1212464 : }
     182             : 
     183             : /////////////////////////////////////////////////////////////
     184             : //  MAIN INTERPRETER
     185             : 
     186             : #define CHECK_INIT(ini,word) plumed_massert(ini,"cmd(\"" + word +"\") should be only used after plumed initialization")
     187             : #define CHECK_NOTINIT(ini,word) plumed_massert(!(ini),"cmd(\"" + word +"\") should be only used before plumed initialization")
     188             : #define CHECK_NOTNULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"" + word + "\")");
     189             : 
     190             : 
     191     1040740 : void PlumedMain::cmd(const std::string & word,const TypesafePtr & val) {
     192             : 
     193             : // Enumerate all possible commands:
     194             :   enum {
     195             : #include "PlumedMainEnum.inc"
     196             :   };
     197             : 
     198             : // Static object (initialized once) containing the map of commands:
     199             :   const static std::unordered_map<std::string, int> word_map = {
     200             : #include "PlumedMainMap.inc"
     201     1306698 :   };
     202             : 
     203             :   try {
     204             : 
     205     1040740 :     auto ss=stopwatch.startPause();
     206             : 
     207     1040740 :     std::vector<std::string> words=Tools::getWords(word);
     208     1040740 :     unsigned nw=words.size();
     209     1040740 :     if(nw==0) {
     210             :       // do nothing
     211             :     } else {
     212             :       int iword=-1;
     213             :       double d;
     214             :       const auto it=word_map.find(words[0]);
     215     1040740 :       if(it!=word_map.end()) iword=it->second;
     216     1040733 :       switch(iword) {
     217       43333 :       case cmd_setBox:
     218       43333 :         CHECK_INIT(initialized,word);
     219       43333 :         CHECK_NOTNULL(val,word);
     220       43333 :         atoms.setBox(val);
     221             :         break;
     222       47474 :       case cmd_setPositions:
     223       47474 :         CHECK_INIT(initialized,word);
     224       47474 :         atoms.setPositions(val);
     225             :         break;
     226       47478 :       case cmd_setMasses:
     227       47478 :         CHECK_INIT(initialized,word);
     228       47478 :         atoms.setMasses(val);
     229             :         break;
     230       37570 :       case cmd_setCharges:
     231       37570 :         CHECK_INIT(initialized,word);
     232       37570 :         atoms.setCharges(val);
     233             :         break;
     234           1 :       case cmd_setPositionsX:
     235           1 :         CHECK_INIT(initialized,word);
     236           1 :         atoms.setPositions(val,0);
     237             :         break;
     238           1 :       case cmd_setPositionsY:
     239           1 :         CHECK_INIT(initialized,word);
     240           1 :         atoms.setPositions(val,1);
     241             :         break;
     242           1 :       case cmd_setPositionsZ:
     243           1 :         CHECK_INIT(initialized,word);
     244           1 :         atoms.setPositions(val,2);
     245             :         break;
     246       37675 :       case cmd_setVirial:
     247       37675 :         CHECK_INIT(initialized,word);
     248       37675 :         CHECK_NOTNULL(val,word);
     249       37675 :         atoms.setVirial(val);
     250             :         break;
     251        9792 :       case cmd_setEnergy:
     252        9792 :         CHECK_INIT(initialized,word);
     253        9792 :         CHECK_NOTNULL(val,word);
     254        9792 :         atoms.setEnergy(val);
     255             :         break;
     256       47474 :       case cmd_setForces:
     257       47474 :         CHECK_INIT(initialized,word);
     258       47474 :         atoms.setForces(val);
     259             :         break;
     260           1 :       case cmd_setForcesX:
     261           1 :         CHECK_INIT(initialized,word);
     262           1 :         atoms.setForces(val,0);
     263             :         break;
     264           1 :       case cmd_setForcesY:
     265           1 :         CHECK_INIT(initialized,word);
     266           1 :         atoms.setForces(val,1);
     267             :         break;
     268           1 :       case cmd_setForcesZ:
     269           1 :         CHECK_INIT(initialized,word);
     270           1 :         atoms.setForces(val,2);
     271             :         break;
     272      245716 :       case cmd_calc:
     273      245716 :         CHECK_INIT(initialized,word);
     274      245716 :         calc();
     275             :         break;
     276          99 :       case cmd_prepareDependencies:
     277          99 :         CHECK_INIT(initialized,word);
     278          99 :         prepareDependencies();
     279             :         break;
     280          84 :       case cmd_shareData:
     281          84 :         CHECK_INIT(initialized,word);
     282          84 :         shareData();
     283             :         break;
     284        2070 :       case cmd_prepareCalc:
     285        2070 :         CHECK_INIT(initialized,word);
     286        2070 :         prepareCalc();
     287             :         break;
     288          10 :       case cmd_performCalc:
     289          10 :         CHECK_INIT(initialized,word);
     290          10 :         performCalc();
     291             :         break;
     292        2134 :       case cmd_performCalcNoUpdate:
     293        2134 :         CHECK_INIT(initialized,word);
     294        2134 :         performCalcNoUpdate();
     295             :         break;
     296          10 :       case cmd_performCalcNoForces:
     297          10 :         CHECK_INIT(initialized,word);
     298          10 :         performCalcNoForces();
     299             :         break;
     300          79 :       case cmd_update:
     301          79 :         CHECK_INIT(initialized,word);
     302          79 :         update();
     303             :         break;
     304       10028 :       case cmd_setStep:
     305       10028 :         CHECK_INIT(initialized,word);
     306       10034 :         CHECK_NOTNULL(val,word);
     307       10025 :         step=val.get<int>();
     308       10025 :         atoms.startStep();
     309             :         break;
     310      237805 :       case cmd_setStepLong:
     311      237805 :         CHECK_INIT(initialized,word);
     312      237805 :         CHECK_NOTNULL(val,word);
     313      237805 :         step=val.get<long int>();
     314      237805 :         atoms.startStep();
     315             :         break;
     316             :       // words used less frequently:
     317        1140 :       case cmd_setAtomsNlocal:
     318        1140 :         CHECK_INIT(initialized,word);
     319        1140 :         CHECK_NOTNULL(val,word);
     320        1140 :         atoms.setAtomsNlocal(val.get<int>());
     321             :         break;
     322         988 :       case cmd_setAtomsGatindex:
     323         988 :         CHECK_INIT(initialized,word);
     324         988 :         atoms.setAtomsGatindex(val,false);
     325             :         break;
     326           0 :       case cmd_setAtomsFGatindex:
     327           0 :         CHECK_INIT(initialized,word);
     328           0 :         atoms.setAtomsGatindex(val,true);
     329             :         break;
     330         152 :       case cmd_setAtomsContiguous:
     331         152 :         CHECK_INIT(initialized,word);
     332         152 :         CHECK_NOTNULL(val,word);
     333         152 :         atoms.setAtomsContiguous(val.get<int>());
     334             :         break;
     335         116 :       case cmd_createFullList:
     336         116 :         CHECK_INIT(initialized,word);
     337         116 :         CHECK_NOTNULL(val,word);
     338         116 :         atoms.createFullList(val);
     339             :         break;
     340         116 :       case cmd_getFullList:
     341         116 :         CHECK_INIT(initialized,word);
     342         116 :         CHECK_NOTNULL(val,word);
     343         116 :         atoms.getFullList(val);
     344             :         break;
     345         116 :       case cmd_clearFullList:
     346         116 :         CHECK_INIT(initialized,word);
     347         116 :         atoms.clearFullList();
     348             :         break;
     349             :       /* ADDED WITH API==6 */
     350          64 :       case cmd_getDataRank:
     351          64 :         CHECK_INIT(initialized,words[0]); plumed_assert(nw==2 || nw==3);
     352         128 :         if( nw==2 ) DataFetchingObject::get_rank( actionSet, words[1], "", val);
     353           0 :         else DataFetchingObject::get_rank( actionSet, words[1], words[2], val);
     354             :         break;
     355             :       /* ADDED WITH API==6 */
     356           0 :       case cmd_getDataShape:
     357           0 :         CHECK_INIT(initialized,words[0]); plumed_assert(nw==2 || nw==3);
     358           0 :         if( nw==2 ) DataFetchingObject::get_shape( actionSet, words[1], "", val );
     359           0 :         else DataFetchingObject::get_shape( actionSet, words[1], words[2], val );
     360             :         break;
     361             :       /* ADDED WITH API==6 */
     362          64 :       case cmd_setMemoryForData:
     363          64 :         CHECK_INIT(initialized,words[0]); plumed_assert(nw==2 || nw==3);
     364         128 :         if( nw==2 ) mydatafetcher->setData( words[1], "", val );
     365           0 :         else mydatafetcher->setData( words[1], words[2], val );
     366             :         break;
     367             :       /* ADDED WITH API==6 */
     368             :       case cmd_setErrorHandler:
     369             :       {
     370           0 :         if(val) error_handler=*static_cast<const plumed_error_handler*>(val.get<const void*>());
     371           0 :         else error_handler.handler=NULL;
     372             :       }
     373             :       break;
     374           0 :       case cmd_read:
     375           0 :         CHECK_INIT(initialized,word);
     376           0 :         if(val)readInputFile(val.get<const char*>());
     377           0 :         else   readInputFile("plumed.dat");
     378             :         break;
     379         269 :       case cmd_readInputLine:
     380         269 :         CHECK_INIT(initialized,word);
     381         269 :         CHECK_NOTNULL(val,word);
     382         269 :         readInputLine(val.get<const char*>());
     383         230 :         break;
     384           1 :       case cmd_readInputLines:
     385           1 :         CHECK_INIT(initialized,word);
     386           1 :         CHECK_NOTNULL(val,word);
     387           1 :         readInputLines(val.get<const char*>());
     388           1 :         break;
     389           1 :       case cmd_clear:
     390           1 :         CHECK_INIT(initialized,word);
     391           1 :         actionSet.clearDelete();
     392             :         break;
     393             :       case cmd_getApiVersion:
     394          21 :         CHECK_NOTNULL(val,word);
     395          21 :         val.set(int(9));
     396             :         break;
     397             :       // commands which can be used only before initialization:
     398         914 :       case cmd_init:
     399         914 :         CHECK_NOTINIT(initialized,word);
     400         914 :         init();
     401             :         break;
     402         781 :       case cmd_setRealPrecision:
     403         781 :         CHECK_NOTINIT(initialized,word);
     404         781 :         CHECK_NOTNULL(val,word);
     405         781 :         atoms.setRealPrecision(val.get<int>());
     406        1560 :         mydatafetcher=DataFetchingObject::create(val.get<int>(),*this);
     407         780 :         break;
     408         718 :       case cmd_setMDLengthUnits:
     409         718 :         CHECK_NOTINIT(initialized,word);
     410         718 :         CHECK_NOTNULL(val,word);
     411         718 :         atoms.MD2double(val,d);
     412         718 :         atoms.setMDLengthUnits(d);
     413             :         break;
     414         718 :       case cmd_setMDChargeUnits:
     415         718 :         CHECK_NOTINIT(initialized,word);
     416         718 :         CHECK_NOTNULL(val,word);
     417         718 :         atoms.MD2double(val,d);
     418         718 :         atoms.setMDChargeUnits(d);
     419             :         break;
     420         718 :       case cmd_setMDMassUnits:
     421         718 :         CHECK_NOTINIT(initialized,word);
     422         718 :         CHECK_NOTNULL(val,word);
     423         718 :         atoms.MD2double(val,d);
     424         718 :         atoms.setMDMassUnits(d);
     425             :         break;
     426          45 :       case cmd_setMDEnergyUnits:
     427          45 :         CHECK_NOTINIT(initialized,word);
     428          45 :         CHECK_NOTNULL(val,word);
     429          45 :         atoms.MD2double(val,d);
     430          45 :         atoms.setMDEnergyUnits(d);
     431             :         break;
     432           6 :       case cmd_setMDTimeUnits:
     433           6 :         CHECK_NOTINIT(initialized,word);
     434           6 :         CHECK_NOTNULL(val,word);
     435           6 :         atoms.MD2double(val,d);
     436           6 :         atoms.setMDTimeUnits(d);
     437             :         break;
     438           0 :       case cmd_setNaturalUnits:
     439             :         // set the boltzman constant for MD in natural units (kb=1)
     440             :         // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...)
     441             :         // use as cmd("setNaturalUnits")
     442           0 :         CHECK_NOTINIT(initialized,word);
     443           0 :         atoms.setMDNaturalUnits(true);
     444             :         break;
     445          52 :       case cmd_setNoVirial:
     446          52 :         CHECK_NOTINIT(initialized,word);
     447          52 :         novirial=true;
     448          52 :         break;
     449         773 :       case cmd_setPlumedDat:
     450         773 :         CHECK_NOTINIT(initialized,word);
     451         773 :         CHECK_NOTNULL(val,word);
     452         773 :         plumedDat=val.get<const char*>();
     453             :         break;
     454         337 :       case cmd_setMPIComm:
     455         337 :         CHECK_NOTINIT(initialized,word);
     456         337 :         comm.Set_comm(val);
     457         337 :         atoms.setDomainDecomposition(comm);
     458             :         break;
     459           0 :       case cmd_setMPIFComm:
     460           0 :         CHECK_NOTINIT(initialized,word);
     461           0 :         comm.Set_fcomm(val);
     462           0 :         atoms.setDomainDecomposition(comm);
     463             :         break;
     464           0 :       case cmd_setMPImultiSimComm:
     465           0 :         CHECK_NOTINIT(initialized,word);
     466           0 :         multi_sim_comm.Set_comm(val);
     467             :         break;
     468         897 :       case cmd_setNatoms:
     469         897 :         CHECK_NOTINIT(initialized,word);
     470         897 :         CHECK_NOTNULL(val,word);
     471         897 :         atoms.setNatoms(val.get<int>());
     472             :         break;
     473         774 :       case cmd_setTimestep:
     474         774 :         CHECK_NOTINIT(initialized,word);
     475         774 :         CHECK_NOTNULL(val,word);
     476         774 :         atoms.setTimeStep(val);
     477             :         break;
     478             :       /* ADDED WITH API==2 */
     479          59 :       case cmd_setKbT:
     480          59 :         CHECK_NOTINIT(initialized,word);
     481          59 :         CHECK_NOTNULL(val,word);
     482          59 :         atoms.setKbT(val);
     483             :         break;
     484             :       /* ADDED WITH API==3 */
     485           8 :       case cmd_setRestart:
     486           8 :         CHECK_NOTINIT(initialized,word);
     487           8 :         CHECK_NOTNULL(val,word);
     488           8 :         if(val.get<int>()!=0) restart=true;
     489             :         break;
     490             :       /* ADDED WITH API==4 */
     491           0 :       case cmd_doCheckPoint:
     492           0 :         CHECK_INIT(initialized,word);
     493           0 :         CHECK_NOTNULL(val,word);
     494           0 :         doCheckPoint = false;
     495           0 :         if(val.get<int>()!=0) doCheckPoint = true;
     496             :         break;
     497             :       /* ADDED WITH API==6 */
     498             :       case cmd_setNumOMPthreads:
     499           0 :         CHECK_NOTNULL(val,word);
     500             :         {
     501           0 :           auto nt=val.get<unsigned>();
     502             :           if(nt==0) nt=1;
     503           0 :           OpenMP::setNumThreads(nt);
     504             :         }
     505             :         break;
     506             :       /* ADDED WITH API==6 */
     507             :       /* only used for testing */
     508             :       case cmd_throw:
     509          26 :         CHECK_NOTNULL(val,word);
     510          26 :         testThrow(val.get<const char*>());
     511             :       /* STOP API */
     512         771 :       case cmd_setMDEngine:
     513         771 :         CHECK_NOTINIT(initialized,word);
     514         771 :         CHECK_NOTNULL(val,word);
     515         771 :         MDEngine=val.get<const char*>();
     516             :         break;
     517         758 :       case cmd_setLog:
     518         758 :         CHECK_NOTINIT(initialized,word);
     519         758 :         log.link(val.get<FILE*>());
     520             :         break;
     521          52 :       case cmd_setLogFile:
     522          52 :         CHECK_NOTINIT(initialized,word);
     523          52 :         CHECK_NOTNULL(val,word);
     524         138 :         log.open(val.get<const char*>());
     525          52 :         break;
     526             :       // other commands that should be used after initialization:
     527      245643 :       case cmd_setStopFlag:
     528      245643 :         CHECK_INIT(initialized,word);
     529      245643 :         CHECK_NOTNULL(val,word);
     530      245643 :         val.get<int*>(); // just check type and discard pointer
     531      245642 :         stopFlag=val.copy();
     532      245642 :         break;
     533           0 :       case cmd_getExchangesFlag:
     534           0 :         CHECK_INIT(initialized,word);
     535           0 :         CHECK_NOTNULL(val,word);
     536           0 :         exchangePatterns.getFlag(*val.get<int*>()); // note: getFlag changes the value of the reference!
     537             :         break;
     538           0 :       case cmd_setExchangesSeed:
     539           0 :         CHECK_INIT(initialized,word);
     540           0 :         CHECK_NOTNULL(val,word);
     541           0 :         exchangePatterns.setSeed(val.get<int>());
     542             :         break;
     543           0 :       case cmd_setNumberOfReplicas:
     544           0 :         CHECK_INIT(initialized,word);
     545           0 :         CHECK_NOTNULL(val,word);
     546           0 :         exchangePatterns.setNofR(val.get<int>());
     547             :         break;
     548           0 :       case cmd_getExchangesList:
     549           0 :         CHECK_INIT(initialized,word);
     550           0 :         CHECK_NOTNULL(val,word);
     551           0 :         exchangePatterns.getList(val.get<int*>());
     552           0 :         break;
     553         721 :       case cmd_runFinalJobs:
     554         721 :         CHECK_INIT(initialized,word);
     555         721 :         runJobsAtEndOfCalculation();
     556             :         break;
     557          96 :       case cmd_isEnergyNeeded:
     558          96 :         CHECK_INIT(initialized,word);
     559          96 :         CHECK_NOTNULL(val,word);
     560          96 :         if(atoms.isEnergyNeeded()) val.set(int(1));
     561          96 :         else                       val.set(int(0));
     562             :         break;
     563        2172 :       case cmd_getBias:
     564        2172 :         CHECK_INIT(initialized,word);
     565        2172 :         CHECK_NOTNULL(val,word);
     566        2172 :         atoms.double2MD(getBias()/(atoms.getMDUnits().getEnergy()/atoms.getUnits().getEnergy()),val);
     567        2172 :         break;
     568             :       case cmd_checkAction:
     569           2 :         CHECK_NOTNULL(val,word);
     570           2 :         plumed_assert(nw==2);
     571           3 :         val.set(int(actionRegister().check(words[1]) ? 1:0));
     572           2 :         break;
     573             :       case cmd_setExtraCV:
     574          20 :         CHECK_NOTNULL(val,word);
     575          20 :         plumed_assert(nw==2);
     576          20 :         atoms.setExtraCV(words[1],val);
     577             :         break;
     578             :       case cmd_setExtraCVForce:
     579          20 :         CHECK_NOTNULL(val,word);
     580          20 :         plumed_assert(nw==2);
     581          20 :         atoms.setExtraCVForce(words[1],val);
     582             :         break;
     583        1077 :       case cmd_GREX:
     584        1077 :         if(!grex) grex=Tools::make_unique<GREX>(*this);
     585        1077 :         plumed_massert(grex,"error allocating grex");
     586             :         {
     587        1077 :           std::string kk=words[1];
     588        1248 :           for(unsigned i=2; i<words.size(); i++) kk+=" "+words[i];
     589        2154 :           grex->cmd(kk.c_str(),val);
     590             :         }
     591        1077 :         break;
     592       10668 :       case cmd_CLTool:
     593       10668 :         CHECK_NOTINIT(initialized,word);
     594       10668 :         if(!cltool) cltool=Tools::make_unique<CLToolMain>();
     595             :         {
     596       10668 :           std::string kk=words[1];
     597       10668 :           for(unsigned i=2; i<words.size(); i++) kk+=" "+words[i];
     598       21336 :           cltool->cmd(kk.c_str(),val);
     599             :         }
     600       10668 :         break;
     601             :       /* ADDED WITH API==7 */
     602             :       case cmd_convert:
     603             :       {
     604             :         double v;
     605          22 :         plumed_assert(words.size()==2);
     606          22 :         if(Tools::convertNoexcept(words[1],v)) atoms.double2MD(v,val);
     607             :       }
     608          22 :       break;
     609           7 :       default:
     610          21 :         plumed_merror("cannot interpret cmd(\"" + word + "\"). check plumed developers manual to see the available commands.");
     611             :         break;
     612             :       }
     613             :     }
     614             : 
     615     1040912 :   } catch (const std::exception &e) {
     616          86 :     if(log.isOpen()) {
     617          51 :       log<<"\n\n################################################################################\n\n";
     618          51 :       log<<e.what();
     619          51 :       log<<"\n\n################################################################################\n\n";
     620          51 :       log.flush();
     621             :     }
     622          86 :     throw;
     623          86 :   }
     624     1040654 : }
     625             : 
     626             : ////////////////////////////////////////////////////////////////////////
     627             : 
     628         914 : void PlumedMain::init() {
     629             : // check that initialization just happens once
     630         914 :   initialized=true;
     631         914 :   atoms.init();
     632         914 :   if(!log.isOpen()) log.link(stdout);
     633         914 :   log<<"PLUMED is starting\n";
     634        2742 :   log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") "
     635        3656 :      <<"compiled on " <<config::getCompilationDate() << " at " << config::getCompilationTime() << "\n";
     636         914 :   log<<"Please cite these papers when using PLUMED ";
     637        1828 :   log<<cite("The PLUMED consortium, Nat. Methods 16, 670 (2019)");
     638        1828 :   log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
     639         914 :   log<<"\n";
     640         914 :   log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
     641         914 :   log<<"Root: "<<config::getPlumedRoot()<<"\n";
     642        1828 :   log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
     643         914 :   log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
     644         914 :   log.printf("Precision of reals: %d\n",atoms.getRealPrecision());
     645        1604 :   log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
     646         914 :   log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
     647         914 :   log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
     648         914 :   log.printf("Number of atoms: %d\n",atoms.getNatoms());
     649         914 :   if(grex) log.printf("GROMACS-like replica exchange is on\n");
     650         914 :   log.printf("File suffix: %s\n",getSuffix().c_str());
     651         914 :   if(plumedDat.length()>0) {
     652         773 :     readInputFile(plumedDat);
     653             :     plumedDat="";
     654             :   }
     655         914 :   atoms.updateUnits();
     656         914 :   log.printf("Timestep: %f\n",atoms.getTimeStep());
     657         914 :   if(atoms.getKbT()>0.0)
     658          53 :     log.printf("KbT: %f\n",atoms.getKbT());
     659             :   else {
     660         861 :     log.printf("KbT has not been set by the MD engine\n");
     661         861 :     log.printf("It should be set by hand where needed\n");
     662             :   }
     663         914 :   log<<"Relevant bibliography:\n";
     664         914 :   log<<citations;
     665         914 :   log<<"Please read and cite where appropriate!\n";
     666         914 :   log<<"Finished setup\n";
     667         914 : }
     668             : 
     669         791 : void PlumedMain::readInputFile(const std::string & str) {
     670         791 :   plumed_assert(initialized);
     671         791 :   log<<"FILE: "<<str<<"\n";
     672         791 :   IFile ifile;
     673         791 :   ifile.link(*this);
     674         791 :   ifile.open(str);
     675         791 :   ifile.allowNoEOL();
     676         791 :   readInputFile(ifile);
     677         791 :   log<<"END FILE: "<<str<<"\n";
     678         791 :   log.flush();
     679             : 
     680         791 : }
     681             : 
     682         792 : void PlumedMain::readInputFile(IFile & ifile) {
     683             :   std::vector<std::string> words;
     684       14523 :   while(Tools::getParsedLine(ifile,words) && !endPlumed) readInputWords(words);
     685         792 :   endPlumed=false;
     686         792 :   pilots=actionSet.select<ActionPilot*>();
     687         792 : }
     688             : 
     689         353 : void PlumedMain::readInputLine(const std::string & str) {
     690         353 :   plumed_assert(initialized);
     691         353 :   if(str.empty()) return;
     692         353 :   std::vector<std::string> words=Tools::getWords(str);
     693         353 :   citations.clear();
     694         353 :   readInputWords(words);
     695         314 :   if(!citations.empty()) {
     696           2 :     log<<"Relevant bibliography:\n";
     697           2 :     log<<citations;
     698           2 :     log<<"Please read and cite where appropriate!\n";
     699             :   }
     700         353 : }
     701             : 
     702           1 : void PlumedMain::readInputLines(const std::string & str) {
     703           1 :   plumed_assert(initialized);
     704           1 :   if(str.empty()) return;
     705             : 
     706           1 :   log<<"FILE: (temporary)\n";
     707             : 
     708             :   // Open a temporary file
     709           1 :   auto fp=std::tmpfile();
     710           1 :   plumed_assert(fp);
     711             : 
     712             :   // make sure file is closed (and thus deleted) also if an exception occurs
     713           1 :   auto deleter=[](FILE* fp) { std::fclose(fp); };
     714             :   std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
     715             : 
     716           1 :   auto ret=std::fputs(str.c_str(),fp);
     717           1 :   plumed_assert(ret!=EOF);
     718             : 
     719           1 :   std::rewind(fp);
     720             : 
     721           1 :   IFile ifile;
     722           1 :   ifile.link(*this);
     723           1 :   ifile.link(fp);
     724           1 :   ifile.allowNoEOL();
     725             : 
     726           1 :   readInputFile(ifile);
     727           1 :   log<<"END FILE: (temporary)\n";
     728           1 : }
     729             : 
     730       14110 : void PlumedMain::readInputWords(const std::vector<std::string> & words) {
     731       14110 :   plumed_assert(initialized);
     732       14110 :   if(words.empty())return;
     733       14110 :   else if(words[0]=="_SET_SUFFIX") {
     734           3 :     plumed_assert(words.size()==2);
     735             :     setSuffix(words[1]);
     736             :   } else {
     737       14107 :     std::vector<std::string> interpreted(words);
     738       14107 :     Tools::interpretLabel(interpreted);
     739       28177 :     auto action=actionRegister().create(ActionOptions(*this,interpreted));
     740       14070 :     if(!action) {
     741             :       std::string msg;
     742             :       msg ="ERROR\nI cannot understand line:";
     743          10 :       for(unsigned i=0; i<interpreted.size(); ++i) msg+=" "+interpreted[i];
     744             :       msg+="\nMaybe a missing space or a typo?";
     745           2 :       log << msg;
     746           2 :       log.flush();
     747           4 :       plumed_merror(msg);
     748             :     }
     749       14068 :     action->checkRead();
     750       14068 :     actionSet.emplace_back(std::move(action));
     751       14109 :   };
     752             : 
     753       28142 :   pilots=actionSet.select<ActionPilot*>();
     754             : }
     755             : 
     756             : ////////////////////////////////////////////////////////////////////////
     757             : 
     758           0 : void PlumedMain::exit(int c) {
     759           0 :   comm.Abort(c);
     760           0 : }
     761             : 
     762       14105 : Log& PlumedMain::getLog() {
     763       14105 :   return log;
     764             : }
     765             : 
     766      245716 : void PlumedMain::calc() {
     767      245716 :   prepareCalc();
     768      245716 :   performCalc();
     769      245716 : }
     770             : 
     771      247786 : void PlumedMain::prepareCalc() {
     772      247786 :   prepareDependencies();
     773      247786 :   shareData();
     774      247786 : }
     775             : 
     776             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     777             : // here we have the main steps in "calc()"
     778             : // they can be called individually, but the standard thing is to
     779             : // traverse them in this order:
     780      248113 : void PlumedMain::prepareDependencies() {
     781             : 
     782             : // Stopwatch is stopped when sw goes out of scope
     783      248113 :   auto sw=stopwatch.startStop("1 Prepare dependencies");
     784             : 
     785             : // activate all the actions which are on step
     786             : // activation is recursive and enables also the dependencies
     787             : // before doing that, the prepare() method is called to see if there is some
     788             : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
     789             : // which can be dynamically changed).
     790             : 
     791             : // First switch off all actions
     792     2071737 :   for(const auto & p : actionSet) {
     793     1823624 :     p->deactivate();
     794             :   }
     795             : 
     796             : // for optimization, an "active" flag remains false if no action at all is active
     797      248113 :   active=mydatafetcher->activate();
     798     1587111 :   for(unsigned i=0; i<pilots.size(); ++i) {
     799     1338998 :     if(pilots[i]->onStep()) {
     800     1269461 :       pilots[i]->activate();
     801     1269461 :       active=true;
     802             :     }
     803             :   };
     804             : 
     805             : // also, if one of them is the total energy, tell to atoms that energy should be collected
     806     2071737 :   for(const auto & p : actionSet) {
     807     1823624 :     if(p->isActive()) {
     808     1642537 :       if(p->checkNeedsGradients()) p->setOption("GRADIENTS");
     809             :     }
     810             :   }
     811             : 
     812      248113 : }
     813             : 
     814      247870 : void PlumedMain::shareData() {
     815             : // atom positions are shared (but only if there is something to do)
     816      247870 :   if(!active)return;
     817             : // Stopwatch is stopped when sw goes out of scope
     818      246382 :   auto sw=stopwatch.startStop("2 Sharing data");
     819      246382 :   if(atoms.getNatoms()>0) atoms.share();
     820      246382 : }
     821             : 
     822        2134 : void PlumedMain::performCalcNoUpdate() {
     823        2134 :   waitData();
     824        2134 :   justCalculate();
     825        2134 :   backwardPropagate();
     826        2134 : }
     827             : 
     828          10 : void PlumedMain::performCalcNoForces() {
     829          10 :   waitData();
     830          10 :   justCalculate();
     831          10 : }
     832             : 
     833      245726 : void PlumedMain::performCalc() {
     834      245726 :   waitData();
     835      245726 :   justCalculate();
     836      245726 :   backwardPropagate();
     837      245726 :   update();
     838      245726 :   mydatafetcher->finishDataGrab();
     839      245726 : }
     840             : 
     841      247984 : void PlumedMain::waitData() {
     842      247984 :   if(!active)return;
     843             : // Stopwatch is stopped when sw goes out of scope
     844      246496 :   auto sw=stopwatch.startStop("3 Waiting for data");
     845      246496 :   if(atoms.getNatoms()>0) atoms.wait();
     846      246496 : }
     847             : 
     848      247984 : void PlumedMain::justCalculate() {
     849      247984 :   if(!active)return;
     850             : // Stopwatch is stopped when sw goes out of scope
     851      246496 :   auto sw=stopwatch.startStop("4 Calculating (forward loop)");
     852      246496 :   bias=0.0;
     853      246496 :   work=0.0;
     854             : 
     855      246496 :   int iaction=0;
     856             : // calculate the active actions in order (assuming *backward* dependence)
     857     2060664 :   for(const auto & pp : actionSet) {
     858             :     Action* p(pp.get());
     859     1814168 :     if(p->isActive()) {
     860             : // Stopwatch is stopped when sw goes out of scope.
     861             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
     862     1641587 :       Stopwatch::Handler sw;
     863     1641587 :       if(detailedTimers) {
     864             :         std::string actionNumberLabel;
     865        1690 :         Tools::convert(iaction,actionNumberLabel);
     866        1690 :         const unsigned m=actionSet.size();
     867        5070 :         unsigned k=0; unsigned n=1; while(n<m) { n*=10; k++; }
     868        1690 :         const int pad=k-actionNumberLabel.length();
     869        2815 :         for(int i=0; i<pad; i++) actionNumberLabel=" "+actionNumberLabel;
     870        1690 :         sw=stopwatch.startStop("4A "+actionNumberLabel+" "+p->getLabel());
     871             :       }
     872     1641587 :       ActionWithValue*av=dynamic_cast<ActionWithValue*>(p);
     873     1641587 :       ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(p);
     874             :       {
     875     1641587 :         if(av) av->clearInputForces();
     876     1641587 :         if(av) av->clearDerivatives();
     877             :       }
     878             :       {
     879     1641587 :         if(aa) aa->clearOutputForces();
     880     1641587 :         if(aa) if(aa->isActive()) aa->retrieveAtoms();
     881             :       }
     882     1641587 :       if(p->checkNumericalDerivatives()) p->calculateNumericalDerivatives();
     883     1641020 :       else p->calculate();
     884             :       // This retrieves components called bias
     885     1641587 :       if(av) {
     886     1389822 :         bias+=av->getOutputQuantity("bias");
     887     1389822 :         work+=av->getOutputQuantity("work");
     888     1389822 :         av->setGradientsIfNeeded();
     889             :       }
     890     1641587 :       ActionWithVirtualAtom*avv=dynamic_cast<ActionWithVirtualAtom*>(p);
     891     1641587 :       if(avv)avv->setGradientsIfNeeded();
     892     1641587 :     }
     893     1814168 :     iaction++;
     894             :   }
     895      246496 : }
     896             : 
     897           0 : void PlumedMain::justApply() {
     898           0 :   backwardPropagate();
     899           0 :   update();
     900           0 : }
     901             : 
     902      247860 : void PlumedMain::backwardPropagate() {
     903      247860 :   if(!active)return;
     904      246372 :   int iaction=0;
     905             : // Stopwatch is stopped when sw goes out of scope
     906      246372 :   auto sw=stopwatch.startStop("5 Applying (backward loop)");
     907             : // apply them in reverse order
     908     2059606 :   for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
     909             :     const auto & p(pp->get());
     910     1813234 :     if(p->isActive()) {
     911             : 
     912             : // Stopwatch is stopped when sw goes out of scope.
     913             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
     914     1640833 :       Stopwatch::Handler sw;
     915     1640833 :       if(detailedTimers) {
     916             :         std::string actionNumberLabel;
     917        1690 :         Tools::convert(iaction,actionNumberLabel);
     918        1690 :         const unsigned m=actionSet.size();
     919        5070 :         unsigned k=0; unsigned n=1; while(n<m) { n*=10; k++; }
     920        1690 :         const int pad=k-actionNumberLabel.length();
     921        2815 :         for(int i=0; i<pad; i++) actionNumberLabel=" "+actionNumberLabel;
     922        1690 :         sw=stopwatch.startStop("5A "+actionNumberLabel+" "+p->getLabel());
     923             :       }
     924             : 
     925     1640833 :       p->apply();
     926     1640833 :       ActionAtomistic*a=dynamic_cast<ActionAtomistic*>(p);
     927             : // still ActionAtomistic has a special treatment, since they may need to add forces on atoms
     928     1640833 :       if(a) a->applyForces();
     929             : 
     930     1640833 :     }
     931     1813234 :     iaction++;
     932             :   }
     933             : 
     934             : // Stopwatch is stopped when sw goes out of scope.
     935             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
     936      246372 :   Stopwatch::Handler sw1;
     937      246485 :   if(detailedTimers) sw1=stopwatch.startStop("5B Update forces");
     938             : // this is updating the MD copy of the forces
     939      246372 :   if(atoms.getNatoms()>0) atoms.updateForces();
     940      246372 : }
     941             : 
     942      245805 : void PlumedMain::update() {
     943      245805 :   if(!active)return;
     944             : 
     945             : // Stopwatch is stopped when sw goes out of scope
     946      244317 :   auto sw=stopwatch.startStop("6 Update");
     947             : 
     948             : // update step (for statistics, etc)
     949      244317 :   updateFlags.push(true);
     950     2051084 :   for(const auto & p : actionSet) {
     951     1806767 :     p->beforeUpdate();
     952     3440763 :     if(p->isActive() && p->checkUpdate() && updateFlagsTop()) p->update();
     953             :   }
     954      488638 :   while(!updateFlags.empty()) updateFlags.pop();
     955             :   if(!updateFlags.empty()) plumed_merror("non matching changes in the update flags");
     956             : // Check that no action has told the calculation to stop
     957      244317 :   if(stopNow) {
     958          65 :     if(stopFlag) stopFlag.set(int(1));
     959           0 :     else plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
     960             :   }
     961             : 
     962             : // flush by default every 10000 steps
     963             : // hopefully will not affect performance
     964             : // also if receive checkpointing signal
     965      244317 :   if(step%10000==0||doCheckPoint) {
     966         886 :     fflush();
     967         886 :     log.flush();
     968       15368 :     for(const auto & p : actionSet) p->fflush();
     969             :   }
     970      244317 : }
     971             : 
     972           2 : void PlumedMain::load(const std::string& ss) {
     973           2 :   if(DLLoader::installed()) {
     974           2 :     std::string s=ss;
     975           2 :     size_t n=s.find_last_of(".");
     976           3 :     std::string extension="";
     977           2 :     std::string base=s;
     978           4 :     if(n!=std::string::npos && n<s.length()-1) extension=s.substr(n+1);
     979           4 :     if(n!=std::string::npos && n<s.length())   base=s.substr(0,n);
     980           2 :     if(extension=="cpp") {
     981             : // full path command, including environment setup
     982             : // this will work even if plumed is not in the execution path or if it has been
     983             : // installed with a name different from "plumed"
     984           4 :       std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh "+s;
     985           2 :       log<<"Executing: "<<cmd;
     986           2 :       if(comm.Get_size()>0) log<<" (only on master node)";
     987           2 :       log<<"\n";
     988           2 :       if(comm.Get_rank()==0) {
     989           2 :         int ret=std::system(cmd.c_str());
     990           3 :         if(ret!=0) plumed_error() <<"An error happened while executing command "<<cmd<<"\n";
     991             :       }
     992           1 :       comm.Barrier();
     993           2 :       base="./"+base;
     994             :     }
     995           2 :     s=base+"."+config::getSoExt();
     996           1 :     void *p=dlloader.load(s);
     997           1 :     if(!p) {
     998           0 :       plumed_error()<<"I cannot load library " << ss << " " << dlloader.error();
     999             :     }
    1000           2 :     log<<"Loading shared library "<<s.c_str()<<"\n";
    1001           1 :     log<<"Here is the new list of available actions\n";
    1002           1 :     log<<actionRegister();
    1003           0 :   } else plumed_error()<<"While loading library "<< ss << " loading was not enabled, please check if dlopen was found at configure time";
    1004           1 : }
    1005             : 
    1006        2805 : double PlumedMain::getBias() const {
    1007        2805 :   return bias;
    1008             : }
    1009             : 
    1010         450 : double PlumedMain::getWork() const {
    1011         450 :   return work;
    1012             : }
    1013             : 
    1014          73 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
    1015          73 :   std::string mmode(mode);
    1016          73 :   std::string ppath(path);
    1017          73 :   std::string suffix(getSuffix());
    1018          73 :   std::string ppathsuf=ppath+suffix;
    1019          73 :   FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
    1020          73 :   if(!fp) fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
    1021          73 :   plumed_massert(fp,"file " + ppath + " cannot be found");
    1022          73 :   return fp;
    1023             : }
    1024             : 
    1025          91 : int PlumedMain::fclose(FILE*fp) {
    1026          91 :   return std::fclose(fp);
    1027             : }
    1028             : 
    1029        3576 : std::string PlumedMain::cite(const std::string&item) {
    1030        3576 :   return citations.cite(item);
    1031             : }
    1032             : 
    1033        1447 : void PlumedMain::fflush() {
    1034        4578 :   for(const auto  & p : files) {
    1035        3131 :     p->flush();
    1036             :   }
    1037        1447 : }
    1038             : 
    1039        4317 : void PlumedMain::insertFile(FileBase&f) {
    1040        4317 :   files.insert(&f);
    1041        4317 : }
    1042             : 
    1043        4607 : void PlumedMain::eraseFile(FileBase&f) {
    1044        4607 :   files.erase(&f);
    1045        4607 : }
    1046             : 
    1047          65 : void PlumedMain::stop() {
    1048          65 :   stopNow=true;
    1049          65 : }
    1050             : 
    1051         721 : void PlumedMain::runJobsAtEndOfCalculation() {
    1052       14277 :   for(const auto & p : actionSet) {
    1053       13556 :     p->runFinalJobs();
    1054             :   }
    1055         721 : }
    1056             : 
    1057             : #ifdef __PLUMED_HAS_PYTHON
    1058             : // This is here to stop cppcheck throwing an error
    1059             : #endif
    1060             : 
    1061             : }
    1062             : 
    1063             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.15