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

Generated by: LCOV version 1.16