LCOV - code coverage report
Current view: top level - core - PlumedMain.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 947 1070 88.5 %
Date: 2025-03-25 09:33:27 Functions: 65 70 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 "ActionForInterface.h"
      26             : #include "ActionRegister.h"
      27             : #include "ActionSet.h"
      28             : #include "ActionWithValue.h"
      29             : #include "ActionWithVirtualAtom.h"
      30             : #include "ActionToGetData.h"
      31             : #include "ActionToPutData.h"
      32             : #include "CLToolMain.h"
      33             : #include "ExchangePatterns.h"
      34             : #include "GREX.h"
      35             : #include "DomainDecomposition.h"
      36             : #include "config/Config.h"
      37             : #include "tools/Citations.h"
      38             : #include "tools/Communicator.h"
      39             : #include "tools/DLLoader.h"
      40             : #include "tools/Exception.h"
      41             : #include "tools/IFile.h"
      42             : #include "tools/Log.h"
      43             : #include "tools/OpenMP.h"
      44             : #include "tools/Tools.h"
      45             : #include "tools/Stopwatch.h"
      46             : #include "tools/TypesafePtr.h"
      47             : #include "lepton/Exception.h"
      48             : #include "DataPassingTools.h"
      49             : #include "small_vector/small_vector.h"
      50             : #include <cstdlib>
      51             : #include <cstdio>
      52             : #include <cstring>
      53             : #include <set>
      54             : #include <exception>
      55             : #include <stdexcept>
      56             : #include <ios>
      57             : #include <new>
      58             : #include <typeinfo>
      59             : #include <iostream>
      60             : #include <algorithm>
      61             : #include <system_error>
      62             : #include <future>
      63             : #include <memory>
      64             : #include <functional>
      65             : #include <regex>
      66             : #include <any>
      67             : #include <optional>
      68             : #include <variant>
      69             : #include <filesystem>
      70             : 
      71             : namespace PLMD {
      72             : 
      73             : /// Small utility just used in this file to throw arbitrary exceptions
      74          61 : [[noreturn]] static void testThrow(const char* what) {
      75          61 :   auto words=Tools::getWords(what);
      76          61 :   plumed_assert(words.size()>0);
      77             : #define __PLUMED_THROW_NOMSG(type) if(words[0]==#type) throw type()
      78             : #define __PLUMED_THROW_MSG(type) if(words[0]==#type) throw type(what)
      79          62 :   __PLUMED_THROW_MSG(PLMD::ExceptionError);
      80          61 :   __PLUMED_THROW_MSG(PLMD::ExceptionDebug);
      81          60 :   __PLUMED_THROW_MSG(PLMD::Exception);
      82          59 :   __PLUMED_THROW_MSG(PLMD::lepton::Exception);
      83          57 :   __PLUMED_THROW_NOMSG(std::bad_exception);
      84          56 :   __PLUMED_THROW_NOMSG(std::bad_array_new_length);
      85          55 :   __PLUMED_THROW_NOMSG(std::bad_alloc);
      86          54 :   __PLUMED_THROW_NOMSG(std::bad_function_call);
      87          53 :   __PLUMED_THROW_NOMSG(std::bad_weak_ptr);
      88          52 :   __PLUMED_THROW_NOMSG(std::bad_cast);
      89          51 :   __PLUMED_THROW_NOMSG(std::bad_typeid);
      90          50 :   __PLUMED_THROW_NOMSG(std::bad_variant_access);
      91          49 :   __PLUMED_THROW_NOMSG(std::bad_optional_access);
      92          48 :   __PLUMED_THROW_NOMSG(std::bad_any_cast);
      93          47 :   __PLUMED_THROW_MSG(std::underflow_error);
      94          46 :   __PLUMED_THROW_MSG(std::overflow_error);
      95          45 :   __PLUMED_THROW_MSG(std::range_error);
      96          44 :   __PLUMED_THROW_MSG(std::runtime_error);
      97          43 :   __PLUMED_THROW_MSG(std::out_of_range);
      98          42 :   __PLUMED_THROW_MSG(std::length_error);
      99          41 :   __PLUMED_THROW_MSG(std::domain_error);
     100          40 :   __PLUMED_THROW_MSG(std::invalid_argument);
     101          39 :   __PLUMED_THROW_MSG(std::logic_error);
     102             : 
     103             : 
     104             : 
     105          38 :   if(words[0]=="std::system_error") {
     106           4 :     plumed_assert(words.size()>2);
     107             :     int error_code;
     108           4 :     Tools::convert(words[2],error_code);
     109           4 :     if(words[1]=="std::generic_category") {
     110           1 :       throw std::system_error(error_code,std::generic_category(),what);
     111             :     }
     112           3 :     if(words[1]=="std::system_category") {
     113           1 :       throw std::system_error(error_code,std::system_category(),what);
     114             :     }
     115           2 :     if(words[1]=="std::iostream_category") {
     116           1 :       throw std::system_error(error_code,std::iostream_category(),what);
     117             :     }
     118           1 :     if(words[1]=="std::future_category") {
     119           1 :       throw std::system_error(error_code,std::future_category(),what);
     120             :     }
     121             :   }
     122             : 
     123          34 :   if(words[0]=="std::filesystem::filesystem_error") {
     124             :     int error_code;
     125           3 :     plumed_assert(words.size()>2);
     126           3 :     Tools::convert(words[2],error_code);
     127             :     std::error_code x_error_code;
     128           3 :     if(words[1]=="std::generic_category") {
     129           3 :       x_error_code=::std::error_code(error_code,::std::generic_category());
     130             :     }
     131           3 :     if(words[1]=="std::system_category") {
     132           0 :       x_error_code=::std::error_code(error_code,::std::system_category());
     133             :     }
     134           3 :     if(words[1]=="std::iostream_category") {
     135           0 :       x_error_code=::std::error_code(error_code,::std::iostream_category());
     136             :     }
     137           3 :     if(words[1]=="std::future_category") {
     138           0 :       x_error_code=::std::error_code(error_code,::std::future_category());
     139             :     }
     140             : 
     141           3 :     if(words.size()<4) {
     142           2 :       throw std::filesystem::filesystem_error(what,x_error_code);
     143             :     }
     144           2 :     if(words.size()<5) {
     145           3 :       throw std::filesystem::filesystem_error(what,std::filesystem::path(words[3]),x_error_code);
     146             :     }
     147           4 :     throw std::filesystem::filesystem_error(what,std::filesystem::path(words[3]),std::filesystem::path(words[4]),x_error_code);
     148             :   }
     149             : 
     150             : #define __PLUMED_THROW_REGEX(name) if(words[1]=="std::regex_constants::error_" #name) throw std::regex_error(std::regex_constants::error_ ##name)
     151          31 :   if(words[0]=="std::regex_error") {
     152          13 :     plumed_assert(words.size()>1);
     153          13 :     __PLUMED_THROW_REGEX(collate);
     154          12 :     __PLUMED_THROW_REGEX(ctype);
     155          11 :     __PLUMED_THROW_REGEX(escape);
     156          10 :     __PLUMED_THROW_REGEX(backref);
     157           9 :     __PLUMED_THROW_REGEX(brack);
     158           8 :     __PLUMED_THROW_REGEX(paren);
     159           7 :     __PLUMED_THROW_REGEX(brace);
     160           6 :     __PLUMED_THROW_REGEX(badbrace);
     161           5 :     __PLUMED_THROW_REGEX(range);
     162           4 :     __PLUMED_THROW_REGEX(space);
     163           3 :     __PLUMED_THROW_REGEX(badrepeat);
     164           2 :     __PLUMED_THROW_REGEX(complexity);
     165           1 :     __PLUMED_THROW_REGEX(stack);
     166             :   }
     167             : 
     168             : #define __PLUMED_THROW_FUTURE(name) if(words[1]=="std::future_errc::" #name) throw std::future_error(::std::future_errc::name)
     169          18 :   if(words[0]=="std::future_error") {
     170           4 :     plumed_assert(words.size()>1);
     171           4 :     __PLUMED_THROW_FUTURE(broken_promise);
     172           3 :     __PLUMED_THROW_FUTURE(future_already_retrieved);
     173           2 :     __PLUMED_THROW_FUTURE(promise_already_satisfied);
     174           1 :     __PLUMED_THROW_FUTURE(no_state);
     175             :   }
     176             : 
     177          14 :   if(words[0]=="std::ios_base::failure") {
     178           1 :     int error_code=0;
     179           1 :     if(words.size()>2) {
     180           0 :       Tools::convert(words[2],error_code);
     181             :     }
     182           1 :     if(words.size()>1 && words[1]=="std::generic_category") {
     183           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::generic_category()));
     184             :     }
     185           1 :     if(words.size()>1 && words[1]=="std::system_category") {
     186           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::system_category()));
     187             :     }
     188           1 :     if(words.size()>1 && words[1]=="std::iostream_category") {
     189           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::iostream_category()));
     190             :     }
     191           1 :     if(words.size()>1 && words[1]=="std::future_category") {
     192           0 :       throw std::ios_base::failure(what,std::error_code(error_code,std::future_category()));
     193             :     }
     194           2 :     throw std::ios_base::failure(what);
     195             :   }
     196             : 
     197          13 :   if(words[0]=="int") {
     198           1 :     int value=0;
     199           1 :     if(words.size()>1) {
     200           0 :       Tools::convert(words[1],value);
     201             :     }
     202           1 :     throw value;
     203             :   }
     204             : 
     205          12 :   if(words[0]=="test_nested1") {
     206             :     try {
     207          12 :       throw Exception(std::string("inner ")+what);
     208           6 :     } catch(...) {
     209             :       try {
     210          18 :         std::throw_with_nested(Exception(std::string("middle ")+what));
     211           6 :       } catch(...) {
     212          18 :         std::throw_with_nested(Exception(std::string("outer ")+what));
     213           6 :       }
     214           6 :     }
     215             :   }
     216             : 
     217           6 :   if(words[0]=="test_nested2") {
     218             :     try {
     219           3 :       throw std::bad_alloc();
     220           3 :     } catch(...) {
     221             :       try {
     222           9 :         std::throw_with_nested(Exception(std::string("middle ")+what));
     223           3 :       } catch(...) {
     224           9 :         std::throw_with_nested(Exception(std::string("outer ")+what));
     225           3 :       }
     226           3 :     }
     227             :   }
     228             : 
     229           3 :   if(words[0]=="test_nested3") {
     230             :     try {
     231           2 :       throw "inner";
     232           2 :     } catch(...) {
     233             :       try {
     234           6 :         std::throw_with_nested(Exception(std::string("middle ")+what));
     235           2 :       } catch(...) {
     236           6 :         std::throw_with_nested(Exception(std::string("outer ")+what));
     237           2 :       }
     238           2 :     }
     239             :   }
     240             : 
     241           2 :   plumed_error() << "unknown exception " << what;
     242          61 : }
     243             : 
     244             : namespace {
     245             : /// This is an internal tool used to count how many PlumedMain objects have been created
     246             : /// and if they were correctly destroyed.
     247             : /// When using debug options, it leads to a crash
     248             : /// Otherwise, it just prints a message
     249             : class CountInstances {
     250             :   std::atomic<int> counter{};
     251             :   // private constructor to avoid direct usage
     252        5394 :   CountInstances() noexcept {}
     253        5394 :   ~CountInstances() {
     254        5394 :     if(counter!=0) {
     255           0 :       std::cerr<<"WARNING: internal inconsistency in allocated PlumedMain instances (" <<counter<< ")\n";
     256           0 :       std::cerr<<"Might be a consequence of incorrectly paired plumed_create/plumed_finalize in the C interface\n";
     257           0 :       std::cerr<<"Or it could be due to incorrect calls to std::exit, without properly destroying all PlumedMain objects\n";
     258             : #ifndef NDEBUG
     259             :       std::cerr<<"This is a debug build, so the warning will make PLUMED abort\n";
     260             :       std::abort();
     261             : #endif
     262             :     }
     263        5394 :   }
     264     1613640 :   static CountInstances & instance() {
     265     1613640 :     static CountInstances counter;
     266     1613640 :     return counter;
     267             :   }
     268             : public:
     269             :   /// Only access through these static functions
     270             :   /// The first call to increase() ensures the instance is constructed
     271             :   /// This should provide the correct construction and destruction order
     272             :   /// also in cases where the PlumedMain object is constructed in the
     273             :   /// constructor of a static object
     274      806820 :   static void increase() noexcept {
     275      806820 :     ++instance().counter;
     276      806820 :   }
     277             :   /// See increase()
     278      806820 :   static void decrease() noexcept {
     279      806820 :     --instance().counter;
     280      806820 :   }
     281             : };
     282             : 
     283             : }
     284             : 
     285             : 
     286      806820 : PlumedMain::PlumedMain():
     287      806820 :   datoms_fwd(*this),
     288             : // automatically write on log in destructor
     289      806820 :   stopwatch_fwd(log),
     290      806820 :   actionSet_fwd(*this),
     291      806820 :   passtools(DataPassingTools::create(sizeof(double))) {
     292      806820 :   passtools->usingNaturalUnits=false;
     293      806820 :   increaseReferenceCounter();
     294      806820 :   log.link(comm);
     295      806820 :   log.setLinePrefix("PLUMED: ");
     296             :   // this is at last so as to avoid inconsistencies if an exception is thrown
     297      806820 :   CountInstances::increase(); // noexcept
     298      806820 : }
     299             : 
     300             : // destructor needed to delete forward declarated objects
     301     1612642 : PlumedMain::~PlumedMain() {
     302      806820 :   CountInstances::decrease();
     303     4839922 : }
     304             : 
     305             : /////////////////////////////////////////////////////////////
     306             : //  MAIN INTERPRETER
     307             : 
     308             : #define CHECK_INIT(ini,word) plumed_assert(ini)<<"cmd(\"" << word << "\") should be only used after plumed initialization"
     309             : #define CHECK_NOTINIT(ini,word) plumed_assert(!(ini))<<"cmd(\"" << word << "\") should be only used before plumed initialization"
     310             : #define CHECK_NOTNULL(val,word) plumed_assert(val)<<"NULL pointer received in cmd(\"" << word << "\")"
     311             : 
     312             : 
     313     1350634 : void PlumedMain::cmd(std::string_view word,const TypesafePtr & val) {
     314             : 
     315             : // Enumerate all possible commands:
     316             :   enum {
     317             : #include "PlumedMainEnum.inc"
     318             :   };
     319             : 
     320             : // Static object (initialized once) containing the map of commands:
     321             :   const static Tools::FastStringUnorderedMap<int> word_map = {
     322             : #include "PlumedMainMap.inc"
     323     1350634 :   };
     324             : 
     325             :   try {
     326             : 
     327     1350634 :     auto ss=stopwatch.startPause();
     328             : 
     329             :     gch::small_vector<std::string_view> words;
     330     1350634 :     Tools::getWordsSimple(words,word);
     331             : 
     332     1350634 :     unsigned nw=words.size();
     333     1350634 :     if(nw==0) {
     334             :       // do nothing
     335             :     } else {
     336             :       int iword=-1;
     337             :       const auto it=word_map.find(words[0]);
     338     1350633 :       if(it!=word_map.end()) {
     339     1350626 :         iword=it->second;
     340             :       }
     341             : 
     342     1350626 :       switch(iword) {
     343       70588 :       case cmd_setBox:
     344       70588 :         CHECK_INIT(initialized,word);
     345       70588 :         CHECK_NOTNULL(val,word);
     346       70588 :         setInputValue( "Box", 0, 1, val );
     347       70587 :         break;
     348       74765 :       case cmd_setPositions:
     349       74765 :         CHECK_INIT(initialized,word);
     350       74765 :         setInputValue("posx", 0, 3, val );
     351       74765 :         setInputValue("posy", 1, 3, val );
     352       74765 :         setInputValue("posz", 2, 3, val );
     353       74765 :         break;
     354       74728 :       case cmd_setMasses:
     355       74728 :         CHECK_INIT(initialized,word);
     356       74728 :         setInputValue("Masses", 0, 1, val );
     357       74725 :         break;
     358       66653 :       case cmd_setCharges:
     359       66653 :         CHECK_INIT(initialized,word);
     360       66653 :         setInputValue("Charges", 0, 1, val);
     361       66653 :         break;
     362           1 :       case cmd_setPositionsX:
     363           1 :         CHECK_INIT(initialized,word);
     364           1 :         setInputValue("posx", 0, 1, val);
     365           1 :         break;
     366           1 :       case cmd_setPositionsY:
     367           1 :         CHECK_INIT(initialized,word);
     368           1 :         setInputValue("posy", 0, 1, val);
     369           1 :         break;
     370           1 :       case cmd_setPositionsZ:
     371           1 :         CHECK_INIT(initialized,word);
     372           1 :         setInputValue("posz", 0, 1, val);
     373           1 :         break;
     374       66902 :       case cmd_setVirial:
     375       66902 :         CHECK_INIT(initialized,word);
     376       66902 :         CHECK_NOTNULL(val,word);
     377       66902 :         setInputForce("Box",val);
     378       66884 :         break;
     379        7842 :       case cmd_setEnergy:
     380        7842 :         CHECK_INIT(initialized,word);
     381        7842 :         CHECK_NOTNULL(val,word);
     382        7842 :         if( name_of_energy!="" ) {
     383        3989 :           setInputValue( name_of_energy, 0, 1,  val );
     384             :         }
     385             :         break;
     386       74732 :       case cmd_setForces:
     387       74732 :         CHECK_INIT(initialized,word);
     388       74732 :         setInputForce("posx",val);
     389       74732 :         setInputForce("posy",val);
     390       74732 :         setInputForce("posz",val);
     391       74732 :         break;
     392           1 :       case cmd_setForcesX:
     393           1 :         CHECK_INIT(initialized,word);
     394           1 :         setInputForce("posx",val);
     395           1 :         break;
     396           1 :       case cmd_setForcesY:
     397           1 :         CHECK_INIT(initialized,word);
     398           1 :         setInputForce("posy",val);
     399           1 :         break;
     400           1 :       case cmd_setForcesZ:
     401           1 :         CHECK_INIT(initialized,word);
     402           1 :         setInputForce("posz",val);
     403           1 :         break;
     404      280115 :       case cmd_calc:
     405      280115 :         CHECK_INIT(initialized,word);
     406      280115 :         calc();
     407             :         break;
     408          99 :       case cmd_prepareDependencies:
     409          99 :         CHECK_INIT(initialized,word);
     410          99 :         prepareDependencies();
     411             :         break;
     412          84 :       case cmd_shareData:
     413          84 :         CHECK_INIT(initialized,word);
     414          84 :         shareData();
     415             :         break;
     416        6951 :       case cmd_prepareCalc:
     417        6951 :         CHECK_INIT(initialized,word);
     418        6951 :         prepareCalc();
     419             :         break;
     420          10 :       case cmd_performCalc:
     421          10 :         CHECK_INIT(initialized,word);
     422          10 :         performCalc();
     423             :         break;
     424        7011 :       case cmd_performCalcNoUpdate:
     425        7011 :         CHECK_INIT(initialized,word);
     426        7011 :         performCalcNoUpdate();
     427             :         break;
     428          10 :       case cmd_performCalcNoForces:
     429          10 :         CHECK_INIT(initialized,word);
     430          10 :         performCalcNoForces();
     431             :         break;
     432          79 :       case cmd_update:
     433          79 :         CHECK_INIT(initialized,word);
     434          79 :         update();
     435             :         break;
     436       16009 :       case cmd_setStep:
     437       16009 :         CHECK_INIT(initialized,word);
     438       16012 :         CHECK_NOTNULL(val,word);
     439       16006 :         step=val.get<int>();
     440       16005 :         startStep();
     441             :         break;
     442           0 :       case cmd_setStepLong:
     443           0 :         CHECK_INIT(initialized,word);
     444           0 :         CHECK_NOTNULL(val,word);
     445           0 :         step=val.get<long int>();
     446           0 :         startStep();
     447             :         break;
     448      271058 :       case cmd_setStepLongLong:
     449      271058 :         CHECK_INIT(initialized,word);
     450      271058 :         CHECK_NOTNULL(val,word);
     451      271058 :         step=val.get<long long int>();
     452      271058 :         startStep();
     453             :         break;
     454       23456 :       case cmd_setValue: {
     455       23456 :         CHECK_INIT(initialized,words[0]);
     456       23456 :         plumed_assert(nw==2);
     457       23456 :         setInputValue( std::string(words[1]), 0, 1, val );
     458             :       }
     459       23456 :       break;
     460             :       /* ADDED WITH API=7 */
     461           0 :       case cmd_setValueForces: {
     462           0 :         CHECK_INIT(initialized,words[0]);
     463           0 :         plumed_assert(nw==2);
     464           0 :         setInputForce( std::string(words[1]), val );
     465             :       }
     466           0 :       break;
     467             :       // words used less frequently:
     468        1140 :       case cmd_setAtomsNlocal:
     469        1140 :         CHECK_INIT(initialized,word);
     470        1140 :         CHECK_NOTNULL(val,word);
     471        4582 :         for(const auto & pp : inputs ) {
     472        3442 :           plumed_assert(pp);
     473        3442 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     474        3442 :           if( dd ) {
     475        1140 :             dd->setAtomsNlocal(val.get<int>());
     476             :           }
     477             :         }
     478             :         break;
     479         988 :       case cmd_setAtomsGatindex:
     480         988 :         CHECK_INIT(initialized,word);
     481        3974 :         for(const auto & pp : inputs ) {
     482        2986 :           plumed_assert(pp);
     483        2986 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     484        2986 :           if( dd ) {
     485         988 :             dd->setAtomsGatindex(val,false);
     486             :           }
     487             :         }
     488             :         break;
     489           0 :       case cmd_setAtomsFGatindex:
     490           0 :         CHECK_INIT(initialized,word);
     491           0 :         for(const auto & pp : inputs ) {
     492           0 :           plumed_assert(pp);
     493           0 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     494           0 :           if( dd ) {
     495           0 :             dd->setAtomsGatindex(val,false);
     496             :           }
     497             :         }
     498             :         break;
     499         152 :       case cmd_setAtomsContiguous:
     500         152 :         CHECK_INIT(initialized,word);
     501         152 :         CHECK_NOTNULL(val,word);
     502         608 :         for(const auto & pp : inputs ) {
     503         456 :           plumed_assert(pp);
     504         456 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     505         456 :           if( dd ) {
     506         152 :             dd->setAtomsContiguous(val.get<int>());
     507             :           }
     508             :         }
     509             :         break;
     510         116 :       case cmd_createFullList:
     511         116 :         CHECK_INIT(initialized,word);
     512         116 :         CHECK_NOTNULL(val,word);
     513         553 :         for(const auto & pp : inputs ) {
     514         437 :           plumed_assert(pp);
     515         437 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     516         437 :           if( dd ) {
     517         116 :             dd->createFullList(val);
     518             :           }
     519             :         }
     520             :         break;
     521         116 :       case cmd_getFullList: {
     522         116 :         CHECK_INIT(initialized,word);
     523         116 :         CHECK_NOTNULL(val,word);
     524             :         unsigned nlists=0;
     525         553 :         for(const auto & pp : inputs ) {
     526         437 :           plumed_assert(pp);
     527         437 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     528         437 :           if( dd ) {
     529         116 :             dd->getFullList(val);
     530         116 :             nlists++;
     531             :           }
     532             :         }
     533         116 :         plumed_assert( nlists==1 );
     534             :       }
     535             :       break;
     536         116 :       case cmd_clearFullList:
     537         116 :         CHECK_INIT(initialized,word);
     538         553 :         for(const auto & pp : inputs ) {
     539         437 :           plumed_assert(pp);
     540         437 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     541         437 :           if( dd ) {
     542         116 :             dd->clearFullList();
     543             :           }
     544             :         }
     545             :         break;
     546             :       /* ADDED WITH API==6 */
     547         115 :       case cmd_getDataRank: {
     548         115 :         CHECK_INIT(initialized,words[0]);
     549         115 :         plumed_assert(nw==2 || nw==3);
     550         115 :         std::string vtype="";
     551         115 :         if( nw==3 ) {
     552           0 :           vtype=" TYPE="+std::string(words[2]);
     553             :         }
     554         345 :         readInputLine( "grab_" + std::string(words[1]) + ": GET ARG=" + std::string(words[1]) + vtype );
     555         230 :         ActionToGetData* as=actionSet.selectWithLabel<ActionToGetData*>("grab_"+std::string(words[1]));
     556         115 :         plumed_assert( as );
     557         115 :         as->get_rank( val );
     558             :       }
     559         115 :       break;
     560             :       /* ADDED WITH API==6 */
     561          51 :       case cmd_getDataShape: {
     562          51 :         CHECK_INIT(initialized,std::string(words[0]));
     563         102 :         ActionToGetData* as1=actionSet.selectWithLabel<ActionToGetData*>("grab_"+std::string(words[1]));
     564          51 :         plumed_assert( as1 );
     565          51 :         as1->get_shape( val );
     566             :       }
     567             :       break;
     568             :       /* ADDED WITH API==6 */
     569         115 :       case cmd_setMemoryForData: {
     570         115 :         CHECK_INIT(initialized,words[0]);
     571         115 :         plumed_assert(nw==2 || nw==3);
     572         230 :         ActionToGetData* as2=actionSet.selectWithLabel<ActionToGetData*>("grab_"+std::string(words[1]));
     573         115 :         plumed_assert( as2 );
     574         115 :         as2->set_memory( val );
     575             :       }
     576             :       break;
     577             :       /* ADDED WITH API==6 */
     578             :       case cmd_setErrorHandler: {
     579           0 :         if(val) {
     580           0 :           error_handler=*static_cast<const plumed_error_handler*>(val.get<const void*>());
     581             :         } else {
     582           0 :           error_handler.handler=NULL;
     583             :         }
     584             :       }
     585             :       break;
     586           0 :       case cmd_read:
     587           0 :         CHECK_INIT(initialized,word);
     588           0 :         if(val) {
     589           0 :           readInputFile(val.getCString());
     590             :         } else {
     591           0 :           readInputFile("plumed.dat");
     592             :         }
     593             :         break;
     594         819 :       case cmd_readInputLine:
     595         819 :         CHECK_INIT(initialized,word);
     596         819 :         CHECK_NOTNULL(val,word);
     597         819 :         readInputLine(val.getCString());
     598         777 :         break;
     599           2 :       case cmd_readInputLines:
     600           2 :         CHECK_INIT(initialized,word);
     601           2 :         CHECK_NOTNULL(val,word);
     602           2 :         readInputLines(val.getCString());
     603           2 :         break;
     604           3 :       case cmd_clear: {
     605           3 :         CHECK_INIT(initialized,word);
     606             :         std::vector<int> natoms;
     607           7 :         for(const auto & pp : inputs ) {
     608           4 :           plumed_assert(pp);
     609           4 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     610           4 :           if ( dd ) {
     611           1 :             natoms.push_back( dd->getNumberOfAtoms() );
     612             :           }
     613             :         }
     614           3 :         actionSet.clearDelete();
     615             :         inputs.clear();
     616           4 :         for(unsigned i=0; i<natoms.size(); ++i) {
     617             :           std::string str_natoms;
     618           1 :           Tools::convert( natoms[i], str_natoms );
     619           3 :           readInputLine( MDEngine + ": DOMAIN_DECOMPOSITION NATOMS=" + str_natoms +
     620           2 :                          " VALUE1=posx UNIT1=length PERIODIC1=NO CONSTANT1=False ROLE1=x" +
     621           2 :                          " VALUE2=posy UNIT2=length PERIODIC2=NO CONSTANT2=False ROLE2=y" +
     622           2 :                          " VALUE3=posz UNIT3=length PERIODIC3=NO CONSTANT3=False ROLE3=z" +
     623           2 :                          " VALUE4=Masses UNIT4=mass PERIODIC4=NO CONSTANT4=True ROLE4=m" +
     624             :                          " VALUE5=Charges UNIT5=charge PERIODIC5=NO CONSTANT5=True ROLE5=q");
     625             : 
     626             :         }
     627           3 :         setUnits( passtools->usingNaturalUnits, passtools->units );
     628             :       }
     629           3 :       break;
     630             :       case cmd_getApiVersion:
     631          44 :         CHECK_NOTNULL(val,word);
     632          44 :         val.set(int(10));
     633             :         break;
     634             :       // commands which can be used only before initialization:
     635        1310 :       case cmd_init:
     636        1310 :         CHECK_NOTINIT(initialized,word);
     637        1310 :         init();
     638             :         break;
     639        1065 :       case cmd_setRealPrecision:
     640        1065 :         CHECK_NOTINIT(initialized,word);
     641        1065 :         CHECK_NOTNULL(val,word);
     642        2129 :         passtools=DataPassingTools::create(val.get<int>());
     643        1064 :         passtools->usingNaturalUnits=false;
     644        1064 :         break;
     645         977 :       case cmd_setMDLengthUnits:
     646         977 :         CHECK_NOTINIT(initialized,word);
     647         977 :         CHECK_NOTNULL(val,word);
     648         977 :         passtools->MDUnits.setLength(passtools->MD2double(val));
     649             :         break;
     650         977 :       case cmd_setMDChargeUnits:
     651         977 :         CHECK_NOTINIT(initialized,word);
     652         977 :         CHECK_NOTNULL(val,word);
     653         977 :         passtools->MDUnits.setCharge(passtools->MD2double(val));
     654             :         break;
     655         977 :       case cmd_setMDMassUnits:
     656         977 :         CHECK_NOTINIT(initialized,word);
     657         977 :         CHECK_NOTNULL(val,word);
     658         977 :         passtools->MDUnits.setMass(passtools->MD2double(val));
     659             :         break;
     660          45 :       case cmd_setMDEnergyUnits:
     661          45 :         CHECK_NOTINIT(initialized,word);
     662          45 :         CHECK_NOTNULL(val,word);
     663          45 :         passtools->MDUnits.setEnergy(passtools->MD2double(val));
     664             :         break;
     665           6 :       case cmd_setMDTimeUnits:
     666           6 :         CHECK_NOTINIT(initialized,word);
     667           6 :         CHECK_NOTNULL(val,word);
     668           6 :         passtools->MDUnits.setTime(passtools->MD2double(val));
     669             :         break;
     670           0 :       case cmd_setNaturalUnits:
     671             :         // set the boltzman constant for MD in natural units (kb=1)
     672             :         // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...)
     673             :         // use as cmd("setNaturalUnits")
     674           0 :         CHECK_NOTINIT(initialized,word);
     675           0 :         passtools->usingNaturalUnits=true;
     676           0 :         break;
     677          62 :       case cmd_setNoVirial: {
     678          62 :         CHECK_NOTINIT(initialized,word);
     679          62 :         ActionToPutData* ap=actionSet.selectWithLabel<ActionToPutData*>("Box");
     680          62 :         if( ap ) {
     681          52 :           ap->noforce=true;
     682             :         } else {
     683          10 :           ActionForInterface* af = actionSet.selectWithLabel<ActionForInterface*>(MDEngine);
     684          10 :           if( af ) {
     685           0 :             plumed_merror("setNoVirial should be called after number of atoms have been set");
     686             :           }
     687             :         }
     688             :       }
     689             :       break;
     690        1027 :       case cmd_setPlumedDat:
     691        1027 :         CHECK_NOTINIT(initialized,word);
     692        1027 :         CHECK_NOTNULL(val,word);
     693        1027 :         plumedDat=val.getCString();
     694             :         break;
     695         362 :       case cmd_setMPIComm:
     696         362 :         CHECK_NOTINIT(initialized,word);
     697         362 :         comm.Set_comm(val);
     698         364 :         for(const auto & pp : inputs ) {
     699           2 :           pp->Set_comm(comm);
     700             :         }
     701             :         break;
     702           0 :       case cmd_setMPIFComm:
     703           0 :         CHECK_NOTINIT(initialized,word);
     704           0 :         comm.Set_fcomm(val);
     705           0 :         for(const auto & pp : inputs ) {
     706           0 :           pp->Set_comm(comm);
     707             :         }
     708             :         break;
     709           0 :       case cmd_setMPImultiSimComm:
     710           0 :         CHECK_NOTINIT(initialized,word);
     711           0 :         multi_sim_comm.Set_comm(val);
     712             :         break;
     713        1294 :       case cmd_setNatoms: {
     714        1294 :         CHECK_NOTINIT(initialized,word);
     715        1294 :         CHECK_NOTNULL(val,word);
     716        1294 :         int natoms = val.get<int>();
     717             :         std::string str_natoms;
     718        1284 :         Tools::convert( natoms, str_natoms );
     719        1284 :         ActionForInterface* dd=actionSet.selectWithLabel<ActionForInterface*>(MDEngine);
     720        1284 :         if( !dd && natoms>0 )
     721        3645 :           readInputLine( MDEngine + ": DOMAIN_DECOMPOSITION NATOMS=" + str_natoms +  +
     722        2430 :                          " VALUE1=posx UNIT1=length PERIODIC1=NO CONSTANT1=False ROLE1=x" +
     723        2430 :                          " VALUE2=posy UNIT2=length PERIODIC2=NO CONSTANT2=False ROLE2=y" +
     724        2430 :                          " VALUE3=posz UNIT3=length PERIODIC3=NO CONSTANT3=False ROLE3=z" +
     725        2430 :                          " VALUE4=Masses UNIT4=mass PERIODIC4=NO CONSTANT4=True ROLE4=m" +
     726        2430 :                          " VALUE5=Charges UNIT5=charge PERIODIC5=NO CONSTANT5=True ROLE5=q", true );
     727             :       }
     728        1284 :       break;
     729        1045 :       case cmd_setTimestep: {
     730        1045 :         CHECK_NOTINIT(initialized,word);
     731        1045 :         CHECK_NOTNULL(val,word);
     732        1045 :         ActionToPutData* ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
     733        1045 :         if( !ts ) {
     734        1043 :           readInputLine("timestep: PUT UNIT=time PERIODIC=NO CONSTANT", true);
     735        2086 :           ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
     736             :         }
     737        2090 :         if( !ts->setValuePointer("timestep", val ) ) {
     738           0 :           plumed_error();
     739             :         }
     740             :         // The following is to avoid extra digits in case the MD code uses floats
     741             :         // e.g.: float f=0.002 when converted to double becomes 0.002000000094995
     742             :         // To avoid this, we keep only up to 6 significant digits after first one
     743        1045 :         if( getRealPrecision()<=4 ) {
     744         166 :           Value* tstepv = ts->copyOutput(0);
     745           0 :           double magnitude=std::pow(10,std::floor(std::log10(tstepv->get())));
     746           0 :           tstepv->set( std::round(tstepv->get()/magnitude*1e6)/1e6*magnitude );
     747             :         }
     748        1045 :         ts->updateUnits( passtools.get() );
     749             :       }
     750             :       break;
     751             :       /* ADDED WITH API==2 */
     752          61 :       case cmd_setKbT: {
     753          61 :         CHECK_NOTINIT(initialized,word);
     754          61 :         CHECK_NOTNULL(val,word);
     755          61 :         readInputLine("kBT: PUT CONSTANT PERIODIC=NO UNIT=energy", true);
     756          61 :         ActionToPutData* kb = actionSet.selectWithLabel<ActionToPutData*>("kBT");
     757         122 :         if( !kb->setValuePointer("kBT", val ) ) {
     758           0 :           plumed_error();
     759             :         }
     760          61 :         kb->updateUnits( passtools.get() );
     761             :       }
     762             :       break;
     763             :       /* ADDED WITH API==3 */
     764           8 :       case cmd_setRestart:
     765           8 :         CHECK_NOTINIT(initialized,word);
     766           8 :         CHECK_NOTNULL(val,word);
     767           8 :         if(val.get<int>()!=0) {
     768           2 :           restart=true;
     769             :         }
     770             :         break;
     771             :       /* ADDED WITH API==4 */
     772           0 :       case cmd_doCheckPoint:
     773           0 :         CHECK_INIT(initialized,word);
     774           0 :         CHECK_NOTNULL(val,word);
     775           0 :         doCheckPoint = false;
     776           0 :         if(val.get<int>()!=0) {
     777           0 :           doCheckPoint = true;
     778             :         }
     779             :         break;
     780             :       /* ADDED WITH API==6 */
     781             :       case cmd_setNumOMPthreads:
     782           0 :         CHECK_NOTNULL(val,word);
     783             :         {
     784           0 :           auto nt=val.get<unsigned>();
     785             :           if(nt==0) {
     786             :             nt=1;
     787             :           }
     788           0 :           OpenMP::setNumThreads(nt);
     789             :         }
     790             :         break;
     791             :       /* ADDED WITH API==10 */
     792             :       case cmd_setGpuDeviceId:
     793           0 :         CHECK_NOTNULL(val,word);
     794             :         {
     795           0 :           auto id=val.get<int>();
     796           0 :           if(id>=0) {
     797           0 :             gpuDeviceId=id;
     798             :           }
     799             :         }
     800             :         break;
     801             :       /* ADDED WITH API==6 */
     802             :       /* only used for testing */
     803             :       case cmd_throw:
     804          61 :         CHECK_NOTNULL(val,word);
     805          61 :         testThrow(val.getCString());
     806             :       /* ADDED WITH API==10 */
     807             :       case cmd_setNestedExceptions:
     808          27 :         CHECK_NOTNULL(val,word);
     809          27 :         if(val.get<int>()!=0) {
     810          26 :           nestedExceptions=true;
     811             :         } else {
     812           1 :           nestedExceptions=false;
     813             :         }
     814             :         break;
     815             :       /* STOP API */
     816        1042 :       case cmd_setMDEngine:
     817        1042 :         CHECK_NOTINIT(initialized,word);
     818        1042 :         CHECK_NOTNULL(val,word);
     819        1042 :         MDEngine=val.getCString();
     820             :         break;
     821        1017 :       case cmd_setLog:
     822        1017 :         CHECK_NOTINIT(initialized,word);
     823        1017 :         log.link(val.get<FILE*>());
     824             :         break;
     825         169 :       case cmd_setLogFile:
     826         169 :         CHECK_NOTINIT(initialized,word);
     827         169 :         CHECK_NOTNULL(val,word);
     828         169 :         log.open(val.getCString());
     829         169 :         break;
     830             :       // other commands that should be used after initialization:
     831      268201 :       case cmd_setStopFlag:
     832      268201 :         CHECK_INIT(initialized,word);
     833      268201 :         CHECK_NOTNULL(val,word);
     834      268201 :         val.get<int*>(); // just check type and discard pointer
     835      268200 :         stopFlag=val.copy();
     836      268200 :         break;
     837           0 :       case cmd_getExchangesFlag:
     838           0 :         CHECK_INIT(initialized,word);
     839           0 :         CHECK_NOTNULL(val,word);
     840           0 :         exchangePatterns.getFlag(*val.get<int*>()); // note: getFlag changes the value of the reference!
     841             :         break;
     842           0 :       case cmd_setExchangesSeed:
     843           0 :         CHECK_INIT(initialized,word);
     844           0 :         CHECK_NOTNULL(val,word);
     845           0 :         exchangePatterns.setSeed(val.get<int>());
     846             :         break;
     847           0 :       case cmd_setNumberOfReplicas:
     848           0 :         CHECK_INIT(initialized,word);
     849           0 :         CHECK_NOTNULL(val,word);
     850           0 :         exchangePatterns.setNofR(val.get<int>());
     851             :         break;
     852           0 :       case cmd_getExchangesList:
     853           0 :         CHECK_INIT(initialized,word);
     854           0 :         CHECK_NOTNULL(val,word);
     855           0 :         exchangePatterns.getList(val);
     856             :         break;
     857         967 :       case cmd_runFinalJobs:
     858         967 :         CHECK_INIT(initialized,word);
     859         967 :         runJobsAtEndOfCalculation();
     860             :         break;
     861          96 :       case cmd_isEnergyNeeded: {
     862          96 :         CHECK_INIT(initialized,word);
     863          96 :         CHECK_NOTNULL(val,word);
     864          96 :         if( name_of_energy =="" ) {
     865          96 :           val.set(int(0));
     866             :         } else {
     867           0 :           ActionToPutData* ap=actionSet.selectWithLabel<ActionToPutData*>(name_of_energy);
     868           0 :           if(ap->isActive()) {
     869           0 :             val.set(int(1));
     870             :           } else {
     871           0 :             val.set(int(0));
     872             :           }
     873             :         }
     874             :       }
     875             :       break;
     876        7051 :       case cmd_getBias:
     877        7051 :         CHECK_INIT(initialized,word);
     878        7051 :         CHECK_NOTNULL(val,word);
     879        7051 :         plumedQuantityToMD( "energy", getBias(), val );
     880        7051 :         break;
     881             :       case cmd_checkAction:
     882           2 :         CHECK_NOTNULL(val,word);
     883           2 :         plumed_assert(nw==2);
     884           3 :         val.set(int(actionRegister().check(dlloader.getHandles(), std::string(words[1])) ? 1:0));
     885           2 :         break;
     886             :       case cmd_setExtraCV: {
     887          30 :         CHECK_NOTNULL(val,word);
     888          30 :         plumed_assert(nw==2);
     889          60 :         if( valueExists(std::string(words[1])) ) {
     890          60 :           setInputValue( std::string(words[1]), 0, 1, val );
     891             :         }
     892             :       }
     893             :       break;
     894             :       case cmd_setExtraCVForce: {
     895          30 :         CHECK_NOTNULL(val,word);
     896          30 :         plumed_assert(nw==2);
     897          60 :         if( valueExists(std::string(words[1])) ) {
     898          60 :           setInputForce( std::string(words[1]), val );
     899             :         }
     900             :       }
     901             :       break;
     902             :       /* ADDED WITH API==10 */
     903             :       case cmd_isExtraCVNeeded:
     904          10 :         CHECK_NOTNULL(val,word);
     905          10 :         plumed_assert(nw==2);
     906          10 :         val.set(int(0));
     907          56 :         for(const auto & p : inputs) {
     908          50 :           if( p->getLabel()==words[1] && p->isActive() ) {
     909           4 :             val.set(int(1));
     910             :             break;
     911             :           }
     912             :         }
     913             :         break;
     914        1089 :       case cmd_GREX:
     915        1089 :         if(!grex) {
     916         208 :           grex=Tools::make_unique<GREX>(*this);
     917             :         }
     918        1089 :         plumed_massert(grex,"error allocating grex");
     919             :         {
     920        1089 :           std::string kk=std::string(words[1]);
     921        1260 :           for(unsigned i=2; i<words.size(); i++) {
     922         342 :             kk+=" "+std::string(words[i]);
     923             :           }
     924        1089 :           grex->cmd(kk.c_str(),val);
     925             :         }
     926        1089 :         break;
     927       16686 :       case cmd_CLTool:
     928       16686 :         CHECK_NOTINIT(initialized,word);
     929       16686 :         if(!cltool) {
     930        5464 :           cltool=Tools::make_unique<CLToolMain>();
     931             :         }
     932             :         {
     933       16686 :           std::string kk(words[1]);
     934       16686 :           for(unsigned i=2; i<words.size(); i++) {
     935           0 :             kk+=" "+std::string(words[i]);
     936             :           }
     937       16686 :           cltool->cmd(kk.c_str(),val);
     938             :         }
     939       16686 :         break;
     940             :         break;
     941             :       /* ADDED WITH API==7 */
     942             :       case cmd_convert: {
     943             :         double v;
     944          57 :         plumed_assert(words.size()==2);
     945         280 :         if(Tools::convertNoexcept(std::string(words[1]),v)) {
     946          47 :           passtools->double2MD(v,val);
     947             :         }
     948             :       }
     949          57 :       break;
     950           7 :       default:
     951          14 :         plumed_error() << "cannot interpret cmd(\"" << word << "\"). check plumed developers manual to see the available commands.";
     952             :         break;
     953             :       }
     954             :     }
     955             : 
     956     1350800 :   } catch (...) {
     957         166 :     if(log.isOpen()) {
     958             :       try {
     959          92 :         log<<"\n################################################################################\n";
     960          92 :         log<<Tools::concatenateExceptionMessages();
     961          92 :         log<<"\n################################################################################\n";
     962          92 :         log.flush();
     963           0 :       } catch(...) {
     964             :         // ignore errors here.
     965             :         // in any case, we are rethrowing this below
     966           0 :       }
     967             :     }
     968         166 :     throw;
     969         166 :   }
     970     1350468 : }
     971             : 
     972             : ////////////////////////////////////////////////////////////////////////
     973             : 
     974        1310 : void PlumedMain::init() {
     975             : // check that initialization just happens once
     976        1310 :   initialized=true;
     977        1310 :   if(!log.isOpen()) {
     978         124 :     log.link(stdout);
     979             :   }
     980        1310 :   log<<"PLUMED is starting\n";
     981        3930 :   log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") "
     982        5240 :      <<"compiled on " <<config::getCompilationDate() << " at " << config::getCompilationTime() << "\n";
     983        1310 :   log<<"Please cite these papers when using PLUMED ";
     984        2620 :   log<<cite("The PLUMED consortium, Nat. Methods 16, 670 (2019)");
     985        2620 :   log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
     986        1310 :   log<<"\n";
     987        1310 :   log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
     988        1310 :   log<<"Root: "<<config::getPlumedRoot()<<"\n";
     989        1310 :   log<<"LibraryPath: "<<config::getLibraryPath()<<"\n";
     990        2620 :   log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
     991        1310 :   log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
     992        1310 :   log.printf("Precision of reals: %d\n",passtools->getRealPrecision());
     993        2374 :   log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
     994        1310 :   log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
     995        1310 :   log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
     996        4862 :   for(const auto & pp : inputs ) {
     997        3552 :     plumed_assert(pp);
     998        3552 :     DomainDecomposition* dd=pp->castToDomainDecomposition();
     999        3552 :     if ( dd ) {
    1000        1214 :       log.printf("Number of atoms: %d\n",dd->getNumberOfAtoms());
    1001             :     }
    1002             :   }
    1003        1310 :   if(grex) {
    1004         208 :     log.printf("GROMACS-like replica exchange is on\n");
    1005             :   }
    1006        1310 :   log.printf("File suffix: %s\n",getSuffix().c_str());
    1007        1310 :   if(plumedDat.length()>0) {
    1008        1027 :     readInputFile(plumedDat);
    1009             :     plumedDat="";
    1010             :   }
    1011        1310 :   setUnits( passtools->usingNaturalUnits, passtools->units );
    1012        1310 :   ActionToPutData* ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
    1013        1310 :   if(ts) {
    1014        1043 :     log.printf("Timestep: %f\n",(ts->copyOutput(0))->get());
    1015             :   }
    1016        1310 :   ActionToPutData* kb = actionSet.selectWithLabel<ActionToPutData*>("kBT");
    1017        1310 :   if(kb) {
    1018          61 :     log.printf("KbT: %f\n",(kb->copyOutput(0))->get());
    1019             :   } else {
    1020        1249 :     log.printf("KbT has not been set by the MD engine\n");
    1021        1249 :     log.printf("It should be set by hand where needed\n");
    1022             :   }
    1023        1310 :   log<<"Relevant bibliography:\n";
    1024        1310 :   log<<citations;
    1025        1310 :   log<<"Please read and cite where appropriate!\n";
    1026        1310 :   log<<"Finished setup\n";
    1027        1310 : }
    1028             : 
    1029       51979 : void PlumedMain::setupInterfaceActions() {
    1030       51979 :   inputs.clear();
    1031       51979 :   std::vector<ActionForInterface*> ap=actionSet.select<ActionForInterface*>();
    1032      420645 :   for(unsigned i=0; i<ap.size(); ++i) {
    1033      368666 :     if( ap[i]->getName()=="ENERGY" || ap[i]->getDependencies().size()==0 ) {
    1034      140901 :       inputs.push_back( ap[i] );
    1035             :     }
    1036             :   }
    1037       51979 : }
    1038             : 
    1039        1050 : void PlumedMain::readInputFile(const std::string & str) {
    1040        1050 :   plumed_assert(initialized);
    1041        1050 :   log<<"FILE: "<<str<<"\n";
    1042        1050 :   IFile ifile;
    1043        1050 :   ifile.link(*this);
    1044        1050 :   ifile.open(str);
    1045        1050 :   ifile.allowNoEOL();
    1046        1050 :   readInputFile(ifile);
    1047        1050 :   log<<"END FILE: "<<str<<"\n";
    1048        1050 :   log.flush();
    1049             : 
    1050        1050 : }
    1051             : 
    1052        1052 : void PlumedMain::readInputFile(IFile & ifile) {
    1053             :   std::vector<std::string> words;
    1054       19689 :   while(Tools::getParsedLine(ifile,words) && !endPlumed) {
    1055       18637 :     readInputWords(words,false);
    1056             :   }
    1057        1052 :   endPlumed=false;
    1058        1052 :   pilots=actionSet.select<ActionPilot*>();
    1059        1052 :   setupInterfaceActions();
    1060        1052 : }
    1061             : 
    1062       10618 : void PlumedMain::readInputLine(const std::string & str, const bool& before_init) {
    1063       10618 :   if( !before_init ) {
    1064         988 :     plumed_assert(initialized);
    1065             :   }
    1066       10618 :   if(str.empty()) {
    1067           0 :     return;
    1068             :   }
    1069       10618 :   std::vector<std::string> words=Tools::getWords(str);
    1070       10618 :   if( before_init ) {
    1071        9630 :     plumed_assert( citations.empty() );
    1072             :   }
    1073       10618 :   citations.clear();
    1074       10618 :   readInputWords(words,before_init);
    1075       10578 :   if(!citations.empty()) {
    1076           3 :     log<<"Relevant bibliography:\n";
    1077           3 :     log<<citations;
    1078           3 :     log<<"Please read and cite where appropriate!\n";
    1079             :   }
    1080       10618 : }
    1081             : 
    1082           2 : void PlumedMain::readInputLines(const std::string & str) {
    1083           2 :   plumed_assert(initialized);
    1084           2 :   if(str.empty()) {
    1085           0 :     return;
    1086             :   }
    1087             : 
    1088           2 :   log<<"FILE: (temporary)\n";
    1089             : 
    1090             :   // Open a temporary file
    1091           2 :   auto fp=std::tmpfile();
    1092           2 :   plumed_assert(fp);
    1093             : 
    1094             :   // make sure file is closed (and thus deleted) also if an exception occurs
    1095             :   auto deleter=[](auto fp) {
    1096           2 :     std::fclose(fp);
    1097             :   };
    1098             :   std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
    1099             : 
    1100           2 :   auto ret=std::fputs(str.c_str(),fp);
    1101           2 :   plumed_assert(ret!=EOF);
    1102             : 
    1103           2 :   std::rewind(fp);
    1104             : 
    1105           2 :   IFile ifile;
    1106           2 :   ifile.link(*this);
    1107           2 :   ifile.link(fp);
    1108           2 :   ifile.allowNoEOL();
    1109             : 
    1110           2 :   readInputFile(ifile);
    1111           2 :   log<<"END FILE: (temporary)\n";
    1112           2 : }
    1113             : 
    1114       51154 : void PlumedMain::readInputWords(const std::vector<std::string> & words, const bool& before_init) {
    1115       51154 :   if( !before_init ) {
    1116       41524 :     plumed_assert(initialized);
    1117             :   }
    1118       51154 :   if(words.empty()) {
    1119             :     return;
    1120       50982 :   } else if(words[0]=="_SET_SUFFIX") {
    1121           3 :     plumed_assert(words.size()==2);
    1122             :     setSuffix(words[1]);
    1123             :   } else {
    1124       50979 :     std::vector<std::string> interpreted(words);
    1125       50979 :     Tools::interpretLabel(interpreted);
    1126      101903 :     auto action=actionRegister().create(dlloader.getHandles(),ActionOptions(*this,interpreted));
    1127       50924 :     if(!action) {
    1128             :       std::string msg;
    1129             :       msg ="ERROR\nI cannot understand line:";
    1130           0 :       for(unsigned i=0; i<interpreted.size(); ++i) {
    1131           0 :         msg+=" "+interpreted[i];
    1132             :       }
    1133             :       msg+="\nMaybe a missing space or a typo?";
    1134           0 :       log << msg;
    1135           0 :       log.flush();
    1136           0 :       plumed_merror(msg);
    1137             :     }
    1138       50924 :     action->checkRead();
    1139       50924 :     actionSet.emplace_back(std::move(action));
    1140       50979 :   };
    1141             : 
    1142       50927 :   pilots=actionSet.select<ActionPilot*>();
    1143       50927 :   setupInterfaceActions();
    1144             : }
    1145             : 
    1146             : ////////////////////////////////////////////////////////////////////////
    1147             : 
    1148           0 : void PlumedMain::exit(int c) {
    1149           0 :   comm.Abort(c);
    1150           0 : }
    1151             : 
    1152       50977 : Log& PlumedMain::getLog() {
    1153       50977 :   return log;
    1154             : }
    1155             : 
    1156      280115 : void PlumedMain::calc() {
    1157      280115 :   prepareCalc();
    1158      280099 :   performCalc();
    1159      280097 : }
    1160             : 
    1161      287066 : void PlumedMain::prepareCalc() {
    1162      287066 :   prepareDependencies();
    1163      287066 :   shareData();
    1164      287050 : }
    1165             : 
    1166             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    1167             : // here we have the main steps in "calc()"
    1168             : // they can be called individually, but the standard thing is to
    1169             : // traverse them in this order:
    1170      287393 : void PlumedMain::prepareDependencies() {
    1171             : 
    1172             : // Stopwatch is stopped when sw goes out of scope
    1173      287393 :   auto sw=stopwatch.startStop("1 Prepare dependencies");
    1174             : 
    1175             : // activate all the actions which are on step
    1176             : // activation is recursive and enables also the dependencies
    1177             : // before doing that, the prepare() method is called to see if there is some
    1178             : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
    1179             : // which can be dynamically changed).
    1180             : 
    1181             : // First switch off all actions
    1182     4674443 :   for(const auto & p : actionSet) {
    1183     4387050 :     p->deactivate();
    1184             :   }
    1185             : 
    1186             : // for optimization, an "active" flag remains false if no action at all is active
    1187      287393 :   active=false;
    1188     1730927 :   for(unsigned i=0; i<pilots.size(); ++i) {
    1189     1443534 :     if(pilots[i]->onStep()) {
    1190     1350283 :       pilots[i]->activate();
    1191     1350283 :       active=true;
    1192             :     }
    1193             :   };
    1194             : 
    1195             : // This stops the driver calculation if there is not a read action
    1196      287393 :   if( !active && !inputsAreActive() ) {
    1197           2 :     stopFlag.set(int(1));
    1198             :   }
    1199             : 
    1200             : // also, if one of them is the total energy, tell to atoms that energy should be collected
    1201     4674443 :   for(const auto & p : actionSet) {
    1202     4387050 :     if(p->isActive()) {
    1203     2648452 :       if(p->checkNeedsGradients()) {
    1204         172 :         p->setOption("GRADIENTS");
    1205             :       }
    1206             :     }
    1207             :   }
    1208             : 
    1209      287393 : }
    1210             : 
    1211        1763 : bool PlumedMain::inputsAreActive() const {
    1212        5178 :   for(const auto & ip : inputs) {
    1213        5122 :     if( ip->onStep() ) {
    1214             :       return true;
    1215             :     }
    1216             :   }
    1217             :   return false;
    1218             : }
    1219             : 
    1220         114 : void PlumedMain::shareAll() {
    1221         456 :   for(const auto & ip : inputs) {
    1222         342 :     ip->shareAll();
    1223             :   }
    1224         114 : }
    1225             : 
    1226      287150 : void PlumedMain::shareData() {
    1227             : // atom positions are shared (but only if there is something to do)
    1228      287150 :   if(!active) {
    1229        1703 :     return;
    1230             :   }
    1231             : // Stopwatch is stopped when sw goes out of scope
    1232      285447 :   auto sw=stopwatch.startStop("2 Sharing data");
    1233      752210 :   for(const auto & ip : inputs) {
    1234      466779 :     ip->share();
    1235             :   }
    1236      285447 : }
    1237             : 
    1238        7011 : void PlumedMain::performCalcNoUpdate() {
    1239        7011 :   waitData();
    1240        7011 :   justCalculate();
    1241        7011 :   backwardPropagate();
    1242        7011 :   resetInputs();
    1243        7011 : }
    1244             : 
    1245          10 : void PlumedMain::performCalcNoForces() {
    1246          10 :   waitData();
    1247          10 :   justCalculate();
    1248          10 : }
    1249             : 
    1250      280109 : void PlumedMain::performCalc() {
    1251      280109 :   waitData();
    1252      280109 :   justCalculate();
    1253      280109 :   backwardPropagate();
    1254      280107 :   update();
    1255      280107 :   resetInputs();
    1256      280107 : }
    1257             : 
    1258      287244 : void PlumedMain::waitData() {
    1259      287244 :   if(!active) {
    1260        1703 :     return;
    1261             :   }
    1262             : // Stopwatch is stopped when sw goes out of scope
    1263      285541 :   auto sw=stopwatch.startStop("3 Waiting for data");
    1264      752622 :   for(const auto & ip : inputs) {
    1265      467081 :     if( ip->isActive() && ip->hasBeenSet() ) {
    1266      168631 :       ip->wait();
    1267      298450 :     } else if( ip->isActive() ) {
    1268        8084 :       ip->warning("input requested but this quantity has not been set");
    1269             :     }
    1270             :   }
    1271      285541 : }
    1272             : 
    1273      287244 : void PlumedMain::justCalculate() {
    1274      287244 :   if(!active) {
    1275        1703 :     return;
    1276             :   }
    1277             : // Stopwatch is stopped when sw goes out of scope
    1278      285541 :   auto sw=stopwatch.startStop("4 Calculating (forward loop)");
    1279      285541 :   bias=0.0;
    1280      285541 :   work=0.0;
    1281             : 
    1282             :   // Check the input actions to determine if we need to calculate constants that
    1283             :   // depend on masses and charges
    1284             :   bool firststep=false;
    1285      752622 :   for(const auto & ip : inputs) {
    1286      467081 :     if( ip->firststep ) {
    1287             :       firststep=true;
    1288             :     }
    1289             :   }
    1290      285541 :   if( firststep ) {
    1291        4548 :     for(const auto & ip : inputs) {
    1292        3370 :       ip->firststep=false;
    1293             :     }
    1294             :   }
    1295             : 
    1296             :   int iaction=0;
    1297             : // calculate the active actions in order (assuming *backward* dependence)
    1298     4641593 :   for(const auto & pp : actionSet) {
    1299             :     Action* p(pp.get());
    1300     4356052 :     plumed_assert(p);
    1301             :     try {
    1302     4356052 :       if(p->isActive()) {
    1303             : // Stopwatch is stopped when sw goes out of scope.
    1304             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1305     2646457 :         Stopwatch::Handler sw;
    1306     2646457 :         if(detailedTimers) {
    1307        2481 :           auto actionNumberLabel=std::to_string(iaction);
    1308        2481 :           const unsigned m=actionSet.size();
    1309             :           unsigned k=0;
    1310             :           unsigned n=1;
    1311        7443 :           while(n<m) {
    1312        4962 :             n*=10;
    1313        4962 :             k++;
    1314             :           }
    1315        2481 :           auto spaces=std::string(k-actionNumberLabel.length(),' ');
    1316        2481 :           sw=stopwatch.startStop("4A " + spaces + actionNumberLabel+" "+p->getLabel());
    1317             :         }
    1318     2646457 :         ActionWithValue*av=p->castToActionWithValue();
    1319     2646457 :         ActionAtomistic*aa=p->castToActionAtomistic();
    1320             :         {
    1321     2646457 :           if(av) {
    1322     2362757 :             av->clearInputForces();
    1323             :           }
    1324     2646457 :           if(av) {
    1325     2362757 :             av->clearDerivatives();
    1326             :           }
    1327     2646457 :           if( av && av->calculateOnUpdate() ) {
    1328             :             continue ;
    1329             :           }
    1330             :         }
    1331             :         {
    1332     2642442 :           if(aa)
    1333      483323 :             if(aa->isActive()) {
    1334      483323 :               aa->retrieveAtoms();
    1335             :             }
    1336             :         }
    1337     2642442 :         if(p->checkNumericalDerivatives()) {
    1338         251 :           p->calculateNumericalDerivatives();
    1339             :         } else {
    1340     2642191 :           p->calculate();
    1341             :         }
    1342             :         // This retrieves components called bias
    1343     2642442 :         if(av) {
    1344     2358742 :           bias+=av->getOutputQuantity("bias");
    1345     2358742 :           work+=av->getOutputQuantity("work");
    1346     2358742 :           av->setGradientsIfNeeded();
    1347             :         }
    1348             :         // This makes all values that depend on the (fixed) masses and charges constant
    1349     2642442 :         if( firststep ) {
    1350       28251 :           p->setupConstantValues( true );
    1351             :         }
    1352     2642442 :         ActionWithVirtualAtom*avv=p->castToActionWithVirtualAtom();
    1353     2642442 :         if(avv) {
    1354       35094 :           avv->setGradientsIfNeeded();
    1355             :         }
    1356     2646457 :       }
    1357           0 :     } catch(...) {
    1358           0 :       plumed_error_nested() << "An error happened while calculating " << p->getLabel();
    1359           0 :     }
    1360     4352037 :     iaction++;
    1361             :   }
    1362      285541 : }
    1363             : 
    1364           0 : void PlumedMain::justApply() {
    1365           0 :   backwardPropagate();
    1366           0 :   update();
    1367           0 :   resetInputs();
    1368           0 : }
    1369             : 
    1370      287120 : void PlumedMain::backwardPropagate() {
    1371      287120 :   if(!active) {
    1372        1703 :     return;
    1373             :   }
    1374             :   int iaction=0;
    1375             : // Stopwatch is stopped when sw goes out of scope
    1376      285417 :   auto sw=stopwatch.startStop("5 Applying (backward loop)");
    1377             : // apply them in reverse order
    1378     4639127 :   for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
    1379             :     const auto & p(pp->get());
    1380     4353712 :     if(p->isActive()) {
    1381             : 
    1382             : // Stopwatch is stopped when sw goes out of scope.
    1383             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1384     2644781 :       Stopwatch::Handler sw;
    1385     2644781 :       if(detailedTimers) {
    1386        2481 :         auto actionNumberLabel=std::to_string(iaction);
    1387        2481 :         const unsigned m=actionSet.size();
    1388             :         unsigned k=0;
    1389             :         unsigned n=1;
    1390        7443 :         while(n<m) {
    1391        4962 :           n*=10;
    1392        4962 :           k++;
    1393             :         }
    1394        2481 :         auto spaces=std::string(k-actionNumberLabel.length(),' ');
    1395        2481 :         sw=stopwatch.startStop("5A " + spaces + actionNumberLabel+" "+p->getLabel());
    1396             :       }
    1397             : 
    1398     2644781 :       p->apply();
    1399     2644781 :     }
    1400     4353710 :     iaction++;
    1401             :   }
    1402             : 
    1403             : // Stopwatch is stopped when sw goes out of scope.
    1404             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1405      285415 :   Stopwatch::Handler sw1;
    1406      285415 :   if(detailedTimers) {
    1407         113 :     sw1=stopwatch.startStop("5B Update forces");
    1408             :   }
    1409      285417 : }
    1410             : 
    1411      280186 : void PlumedMain::update() {
    1412      280186 :   if(!active) {
    1413        1703 :     return;
    1414             :   }
    1415             : 
    1416             : // Stopwatch is stopped when sw goes out of scope
    1417      278483 :   auto sw=stopwatch.startStop("6 Update");
    1418             : 
    1419             : // update step (for statistics, etc)
    1420      278483 :   updateFlags.push(true);
    1421     4414908 :   for(const auto & p : actionSet) {
    1422     4136425 :     p->beforeUpdate();
    1423     6686197 :     if(p->isActive() && p->checkUpdate() && updateFlagsTop()) {
    1424     2549752 :       ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
    1425     2549752 :       if( av && av->calculateOnUpdate() ) {
    1426        4015 :         p->prepare();
    1427        4015 :         p->calculate();
    1428             :       } else {
    1429     2545737 :         p->update();
    1430             :       }
    1431             :     }
    1432             :   }
    1433      556970 :   while(!updateFlags.empty()) {
    1434             :     updateFlags.pop();
    1435             :   }
    1436             :   if(!updateFlags.empty()) {
    1437             :     plumed_merror("non matching changes in the update flags");
    1438             :   }
    1439             : // Check that no action has told the calculation to stop
    1440      278483 :   if(stopNow) {
    1441          65 :     if(stopFlag) {
    1442          65 :       stopFlag.set(int(1));
    1443             :     } else {
    1444           0 :       plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
    1445             :     }
    1446             :   }
    1447             : 
    1448             : // flush by default every 10000 steps
    1449             : // hopefully will not affect performance
    1450             : // also if receive checkpointing signal
    1451      278483 :   if(step%10000==0||doCheckPoint) {
    1452        1225 :     fflush();
    1453        1225 :     log.flush();
    1454       53126 :     for(const auto & p : actionSet) {
    1455       51901 :       p->fflush();
    1456             :     }
    1457             :   }
    1458      278483 : }
    1459             : 
    1460          42 : void PlumedMain::load(const std::string& fileName) {
    1461          42 :   if(DLLoader::installed()) {
    1462          42 :     std::string libName=fileName;
    1463          42 :     size_t n=libName.find_last_of(".");
    1464          43 :     std::string extension="";
    1465          42 :     std::string base=libName;
    1466          42 :     if(n!=std::string::npos && n<libName.length()-1) {
    1467          84 :       extension=libName.substr(n+1);
    1468             :     }
    1469          42 :     if(n!=std::string::npos && n<libName.length()) {
    1470          84 :       base=libName.substr(0,n);
    1471             :     }
    1472             : 
    1473          42 :     if(extension=="cpp") {
    1474          46 :       libName="./"+base+"."+config::getVersionLong()+"."+config::getSoExt();
    1475             : // full path command, including environment setup
    1476             : // this will work even if plumed is not in the execution path or if it has been
    1477             : // installed with a name different from "plumed"
    1478          46 :       std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh -n -o "+libName+" "+fileName;
    1479             : 
    1480          23 :       if(std::getenv("PLUMED_LOAD_ACTION_DEBUG")) {
    1481           0 :         log<<"Executing: "<<cmd;
    1482             :       } else {
    1483          23 :         log<<"Compiling: "<<fileName<<" to "<<libName;
    1484             :       }
    1485             : 
    1486          23 :       if(comm.Get_size()>0) {
    1487          23 :         log<<" (only on master node)";
    1488             :       }
    1489          23 :       log<<"\n";
    1490             : 
    1491             :       // On MPI process (intracomm), we use Get_rank to make sure a single process does the compilation
    1492             :       // Processes from multiple replicas might simultaneously do the compilation.
    1493          23 :       if(comm.Get_rank()==0) {
    1494          23 :         static Tools::CriticalSectionWithKey<std::string> section;
    1495             :         // This is only locking commands that are running with identical arguments.
    1496             :         // It is not necessary for correctness (a second mklib would just result in a no op since
    1497             :         // the library is already there, even if running simultaneously).
    1498             :         // It however decreases the system load if many threads are used.
    1499             :         auto s=section.startStop(cmd);
    1500          23 :         int ret=std::system(cmd.c_str());
    1501          23 :         if(ret!=0) {
    1502           2 :           plumed_error() <<"An error happened while executing command "<<cmd<<"\n";
    1503             :         }
    1504          23 :       }
    1505          22 :       comm.Barrier();
    1506             :     } else {
    1507          38 :       libName=base+"."+config::getSoExt();
    1508             :     }
    1509             : 
    1510             :     // If we have multiple threads (each holding a Plumed object), each of them
    1511             :     // will load the library, but each of them will only see actions registered
    1512             :     // from the owned library
    1513          41 :     auto *p=dlloader.load(libName);
    1514          42 :     log<<"Loading shared library "<<libName.c_str()<<" at "<<p<<"\n";
    1515          41 :     log<<"Here is the list of new actions\n";
    1516          41 :     log<<"\n";
    1517          82 :     for(const auto & a : actionRegister().getKeysWithDLHandle(p)) {
    1518          41 :       log<<a<<"\n";
    1519          41 :     }
    1520          41 :     log<<"\n";
    1521             :   } else {
    1522           0 :     plumed_error()<<"While loading library "<< fileName << " loading was not enabled, please check if dlopen was found at configure time";
    1523             :   }
    1524          41 : }
    1525             : 
    1526      287118 : void PlumedMain::resetInputs() {
    1527      758958 :   for(const auto & ip : inputs) {
    1528      471840 :     if( ip->isActive() && ip->hasBeenSet() ) {
    1529      168355 :       ip->reset();
    1530             :     }
    1531             :   }
    1532      287118 : }
    1533             : 
    1534        7684 : double PlumedMain::getBias() const {
    1535        7684 :   return bias;
    1536             : }
    1537             : 
    1538         450 : double PlumedMain::getWork() const {
    1539         450 :   return work;
    1540             : }
    1541             : 
    1542          82 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
    1543          82 :   std::string mmode(mode);
    1544          83 :   std::string ppath(path);
    1545          82 :   std::string suffix(getSuffix());
    1546          82 :   std::string ppathsuf=ppath+suffix;
    1547          82 :   FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
    1548          82 :   if(!fp) {
    1549           1 :     fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
    1550             :   }
    1551          84 :   plumed_massert(fp,"file " + ppath + " cannot be found");
    1552          81 :   return fp;
    1553             : }
    1554             : 
    1555          99 : int PlumedMain::fclose(FILE*fp) {
    1556          99 :   return std::fclose(fp);
    1557             : }
    1558             : 
    1559        4886 : std::string PlumedMain::cite(const std::string&item) {
    1560        4886 :   return citations.cite(item);
    1561             : }
    1562             : 
    1563        1786 : void PlumedMain::fflush() {
    1564        5382 :   for(const auto  & p : files) {
    1565        3596 :     p->flush();
    1566             :   }
    1567        1786 : }
    1568             : 
    1569        5199 : void PlumedMain::insertFile(FileBase&f) {
    1570        5199 :   files.insert(&f);
    1571        5199 : }
    1572             : 
    1573        5482 : void PlumedMain::eraseFile(FileBase&f) {
    1574        5482 :   files.erase(&f);
    1575        5482 : }
    1576             : 
    1577          65 : void PlumedMain::stop() {
    1578          65 :   stopNow=true;
    1579          65 : }
    1580             : 
    1581         967 : void PlumedMain::runJobsAtEndOfCalculation() {
    1582       47461 :   for(const auto & p : actionSet) {
    1583       46494 :     ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
    1584       46494 :     if( av && av->calculateOnUpdate() ) {
    1585         405 :       p->activate();
    1586             :     }
    1587             :   }
    1588       47461 :   for(const auto & p : actionSet) {
    1589       46494 :     ActionPilot* ap=dynamic_cast<ActionPilot*>(p.get());
    1590       46494 :     ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
    1591       46494 :     if( av && av->calculateOnUpdate() ) {
    1592         405 :       p->calculate();
    1593       46089 :     } else if( ap && !av && ap->getStride()==0 ) {
    1594          70 :       p->update();
    1595             :     } else {
    1596       46019 :       p->runFinalJobs();
    1597             :     }
    1598             :   }
    1599         967 : }
    1600             : 
    1601     8807491 : unsigned PlumedMain::increaseReferenceCounter() noexcept {
    1602     8807491 :   return ++referenceCounter;
    1603             : }
    1604             : 
    1605     8806391 : unsigned PlumedMain::decreaseReferenceCounter() noexcept {
    1606     8806391 :   return --referenceCounter;
    1607             : }
    1608             : 
    1609          42 : unsigned PlumedMain::useCountReferenceCounter() const noexcept {
    1610          42 :   return referenceCounter;
    1611             : }
    1612             : 
    1613          60 : bool PlumedMain::valueExists( const std::string& name ) const {
    1614         240 :   for(const auto & p : inputs) {
    1615         240 :     if( p->getLabel()==name ) {
    1616             :       return true;
    1617             :     }
    1618             :   }
    1619             :   return false;
    1620             : }
    1621             : 
    1622      463742 : void PlumedMain::setInputValue( const std::string& name, const unsigned& start, const unsigned& stride, const TypesafePtr & val ) {
    1623             :   bool found=false;
    1624     1257419 :   for(const auto & pp : inputs) {
    1625     1257419 :     if( pp->setValuePointer( name, val ) ) {
    1626      463738 :       pp->setStart(name, start);
    1627      463738 :       pp->setStride(name, stride);
    1628             :       found=true;
    1629             :       break;
    1630             :     }
    1631             :   }
    1632           0 :   plumed_massert( found, "found no action to set named " + name );
    1633      463738 : }
    1634             : 
    1635      291131 : void PlumedMain::setInputForce( const std::string& name, const TypesafePtr & val ) {
    1636             :   bool found=false;
    1637      782236 :   for(const auto & pp : inputs) {
    1638      782236 :     if( pp->setForcePointer( name, val ) ) {
    1639             :       found=true;
    1640             :       break;
    1641             :     }
    1642             :   }
    1643      291113 :   plumed_massert( found, "found no action to set named " + name );
    1644      291113 : }
    1645             : 
    1646        1347 : void PlumedMain::setUnits( const bool& natural, const Units& u ) {
    1647        1347 :   passtools->usingNaturalUnits = natural;
    1648        1347 :   passtools->units=u;
    1649        1347 :   std::vector<ActionToPutData*> idata = actionSet.select<ActionToPutData*>();
    1650       10041 :   for(const auto & ip : idata) {
    1651        8694 :     ip->updateUnits( passtools.get() );
    1652             :   }
    1653       50806 :   for(const auto & p : actionSet ) {
    1654       49459 :     p->resetStoredTimestep();
    1655             :   }
    1656        1347 : }
    1657             : 
    1658      287063 : void PlumedMain::startStep() {
    1659      758695 :   for(const auto & ip : inputs) {
    1660      471632 :     ip->resetForStepStart();
    1661             :   }
    1662      287063 : }
    1663             : 
    1664         114 : void PlumedMain::writeBinary(std::ostream&o)const {
    1665         456 :   for(const auto & ip : inputs) {
    1666         342 :     ip->writeBinary(o);
    1667             :   }
    1668         114 : }
    1669             : 
    1670         114 : void PlumedMain::readBinary(std::istream&i) {
    1671         456 :   for(const auto & ip : inputs) {
    1672         342 :     ip->readBinary(i);
    1673             :   }
    1674         114 : }
    1675             : 
    1676          40 : void PlumedMain::setEnergyValue( const std::string& name ) {
    1677          40 :   name_of_energy = name;
    1678          40 : }
    1679             : 
    1680        9625 : int PlumedMain::getRealPrecision() const {
    1681        9625 :   return passtools->getRealPrecision();
    1682             : }
    1683             : 
    1684        5091 : bool PlumedMain::usingNaturalUnits() const {
    1685        5091 :   return passtools->usingNaturalUnits;
    1686             : }
    1687             : 
    1688    16252429 : const Units& PlumedMain::getUnits() {
    1689    16252429 :   return passtools->units;
    1690             : }
    1691             : 
    1692           4 : PlumedMain::DeprecatedAtoms& PlumedMain::getAtoms() {
    1693           4 :   return datoms;
    1694             : }
    1695             : 
    1696        7222 : void PlumedMain::plumedQuantityToMD( const std::string& unit, const double& eng, const TypesafePtr & m) const {
    1697        7222 :   passtools->double2MD( eng/passtools->getUnitConversion(unit),m );
    1698        7222 : }
    1699             : 
    1700           0 : double PlumedMain::MDQuantityToPLUMED( const std::string& unit, const TypesafePtr & m) const {
    1701           0 :   double x=passtools->MD2double(m);
    1702           0 :   return x*passtools->getUnitConversion(unit);
    1703             : }
    1704             : 
    1705           1 : double PlumedMain::DeprecatedAtoms::getKBoltzmann() const {
    1706           1 :   if( plumed.usingNaturalUnits() ) {
    1707             :     return 1.0;
    1708             :   }
    1709           1 :   return kBoltzmann/plumed.getUnits().getEnergy();
    1710             : }
    1711             : 
    1712           1 : double PlumedMain::DeprecatedAtoms::getKbT() const {
    1713           1 :   ActionForInterface* kb=plumed.getActionSet().selectWithLabel<ActionForInterface*>("kBT");
    1714           1 :   if( kb ) {
    1715           1 :     return (kb->copyOutput(0))->get();
    1716             :   }
    1717             :   return 0.0;
    1718             : }
    1719             : 
    1720           1 : int PlumedMain::DeprecatedAtoms::getNatoms() const {
    1721           1 :   std::vector<ActionToPutData*> inputs=plumed.getActionSet().select<ActionToPutData*>();
    1722           1 :   for(const auto & pp : inputs ) {
    1723           2 :     if( pp->getRole()=="x" ) {
    1724           1 :       return (pp->copyOutput(0))->getShape()[0];
    1725             :     }
    1726             :   }
    1727             :   return 0;
    1728             : }
    1729             : 
    1730           1 : bool PlumedMain::DeprecatedAtoms::usingNaturalUnits() const {
    1731           1 :   return plumed.usingNaturalUnits();
    1732             : }
    1733             : 
    1734           0 : void PlumedMain::DeprecatedAtoms::setCollectEnergy(bool b) const {
    1735           0 :   plumed.readInputWords( Tools::getWords(plumed.MDEngine + "_energy: ENERGY"), false );
    1736           0 :   plumed.setEnergyValue( plumed.MDEngine + "_energy" );
    1737           0 : }
    1738             : 
    1739           0 : double PlumedMain::DeprecatedAtoms::getEnergy() const {
    1740           0 :   ActionToPutData* av = plumed.getActionSet().selectWithLabel<ActionToPutData*>( plumed.MDEngine + "_energy" );
    1741           0 :   return (av->copyOutput(0))->get();
    1742             : }
    1743             : 
    1744           5 : void PlumedMain::activateParseOnlyMode() {
    1745           5 :   doParseOnly=true;
    1746           5 : }
    1747             : 
    1748        2246 : bool PlumedMain::parseOnlyMode() const {
    1749        2246 :   return doParseOnly;
    1750             : }
    1751             : 
    1752          96 : void PlumedMain::getKeywordsForAction( const std::string& action, Keywords& keys ) const {
    1753          96 :   actionRegister().getKeywords( dlloader.getHandles(), action, keys );
    1754          96 : }
    1755             : 
    1756             : #ifdef __PLUMED_HAS_PYTHON
    1757             : // This is here to stop cppcheck throwing an error
    1758             : #endif
    1759             : 
    1760             : #ifdef __PLUMED_HAS_DLADDR
    1761             : // This is here to stop cppcheck throwing an error
    1762             : #endif
    1763             : 
    1764             : }
    1765             : 
    1766             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.16