LCOV - code coverage report
Current view: top level - core - PlumedMain.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 952 1066 89.3 %
Date: 2026-06-05 17:04:24 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        5866 :   CountInstances() noexcept {}
     253        5866 :   ~CountInstances() {
     254        5866 :     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        5866 :   }
     264     1614600 :   static CountInstances & instance() {
     265     1614600 :     static CountInstances counter;
     266     1614600 :     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      807300 :   static void increase() noexcept {
     275      807300 :     ++instance().counter;
     276      807300 :   }
     277             :   /// See increase()
     278      807300 :   static void decrease() noexcept {
     279      807300 :     --instance().counter;
     280      807300 :   }
     281             : };
     282             : 
     283             : }
     284             : 
     285             : 
     286      807300 : PlumedMain::PlumedMain():
     287      807300 :   datoms_fwd(*this),
     288             : // automatically write on log in destructor
     289      807300 :   stopwatch_fwd(log),
     290      807300 :   actionSet_fwd(*this),
     291      807300 :   passtools(DataPassingTools::create(sizeof(double))) {
     292      807300 :   passtools->usingNaturalUnits=false;
     293      807300 :   increaseReferenceCounter();
     294      807300 :   log.link(comm);
     295      807300 :   log.setLinePrefix("PLUMED: ");
     296             :   // this is at last so as to avoid inconsistencies if an exception is thrown
     297      807300 :   CountInstances::increase(); // noexcept
     298      807300 : }
     299             : 
     300             : // destructor needed to delete forward declarated objects
     301     1613598 : PlumedMain::~PlumedMain() {
     302      807300 :   CountInstances::decrease();
     303     4842798 : }
     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     1352223 : 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     1352223 :   };
     324             : 
     325             :   try {
     326             : 
     327     1352223 :     auto ss=stopwatch.startPause();
     328             : 
     329             :     gch::small_vector<std::string_view> words;
     330     1352223 :     Tools::getWordsSimple(words,word);
     331             : 
     332     1352223 :     unsigned nw=words.size();
     333     1352223 :     if(nw==0) {
     334             :       // do nothing
     335             :     } else {
     336             :       int iword=-1;
     337             :       const auto it=word_map.find(words[0]);
     338     1352222 :       if(it!=word_map.end()) {
     339     1352215 :         iword=it->second;
     340             :       }
     341             : 
     342     1352215 :       switch(iword) {
     343       70601 :       case cmd_setBox:
     344       70601 :         CHECK_INIT(initialized,word);
     345       70601 :         CHECK_NOTNULL(val,word);
     346       70601 :         setInputValue( "Box", 0, 1, val );
     347       70600 :         break;
     348       74778 :       case cmd_setPositions:
     349       74778 :         CHECK_INIT(initialized,word);
     350       74778 :         setInputValue("posx", 0, 3, val );
     351       74778 :         setInputValue("posy", 1, 3, val );
     352       74778 :         setInputValue("posz", 2, 3, val );
     353       74778 :         break;
     354       74741 :       case cmd_setMasses:
     355       74741 :         CHECK_INIT(initialized,word);
     356       74741 :         setInputValue("Masses", 0, 1, val );
     357       74738 :         break;
     358       66662 :       case cmd_setCharges:
     359       66662 :         CHECK_INIT(initialized,word);
     360       66662 :         setInputValue("Charges", 0, 1, val);
     361       66662 :         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       66915 :       case cmd_setVirial:
     375       66915 :         CHECK_INIT(initialized,word);
     376       66915 :         CHECK_NOTNULL(val,word);
     377       66915 :         setInputForce("Box",val);
     378       66897 :         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       74745 :       case cmd_setForces:
     387       74745 :         CHECK_INIT(initialized,word);
     388       74745 :         setInputForce("posx",val);
     389       74745 :         setInputForce("posy",val);
     390       74745 :         setInputForce("posz",val);
     391       74745 :         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      280128 :       case cmd_calc:
     405      280128 :         CHECK_INIT(initialized,word);
     406      280128 :         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       16013 :       case cmd_setStep:
     437       16013 :         CHECK_INIT(initialized,word);
     438       16016 :         CHECK_NOTNULL(val,word);
     439       16010 :         step=val.get<int>();
     440       16009 :         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      271067 :       case cmd_setStepLongLong:
     449      271067 :         CHECK_INIT(initialized,word);
     450      271067 :         CHECK_NOTNULL(val,word);
     451      271067 :         step=val.get<long long int>();
     452      271067 :         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        1142 :       case cmd_setAtomsNlocal:
     469        1142 :         CHECK_INIT(initialized,word);
     470        1142 :         CHECK_NOTNULL(val,word);
     471        4588 :         for(const auto & pp : inputs ) {
     472        3446 :           plumed_assert(pp);
     473        3446 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     474        3446 :           if( dd ) {
     475        1142 :             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           2 :       case cmd_setAtomsFGatindex:
     490           2 :         CHECK_INIT(initialized,word);
     491           6 :         for(const auto & pp : inputs ) {
     492           4 :           plumed_assert(pp);
     493           4 :           DomainDecomposition* dd=pp->castToDomainDecomposition();
     494           4 :           if( dd ) {
     495           2 :             dd->setAtomsGatindex(val,true);
     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         821 :       case cmd_readInputLine:
     595         821 :         CHECK_INIT(initialized,word);
     596         821 :         CHECK_NOTNULL(val,word);
     597         821 :         readInputLine(val.getCString());
     598         779 :         break;
     599           4 :       case cmd_readInputLines:
     600           4 :         CHECK_INIT(initialized,word);
     601           4 :         CHECK_NOTNULL(val,word);
     602           4 :         readInputLines(val.getCString());
     603           4 :         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          45 :         CHECK_NOTNULL(val,word);
     632          45 :         val.set(int(10));
     633             :         break;
     634             :       // commands which can be used only before initialization:
     635        1318 :       case cmd_init:
     636        1318 :         CHECK_NOTINIT(initialized,word);
     637        1318 :         init();
     638             :         break;
     639        1072 :       case cmd_setRealPrecision:
     640        1072 :         CHECK_NOTINIT(initialized,word);
     641        1072 :         CHECK_NOTNULL(val,word);
     642        2143 :         passtools=DataPassingTools::create(val.get<int>());
     643        1071 :         passtools->usingNaturalUnits=false;
     644        1071 :         break;
     645         981 :       case cmd_setMDLengthUnits:
     646         981 :         CHECK_NOTINIT(initialized,word);
     647         981 :         CHECK_NOTNULL(val,word);
     648         981 :         passtools->MDUnits.setLength(passtools->MD2double(val));
     649             :         break;
     650         981 :       case cmd_setMDChargeUnits:
     651         981 :         CHECK_NOTINIT(initialized,word);
     652         981 :         CHECK_NOTNULL(val,word);
     653         981 :         passtools->MDUnits.setCharge(passtools->MD2double(val));
     654             :         break;
     655         981 :       case cmd_setMDMassUnits:
     656         981 :         CHECK_NOTINIT(initialized,word);
     657         981 :         CHECK_NOTNULL(val,word);
     658         981 :         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        1031 :       case cmd_setPlumedDat:
     691        1031 :         CHECK_NOTINIT(initialized,word);
     692        1031 :         CHECK_NOTNULL(val,word);
     693        1031 :         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        1302 :       case cmd_setNatoms: {
     714        1302 :         CHECK_NOTINIT(initialized,word);
     715        1302 :         CHECK_NOTNULL(val,word);
     716        1302 :         int natoms = val.get<int>();
     717             :         std::string str_natoms;
     718        1292 :         Tools::convert( natoms, str_natoms );
     719        1292 :         ActionForInterface* dd=actionSet.selectWithLabel<ActionForInterface*>(MDEngine);
     720        1292 :         if( !dd && natoms>0 )
     721        3669 :           readInputLine( MDEngine + ": DOMAIN_DECOMPOSITION NATOMS=" + str_natoms +  +
     722        2446 :                          " VALUE1=posx UNIT1=length PERIODIC1=NO CONSTANT1=False ROLE1=x" +
     723        2446 :                          " VALUE2=posy UNIT2=length PERIODIC2=NO CONSTANT2=False ROLE2=y" +
     724        2446 :                          " VALUE3=posz UNIT3=length PERIODIC3=NO CONSTANT3=False ROLE3=z" +
     725        2446 :                          " VALUE4=Masses UNIT4=mass PERIODIC4=NO CONSTANT4=True ROLE4=m" +
     726        2446 :                          " VALUE5=Charges UNIT5=charge PERIODIC5=NO CONSTANT5=True ROLE5=q", true );
     727             :       }
     728        1292 :       break;
     729        1051 :       case cmd_setTimestep: {
     730        1051 :         CHECK_NOTINIT(initialized,word);
     731        1051 :         CHECK_NOTNULL(val,word);
     732        1051 :         ActionToPutData* ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
     733        1051 :         if( !ts ) {
     734        1049 :           readInputLine("timestep: PUT UNIT=time PERIODIC=NO CONSTANT", true);
     735        2098 :           ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
     736             :         }
     737        2102 :         if( !ts->setValuePointer("timestep", val ) ) {
     738           0 :           plumed_error();
     739             :         }
     740        1051 :         ts->updateUnits( passtools.get() );
     741             :       }
     742             :       break;
     743             :       /* ADDED WITH API==2 */
     744          61 :       case cmd_setKbT: {
     745          61 :         CHECK_NOTINIT(initialized,word);
     746          61 :         CHECK_NOTNULL(val,word);
     747          61 :         readInputLine("kBT: PUT CONSTANT PERIODIC=NO UNIT=energy", true);
     748          61 :         ActionToPutData* kb = actionSet.selectWithLabel<ActionToPutData*>("kBT");
     749         122 :         if( !kb->setValuePointer("kBT", val ) ) {
     750           0 :           plumed_error();
     751             :         }
     752          61 :         kb->updateUnits( passtools.get() );
     753             :       }
     754             :       break;
     755             :       /* ADDED WITH API==3 */
     756           8 :       case cmd_setRestart:
     757           8 :         CHECK_NOTINIT(initialized,word);
     758           8 :         CHECK_NOTNULL(val,word);
     759           8 :         if(val.get<int>()!=0) {
     760           2 :           restart=true;
     761             :         }
     762             :         break;
     763             :       /* ADDED WITH API==4 */
     764           0 :       case cmd_doCheckPoint:
     765           0 :         CHECK_INIT(initialized,word);
     766           0 :         CHECK_NOTNULL(val,word);
     767           0 :         doCheckPoint = false;
     768           0 :         if(val.get<int>()!=0) {
     769           0 :           doCheckPoint = true;
     770             :         }
     771             :         break;
     772             :       /* ADDED WITH API==6 */
     773             :       case cmd_setNumOMPthreads:
     774           0 :         CHECK_NOTNULL(val,word);
     775             :         {
     776           0 :           auto nt=val.get<unsigned>();
     777             :           if(nt==0) {
     778             :             nt=1;
     779             :           }
     780           0 :           OpenMP::setNumThreads(nt);
     781             :         }
     782             :         break;
     783             :       /* ADDED WITH API==10 */
     784             :       case cmd_setGpuDeviceId:
     785           0 :         CHECK_NOTNULL(val,word);
     786             :         {
     787           0 :           auto id=val.get<int>();
     788           0 :           if(id>=0) {
     789           0 :             gpuDeviceId=id;
     790             :           }
     791             :         }
     792             :         break;
     793             :       /* ADDED WITH API==6 */
     794             :       /* only used for testing */
     795             :       case cmd_throw:
     796          61 :         CHECK_NOTNULL(val,word);
     797          61 :         testThrow(val.getCString());
     798             :       /* ADDED WITH API==10 */
     799             :       case cmd_setNestedExceptions:
     800          28 :         CHECK_NOTNULL(val,word);
     801          28 :         if(val.get<int>()!=0) {
     802          27 :           nestedExceptions=true;
     803             :         } else {
     804           1 :           nestedExceptions=false;
     805             :         }
     806             :         break;
     807             :       /* STOP API */
     808        1046 :       case cmd_setMDEngine:
     809        1046 :         CHECK_NOTINIT(initialized,word);
     810        1046 :         CHECK_NOTNULL(val,word);
     811        1046 :         MDEngine=val.getCString();
     812             :         break;
     813        1021 :       case cmd_setLog:
     814        1021 :         CHECK_NOTINIT(initialized,word);
     815        1021 :         log.link(val.get<FILE*>());
     816             :         break;
     817         169 :       case cmd_setLogFile:
     818         169 :         CHECK_NOTINIT(initialized,word);
     819         169 :         CHECK_NOTNULL(val,word);
     820         169 :         log.open(val.getCString());
     821         169 :         break;
     822             :       // other commands that should be used after initialization:
     823      268210 :       case cmd_setStopFlag:
     824      268210 :         CHECK_INIT(initialized,word);
     825      268210 :         CHECK_NOTNULL(val,word);
     826      268210 :         val.get<int*>(); // just check type and discard pointer
     827      268209 :         stopFlag=val.copy();
     828      268209 :         break;
     829           0 :       case cmd_getExchangesFlag:
     830           0 :         CHECK_INIT(initialized,word);
     831           0 :         CHECK_NOTNULL(val,word);
     832           0 :         exchangePatterns.getFlag(*val.get<int*>()); // note: getFlag changes the value of the reference!
     833             :         break;
     834           0 :       case cmd_setExchangesSeed:
     835           0 :         CHECK_INIT(initialized,word);
     836           0 :         CHECK_NOTNULL(val,word);
     837           0 :         exchangePatterns.setSeed(val.get<int>());
     838             :         break;
     839           0 :       case cmd_setNumberOfReplicas:
     840           0 :         CHECK_INIT(initialized,word);
     841           0 :         CHECK_NOTNULL(val,word);
     842           0 :         exchangePatterns.setNofR(val.get<int>());
     843             :         break;
     844           0 :       case cmd_getExchangesList:
     845           0 :         CHECK_INIT(initialized,word);
     846           0 :         CHECK_NOTNULL(val,word);
     847           0 :         exchangePatterns.getList(val);
     848             :         break;
     849         971 :       case cmd_runFinalJobs:
     850         971 :         CHECK_INIT(initialized,word);
     851         971 :         runJobsAtEndOfCalculation();
     852             :         break;
     853          96 :       case cmd_isEnergyNeeded: {
     854          96 :         CHECK_INIT(initialized,word);
     855          96 :         CHECK_NOTNULL(val,word);
     856          96 :         if( name_of_energy =="" ) {
     857          96 :           val.set(int(0));
     858             :         } else {
     859           0 :           ActionToPutData* ap=actionSet.selectWithLabel<ActionToPutData*>(name_of_energy);
     860           0 :           if(ap->isActive()) {
     861           0 :             val.set(int(1));
     862             :           } else {
     863           0 :             val.set(int(0));
     864             :           }
     865             :         }
     866             :       }
     867             :       break;
     868        7051 :       case cmd_getBias:
     869        7051 :         CHECK_INIT(initialized,word);
     870        7051 :         CHECK_NOTNULL(val,word);
     871        7051 :         plumedQuantityToMD( "energy", getBias(), val );
     872        7051 :         break;
     873             :       case cmd_checkAction:
     874           2 :         CHECK_NOTNULL(val,word);
     875           2 :         plumed_assert(nw==2);
     876           3 :         val.set(int(actionRegister().check(dlloader.getHandles(), std::string(words[1])) ? 1:0));
     877           2 :         break;
     878             :       case cmd_setExtraCV: {
     879          30 :         CHECK_NOTNULL(val,word);
     880          30 :         plumed_assert(nw==2);
     881          60 :         if( valueExists(std::string(words[1])) ) {
     882          60 :           setInputValue( std::string(words[1]), 0, 1, val );
     883             :         }
     884             :       }
     885             :       break;
     886             :       case cmd_setExtraCVForce: {
     887          30 :         CHECK_NOTNULL(val,word);
     888          30 :         plumed_assert(nw==2);
     889          60 :         if( valueExists(std::string(words[1])) ) {
     890          60 :           setInputForce( std::string(words[1]), val );
     891             :         }
     892             :       }
     893             :       break;
     894             :       /* ADDED WITH API==10 */
     895             :       case cmd_isExtraCVNeeded:
     896          10 :         CHECK_NOTNULL(val,word);
     897          10 :         plumed_assert(nw==2);
     898          10 :         val.set(int(0));
     899          56 :         for(const auto & p : inputs) {
     900          50 :           if( p->getLabel()==words[1] && p->isActive() ) {
     901           4 :             val.set(int(1));
     902             :             break;
     903             :           }
     904             :         }
     905             :         break;
     906        1089 :       case cmd_GREX:
     907        1089 :         if(!grex) {
     908         208 :           grex=Tools::make_unique<GREX>(*this);
     909             :         }
     910        1089 :         plumed_massert(grex,"error allocating grex");
     911             :         {
     912        1089 :           std::string kk=std::string(words[1]);
     913        1260 :           for(unsigned i=2; i<words.size(); i++) {
     914         342 :             kk+=" "+std::string(words[i]);
     915             :           }
     916        1089 :           grex->cmd(kk.c_str(),val);
     917             :         }
     918        1089 :         break;
     919       18099 :       case cmd_CLTool:
     920       18099 :         CHECK_NOTINIT(initialized,word);
     921       18099 :         if(!cltool) {
     922        5935 :           cltool=Tools::make_unique<CLToolMain>();
     923             :         }
     924             :         {
     925       18099 :           std::string kk(words[1]);
     926       18099 :           for(unsigned i=2; i<words.size(); i++) {
     927           0 :             kk+=" "+std::string(words[i]);
     928             :           }
     929       18099 :           cltool->cmd(kk.c_str(),val);
     930             :         }
     931       18099 :         break;
     932             :         break;
     933             :       /* ADDED WITH API==7 */
     934             :       case cmd_convert: {
     935             :         double v;
     936          57 :         plumed_assert(words.size()==2);
     937         280 :         if(Tools::convertNoexcept(std::string(words[1]),v)) {
     938          47 :           passtools->double2MD(v,val);
     939             :         }
     940             :       }
     941          57 :       break;
     942           7 :       default:
     943          14 :         plumed_error() << "cannot interpret cmd(\"" << word << "\"). check plumed developers manual to see the available commands.";
     944             :         break;
     945             :       }
     946             :     }
     947             : 
     948     1352389 :   } catch (...) {
     949         166 :     if(log.isOpen()) {
     950             :       try {
     951          92 :         log<<"\n################################################################################\n";
     952          92 :         log<<Tools::concatenateExceptionMessages();
     953          92 :         log<<"\n################################################################################\n";
     954          92 :         log.flush();
     955           0 :       } catch(...) {
     956             :         // ignore errors here.
     957             :         // in any case, we are rethrowing this below
     958           0 :       }
     959             :     }
     960         166 :     throw;
     961         166 :   }
     962     1352057 : }
     963             : 
     964             : ////////////////////////////////////////////////////////////////////////
     965             : 
     966        1318 : void PlumedMain::init() {
     967             : // check that initialization just happens once
     968        1318 :   initialized=true;
     969        1318 :   if(!log.isOpen()) {
     970         128 :     log.link(stdout);
     971             :   }
     972        1318 :   log<<"PLUMED is starting\n";
     973        3954 :   log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") "
     974        5272 :      <<"compiled on " <<config::getCompilationDate() << " at " << config::getCompilationTime() << "\n";
     975        1318 :   log<<"Please cite these papers when using PLUMED ";
     976        2636 :   log<<cite("The PLUMED consortium, Nat. Methods 16, 670 (2019)");
     977        2636 :   log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
     978        1318 :   log<<"\n";
     979        1318 :   log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
     980        1318 :   log<<"Root: "<<config::getPlumedRoot()<<"\n";
     981        1318 :   log<<"LibraryPath: "<<config::getLibraryPath()<<"\n";
     982        2636 :   log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
     983        1318 :   log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
     984        1318 :   log.printf("Precision of reals: %d\n",passtools->getRealPrecision());
     985        2390 :   log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
     986        1318 :   log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
     987        1318 :   log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
     988        4892 :   for(const auto & pp : inputs ) {
     989        3574 :     plumed_assert(pp);
     990        3574 :     DomainDecomposition* dd=pp->castToDomainDecomposition();
     991        3574 :     if ( dd ) {
     992        1222 :       log.printf("Number of atoms: %d\n",dd->getNumberOfAtoms());
     993             :     }
     994             :   }
     995        1318 :   if(grex) {
     996         208 :     log.printf("GROMACS-like replica exchange is on\n");
     997             :   }
     998        1318 :   log.printf("File suffix: %s\n",getSuffix().c_str());
     999        1318 :   if(plumedDat.length()>0) {
    1000        1031 :     readInputFile(plumedDat);
    1001             :     plumedDat="";
    1002             :   }
    1003        1318 :   setUnits( passtools->usingNaturalUnits, passtools->units );
    1004        1318 :   ActionToPutData* ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
    1005        1318 :   if(ts) {
    1006        1049 :     log.printf("Timestep: %f\n",(ts->copyOutput(0))->get());
    1007             :   }
    1008        1318 :   ActionToPutData* kb = actionSet.selectWithLabel<ActionToPutData*>("kBT");
    1009        1318 :   if(kb) {
    1010          61 :     log.printf("KbT: %f\n",(kb->copyOutput(0))->get());
    1011             :   } else {
    1012        1257 :     log.printf("KbT has not been set by the MD engine\n");
    1013        1257 :     log.printf("It should be set by hand where needed\n");
    1014             :   }
    1015        1318 :   log<<"Relevant bibliography:\n";
    1016        1318 :   log<<citations;
    1017        1318 :   log<<"Please read and cite where appropriate!\n";
    1018        1318 :   log<<"Finished setup\n";
    1019        1318 : }
    1020             : 
    1021       52105 : void PlumedMain::setupInterfaceActions() {
    1022       52105 :   inputs.clear();
    1023       52105 :   std::vector<ActionForInterface*> ap=actionSet.select<ActionForInterface*>();
    1024      421469 :   for(unsigned i=0; i<ap.size(); ++i) {
    1025      369364 :     if( ap[i]->getName()=="ENERGY" || ap[i]->getDependencies().size()==0 ) {
    1026      141169 :       inputs.push_back( ap[i] );
    1027             :     }
    1028             :   }
    1029       52105 : }
    1030             : 
    1031        1054 : void PlumedMain::readInputFile(const std::string & str) {
    1032        1054 :   plumed_assert(initialized);
    1033        1054 :   log<<"FILE: "<<str<<"\n";
    1034        1054 :   IFile ifile;
    1035        1054 :   ifile.link(*this);
    1036        1054 :   ifile.open(str);
    1037        1054 :   ifile.allowNoEOL();
    1038        1054 :   readInputFile(ifile);
    1039        1054 :   log<<"END FILE: "<<str<<"\n";
    1040        1054 :   log.flush();
    1041             : 
    1042        1054 : }
    1043             : 
    1044        1058 : void PlumedMain::readInputFile(IFile & ifile) {
    1045             :   std::vector<std::string> words;
    1046       19726 :   while(Tools::getParsedLine(ifile,words) && !endPlumed) {
    1047       18668 :     readInputWords(words,false);
    1048             :   }
    1049        1058 :   endPlumed=false;
    1050        1058 :   pilots=actionSet.select<ActionPilot*>();
    1051        1058 :   setupInterfaceActions();
    1052        1058 : }
    1053             : 
    1054       10682 : void PlumedMain::readInputLine(const std::string & str, const bool& before_init) {
    1055       10682 :   if( !before_init ) {
    1056         985 :     plumed_assert(initialized);
    1057             :   }
    1058       10682 :   if(str.empty()) {
    1059           0 :     return;
    1060             :   }
    1061       10682 :   std::vector<std::string> words=Tools::getWords(str);
    1062       10682 :   if( before_init ) {
    1063        9697 :     plumed_assert( citations.empty() );
    1064             :   }
    1065       10682 :   citations.clear();
    1066       10682 :   readInputWords(words,before_init);
    1067       10642 :   if(!citations.empty()) {
    1068           3 :     log<<"Relevant bibliography:\n";
    1069           3 :     log<<citations;
    1070           3 :     log<<"Please read and cite where appropriate!\n";
    1071             :   }
    1072       10682 : }
    1073             : 
    1074           4 : void PlumedMain::readInputLines(const std::string & str) {
    1075           4 :   plumed_assert(initialized);
    1076           4 :   if(str.empty()) {
    1077           0 :     return;
    1078             :   }
    1079             : 
    1080           4 :   log<<"FILE: (temporary)\n";
    1081             : 
    1082             :   // Open a temporary file
    1083           4 :   auto fp=std::tmpfile();
    1084           4 :   plumed_assert(fp);
    1085             : 
    1086             :   // make sure file is closed (and thus deleted) also if an exception occurs
    1087             :   auto deleter=[](auto fp) {
    1088           4 :     std::fclose(fp);
    1089             :   };
    1090             :   std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
    1091             : 
    1092           4 :   auto ret=std::fputs(str.c_str(),fp);
    1093           4 :   plumed_assert(ret!=EOF);
    1094             : 
    1095           4 :   std::rewind(fp);
    1096             : 
    1097           4 :   IFile ifile;
    1098           4 :   ifile.link(*this);
    1099           4 :   ifile.link(fp);
    1100           4 :   ifile.allowNoEOL();
    1101             : 
    1102           4 :   readInputFile(ifile);
    1103           4 :   log<<"END FILE: (temporary)\n";
    1104           4 : }
    1105             : 
    1106       51274 : void PlumedMain::readInputWords(const std::vector<std::string> & words, const bool& before_init) {
    1107       51274 :   if( !before_init ) {
    1108       41577 :     plumed_assert(initialized);
    1109             :   }
    1110       51274 :   if(words.empty()) {
    1111             :     return;
    1112       51102 :   } else if(words[0]=="_SET_SUFFIX") {
    1113           3 :     plumed_assert(words.size()==2);
    1114             :     setSuffix(words[1]);
    1115             :   } else {
    1116       51099 :     std::vector<std::string> interpreted(words);
    1117       51099 :     Tools::interpretLabel(interpreted);
    1118      102143 :     auto action=actionRegister().create(dlloader.getHandles(),ActionOptions(*this,interpreted));
    1119       51044 :     if(!action) {
    1120             :       std::string msg;
    1121             :       msg ="ERROR\nI cannot understand line:";
    1122           0 :       for(unsigned i=0; i<interpreted.size(); ++i) {
    1123           0 :         msg+=" "+interpreted[i];
    1124             :       }
    1125             :       msg+="\nMaybe a missing space or a typo?";
    1126           0 :       log << msg;
    1127           0 :       log.flush();
    1128           0 :       plumed_merror(msg);
    1129             :     }
    1130       51044 :     action->checkRead();
    1131       51044 :     actionSet.emplace_back(std::move(action));
    1132       51099 :   };
    1133             : 
    1134       51047 :   pilots=actionSet.select<ActionPilot*>();
    1135       51047 :   setupInterfaceActions();
    1136             : }
    1137             : 
    1138             : ////////////////////////////////////////////////////////////////////////
    1139             : 
    1140           0 : void PlumedMain::exit(int c) {
    1141           0 :   comm.Abort(c);
    1142           0 : }
    1143             : 
    1144       51097 : Log& PlumedMain::getLog() {
    1145       51097 :   return log;
    1146             : }
    1147             : 
    1148      280128 : void PlumedMain::calc() {
    1149      280128 :   prepareCalc();
    1150      280112 :   performCalc();
    1151      280110 : }
    1152             : 
    1153      287079 : void PlumedMain::prepareCalc() {
    1154      287079 :   prepareDependencies();
    1155      287079 :   shareData();
    1156      287063 : }
    1157             : 
    1158             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    1159             : // here we have the main steps in "calc()"
    1160             : // they can be called individually, but the standard thing is to
    1161             : // traverse them in this order:
    1162      287406 : void PlumedMain::prepareDependencies() {
    1163             : 
    1164             : // Stopwatch is stopped when sw goes out of scope
    1165      287406 :   auto sw=stopwatch.startStop("1 Prepare dependencies");
    1166             : 
    1167             : // activate all the actions which are on step
    1168             : // activation is recursive and enables also the dependencies
    1169             : // before doing that, the prepare() method is called to see if there is some
    1170             : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
    1171             : // which can be dynamically changed).
    1172             : 
    1173             : // First switch off all actions
    1174     4677958 :   for(const auto & p : actionSet) {
    1175     4390552 :     p->deactivate();
    1176             :   }
    1177             : 
    1178             : // for optimization, an "active" flag remains false if no action at all is active
    1179      287406 :   active=false;
    1180     1730965 :   for(unsigned i=0; i<pilots.size(); ++i) {
    1181     1443559 :     if(pilots[i]->onStep()) {
    1182     1350308 :       pilots[i]->activate();
    1183     1350308 :       active=true;
    1184             :     }
    1185             :   };
    1186             : 
    1187             : // This stops the driver calculation if there is not a read action
    1188      287406 :   if( !active && !inputsAreActive() ) {
    1189           2 :     stopFlag.set(int(1));
    1190             :   }
    1191             : 
    1192             : // also, if one of them is the total energy, tell to atoms that energy should be collected
    1193     4677958 :   for(const auto & p : actionSet) {
    1194     4390552 :     if(p->isActive()) {
    1195     2648577 :       if(p->checkNeedsGradients()) {
    1196         172 :         p->setOption("GRADIENTS");
    1197             :       }
    1198             :     }
    1199             :   }
    1200             : 
    1201      287406 : }
    1202             : 
    1203        1763 : bool PlumedMain::inputsAreActive() const {
    1204        5178 :   for(const auto & ip : inputs) {
    1205        5122 :     if( ip->onStep() ) {
    1206             :       return true;
    1207             :     }
    1208             :   }
    1209             :   return false;
    1210             : }
    1211             : 
    1212         114 : void PlumedMain::shareAll() {
    1213         456 :   for(const auto & ip : inputs) {
    1214         342 :     ip->shareAll();
    1215             :   }
    1216         114 : }
    1217             : 
    1218      287163 : void PlumedMain::shareData() {
    1219             : // atom positions are shared (but only if there is something to do)
    1220      287163 :   if(!active) {
    1221        1703 :     return;
    1222             :   }
    1223             : // Stopwatch is stopped when sw goes out of scope
    1224      285460 :   auto sw=stopwatch.startStop("2 Sharing data");
    1225      752260 :   for(const auto & ip : inputs) {
    1226      466816 :     ip->share();
    1227             :   }
    1228      285460 : }
    1229             : 
    1230        7011 : void PlumedMain::performCalcNoUpdate() {
    1231        7011 :   waitData();
    1232        7011 :   justCalculate();
    1233        7011 :   backwardPropagate();
    1234        7011 :   resetInputs();
    1235        7011 : }
    1236             : 
    1237          10 : void PlumedMain::performCalcNoForces() {
    1238          10 :   waitData();
    1239          10 :   justCalculate();
    1240          10 : }
    1241             : 
    1242      280122 : void PlumedMain::performCalc() {
    1243      280122 :   waitData();
    1244      280122 :   justCalculate();
    1245      280122 :   backwardPropagate();
    1246      280120 :   update();
    1247      280120 :   resetInputs();
    1248      280120 : }
    1249             : 
    1250      287257 : void PlumedMain::waitData() {
    1251      287257 :   if(!active) {
    1252        1703 :     return;
    1253             :   }
    1254             : // Stopwatch is stopped when sw goes out of scope
    1255      285554 :   auto sw=stopwatch.startStop("3 Waiting for data");
    1256      752672 :   for(const auto & ip : inputs) {
    1257      467118 :     if( ip->isActive() && ip->hasBeenSet() ) {
    1258      168653 :       ip->wait();
    1259      298465 :     } else if( ip->isActive() ) {
    1260        8084 :       ip->warning("input requested but this quantity has not been set");
    1261             :     }
    1262             :   }
    1263      285554 : }
    1264             : 
    1265      287257 : void PlumedMain::justCalculate() {
    1266      287257 :   if(!active) {
    1267        1703 :     return;
    1268             :   }
    1269             : // Stopwatch is stopped when sw goes out of scope
    1270      285554 :   auto sw=stopwatch.startStop("4 Calculating (forward loop)");
    1271      285554 :   bias=0.0;
    1272      285554 :   work=0.0;
    1273             : 
    1274             :   // Check the input actions to determine if we need to calculate constants that
    1275             :   // depend on masses and charges
    1276             :   bool firststep=false;
    1277      752672 :   for(const auto & ip : inputs) {
    1278      467118 :     if( ip->firststep ) {
    1279             :       firststep=true;
    1280             :     }
    1281             :   }
    1282      285554 :   if( firststep ) {
    1283        4578 :     for(const auto & ip : inputs) {
    1284        3392 :       ip->firststep=false;
    1285             :     }
    1286             :   }
    1287             : 
    1288             :   int iaction=0;
    1289             : // calculate the active actions in order (assuming *backward* dependence)
    1290     4645108 :   for(const auto & pp : actionSet) {
    1291             :     Action* p(pp.get());
    1292     4359554 :     plumed_assert(p);
    1293             :     try {
    1294     4359554 :       if(p->isActive()) {
    1295             : // Stopwatch is stopped when sw goes out of scope.
    1296             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1297     2646582 :         Stopwatch::Handler sw;
    1298     2646582 :         if(detailedTimers) {
    1299        2481 :           auto actionNumberLabel=std::to_string(iaction);
    1300        2481 :           const unsigned m=actionSet.size();
    1301             :           unsigned k=0;
    1302             :           unsigned n=1;
    1303        7443 :           while(n<m) {
    1304        4962 :             n*=10;
    1305        4962 :             k++;
    1306             :           }
    1307        2481 :           auto spaces=std::string(k-actionNumberLabel.length(),' ');
    1308        2481 :           sw=stopwatch.startStop("4A " + spaces + actionNumberLabel+" "+p->getLabel());
    1309             :         }
    1310     2646582 :         ActionWithValue*av=p->castToActionWithValue();
    1311     2646582 :         ActionAtomistic*aa=p->castToActionAtomistic();
    1312             :         {
    1313     2646582 :           if(av) {
    1314     2362861 :             av->clearInputForces();
    1315             :           }
    1316     2646582 :           if(av) {
    1317     2362861 :             av->clearDerivatives();
    1318             :           }
    1319     2646582 :           if( av && av->calculateOnUpdate() ) {
    1320             :             continue ;
    1321             :           }
    1322             :         }
    1323             :         {
    1324     2642567 :           if(aa)
    1325      483344 :             if(aa->isActive()) {
    1326      483344 :               aa->retrieveAtoms();
    1327             :             }
    1328             :         }
    1329     2642567 :         if(p->checkNumericalDerivatives()) {
    1330         256 :           p->calculateNumericalDerivatives();
    1331             :         } else {
    1332     2642311 :           p->calculate();
    1333             :         }
    1334             :         // This retrieves components called bias
    1335     2642567 :         if(av) {
    1336     2358846 :           bias+=av->getOutputQuantity("bias");
    1337     2358846 :           work+=av->getOutputQuantity("work");
    1338     2358846 :           av->setGradientsIfNeeded();
    1339             :         }
    1340             :         // This makes all values that depend on the (fixed) masses and charges constant
    1341     2642567 :         if( firststep ) {
    1342       28324 :           p->setupConstantValues( true );
    1343             :         }
    1344     2642567 :         ActionWithVirtualAtom*avv=p->castToActionWithVirtualAtom();
    1345     2642567 :         if(avv) {
    1346       35094 :           avv->setGradientsIfNeeded();
    1347             :         }
    1348     2646582 :       }
    1349           0 :     } catch(...) {
    1350           0 :       plumed_error_nested() << "An error happened while calculating " << p->getLabel();
    1351           0 :     }
    1352     4355539 :     iaction++;
    1353             :   }
    1354      285554 : }
    1355             : 
    1356           0 : void PlumedMain::justApply() {
    1357           0 :   backwardPropagate();
    1358           0 :   update();
    1359           0 :   resetInputs();
    1360           0 : }
    1361             : 
    1362      287133 : void PlumedMain::backwardPropagate() {
    1363      287133 :   if(!active) {
    1364        1703 :     return;
    1365             :   }
    1366             :   int iaction=0;
    1367             : // Stopwatch is stopped when sw goes out of scope
    1368      285430 :   auto sw=stopwatch.startStop("5 Applying (backward loop)");
    1369             : // apply them in reverse order
    1370     4642642 :   for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
    1371             :     const auto & p(pp->get());
    1372     4357214 :     if(p->isActive()) {
    1373             : 
    1374             : // Stopwatch is stopped when sw goes out of scope.
    1375             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1376     2644906 :       Stopwatch::Handler sw;
    1377     2644906 :       if(detailedTimers) {
    1378        2481 :         auto actionNumberLabel=std::to_string(iaction);
    1379        2481 :         const unsigned m=actionSet.size();
    1380             :         unsigned k=0;
    1381             :         unsigned n=1;
    1382        7443 :         while(n<m) {
    1383        4962 :           n*=10;
    1384        4962 :           k++;
    1385             :         }
    1386        2481 :         auto spaces=std::string(k-actionNumberLabel.length(),' ');
    1387        2481 :         sw=stopwatch.startStop("5A " + spaces + actionNumberLabel+" "+p->getLabel());
    1388             :       }
    1389             : 
    1390     2644906 :       p->apply();
    1391     2644906 :     }
    1392     4357212 :     iaction++;
    1393             :   }
    1394             : 
    1395             : // Stopwatch is stopped when sw goes out of scope.
    1396             : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
    1397      285428 :   Stopwatch::Handler sw1;
    1398      285428 :   if(detailedTimers) {
    1399         113 :     sw1=stopwatch.startStop("5B Update forces");
    1400             :   }
    1401      285430 : }
    1402             : 
    1403      280199 : void PlumedMain::update() {
    1404      280199 :   if(!active) {
    1405        1703 :     return;
    1406             :   }
    1407             : 
    1408             : // Stopwatch is stopped when sw goes out of scope
    1409      278496 :   auto sw=stopwatch.startStop("6 Update");
    1410             : 
    1411             : // update step (for statistics, etc)
    1412      278496 :   updateFlags.push(true);
    1413     4418423 :   for(const auto & p : actionSet) {
    1414     4139927 :     p->beforeUpdate();
    1415     6689824 :     if(p->isActive() && p->checkUpdate() && updateFlagsTop()) {
    1416     2549877 :       ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
    1417     2549877 :       if( av && av->calculateOnUpdate() ) {
    1418        4015 :         p->prepare();
    1419        4015 :         p->calculate();
    1420             :       } else {
    1421     2545862 :         p->update();
    1422             :       }
    1423             :     }
    1424             :   }
    1425      556996 :   while(!updateFlags.empty()) {
    1426             :     updateFlags.pop();
    1427             :   }
    1428             :   if(!updateFlags.empty()) {
    1429             :     plumed_merror("non matching changes in the update flags");
    1430             :   }
    1431             : // Check that no action has told the calculation to stop
    1432      278496 :   if(stopNow) {
    1433          65 :     if(stopFlag) {
    1434          65 :       stopFlag.set(int(1));
    1435             :     } else {
    1436           0 :       plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
    1437             :     }
    1438             :   }
    1439             : 
    1440             : // flush by default every 10000 steps
    1441             : // hopefully will not affect performance
    1442             : // also if receive checkpointing signal
    1443      278496 :   if(step%10000==0||doCheckPoint) {
    1444        1231 :     fflush();
    1445        1231 :     log.flush();
    1446       53236 :     for(const auto & p : actionSet) {
    1447       52005 :       p->fflush();
    1448             :     }
    1449             :   }
    1450      278496 : }
    1451             : 
    1452          42 : void PlumedMain::load(const std::string& fileName) {
    1453          42 :   if(DLLoader::installed()) {
    1454          42 :     std::string libName=fileName;
    1455          42 :     size_t n=libName.find_last_of(".");
    1456          43 :     std::string extension="";
    1457          42 :     std::string base=libName;
    1458          42 :     if(n!=std::string::npos && n<libName.length()-1) {
    1459          84 :       extension=libName.substr(n+1);
    1460             :     }
    1461          42 :     if(n!=std::string::npos && n<libName.length()) {
    1462          84 :       base=libName.substr(0,n);
    1463             :     }
    1464             : 
    1465          42 :     if(extension=="cpp") {
    1466          46 :       libName="./"+base+"."+config::getVersionLong()+"."+config::getSoExt();
    1467             : // full path command, including environment setup
    1468             : // this will work even if plumed is not in the execution path or if it has been
    1469             : // installed with a name different from "plumed"
    1470          46 :       std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh -n -o "+libName+" "+fileName;
    1471             : 
    1472          23 :       if(std::getenv("PLUMED_LOAD_ACTION_DEBUG")) {
    1473           0 :         log<<"Executing: "<<cmd;
    1474             :       } else {
    1475          23 :         log<<"Compiling: "<<fileName<<" to "<<libName;
    1476             :       }
    1477             : 
    1478          23 :       if(comm.Get_size()>0) {
    1479          23 :         log<<" (only on master node)";
    1480             :       }
    1481          23 :       log<<"\n";
    1482             : 
    1483             :       // On MPI process (intracomm), we use Get_rank to make sure a single process does the compilation
    1484             :       // Processes from multiple replicas might simultaneously do the compilation.
    1485          23 :       if(comm.Get_rank()==0) {
    1486          23 :         static Tools::CriticalSectionWithKey<std::string> section;
    1487             :         // This is only locking commands that are running with identical arguments.
    1488             :         // It is not necessary for correctness (a second mklib would just result in a no op since
    1489             :         // the library is already there, even if running simultaneously).
    1490             :         // It however decreases the system load if many threads are used.
    1491             :         auto s=section.startStop(cmd);
    1492          23 :         int ret=std::system(cmd.c_str());
    1493          23 :         if(ret!=0) {
    1494           2 :           plumed_error() <<"An error happened while executing command "<<cmd<<"\n";
    1495             :         }
    1496          23 :       }
    1497          22 :       comm.Barrier();
    1498             :     } else {
    1499          38 :       libName=base+"."+config::getSoExt();
    1500             :     }
    1501             : 
    1502             :     // If we have multiple threads (each holding a Plumed object), each of them
    1503             :     // will load the library, but each of them will only see actions registered
    1504             :     // from the owned library
    1505          41 :     auto *p=dlloader.load(libName);
    1506          42 :     log<<"Loading shared library "<<libName.c_str()<<" at "<<p<<"\n";
    1507          41 :     log<<"Here is the list of new actions\n";
    1508          41 :     log<<"\n";
    1509          82 :     for(const auto & a : actionRegister().getKeysWithDLHandle(p)) {
    1510          41 :       log<<a<<"\n";
    1511          41 :     }
    1512          41 :     log<<"\n";
    1513             :   } else {
    1514           0 :     plumed_error()<<"While loading library "<< fileName << " loading was not enabled, please check if dlopen was found at configure time";
    1515             :   }
    1516          41 : }
    1517             : 
    1518      287131 : void PlumedMain::resetInputs() {
    1519      759008 :   for(const auto & ip : inputs) {
    1520      471877 :     if( ip->isActive() && ip->hasBeenSet() ) {
    1521      168377 :       ip->reset();
    1522             :     }
    1523             :   }
    1524      287131 : }
    1525             : 
    1526        7684 : double PlumedMain::getBias() const {
    1527        7684 :   return bias;
    1528             : }
    1529             : 
    1530         450 : double PlumedMain::getWork() const {
    1531         450 :   return work;
    1532             : }
    1533             : 
    1534          82 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
    1535          82 :   std::string mmode(mode);
    1536          83 :   std::string ppath(path);
    1537          82 :   std::string suffix(getSuffix());
    1538          82 :   std::string ppathsuf=ppath+suffix;
    1539          82 :   FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
    1540          82 :   if(!fp) {
    1541           1 :     fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
    1542             :   }
    1543          84 :   plumed_massert(fp,"file " + ppath + " cannot be found");
    1544          81 :   return fp;
    1545             : }
    1546             : 
    1547          99 : int PlumedMain::fclose(FILE*fp) {
    1548          99 :   return std::fclose(fp);
    1549             : }
    1550             : 
    1551        4886 : std::string PlumedMain::cite(const std::string&item) {
    1552        4886 :   return citations.cite(item);
    1553             : }
    1554             : 
    1555        1792 : void PlumedMain::fflush() {
    1556        5400 :   for(const auto  & p : files) {
    1557        3608 :     p->flush();
    1558             :   }
    1559        1792 : }
    1560             : 
    1561        5217 : void PlumedMain::insertFile(FileBase&f) {
    1562        5217 :   files.insert(&f);
    1563        5217 : }
    1564             : 
    1565        5502 : void PlumedMain::eraseFile(FileBase&f) {
    1566        5502 :   files.erase(&f);
    1567        5502 : }
    1568             : 
    1569          65 : void PlumedMain::stop() {
    1570          65 :   stopNow=true;
    1571          65 : }
    1572             : 
    1573         971 : void PlumedMain::runJobsAtEndOfCalculation() {
    1574       47549 :   for(const auto & p : actionSet) {
    1575       46578 :     ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
    1576       46578 :     if( av && av->calculateOnUpdate() ) {
    1577         414 :       p->activate();
    1578             :     }
    1579             :   }
    1580       47549 :   for(const auto & p : actionSet) {
    1581       46578 :     ActionPilot* ap=dynamic_cast<ActionPilot*>(p.get());
    1582       46578 :     ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
    1583       46578 :     if( av && av->calculateOnUpdate() ) {
    1584         414 :       p->calculate();
    1585       46164 :     } else if( ap && !av && ap->getStride()==0 ) {
    1586          70 :       p->update();
    1587             :     } else {
    1588       46094 :       p->runFinalJobs();
    1589             :     }
    1590             :   }
    1591         971 : }
    1592             : 
    1593     8807971 : unsigned PlumedMain::increaseReferenceCounter() noexcept {
    1594     8807971 :   return ++referenceCounter;
    1595             : }
    1596             : 
    1597     8806867 : unsigned PlumedMain::decreaseReferenceCounter() noexcept {
    1598     8806867 :   return --referenceCounter;
    1599             : }
    1600             : 
    1601          42 : unsigned PlumedMain::useCountReferenceCounter() const noexcept {
    1602          42 :   return referenceCounter;
    1603             : }
    1604             : 
    1605          60 : bool PlumedMain::valueExists( const std::string& name ) const {
    1606         240 :   for(const auto & p : inputs) {
    1607         240 :     if( p->getLabel()==name ) {
    1608             :       return true;
    1609             :     }
    1610             :   }
    1611             :   return false;
    1612             : }
    1613             : 
    1614      463816 : void PlumedMain::setInputValue( const std::string& name, const unsigned& start, const unsigned& stride, const TypesafePtr & val ) {
    1615             :   bool found=false;
    1616     1257608 :   for(const auto & pp : inputs) {
    1617     1257608 :     if( pp->setValuePointer( name, val ) ) {
    1618      463812 :       pp->setStart(name, start);
    1619      463812 :       pp->setStride(name, stride);
    1620             :       found=true;
    1621             :       break;
    1622             :     }
    1623             :   }
    1624           0 :   plumed_massert( found, "found no action to set named " + name );
    1625      463812 : }
    1626             : 
    1627      291183 : void PlumedMain::setInputForce( const std::string& name, const TypesafePtr & val ) {
    1628             :   bool found=false;
    1629      782363 :   for(const auto & pp : inputs) {
    1630      782363 :     if( pp->setForcePointer( name, val ) ) {
    1631             :       found=true;
    1632             :       break;
    1633             :     }
    1634             :   }
    1635      291165 :   plumed_massert( found, "found no action to set named " + name );
    1636      291165 : }
    1637             : 
    1638        1355 : void PlumedMain::setUnits( const bool& natural, const Units& u ) {
    1639        1355 :   passtools->usingNaturalUnits = natural;
    1640        1355 :   passtools->units=u;
    1641        1355 :   std::vector<ActionToPutData*> idata = actionSet.select<ActionToPutData*>();
    1642       10103 :   for(const auto & ip : idata) {
    1643        8748 :     ip->updateUnits( passtools.get() );
    1644             :   }
    1645       50928 :   for(const auto & p : actionSet ) {
    1646       49573 :     p->resetStoredTimestep();
    1647             :   }
    1648        1355 : }
    1649             : 
    1650      287076 : void PlumedMain::startStep() {
    1651      758745 :   for(const auto & ip : inputs) {
    1652      471669 :     ip->resetForStepStart();
    1653             :   }
    1654      287076 : }
    1655             : 
    1656         114 : void PlumedMain::writeBinary(std::ostream&o)const {
    1657         456 :   for(const auto & ip : inputs) {
    1658         342 :     ip->writeBinary(o);
    1659             :   }
    1660         114 : }
    1661             : 
    1662         114 : void PlumedMain::readBinary(std::istream&i) {
    1663         456 :   for(const auto & ip : inputs) {
    1664         342 :     ip->readBinary(i);
    1665             :   }
    1666         114 : }
    1667             : 
    1668          40 : void PlumedMain::setEnergyValue( const std::string& name ) {
    1669          40 :   name_of_energy = name;
    1670          40 : }
    1671             : 
    1672        8634 : int PlumedMain::getRealPrecision() const {
    1673        8634 :   return passtools->getRealPrecision();
    1674             : }
    1675             : 
    1676        5087 : bool PlumedMain::usingNaturalUnits() const {
    1677        5087 :   return passtools->usingNaturalUnits;
    1678             : }
    1679             : 
    1680    15620289 : const Units& PlumedMain::getUnits() {
    1681    15620289 :   return passtools->units;
    1682             : }
    1683             : 
    1684           4 : PlumedMain::DeprecatedAtoms& PlumedMain::getAtoms() {
    1685           4 :   return datoms;
    1686             : }
    1687             : 
    1688        7222 : void PlumedMain::plumedQuantityToMD( const std::string& unit, const double& eng, const TypesafePtr & m) const {
    1689        7222 :   passtools->double2MD( eng/passtools->getUnitConversion(unit),m );
    1690        7222 : }
    1691             : 
    1692           0 : double PlumedMain::MDQuantityToPLUMED( const std::string& unit, const TypesafePtr & m) const {
    1693           0 :   double x=passtools->MD2double(m);
    1694           0 :   return x*passtools->getUnitConversion(unit);
    1695             : }
    1696             : 
    1697           1 : double PlumedMain::DeprecatedAtoms::getKBoltzmann() const {
    1698           1 :   if( plumed.usingNaturalUnits() ) {
    1699             :     return 1.0;
    1700             :   }
    1701           1 :   return kBoltzmann/plumed.getUnits().getEnergy();
    1702             : }
    1703             : 
    1704           1 : double PlumedMain::DeprecatedAtoms::getKbT() const {
    1705           1 :   ActionForInterface* kb=plumed.getActionSet().selectWithLabel<ActionForInterface*>("kBT");
    1706           1 :   if( kb ) {
    1707           1 :     return (kb->copyOutput(0))->get();
    1708             :   }
    1709             :   return 0.0;
    1710             : }
    1711             : 
    1712           1 : int PlumedMain::DeprecatedAtoms::getNatoms() const {
    1713           1 :   std::vector<ActionToPutData*> inputs=plumed.getActionSet().select<ActionToPutData*>();
    1714           1 :   for(const auto & pp : inputs ) {
    1715           2 :     if( pp->getRole()=="x" ) {
    1716           1 :       return (pp->copyOutput(0))->getShape()[0];
    1717             :     }
    1718             :   }
    1719             :   return 0;
    1720             : }
    1721             : 
    1722           1 : bool PlumedMain::DeprecatedAtoms::usingNaturalUnits() const {
    1723           1 :   return plumed.usingNaturalUnits();
    1724             : }
    1725             : 
    1726           0 : void PlumedMain::DeprecatedAtoms::setCollectEnergy(bool b) const {
    1727           0 :   plumed.readInputWords( Tools::getWords(plumed.MDEngine + "_energy: ENERGY"), false );
    1728           0 :   plumed.setEnergyValue( plumed.MDEngine + "_energy" );
    1729           0 : }
    1730             : 
    1731           0 : double PlumedMain::DeprecatedAtoms::getEnergy() const {
    1732           0 :   ActionToPutData* av = plumed.getActionSet().selectWithLabel<ActionToPutData*>( plumed.MDEngine + "_energy" );
    1733           0 :   return (av->copyOutput(0))->get();
    1734             : }
    1735             : 
    1736           5 : void PlumedMain::activateParseOnlyMode() {
    1737           5 :   doParseOnly=true;
    1738           5 : }
    1739             : 
    1740        2260 : bool PlumedMain::parseOnlyMode() const {
    1741        2260 :   return doParseOnly;
    1742             : }
    1743             : 
    1744          97 : void PlumedMain::getKeywordsForAction( const std::string& action, Keywords& keys ) const {
    1745          97 :   actionRegister().getKeywords( dlloader.getHandles(), action, keys );
    1746          97 : }
    1747             : 
    1748             : #ifdef __PLUMED_HAS_PYTHON
    1749             : // This is here to stop cppcheck throwing an error
    1750             : #endif
    1751             : 
    1752             : #ifdef __PLUMED_HAS_DLADDR
    1753             : // This is here to stop cppcheck throwing an error
    1754             : #endif
    1755             : 
    1756             : }
    1757             : 
    1758             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.16