LCOV - code coverage report
Current view: top level - cltools - Driver.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 753 817 92.2 %
Date: 2025-11-25 13:55:50 Functions: 9 12 75.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-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 "CLTool.h"
      23             : #include "core/CLToolRegister.h"
      24             : #include "tools/Tools.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/ActionSet.h"
      27             : #include "core/ActionWithValue.h"
      28             : #include "core/ActionWithVirtualAtom.h"
      29             : #include "core/ActionShortcut.h"
      30             : #include "tools/Communicator.h"
      31             : #include "tools/Random.h"
      32             : #include "tools/Pbc.h"
      33             : #include <cstdio>
      34             : #include <cstring>
      35             : #include <vector>
      36             : #include <map>
      37             : #include <memory>
      38             : #include "tools/Units.h"
      39             : #include "tools/PDB.h"
      40             : #include "tools/FileBase.h"
      41             : #include "tools/IFile.h"
      42             : #include "xdrfile/xdrfile_trr.h"
      43             : #include "xdrfile/xdrfile_xtc.h"
      44             : 
      45             : 
      46             : // when using molfile plugin
      47             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
      48             : #ifndef __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS
      49             : /* Use the internal ones. Alternatively:
      50             :  *    ifeq (,$(findstring __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS,$(CPPFLAGS)))
      51             :  *    CPPFLAGS+=-I../molfile
      52             :  */
      53             : #include "molfile/libmolfile_plugin.h"
      54             : #include "molfile/molfile_plugin.h"
      55             : using namespace PLMD::molfile;
      56             : #else
      57             : #include <libmolfile_plugin.h>
      58             : #include <molfile_plugin.h>
      59             : #endif
      60             : #endif
      61             : 
      62             : namespace PLMD {
      63             : namespace cltools {
      64             : 
      65             : //+PLUMEDOC TOOLS driver-float
      66             : /*
      67             : Equivalent to driver, but using single precision reals.
      68             : 
      69             : The purpose of this tool is just to test what PLUMED does when linked from
      70             : a single precision code.  The documentation is identical to that for \ref driver
      71             : 
      72             : \par Examples
      73             : 
      74             : \verbatim
      75             : plumed driver-float --plumed plumed.dat --ixyz trajectory.xyz
      76             : \endverbatim
      77             : 
      78             : See also examples in \ref driver
      79             : 
      80             : */
      81             : //+ENDPLUMEDOC
      82             : //
      83             : 
      84             : 
      85             : //+PLUMEDOC TOOLS driver
      86             : /*
      87             : driver is a tool that allows one to to use plumed to post-process an existing trajectory.
      88             : 
      89             : The input to driver is specified using the command line arguments described below.
      90             : 
      91             : In addition, you can use the special \subpage READ command inside your plumed input
      92             : to read in colvar files that were generated during your MD simulation.  The values
      93             : read in can then be treated like calculated colvars.
      94             : 
      95             : \warning
      96             : Notice that by default the driver has no knowledge about the masses and charges
      97             : of your atoms! Thus, if you want to compute quantities depending charges (e.g. \ref DHENERGY)
      98             : or masses (e.g. \ref COM) you should pass the proper information to the driver.
      99             : You can do it either with the --pdb option or with the --mc option. The latter
     100             : will read a file produced by \ref DUMPMASSCHARGE .
     101             : 
     102             : 
     103             : \par Examples
     104             : 
     105             : The following command tells plumed to post process the trajectory contained in `trajectory.xyz`
     106             :  by performing the actions described in the input file `plumed.dat`.  If an action that takes the
     107             : stride keyword is given a stride equal to \f$n\f$ then it will be performed only on every \f$n\f$th
     108             : frames in the trajectory file.
     109             : \verbatim
     110             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz
     111             : \endverbatim
     112             : 
     113             : Notice that `xyz` files are expected to be in internal PLUMED units, that is by default nm.
     114             : You can change this behavior by using the `--length-units` option:
     115             : \verbatim
     116             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz --length-units A
     117             : \endverbatim
     118             : The strings accepted by the `--length-units` options are the same ones accepted by the \ref UNITS action.
     119             : Other file formats typically have their default coordinates (e.g., `gro` files are always in nm)
     120             : and it thus should not be necessary to use the `--length-units` option. Additionally,
     121             : consider that the units used by the `driver` might be different by the units used in the PLUMED input
     122             : file `plumed.dat`. For instance consider the command:
     123             : \verbatim
     124             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz --length-units A
     125             : \endverbatim
     126             : where `plumed.dat` is
     127             : \plumedfile
     128             : # no explicit UNITS action here
     129             : d: DISTANCE ATOMS=1,2
     130             : PRINT ARG=d FILE=colvar
     131             : \endplumedfile
     132             : In this case, the driver reads the `xyz` file assuming it to contain coordinates in Angstrom units.
     133             : However, the resulting `colvar` file contains a distance expressed in nm.
     134             : 
     135             : The following command tells plumed to post process the trajectory contained in trajectory.xyz.
     136             :  by performing the actions described in the input file plumed.dat.
     137             : \verbatim
     138             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz --trajectory-stride 100 --timestep 0.001
     139             : \endverbatim
     140             : Here though
     141             : `--trajectory-stride` is set equal to the frequency with which frames were output during the trajectory
     142             : and the `--timestep` is equal to the simulation timestep.  As such the `STRIDE` parameters in the `plumed.dat`
     143             : files are referred to the original timestep and any files output resemble those that would have been generated
     144             : had we run the calculation we are running with driver when the MD simulation was running.
     145             : 
     146             : PLUMED can read xyz files (in PLUMED units) and gro files (in nm). In addition,
     147             : PLUMED includes by default support for a
     148             : subset of the trajectory file formats supported by VMD, e.g. xtc and dcd:
     149             : 
     150             : \verbatim
     151             : plumed driver --plumed plumed.dat --pdb diala.pdb --mf_xtc traj.xtc --trajectory-stride 100 --timestep 0.001
     152             : \endverbatim
     153             : 
     154             : where `--mf_` prefixes the extension of one of the accepted molfile plugin format.
     155             : If PLUMED has been \ref Installation "installed" with full molfile support, other formats will be available.
     156             : Just type `plumed driver --help` to see which plugins are available.
     157             : 
     158             : Molfile plugin require periodic cell to be triangular (i.e. first vector oriented along x and
     159             : second vector in xy plane). This is true for many MD codes. However, it could be false
     160             : if you rotate the coordinates in your trajectory before reading them in the driver.
     161             : Also notice that some formats (e.g. amber crd) do not specify atom number. In this case you can use
     162             : the `--natoms` option:
     163             : \verbatim
     164             : plumed driver --plumed plumed.dat --imf_crd trajectory.crd --natoms 128
     165             : \endverbatim
     166             : 
     167             : Check the available molfile plugins and limitations at [this link](http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/).
     168             : 
     169             : Additionally, you can use the xdrfile implementation of xtc and trr. To this aim, just
     170             : download and install properly the xdrfile library (see [this link](http://www.gromacs.org/Developer_Zone/Programming_Guide/XTC_Library)).
     171             : If the xdrfile library is installed properly the PLUMED configure script should be able to
     172             : detect it and enable it.
     173             : Notice that the xdrfile implementation of xtc and trr
     174             : is more robust than the molfile one, since it provides support for generic cell shapes.
     175             : In addition, it allows \ref DUMPATOMS to write compressed xtc files.
     176             : 
     177             : \par Multiple replicas
     178             : 
     179             : When PLUMED is compiled with MPI support, you can emulate a multi-simulation setup with the `driver` by providing the `--multi`
     180             : option with the appropriate number of ranks. This allows to use the \ref special-replica-syntax and to analyze multiple
     181             : trajectories (see \ref trieste-5-replicas). PLUMED will automatically append a numbered suffix to output files
     182             : (e.g. `COLVAR.0`, `COLVAR.1`, …). Similarly, each replica will search for the corresponding suffixed input file (e.g. `traj.0.xtc`, …)
     183             : or default to the unsuffixed one.
     184             : 
     185             : */
     186             : //+ENDPLUMEDOC
     187             : //
     188             : 
     189             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     190             : static std::vector<molfile_plugin_t *> plugins;
     191             : static std::map <std::string, unsigned> pluginmap;
     192       97956 : static int register_cb(void *v, vmdplugin_t *p) {
     193             :   //const char *key = p->name;
     194      195912 :   const auto ret = pluginmap.insert ( std::pair<std::string,unsigned>(std::string(p->name),plugins.size()) );
     195       97956 :   if (ret.second==false) {
     196             :     //cerr<<"MOLFILE: found duplicate plugin for "<<key<<" : not inserted "<<endl;
     197             :   } else {
     198             :     //cerr<<"MOLFILE: loading plugin "<<key<<" number "<<plugins.size()-1<<endl;
     199       97956 :     plugins.push_back(reinterpret_cast<molfile_plugin_t *>(p));
     200             :   }
     201       97956 :   return VMDPLUGIN_SUCCESS;
     202             : }
     203             : #endif
     204             : 
     205             : template<typename real>
     206             : class Driver : public CLTool {
     207             : public:
     208             :   static void registerKeywords( Keywords& keys );
     209             :   explicit Driver(const CLToolOptions& co );
     210             :   int main(FILE* in,FILE*out,Communicator& pc) override;
     211             :   void evaluateNumericalDerivatives( const long long int& step, PlumedMain& p, const std::vector<real>& coordinates,
     212             :                                      const std::vector<real>& masses, const std::vector<real>& charges,
     213             :                                      std::vector<real>& cell, const double& base, std::vector<real>& numder );
     214             :   std::string description()const override;
     215             : };
     216             : 
     217             : template<typename real>
     218       10884 : void Driver<real>::registerKeywords( Keywords& keys ) {
     219       10884 :   CLTool::registerKeywords( keys );
     220             :   keys.isDriver();
     221       21768 :   keys.addFlag("--help-debug",false,"print special options that can be used to create regtests");
     222       21768 :   keys.add("compulsory","--plumed","plumed.dat","specify the name of the plumed input file");
     223       21768 :   keys.add("compulsory","--timestep","1.0","the timestep that was used in the calculation that produced this trajectory in picoseconds");
     224       21768 :   keys.add("compulsory","--trajectory-stride","1","the frequency with which frames were output to this trajectory during the simulation"
     225             :            " (0 means that the number of the step is read from the trajectory file,"
     226             :            " currently working only for xtc/trr files read with --ixtc/--trr)"
     227             :           );
     228       21768 :   keys.add("compulsory","--multi","0","set number of replicas for multi environment (needs MPI)");
     229       21768 :   keys.addFlag("--noatoms",false,"don't read in a trajectory.  Just use colvar files as specified in plumed.dat");
     230       21768 :   keys.addFlag("--parse-only",false,"read the plumed input file and stop");
     231       21768 :   keys.addFlag("--restart",false,"makes driver behave as if restarting");
     232       21768 :   keys.add("atoms","--ixyz","the trajectory in xyz format");
     233       21768 :   keys.add("atoms","--igro","the trajectory in gro format");
     234       21768 :   keys.add("atoms","--idlp4","the trajectory in DL_POLY_4 format");
     235       21768 :   keys.add("atoms","--ixtc","the trajectory in xtc format (xdrfile implementation)");
     236       21768 :   keys.add("atoms","--itrr","the trajectory in trr format (xdrfile implementation)");
     237       21768 :   keys.add("optional","--shortcut-ofile","the name of the file to output info on the way shortcuts have been expanded.  If there are no shortcuts in your input file nothing is output");
     238       21768 :   keys.add("optional","--valuedict-ofile","output a dictionary giving information about each value in the input file");
     239       21768 :   keys.add("optional","--length-units","units for length, either as a string or a number");
     240       21768 :   keys.add("optional","--mass-units","units for mass in pdb and mc file, either as a string or a number");
     241       21768 :   keys.add("optional","--charge-units","units for charge in pdb and mc file, either as a string or a number");
     242       21768 :   keys.add("optional","--kt","set \\f$k_B T\\f$, it will not be necessary to specify temperature in input file");
     243       21768 :   keys.add("optional","--dump-forces","dump the forces on a file");
     244       21768 :   keys.add("optional","--dump-forces-fmt","( default=%%f ) the format to use to dump the forces");
     245       21768 :   keys.addFlag("--dump-full-virial",false,"with --dump-forces, it dumps the 9 components of the virial");
     246       21768 :   keys.add("optional","--pdb","provides a pdb with masses and charges");
     247       21768 :   keys.add("optional","--mc","provides a file with masses and charges as produced with DUMPMASSCHARGE");
     248       21768 :   keys.add("optional","--box","comma-separated box dimensions (3 for orthorhombic, 9 for generic)");
     249       21768 :   keys.add("optional","--natoms","provides number of atoms - only used if file format does not contain number of atoms");
     250       21768 :   keys.add("optional","--initial-step","provides a number for the initial step, default is 0");
     251       21768 :   keys.add("optional","--debug-forces","output a file containing the forces due to the bias evaluated using numerical derivatives "
     252             :            "and using the analytical derivatives implemented in plumed");
     253       21768 :   keys.add("hidden","--debug-float","[yes/no] turns on the single precision version (to check float interface)");
     254       21768 :   keys.add("hidden","--debug-dd","[yes/no] use a fake domain decomposition");
     255       21768 :   keys.add("hidden","--debug-pd","[yes/no] use a fake particle decomposition");
     256       21768 :   keys.add("hidden","--debug-grex","use a fake gromacs-like replica exchange, specify exchange stride");
     257       21768 :   keys.add("hidden","--debug-grex-log","log file for debug=grex");
     258             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     259       10884 :   MOLFILE_INIT_ALL
     260       10884 :   MOLFILE_REGISTER_ALL(NULL, register_cb)
     261      108840 :   for(unsigned i=0; i<plugins.size(); i++) {
     262      195912 :     std::string kk="--mf_"+std::string(plugins[i]->name);
     263      195912 :     std::string mm=" molfile: the trajectory in "+std::string(plugins[i]->name)+" format " ;
     264      195912 :     keys.add("atoms",kk,mm);
     265             :   }
     266             : #endif
     267       10884 : }
     268             : template<typename real>
     269         975 : Driver<real>::Driver(const CLToolOptions& co ):
     270         975 :   CLTool(co) {
     271         975 :   inputdata=commandline;
     272         975 : }
     273             : template<typename real>
     274           4 : std::string Driver<real>::description()const {
     275           4 :   return "analyze trajectories with plumed";
     276             : }
     277             : 
     278             : template<typename real>
     279         967 : int Driver<real>::main(FILE* in,FILE*out,Communicator& pc) {
     280             : 
     281         967 :   Units units;
     282         967 :   PDB pdb;
     283             : 
     284             : // Parse everything
     285             :   bool printhelpdebug;
     286         967 :   parseFlag("--help-debug",printhelpdebug);
     287         967 :   if( printhelpdebug ) {
     288             :     std::fprintf(out,"%s",
     289             :                  "Additional options for debug (only to be used in regtest):\n"
     290             :                  "  [--debug-float yes]     : turns on the single precision version (to check float interface)\n"
     291             :                  "  [--debug-dd yes]        : use a fake domain decomposition\n"
     292             :                  "  [--debug-pd yes]        : use a fake particle decomposition\n"
     293             :                 );
     294             :     return 0;
     295             :   }
     296             :   // Are we reading trajectory data
     297             :   bool noatoms;
     298         967 :   parseFlag("--noatoms",noatoms);
     299             :   bool parseOnly;
     300        1934 :   parseFlag("--parse-only",parseOnly);
     301             :   std::string full_outputfile;
     302        1934 :   parse("--shortcut-ofile",full_outputfile);
     303             :   std::string valuedict_file;
     304         967 :   parse("--valuedict-ofile",valuedict_file);
     305             :   bool restart;
     306        1934 :   parseFlag("--restart",restart);
     307             : 
     308             :   std::string fakein;
     309             :   bool debug_float=false;
     310             :   fakein="";
     311        1934 :   if(parse("--debug-float",fakein)) {
     312           0 :     if(fakein=="yes") {
     313             :       debug_float=true;
     314           0 :     } else if(fakein=="no") {
     315             :       debug_float=false;
     316             :     } else {
     317           0 :       error("--debug-float should have argument yes or no");
     318             :     }
     319             :   }
     320             : 
     321             :   if(debug_float && sizeof(real)!=sizeof(float)) {
     322           0 :     auto cl=cltoolRegister().create(CLToolOptions("driver-float"));
     323             :     cl->setInputData(this->getInputData());
     324           0 :     int ret=cl->main(in,out,pc);
     325             :     return ret;
     326           0 :   }
     327             : 
     328             :   bool debug_pd=false;
     329             :   fakein="";
     330        1934 :   if(parse("--debug-pd",fakein)) {
     331          12 :     if(fakein=="yes") {
     332             :       debug_pd=true;
     333           0 :     } else if(fakein=="no") {
     334             :       debug_pd=false;
     335             :     } else {
     336           0 :       error("--debug-pd should have argument yes or no");
     337             :     }
     338             :   }
     339             :   if(debug_pd) {
     340             :     std::fprintf(out,"DEBUGGING PARTICLE DECOMPOSITION\n");
     341             :   }
     342             : 
     343             :   bool debug_dd=false;
     344             :   fakein="";
     345        1934 :   if(parse("--debug-dd",fakein)) {
     346          60 :     if(fakein=="yes") {
     347             :       debug_dd=true;
     348           0 :     } else if(fakein=="no") {
     349             :       debug_dd=false;
     350             :     } else {
     351           0 :       error("--debug-dd should have argument yes or no");
     352             :     }
     353             :   }
     354             :   if(debug_dd) {
     355             :     std::fprintf(out,"DEBUGGING DOMAIN DECOMPOSITION\n");
     356             :   }
     357             : 
     358         967 :   if( debug_pd || debug_dd ) {
     359          72 :     if(noatoms) {
     360           0 :       error("cannot debug without atoms");
     361             :     }
     362             :   }
     363             : 
     364             : // set up for multi replica driver:
     365         967 :   int multi=0;
     366         967 :   parse("--multi",multi);
     367         967 :   Communicator intracomm;
     368         967 :   Communicator intercomm;
     369         967 :   if(multi) {
     370         174 :     int ntot=pc.Get_size();
     371         174 :     int nintra=ntot/multi;
     372         174 :     if(multi*nintra!=ntot) {
     373           0 :       error("invalid number of processes for multi environment");
     374             :     }
     375         174 :     pc.Split(pc.Get_rank()/nintra,pc.Get_rank(),intracomm);
     376         174 :     pc.Split(pc.Get_rank()%nintra,pc.Get_rank(),intercomm);
     377             :   } else {
     378         793 :     intracomm.Set_comm(pc.Get_comm());
     379             :   }
     380             : 
     381             : // set up for debug replica exchange:
     382         967 :   bool debug_grex=parse("--debug-grex",fakein);
     383         967 :   int  grex_stride=0;
     384             :   FILE*grex_log=NULL;
     385             : // call fclose when fp goes out of scope
     386        1209 :   auto deleter=[](auto f) {
     387             :     if(f) {
     388        1209 :       std::fclose(f);
     389             :     }
     390             :   };
     391             :   std::unique_ptr<FILE,decltype(deleter)> grex_log_deleter(grex_log,deleter);
     392             : 
     393         967 :   if(debug_grex) {
     394          30 :     if(noatoms) {
     395           0 :       error("must have atoms to debug_grex");
     396             :     }
     397          30 :     if(multi<2) {
     398           0 :       error("--debug_grex needs --multi with at least two replicas");
     399             :     }
     400          30 :     Tools::convert(fakein,grex_stride);
     401             :     std::string n;
     402          30 :     Tools::convert(intercomm.Get_rank(),n);
     403             :     std::string file;
     404          60 :     parse("--debug-grex-log",file);
     405          30 :     if(file.length()>0) {
     406          60 :       file+="."+n;
     407          30 :       grex_log=std::fopen(file.c_str(),"w");
     408             :       grex_log_deleter.reset(grex_log);
     409             :     }
     410             :   }
     411             : 
     412             : // Read the plumed input file name
     413             :   std::string plumedFile;
     414         967 :   parse("--plumed",plumedFile);
     415             : // the timestep
     416             :   double t;
     417         967 :   parse("--timestep",t);
     418         967 :   real timestep=real(t);
     419             : // the stride
     420             :   unsigned stride;
     421         967 :   parse("--trajectory-stride",stride);
     422             : // are we writing forces
     423         967 :   std::string dumpforces(""), debugforces(""), dumpforcesFmt("%f");;
     424         967 :   bool dumpfullvirial=false;
     425         967 :   if(!noatoms) {
     426         911 :     parse("--dump-forces",dumpforces);
     427        1822 :     parse("--debug-forces",debugforces);
     428             :   }
     429        1363 :   if(dumpforces!="" || debugforces!="" ) {
     430        1162 :     parse("--dump-forces-fmt",dumpforcesFmt);
     431             :   }
     432         967 :   if(dumpforces!="") {
     433        1142 :     parseFlag("--dump-full-virial",dumpfullvirial);
     434             :   }
     435         967 :   if( debugforces!="" && (debug_dd || debug_pd) ) {
     436           0 :     error("cannot debug forces and domain/particle decomposition at same time");
     437             :   }
     438           0 :   if( debugforces!="" && sizeof(real)!=sizeof(double) ) {
     439           0 :     error("cannot debug forces in single precision mode");
     440             :   }
     441             : 
     442         967 :   real kt=-1.0;
     443        1934 :   parse("--kt",kt);
     444             :   std::string trajectory_fmt;
     445             : 
     446             :   bool use_molfile=false;
     447             :   molfile_plugin_t *api=NULL;
     448             : 
     449             : // Read in an xyz file
     450         967 :   std::string trajectoryFile(""), pdbfile(""), mcfile("");
     451             :   bool pbc_cli_given=false;
     452         967 :   std::vector<double> pbc_cli_box(9,0.0);
     453         967 :   int command_line_natoms=-1;
     454             : 
     455         967 :   if(!noatoms) {
     456             :     std::string traj_xyz;
     457        1822 :     parse("--ixyz",traj_xyz);
     458             :     std::string traj_gro;
     459        1822 :     parse("--igro",traj_gro);
     460             :     std::string traj_dlp4;
     461        1822 :     parse("--idlp4",traj_dlp4);
     462             :     std::string traj_xtc;
     463             :     std::string traj_trr;
     464         911 :     parse("--ixtc",traj_xtc);
     465         911 :     parse("--itrr",traj_trr);
     466             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     467        9110 :     for(unsigned i=0; i<plugins.size(); i++) {
     468       16398 :       std::string molfile_key="--mf_"+std::string(plugins[i]->name);
     469             :       std::string traj_molfile;
     470        8199 :       parse(molfile_key,traj_molfile);
     471        8199 :       if(traj_molfile.length()>0) {
     472         287 :         std::fprintf(out,"\nDRIVER: Found molfile format trajectory %s with name %s\n",plugins[i]->name,traj_molfile.c_str());
     473             :         trajectoryFile=traj_molfile;
     474         574 :         trajectory_fmt=std::string(plugins[i]->name);
     475             :         use_molfile=true;
     476         287 :         api = plugins[i];
     477             :       }
     478             :     }
     479             : #endif
     480             :     {
     481             :       // check that only one fmt is specified
     482             :       int nn=0;
     483         911 :       if(traj_xyz.length()>0) {
     484             :         nn++;
     485             :       }
     486         911 :       if(traj_gro.length()>0) {
     487         114 :         nn++;
     488             :       }
     489         911 :       if(traj_dlp4.length()>0) {
     490           2 :         nn++;
     491             :       }
     492         911 :       if(traj_xtc.length()>0) {
     493           2 :         nn++;
     494             :       }
     495         911 :       if(traj_trr.length()>0) {
     496           9 :         nn++;
     497             :       }
     498         911 :       if(nn>1) {
     499           0 :         std::fprintf(stderr,"ERROR: cannot provide more than one trajectory file\n");
     500             :         return 1;
     501             :       }
     502             :     }
     503         911 :     if(traj_xyz.length()>0 && trajectoryFile.length()==0) {
     504             :       trajectoryFile=traj_xyz;
     505             :       trajectory_fmt="xyz";
     506             :     }
     507         911 :     if(traj_gro.length()>0 && trajectoryFile.length()==0) {
     508             :       trajectoryFile=traj_gro;
     509             :       trajectory_fmt="gro";
     510             :     }
     511         911 :     if(traj_dlp4.length()>0 && trajectoryFile.length()==0) {
     512             :       trajectoryFile=traj_dlp4;
     513             :       trajectory_fmt="dlp4";
     514             :     }
     515         911 :     if(traj_xtc.length()>0 && trajectoryFile.length()==0) {
     516             :       trajectoryFile=traj_xtc;
     517             :       trajectory_fmt="xdr-xtc";
     518             :     }
     519         911 :     if(traj_trr.length()>0 && trajectoryFile.length()==0) {
     520             :       trajectoryFile=traj_trr;
     521             :       trajectory_fmt="xdr-trr";
     522             :     }
     523         911 :     if(trajectoryFile.length()==0&&!parseOnly) {
     524           0 :       std::fprintf(stderr,"ERROR: missing trajectory data\n");
     525             :       return 1;
     526             :     }
     527         911 :     std::string lengthUnits("");
     528        1822 :     parse("--length-units",lengthUnits);
     529         911 :     if(lengthUnits.length()>0) {
     530          23 :       units.setLength(lengthUnits);
     531             :     }
     532         911 :     std::string chargeUnits("");
     533        1822 :     parse("--charge-units",chargeUnits);
     534         911 :     if(chargeUnits.length()>0) {
     535           1 :       units.setCharge(chargeUnits);
     536             :     }
     537         911 :     std::string massUnits("");
     538        1822 :     parse("--mass-units",massUnits);
     539         911 :     if(massUnits.length()>0) {
     540           1 :       units.setMass(massUnits);
     541             :     }
     542             : 
     543        1822 :     parse("--pdb",pdbfile);
     544         911 :     if(pdbfile.length()>0) {
     545          79 :       bool check=pdb.read(pdbfile,false,1.0);
     546          79 :       if(!check) {
     547           0 :         error("error reading pdb file");
     548             :       }
     549             :     }
     550             : 
     551        1822 :     parse("--mc",mcfile);
     552             : 
     553             :     std::string pbc_cli_list;
     554        1822 :     parse("--box",pbc_cli_list);
     555         911 :     if(pbc_cli_list.length()>0) {
     556             :       pbc_cli_given=true;
     557          43 :       std::vector<std::string> words=Tools::getWords(pbc_cli_list,",");
     558          43 :       if(words.size()==3) {
     559         172 :         for(int i=0; i<3; i++) {
     560         129 :           std::sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[4*i]));
     561             :         }
     562           0 :       } else if(words.size()==9) {
     563           0 :         for(int i=0; i<9; i++) {
     564           0 :           std::sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[i]));
     565             :         }
     566             :       } else {
     567           0 :         std::string msg="ERROR: cannot parse command-line box "+pbc_cli_list;
     568           0 :         std::fprintf(stderr,"%s\n",msg.c_str());
     569             :         return 1;
     570             :       }
     571             : 
     572          43 :     }
     573             : 
     574        1822 :     parse("--natoms",command_line_natoms);
     575             : 
     576             :   }
     577             : 
     578             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     579         287 :   auto mf_deleter=[api](void* h_in) {
     580         287 :     if(h_in) {
     581         287 :       std::unique_ptr<std::lock_guard<std::mutex>> lck;
     582         287 :       if(api->is_reentrant==VMDPLUGIN_THREADUNSAFE) {
     583         444 :         lck=Tools::molfile_lock();
     584             :       }
     585         287 :       api->close_file_read(h_in);
     586         287 :     }
     587             :   };
     588             :   void *h_in=NULL;
     589             :   std::unique_ptr<void,decltype(mf_deleter)> h_in_deleter(h_in,mf_deleter);
     590             : 
     591             :   molfile_timestep_t ts_in; // this is the structure that has the timestep
     592             : // a std::vector<float> with the same scope as ts_in
     593             : // it is necessary in order to store the pointer to ts_in.coords
     594             :   std::vector<float> ts_in_coords;
     595         967 :   ts_in.coords=ts_in_coords.data();
     596         967 :   ts_in.velocities=NULL;
     597         967 :   ts_in.A=-1; // we use this to check whether cell is provided or not
     598             : #endif
     599             : 
     600             : 
     601             : 
     602         967 :   if(debug_dd && debug_pd) {
     603           0 :     error("cannot use debug-dd and debug-pd at the same time");
     604             :   }
     605         967 :   if(debug_pd || debug_dd) {
     606          72 :     if( !Communicator::initialized() ) {
     607           0 :       error("needs mpi for debug-pd");
     608             :     }
     609             :   }
     610             : 
     611         967 :   PlumedMain p;
     612         967 :   if( parseOnly ) {
     613           5 :     p.activateParseOnlyMode();
     614             :   }
     615         967 :   p.cmd("setRealPrecision",(int)sizeof(real));
     616             :   int checknatoms=-1;
     617         967 :   long long int step=0;
     618         967 :   parse("--initial-step",step);
     619             : 
     620         967 :   if(restart) {
     621           2 :     p.cmd("setRestart",1);
     622             :   }
     623             : 
     624         967 :   if(Communicator::initialized()) {
     625         328 :     if(multi) {
     626         174 :       if(intracomm.Get_rank()==0) {
     627         252 :         p.cmd("GREX setMPIIntercomm",&intercomm.Get_comm());
     628             :       }
     629         348 :       p.cmd("GREX setMPIIntracomm",&intracomm.Get_comm());
     630         174 :       p.cmd("GREX init");
     631             :     }
     632         656 :     p.cmd("setMPIComm",&intracomm.Get_comm());
     633             :   }
     634         967 :   p.cmd("setLog",out);
     635         967 :   p.cmd("setMDLengthUnits",units.getLength());
     636         967 :   p.cmd("setMDChargeUnits",units.getCharge());
     637         967 :   p.cmd("setMDMassUnits",units.getMass());
     638         967 :   p.cmd("setMDEngine","driver");
     639         967 :   p.cmd("setTimestep",timestep);
     640         967 :   if( !parseOnly || full_outputfile.length()==0 ) {
     641         962 :     p.cmd("setPlumedDat",plumedFile.c_str());
     642             :   }
     643             : 
     644             :   int natoms;
     645         967 :   int lvl=0;
     646         967 :   int pb=1;
     647             : 
     648         967 :   if(parseOnly) {
     649           5 :     if(command_line_natoms<0) {
     650           0 :       error("--parseOnly requires setting the number of atoms with --natoms");
     651             :     }
     652           5 :     natoms=command_line_natoms;
     653             :   }
     654             : 
     655             : 
     656             :   FILE* fp=NULL;
     657             :   FILE* fp_forces=NULL;
     658         967 :   OFile fp_dforces;
     659             : 
     660             :   std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
     661             :   std::unique_ptr<FILE,decltype(deleter)> fp_forces_deleter(fp_forces,deleter);
     662             : 
     663          11 :   auto xdr_deleter=[](auto xd) {
     664             :     if(xd) {
     665          11 :       xdrfile::xdrfile_close(xd);
     666             :     }
     667             :   };
     668             : 
     669             :   xdrfile::XDRFILE* xd=NULL;
     670             : 
     671             :   std::unique_ptr<xdrfile::XDRFILE,decltype(xdr_deleter)> xd_deleter(xd,xdr_deleter);
     672             : 
     673         967 :   if(!noatoms&&!parseOnly) {
     674         906 :     if (trajectoryFile=="-") {
     675             :       fp=in;
     676             :     } else {
     677         906 :       if(multi) {
     678             :         std::string n;
     679         174 :         Tools::convert(intercomm.Get_rank(),n);
     680         348 :         std::string testfile=FileBase::appendSuffix(trajectoryFile,"."+n);
     681         174 :         FILE* tmp_fp=std::fopen(testfile.c_str(),"r");
     682             :         // no exceptions here
     683         174 :         if(tmp_fp) {
     684         135 :           std::fclose(tmp_fp);
     685             :           trajectoryFile=testfile;
     686             :         }
     687             :       }
     688         906 :       if(use_molfile==true) {
     689             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     690         287 :         std::unique_ptr<std::lock_guard<std::mutex>> lck;
     691         287 :         if(api->is_reentrant==VMDPLUGIN_THREADUNSAFE) {
     692         444 :           lck=Tools::molfile_lock();
     693             :         }
     694         287 :         h_in = api->open_file_read(trajectoryFile.c_str(), trajectory_fmt.c_str(), &natoms);
     695             :         h_in_deleter.reset(h_in);
     696         287 :         if(natoms==MOLFILE_NUMATOMS_UNKNOWN) {
     697           2 :           if(command_line_natoms>=0) {
     698           2 :             natoms=command_line_natoms;
     699             :           } else {
     700           0 :             error("this file format does not provide number of atoms; use --natoms on the command line");
     701             :           }
     702             :         }
     703         287 :         ts_in_coords.resize(3*natoms);
     704         287 :         ts_in.coords = ts_in_coords.data();
     705             : #endif
     706        1523 :       } else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr") {
     707          11 :         xd=xdrfile::xdrfile_open(trajectoryFile.c_str(),"r");
     708             :         xd_deleter.reset(xd);
     709          11 :         if(!xd) {
     710           0 :           std::string msg="ERROR: Error opening trajectory file "+trajectoryFile;
     711           0 :           std::fprintf(stderr,"%s\n",msg.c_str());
     712             :           return 1;
     713             :         }
     714          11 :         if(trajectory_fmt=="xdr-xtc") {
     715           2 :           xdrfile::read_xtc_natoms(&trajectoryFile[0],&natoms);
     716             :         }
     717          11 :         if(trajectory_fmt=="xdr-trr") {
     718           9 :           xdrfile::read_trr_natoms(&trajectoryFile[0],&natoms);
     719             :         }
     720             :       } else {
     721         608 :         fp=std::fopen(trajectoryFile.c_str(),"r");
     722             :         fp_deleter.reset(fp);
     723         608 :         if(!fp) {
     724           0 :           std::string msg="ERROR: Error opening trajectory file "+trajectoryFile;
     725           0 :           std::fprintf(stderr,"%s\n",msg.c_str());
     726             :           return 1;
     727             :         }
     728             :       }
     729             :     }
     730         906 :     if(dumpforces.length()>0) {
     731         571 :       if(Communicator::initialized() && pc.Get_size()>1) {
     732             :         std::string n;
     733         240 :         Tools::convert(pc.Get_rank(),n);
     734         480 :         dumpforces+="."+n;
     735             :       }
     736         571 :       fp_forces=std::fopen(dumpforces.c_str(),"w");
     737             :       fp_forces_deleter.reset(fp_forces);
     738             :     }
     739         906 :     if(debugforces.length()>0) {
     740          15 :       if(Communicator::initialized() && pc.Get_size()>1) {
     741             :         std::string n;
     742           6 :         Tools::convert(pc.Get_rank(),n);
     743          12 :         debugforces+="."+n;
     744             :       }
     745          15 :       fp_dforces.open(debugforces);
     746             :     }
     747             :   }
     748             : 
     749             :   std::string line;
     750             :   std::vector<real> coordinates;
     751             :   std::vector<real> forces;
     752             :   std::vector<real> masses;
     753             :   std::vector<real> charges;
     754             :   std::vector<real> cell;
     755             :   std::vector<real> virial;
     756             :   std::vector<real> numder;
     757             : 
     758             : // variables to test particle decomposition
     759             :   int pd_nlocal=0;
     760             :   int pd_start=0;
     761             : // variables to test random decomposition (=domain decomposition)
     762             :   std::vector<int>  dd_gatindex;
     763             :   std::vector<int>  dd_g2l;
     764             :   std::vector<real> dd_masses;
     765             :   std::vector<real> dd_charges;
     766             :   std::vector<real> dd_forces;
     767             :   std::vector<real> dd_coordinates;
     768             :   int dd_nlocal=0;
     769             : // random stream to choose decompositions
     770         967 :   Random rnd;
     771             : 
     772         967 :   if(trajectory_fmt=="dlp4") {
     773           2 :     if(!Tools::getline(fp,line)) {
     774           0 :       error("error reading title");
     775             :     }
     776           2 :     if(!Tools::getline(fp,line)) {
     777           0 :       error("error reading atoms");
     778             :     }
     779           2 :     std::sscanf(line.c_str(),"%d %d %d",&lvl,&pb,&natoms);
     780             : 
     781             :   }
     782             :   bool lstep=true;
     783      260267 :   while(true) {
     784      261234 :     if(!noatoms&&!parseOnly) {
     785       60647 :       if(use_molfile==true) {
     786             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     787       21010 :         std::unique_ptr<std::lock_guard<std::mutex>> lck;
     788       21010 :         if(api->is_reentrant==VMDPLUGIN_THREADUNSAFE) {
     789       41658 :           lck=Tools::molfile_lock();
     790             :         }
     791             :         int rc;
     792       21010 :         rc = api->read_next_timestep(h_in, natoms, &ts_in);
     793       21010 :         if(rc==MOLFILE_EOF) {
     794             :           break;
     795             :         }
     796             : #endif
     797       73355 :       } else if(trajectory_fmt=="xyz" || trajectory_fmt=="gro" || trajectory_fmt=="dlp4") {
     798       39532 :         if(!Tools::getline(fp,line)) {
     799             :           break;
     800             :         }
     801             :       }
     802             :     }
     803             :     bool first_step=false;
     804      260343 :     if(!noatoms&&!parseOnly) {
     805      111257 :       if(use_molfile==false && (trajectory_fmt=="xyz" || trajectory_fmt=="gro")) {
     806       38908 :         if(trajectory_fmt=="gro")
     807       12343 :           if(!Tools::getline(fp,line)) {
     808           0 :             error("premature end of trajectory file");
     809             :           }
     810       38908 :         std::sscanf(line.c_str(),"%100d",&natoms);
     811             :       }
     812       98789 :       if(use_molfile==false && trajectory_fmt=="dlp4") {
     813             :         char xa[9];
     814             :         int xb,xc,xd;
     815             :         double t;
     816          20 :         std::sscanf(line.c_str(),"%8s %lld %d %d %d %lf",xa,&step,&xb,&xc,&xd,&t);
     817          20 :         if (lstep) {
     818           2 :           p.cmd("setTimestep",real(t));
     819             :           lstep = false;
     820             :         }
     821             :       }
     822             :     }
     823      260343 :     if(checknatoms<0 && !noatoms) {
     824         911 :       pd_nlocal=natoms;
     825             :       pd_start=0;
     826             :       first_step=true;
     827         911 :       masses.assign(natoms,std::numeric_limits<real>::quiet_NaN());
     828         911 :       charges.assign(natoms,std::numeric_limits<real>::quiet_NaN());
     829             : //case pdb: structure
     830         911 :       if(pdbfile.length()>0) {
     831      150980 :         for(unsigned i=0; i<pdb.size(); ++i) {
     832      150901 :           AtomNumber an=pdb.getAtomNumbers()[i];
     833             :           unsigned index=an.index();
     834      150901 :           if( index>=unsigned(natoms) ) {
     835           0 :             error("atom index in pdb exceeds the number of atoms in trajectory");
     836             :           }
     837      150901 :           masses[index]=pdb.getOccupancy()[i];
     838      150901 :           charges[index]=pdb.getBeta()[i];
     839             :         }
     840             :       }
     841         911 :       if(mcfile.length()>0) {
     842          12 :         IFile ifile;
     843          12 :         ifile.open(mcfile);
     844             :         int index;
     845             :         double mass;
     846             :         double charge;
     847      495694 :         while(ifile.scanField("index",index).scanField("mass",mass).scanField("charge",charge).scanField()) {
     848      247835 :           masses[index]=mass;
     849      247835 :           charges[index]=charge;
     850             :         }
     851          12 :       }
     852      259432 :     } else if( checknatoms<0 && noatoms ) {
     853          56 :       natoms=0;
     854             :     }
     855      260343 :     if( checknatoms<0 ) {
     856         967 :       if(kt>=0) {
     857           3 :         p.cmd("setKbT",kt);
     858             :       }
     859         967 :       checknatoms=natoms;
     860         967 :       p.cmd("setNatoms",natoms);
     861         967 :       p.cmd("init");
     862             :       // Check if we have been asked to output the long version of the input and if there are shortcuts
     863         967 :       if( parseOnly && full_outputfile.length()>0 ) {
     864             : 
     865             :         // Read in the plumed input file and store what is in there
     866             :         std::map<std::string,std::vector<std::string> > data;
     867           5 :         IFile ifile;
     868           5 :         ifile.open(plumedFile);
     869             :         std::vector<std::string> words;
     870          29 :         while( Tools::getParsedLine(ifile,words) && !p.getEndPlumed() ) {
     871          24 :           p.readInputWords(words,false);
     872             :           Action* aa=p.getActionSet()[p.getActionSet().size()-1].get();
     873          24 :           plumed_assert(aa); // needed for following calls, see #1046
     874          24 :           ActionWithValue* av=aa->castToActionWithValue();
     875          36 :           if( av && aa->getDefaultString().length()>0 ) {
     876             :             std::vector<std::string> def;
     877          10 :             def.push_back( "defaults " + aa->getDefaultString() );
     878           5 :             data[ aa->getLabel() ] = def;
     879           5 :           }
     880          24 :           ActionShortcut* as=aa->castToActionShortcut();
     881          24 :           if( as ) {
     882          18 :             if( aa->getDefaultString().length()>0 ) {
     883             :               std::vector<std::string> def;
     884           6 :               def.push_back( "defaults " + aa->getDefaultString() );
     885           3 :               data[ as->getShortcutLabel() ] = def;
     886           3 :             }
     887          18 :             std::vector<std::string> shortcut_commands = as->getSavedInputLines();
     888          18 :             if( shortcut_commands.size()==0 ) {
     889             :               continue;
     890             :             }
     891          12 :             if( data.find( as->getShortcutLabel() )!=data.end() ) {
     892          16 :               for(unsigned i=0; i<shortcut_commands.size(); ++i) {
     893          14 :                 data[ as->getShortcutLabel() ].push_back( shortcut_commands[i] );
     894             :               }
     895             :             } else {
     896           4 :               data[ as->getShortcutLabel() ] = shortcut_commands;
     897             :             }
     898          18 :           }
     899             :         }
     900           5 :         ifile.close();
     901             :         // Only output the full version of the input file if there are shortcuts
     902           5 :         if( data.size()>0 ) {
     903           5 :           OFile long_file;
     904           5 :           long_file.open( full_outputfile );
     905           5 :           long_file.printf("{\n");
     906             :           bool firstpass=true;
     907          17 :           for(auto& x : data ) {
     908          12 :             if( !firstpass ) {
     909           7 :               long_file.printf("   },\n");
     910             :             }
     911          12 :             long_file.printf("   \"%s\" : {\n", x.first.c_str() );
     912          12 :             plumed_assert( x.second.size()>0 );
     913             :             unsigned sstart=0;
     914          12 :             if( x.second[0].find("defaults")!=std::string::npos ) {
     915             :               sstart=1;
     916          16 :               long_file.printf("      \"defaults\" : \"%s\"", x.second[0].substr( 9 ).c_str() );
     917           8 :               if( x.second.size()>1 ) {
     918           2 :                 long_file.printf(",\n");
     919             :               } else {
     920           6 :                 long_file.printf("\n");
     921             :               }
     922             :             }
     923          12 :             if( x.second.size()>sstart ) {
     924           6 :               long_file.printf("      \"expansion\" : \"%s", x.second[sstart].c_str() );
     925          36 :               for(unsigned j=sstart+1; j<x.second.size(); ++j) {
     926          30 :                 long_file.printf("\\n%s", x.second[j].c_str() );
     927             :               }
     928           6 :               long_file.printf("\"\n");
     929             :             }
     930             :             firstpass=false;
     931             :           }
     932           5 :           long_file.printf("   }\n}\n");
     933           5 :           long_file.close();
     934           5 :         }
     935           5 :       }
     936         967 :       if( valuedict_file.length()>0 ) {
     937           5 :         OFile valuefile;
     938           5 :         valuefile.open( valuedict_file );
     939           5 :         valuefile.printf("{\n");
     940             :         bool firsta=true;
     941         149 :         for(const auto & pp : p.getActionSet()) {
     942         144 :           if( pp.get()->getName()=="CENTER" ) {
     943           3 :             continue ;
     944             :           }
     945         141 :           ActionWithVirtualAtom* avv=dynamic_cast<ActionWithVirtualAtom*>(pp.get());
     946         414 :           if( avv ||  pp.get()->getName()=="GROUP" || pp.get()->getName()=="DENSITY" ) {
     947             :             Action* p(pp.get());
     948           6 :             if( firsta ) {
     949           0 :               valuefile.printf("  \"%s\" : {\n    \"action\" : \"%s\"", p->getLabel().c_str(), p->getName().c_str() );
     950             :               firsta=false;
     951             :             } else {
     952           6 :               valuefile.printf(",\n  \"%s\" : {\n    \"action\" : \"%s\"", p->getLabel().c_str(), p->getName().c_str() );
     953             :             }
     954           6 :             if( avv ) {
     955           3 :               valuefile.printf(",\n    \"%s\" : { \"type\": \"atoms\", \"description\": \"virtual atom calculated by %s action\" }", avv->getLabel().c_str(), avv->getName().c_str() );
     956             :             } else {
     957           3 :               valuefile.printf(",\n    \"%s\" : { \"type\": \"atoms\", \"description\": \"indices of atoms specified in GROUP\" }", p->getLabel().c_str() );
     958             :             }
     959           6 :             valuefile.printf("\n  }");
     960           6 :             continue;
     961           6 :           }
     962         135 :           ActionWithValue* av=dynamic_cast<ActionWithValue*>(pp.get());
     963         135 :           if( av && av->getNumberOfComponents()>0 ) {
     964          89 :             Keywords keys;
     965          89 :             p.getKeywordsForAction( av->getName(), keys );
     966          89 :             if( firsta ) {
     967          10 :               valuefile.printf("  \"%s\" : {\n    \"action\" : \"%s\"", av->getLabel().c_str(), keys.getDisplayName().c_str() );
     968             :               firsta=false;
     969             :             } else {
     970         168 :               valuefile.printf(",\n  \"%s\" : {\n    \"action\" : \"%s\"", av->getLabel().c_str(), keys.getDisplayName().c_str() );
     971             :             }
     972         207 :             for(unsigned i=0; i<av->getNumberOfComponents(); ++i) {
     973         118 :               Value* myval = av->copyOutput(i);
     974         118 :               std::string compname = myval->getName(), description;
     975         118 :               if( av->getLabel()==compname ) {
     976         150 :                 description = keys.getOutputComponentDescription(".#!value");
     977             :               } else {
     978          43 :                 std::size_t dot=compname.find(av->getLabel() + ".");
     979          43 :                 std::string cname = compname.substr(dot + av->getLabel().length() + 1);
     980          86 :                 description = av->getOutputComponentDescription( cname, keys );
     981             :               }
     982         118 :               if( description.find("\\")!=std::string::npos ) {
     983           0 :                 error("found invalid backslash character in documentation for component " + compname + " in action " + av->getName() + " with label " + av->getLabel() );
     984             :               }
     985         236 :               valuefile.printf(",\n    \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
     986             :             }
     987          89 :             valuefile.printf("\n  }");
     988          89 :           }
     989         135 :           ActionShortcut* as=pp->castToActionShortcut();
     990         135 :           if( as ) {
     991          41 :             std::vector<std::string> cnames( as->getSavedOutputs() );
     992          41 :             if( cnames.size()==0 ) {
     993             :               continue ;
     994             :             }
     995             : 
     996           8 :             if( firsta ) {
     997           0 :               valuefile.printf("  \"shortcut_%s\" : {\n    \"action\" : \"%s\"", as->getShortcutLabel().c_str(), as->getName().c_str() );
     998             :               firsta=false;
     999             :             } else {
    1000           8 :               valuefile.printf(",\n  \"shortcut_%s\" : {\n    \"action\" : \"%s\"", as->getShortcutLabel().c_str(), as->getName().c_str() );
    1001             :             }
    1002           8 :             Keywords keys;
    1003           8 :             p.getKeywordsForAction( as->getName(), keys );
    1004          20 :             for(unsigned i=0; i<cnames.size(); ++i) {
    1005          12 :               ActionWithValue* av2=p.getActionSet().selectWithLabel<ActionWithValue*>( cnames[i] );
    1006          12 :               if( !av2 ) {
    1007           0 :                 plumed_merror("could not find value created by shortcut with name " + cnames[i] );
    1008             :               }
    1009          12 :               if( av2->getNumberOfComponents()==1 ) {
    1010          11 :                 Value* myval = av2->copyOutput(0);
    1011          11 :                 std::string compname = myval->getName(), description;
    1012          11 :                 if( compname==as->getShortcutLabel() ) {
    1013          14 :                   description = keys.getOutputComponentDescription(".#!value");
    1014             :                 } else {
    1015           4 :                   std::size_t pp=compname.find(as->getShortcutLabel());
    1016           8 :                   description = keys.getOutputComponentDescription( compname.substr(pp+as->getShortcutLabel().length()+1) );
    1017             :                 }
    1018          11 :                 if( description.find("\\")!=std::string::npos ) {
    1019           0 :                   error("found invalid backslash character in documentation for component " + compname + " in action " + as->getName() + " with label " + as->getLabel() );
    1020             :                 }
    1021          22 :                 valuefile.printf(",\n    \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
    1022             :               } else {
    1023           4 :                 for(unsigned j=0; j<av2->getNumberOfComponents(); ++j) {
    1024           3 :                   Value* myval = av2->copyOutput(j);
    1025           3 :                   std::string compname = myval->getName(), description;
    1026           3 :                   if( av2->getLabel()==compname ) {
    1027           0 :                     plumed_merror("should not be outputting description of value from action when using shortcuts");
    1028             :                   } else {
    1029           3 :                     std::size_t dot=compname.find(av2->getLabel() + ".");
    1030           3 :                     std::string cname = compname.substr(dot+av2->getLabel().length() + 1);
    1031           6 :                     description = av2->getOutputComponentDescription( cname, keys );
    1032             :                   }
    1033           3 :                   if( description.find("\\")!=std::string::npos ) {
    1034           0 :                     error("found invalid backslash character in documentation for component " + compname + " in action " + av2->getName() + " with label " + av2->getLabel() );
    1035             :                   }
    1036           6 :                   valuefile.printf(",\n    \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
    1037             :                 }
    1038             :               }
    1039             :             }
    1040           8 :             valuefile.printf("\n  }");
    1041          41 :           }
    1042             :         }
    1043           5 :         valuefile.printf("\n}\n");
    1044           5 :         valuefile.close();
    1045           5 :       }
    1046         967 :       if(parseOnly) {
    1047             :         break;
    1048             :       }
    1049             :     }
    1050      260338 :     if(checknatoms!=natoms) {
    1051             :       std::string stepstr;
    1052           0 :       Tools::convert(step,stepstr);
    1053           0 :       error("number of atoms in frame " + stepstr + " does not match number of atoms in first frame");
    1054             :     }
    1055             : 
    1056      260338 :     coordinates.assign(3*natoms,real(0.0));
    1057      260338 :     forces.assign(3*natoms,real(0.0));
    1058      260338 :     cell.assign(9,real(0.0));
    1059      260338 :     virial.assign(9,real(0.0));
    1060             : 
    1061      260338 :     if( first_step || rnd.U01()>0.5) {
    1062      131970 :       if(debug_pd) {
    1063         152 :         int npe=intracomm.Get_size();
    1064         152 :         std::vector<int> loc(npe,0);
    1065         152 :         std::vector<int> start(npe,0);
    1066         608 :         for(int i=0; i<npe-1; i++) {
    1067         456 :           int cc=(natoms*2*rnd.U01())/npe;
    1068         456 :           if(start[i]+cc>natoms) {
    1069          16 :             cc=natoms-start[i];
    1070             :           }
    1071         456 :           loc[i]=cc;
    1072         456 :           start[i+1]=start[i]+loc[i];
    1073             :         }
    1074         152 :         loc[npe-1]=natoms-start[npe-1];
    1075         152 :         intracomm.Bcast(loc,0);
    1076         152 :         intracomm.Bcast(start,0);
    1077         152 :         pd_nlocal=loc[intracomm.Get_rank()];
    1078         152 :         pd_start=start[intracomm.Get_rank()];
    1079         152 :         if(intracomm.Get_rank()==0) {
    1080             :           std::fprintf(out,"\nDRIVER: Reassigning particle decomposition\n");
    1081             :           std::fprintf(out,"DRIVER: ");
    1082         190 :           for(int i=0; i<npe; i++) {
    1083         152 :             std::fprintf(out,"%d ",loc[i]);
    1084             :           }
    1085             :           printf("\n");
    1086             :           std::fprintf(out,"DRIVER: ");
    1087         190 :           for(int i=0; i<npe; i++) {
    1088         152 :             std::fprintf(out,"%d ",start[i]);
    1089             :           }
    1090             :           printf("\n");
    1091             :         }
    1092         152 :         p.cmd("setAtomsNlocal",pd_nlocal);
    1093         152 :         p.cmd("setAtomsContiguous",pd_start);
    1094      131818 :       } else if(debug_dd) {
    1095         956 :         int npe=intracomm.Get_size();
    1096         956 :         int rank=intracomm.Get_rank();
    1097         956 :         dd_charges.assign(natoms,0.0);
    1098         956 :         dd_masses.assign(natoms,0.0);
    1099         956 :         dd_gatindex.assign(natoms,-1);
    1100         956 :         dd_g2l.assign(natoms,-1);
    1101         956 :         dd_coordinates.assign(3*natoms,0.0);
    1102         956 :         dd_forces.assign(3*natoms,0.0);
    1103             :         dd_nlocal=0;
    1104       53786 :         for(int i=0; i<natoms; ++i) {
    1105       52830 :           double r=rnd.U01()*npe;
    1106             :           int n;
    1107      112376 :           for(n=0; n<npe; n++)
    1108      112376 :             if(n+1>r) {
    1109             :               break;
    1110             :             }
    1111       52830 :           plumed_assert(n<npe);
    1112       52830 :           if(n==rank) {
    1113       19827 :             dd_gatindex[dd_nlocal]=i;
    1114       19827 :             dd_g2l[i]=dd_nlocal;
    1115       19827 :             dd_charges[dd_nlocal]=charges[i];
    1116       19827 :             dd_masses[dd_nlocal]=masses[i];
    1117       19827 :             dd_nlocal++;
    1118             :           }
    1119             :         }
    1120         956 :         if(intracomm.Get_rank()==0) {
    1121             :           std::fprintf(out,"\nDRIVER: Reassigning domain decomposition\n");
    1122             :         }
    1123         956 :         p.cmd("setAtomsNlocal",dd_nlocal);
    1124         956 :         p.cmd("setAtomsGatindex",&dd_gatindex[0], {dd_nlocal});
    1125             :       }
    1126             :     }
    1127             : 
    1128      260338 :     int plumedStopCondition=0;
    1129      260338 :     if(!noatoms) {
    1130       59756 :       if(use_molfile) {
    1131             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
    1132       20723 :         if(pbc_cli_given==false) {
    1133       20680 :           if(ts_in.A>0.0) { // this is negative if molfile does not provide box
    1134             :             // info on the cell: convert using pbcset.tcl from pbctools in vmd distribution
    1135       20667 :             real cosBC=cos(real(ts_in.alpha)*pi/180.);
    1136             :             //double sinBC=std::sin(ts_in.alpha*pi/180.);
    1137       20667 :             real cosAC=std::cos(real(ts_in.beta)*pi/180.);
    1138       20667 :             real cosAB=std::cos(real(ts_in.gamma)*pi/180.);
    1139       20667 :             real sinAB=std::sin(real(ts_in.gamma)*pi/180.);
    1140       20667 :             real Ax=real(ts_in.A);
    1141       20667 :             real Bx=real(ts_in.B)*cosAB;
    1142       20667 :             real By=real(ts_in.B)*sinAB;
    1143       20667 :             real Cx=real(ts_in.C)*cosAC;
    1144       20667 :             real Cy=(real(ts_in.C)*real(ts_in.B)*cosBC-Cx*Bx)/By;
    1145       20667 :             real Cz=std::sqrt(real(ts_in.C)*real(ts_in.C)-Cx*Cx-Cy*Cy);
    1146       20667 :             cell[0]=Ax/10.;
    1147       20667 :             cell[1]=0.;
    1148       20667 :             cell[2]=0.;
    1149       20667 :             cell[3]=Bx/10.;
    1150       20667 :             cell[4]=By/10.;
    1151       20667 :             cell[5]=0.;
    1152       20667 :             cell[6]=Cx/10.;
    1153       20667 :             cell[7]=Cy/10.;
    1154       20667 :             cell[8]=Cz/10.;
    1155             :           } else {
    1156          13 :             cell[0]=0.0;
    1157          13 :             cell[1]=0.0;
    1158          13 :             cell[2]=0.0;
    1159          13 :             cell[3]=0.0;
    1160          13 :             cell[4]=0.0;
    1161          13 :             cell[5]=0.0;
    1162          13 :             cell[6]=0.0;
    1163          13 :             cell[7]=0.0;
    1164          13 :             cell[8]=0.0;
    1165             :           }
    1166             :         } else {
    1167         430 :           for(unsigned i=0; i<9; i++) {
    1168         387 :             cell[i]=pbc_cli_box[i];
    1169             :           }
    1170             :         }
    1171             :         // info on coords
    1172             :         // the order is xyzxyz...
    1173    15131240 :         for(int i=0; i<3*natoms; i++) {
    1174    15110517 :           coordinates[i]=real(ts_in.coords[i])/real(10.); //convert to nm
    1175             :           //cerr<<"COOR "<<coordinates[i]<<endl;
    1176             :         }
    1177             : #endif
    1178       78036 :       } else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr") {
    1179             :         int localstep;
    1180             :         float time;
    1181             :         xdrfile::matrix box;
    1182             : // here we cannot use a std::vector<rvec> since it does not compile.
    1183             : // we thus use a std::unique_ptr<rvec[]>
    1184             :         auto pos=Tools::make_unique<xdrfile::rvec[]>(natoms);
    1185             :         float prec,lambda;
    1186             :         int ret=xdrfile::exdrOK;
    1187         105 :         if(trajectory_fmt=="xdr-xtc") {
    1188          30 :           ret=xdrfile::read_xtc(xd,natoms,&localstep,&time,box,pos.get(),&prec);
    1189             :         }
    1190         105 :         if(trajectory_fmt=="xdr-trr") {
    1191          75 :           ret=xdrfile::read_trr(xd,natoms,&localstep,&time,&lambda,box,pos.get(),NULL,NULL);
    1192             :         }
    1193         105 :         if(stride==0) {
    1194          30 :           step=localstep;
    1195             :         }
    1196         105 :         if(ret==xdrfile::exdrENDOFFILE) {
    1197             :           break;
    1198             :         }
    1199         103 :         if(ret!=xdrfile::exdrOK) {
    1200             :           break;
    1201             :         }
    1202         376 :         for(unsigned i=0; i<3; i++)
    1203        1128 :           for(unsigned j=0; j<3; j++) {
    1204         846 :             cell[3*i+j]=box[i][j];
    1205             :           }
    1206        6692 :         for(int i=0; i<natoms; i++)
    1207       26392 :           for(unsigned j=0; j<3; j++) {
    1208       19794 :             coordinates[3*i+j]=real(pos[i][j]);
    1209             :           }
    1210             :       } else {
    1211       38928 :         if(trajectory_fmt=="xyz") {
    1212       26565 :           if(!Tools::getline(fp,line)) {
    1213           0 :             error("premature end of trajectory file");
    1214             :           }
    1215             : 
    1216       26565 :           std::vector<double> celld(9,0.0);
    1217       26565 :           if(pbc_cli_given==false) {
    1218             :             std::vector<std::string> words;
    1219       52394 :             words=Tools::getWords(line);
    1220       26197 :             if(words.size()==3) {
    1221       25618 :               Tools::convert(words[0],celld[0]);
    1222       25618 :               Tools::convert(words[1],celld[4]);
    1223       25618 :               Tools::convert(words[2],celld[8]);
    1224         579 :             } else if(words.size()==9) {
    1225         579 :               Tools::convert(words[0],celld[0]);
    1226         579 :               Tools::convert(words[1],celld[1]);
    1227         579 :               Tools::convert(words[2],celld[2]);
    1228         579 :               Tools::convert(words[3],celld[3]);
    1229         579 :               Tools::convert(words[4],celld[4]);
    1230         579 :               Tools::convert(words[5],celld[5]);
    1231         579 :               Tools::convert(words[6],celld[6]);
    1232         579 :               Tools::convert(words[7],celld[7]);
    1233         579 :               Tools::convert(words[8],celld[8]);
    1234             :             } else {
    1235           0 :               error("needed box in second line of xyz file");
    1236             :             }
    1237       26197 :           } else {                      // from command line
    1238         368 :             celld=pbc_cli_box;
    1239             :           }
    1240      265650 :           for(unsigned i=0; i<9; i++) {
    1241      239085 :             cell[i]=real(celld[i]);
    1242             :           }
    1243             :         }
    1244       38928 :         if(trajectory_fmt=="dlp4") {
    1245          20 :           std::vector<double> celld(9,0.0);
    1246          20 :           if(pbc_cli_given==false) {
    1247          20 :             if(!Tools::getline(fp,line)) {
    1248           0 :               error("error reading vector a of cell");
    1249             :             }
    1250          20 :             std::sscanf(line.c_str(),"%lf %lf %lf",&celld[0],&celld[1],&celld[2]);
    1251          20 :             if(!Tools::getline(fp,line)) {
    1252           0 :               error("error reading vector b of cell");
    1253             :             }
    1254          20 :             std::sscanf(line.c_str(),"%lf %lf %lf",&celld[3],&celld[4],&celld[5]);
    1255          20 :             if(!Tools::getline(fp,line)) {
    1256           0 :               error("error reading vector c of cell");
    1257             :             }
    1258          20 :             std::sscanf(line.c_str(),"%lf %lf %lf",&celld[6],&celld[7],&celld[8]);
    1259             :           } else {
    1260           0 :             celld=pbc_cli_box;
    1261             :           }
    1262         200 :           for(auto i=0; i<9; i++) {
    1263         180 :             cell[i]=real(celld[i])*0.1;
    1264             :           }
    1265             :         }
    1266             :         int ddist=0;
    1267             :         // Read coordinates
    1268     2829815 :         for(int i=0; i<natoms; i++) {
    1269     2790887 :           bool ok=Tools::getline(fp,line);
    1270     2790887 :           if(!ok) {
    1271           0 :             error("premature end of trajectory file");
    1272             :           }
    1273             :           double cc[3];
    1274     2790887 :           if(trajectory_fmt=="xyz") {
    1275             :             char dummy[1000];
    1276     1903610 :             int ret=std::sscanf(line.c_str(),"%999s %100lf %100lf %100lf",dummy,&cc[0],&cc[1],&cc[2]);
    1277     1903610 :             if(ret!=4) {
    1278           0 :               error("cannot read line"+line);
    1279             :             }
    1280      887277 :           } else if(trajectory_fmt=="gro") {
    1281             :             // do the gromacs way
    1282      886637 :             if(!i) {
    1283             :               //
    1284             :               // calculate the distance between dots (as in gromacs gmxlib/confio.c, routine get_w_conf )
    1285             :               //
    1286             :               const char      *p1, *p2, *p3;
    1287             :               p1 = std::strchr(line.c_str(), '.');
    1288       12343 :               if (p1 == NULL) {
    1289           0 :                 error("seems there are no coordinates in the gro file");
    1290             :               }
    1291       12343 :               p2 = std::strchr(&p1[1], '.');
    1292       12343 :               if (p2 == NULL) {
    1293           0 :                 error("seems there is only one coordinates in the gro file");
    1294             :               }
    1295       12343 :               ddist = p2 - p1;
    1296       12343 :               p3 = std::strchr(&p2[1], '.');
    1297       12343 :               if (p3 == NULL) {
    1298           0 :                 error("seems there are only two coordinates in the gro file");
    1299             :               }
    1300       12343 :               if (p3 - p2 != ddist) {
    1301           0 :                 error("not uniform spacing in fields in the gro file");
    1302             :               }
    1303             :             }
    1304      886637 :             Tools::convert(line.substr(20,ddist),cc[0]);
    1305      886637 :             Tools::convert(line.substr(20+ddist,ddist),cc[1]);
    1306     1773274 :             Tools::convert(line.substr(20+ddist+ddist,ddist),cc[2]);
    1307         640 :           } else if(trajectory_fmt=="dlp4") {
    1308             :             char dummy[9];
    1309             :             int idummy;
    1310             :             double m,c;
    1311         640 :             std::sscanf(line.c_str(),"%8s %d %lf %lf",dummy,&idummy,&m,&c);
    1312         640 :             masses[i]=real(m);
    1313         640 :             charges[i]=real(c);
    1314         640 :             if(!Tools::getline(fp,line)) {
    1315           0 :               error("error reading coordinates");
    1316             :             }
    1317         640 :             std::sscanf(line.c_str(),"%lf %lf %lf",&cc[0],&cc[1],&cc[2]);
    1318         640 :             cc[0]*=0.1;
    1319         640 :             cc[1]*=0.1;
    1320         640 :             cc[2]*=0.1;
    1321         640 :             if(lvl>0) {
    1322         640 :               if(!Tools::getline(fp,line)) {
    1323           0 :                 error("error skipping velocities");
    1324             :               }
    1325             :             }
    1326         640 :             if(lvl>1) {
    1327         640 :               if(!Tools::getline(fp,line)) {
    1328           0 :                 error("error skipping forces");
    1329             :               }
    1330             :             }
    1331             :           } else {
    1332           0 :             plumed_error();
    1333             :           }
    1334     2790887 :           if(!debug_pd || ( i>=pd_start && i<pd_start+pd_nlocal) ) {
    1335     2771447 :             coordinates[3*i]=real(cc[0]);
    1336     2771447 :             coordinates[3*i+1]=real(cc[1]);
    1337     2771447 :             coordinates[3*i+2]=real(cc[2]);
    1338             :           }
    1339             :         }
    1340       38928 :         if(trajectory_fmt=="gro") {
    1341       12343 :           if(!Tools::getline(fp,line)) {
    1342           0 :             error("premature end of trajectory file");
    1343             :           }
    1344       12343 :           std::vector<std::string> words=Tools::getWords(line);
    1345       12343 :           if(words.size()<3) {
    1346           0 :             error("cannot understand box format");
    1347             :           }
    1348       12343 :           Tools::convert(words[0],cell[0]);
    1349       12343 :           Tools::convert(words[1],cell[4]);
    1350       12343 :           Tools::convert(words[2],cell[8]);
    1351       12343 :           if(words.size()>3) {
    1352         510 :             Tools::convert(words[3],cell[1]);
    1353             :           }
    1354       12343 :           if(words.size()>4) {
    1355         510 :             Tools::convert(words[4],cell[2]);
    1356             :           }
    1357       12343 :           if(words.size()>5) {
    1358         510 :             Tools::convert(words[5],cell[3]);
    1359             :           }
    1360       12343 :           if(words.size()>6) {
    1361         510 :             Tools::convert(words[6],cell[5]);
    1362             :           }
    1363       12343 :           if(words.size()>7) {
    1364         510 :             Tools::convert(words[7],cell[6]);
    1365             :           }
    1366       12343 :           if(words.size()>8) {
    1367         510 :             Tools::convert(words[8],cell[7]);
    1368             :           }
    1369       12343 :         }
    1370             : 
    1371             :       }
    1372             : 
    1373       59745 :       p.cmd("setStepLongLong",step);
    1374       59745 :       p.cmd("setStopFlag",&plumedStopCondition);
    1375             : 
    1376       59745 :       if(debug_dd) {
    1377       38944 :         for(int i=0; i<dd_nlocal; ++i) {
    1378       37156 :           int kk=dd_gatindex[i];
    1379       37156 :           dd_coordinates[3*i+0]=coordinates[3*kk+0];
    1380       37156 :           dd_coordinates[3*i+1]=coordinates[3*kk+1];
    1381       37156 :           dd_coordinates[3*i+2]=coordinates[3*kk+2];
    1382             :         }
    1383        1788 :         p.cmd("setForces",&dd_forces[0], {dd_nlocal,3});
    1384        1788 :         p.cmd("setPositions",&dd_coordinates[0], {dd_nlocal,3});
    1385        1788 :         p.cmd("setMasses",&dd_masses[0], {dd_nlocal});
    1386        1788 :         p.cmd("setCharges",&dd_charges[0], {dd_nlocal});
    1387             :       } else {
    1388             : // this is required to avoid troubles when the last domain
    1389             : // contains zero atoms
    1390             : // Basically, for empty domains we pass null pointers
    1391             : #define fix_pd(xx) (pd_nlocal!=0?&xx:NULL)
    1392      115914 :         p.cmd("setForces",fix_pd(forces[3*pd_start]), {pd_nlocal,3});
    1393      115914 :         p.cmd("setPositions",fix_pd(coordinates[3*pd_start]), {pd_nlocal,3});
    1394      115914 :         p.cmd("setMasses",fix_pd(masses[pd_start]), {pd_nlocal});
    1395      115914 :         p.cmd("setCharges",fix_pd(charges[pd_start]), {pd_nlocal});
    1396             :       }
    1397       59745 :       p.cmd("setBox",cell.data(), {3,3});
    1398       59745 :       p.cmd("setVirial",virial.data(), {3,3});
    1399             :     } else {
    1400      200582 :       p.cmd("setStepLongLong",step);
    1401      200582 :       p.cmd("setStopFlag",&plumedStopCondition);
    1402             :     }
    1403      260327 :     p.cmd("calc");
    1404      260327 :     if(debugforces.length()>0) {
    1405          96 :       virial.assign(9,real(0.0));
    1406          96 :       forces.assign(3*natoms,real(0.0));
    1407          96 :       p.cmd("prepareCalc");
    1408          96 :       p.cmd("performCalcNoUpdate");
    1409             :     }
    1410             : 
    1411             : // this is necessary as only processor zero is adding to the virial:
    1412      260327 :     intracomm.Bcast(virial,0);
    1413      260327 :     if(debug_pd) {
    1414         240 :       intracomm.Sum(forces);
    1415             :     }
    1416      260327 :     if(debug_dd) {
    1417       38944 :       for(int i=0; i<dd_nlocal; i++) {
    1418       37156 :         forces[3*dd_gatindex[i]+0]=dd_forces[3*i+0];
    1419       37156 :         forces[3*dd_gatindex[i]+1]=dd_forces[3*i+1];
    1420       37156 :         forces[3*dd_gatindex[i]+2]=dd_forces[3*i+2];
    1421             :       }
    1422        1788 :       dd_forces.assign(3*natoms,0.0);
    1423        1788 :       intracomm.Sum(forces);
    1424             :     }
    1425      260327 :     if(debug_grex &&step%grex_stride==0) {
    1426         114 :       p.cmd("GREX savePositions");
    1427         114 :       if(intracomm.Get_rank()>0) {
    1428          57 :         p.cmd("GREX prepare");
    1429             :       } else {
    1430          57 :         int r=intercomm.Get_rank();
    1431          57 :         int n=intercomm.Get_size();
    1432          57 :         int partner=r+(2*((r+step/grex_stride)%2))-1;
    1433             :         if(partner<0) {
    1434             :           partner=0;
    1435             :         }
    1436          57 :         if(partner>=n) {
    1437           8 :           partner=n-1;
    1438             :         }
    1439          57 :         p.cmd("GREX setPartner",partner);
    1440          57 :         p.cmd("GREX calculate");
    1441          57 :         p.cmd("GREX shareAllDeltaBias");
    1442         228 :         for(int i=0; i<n; i++) {
    1443             :           std::string s;
    1444         171 :           Tools::convert(i,s);
    1445         171 :           real a=std::numeric_limits<real>::quiet_NaN();
    1446         342 :           s="GREX getDeltaBias "+s;
    1447         171 :           p.cmd(s,&a);
    1448         171 :           if(grex_log) {
    1449         171 :             std::fprintf(grex_log," %f",a);
    1450             :           }
    1451             :         }
    1452          57 :         if(grex_log) {
    1453             :           std::fprintf(grex_log,"\n");
    1454             :         }
    1455             :       }
    1456             :     }
    1457             : 
    1458             : 
    1459      260327 :     if(fp_forces) {
    1460       37970 :       std::fprintf(fp_forces,"%d\n",natoms);
    1461       75940 :       std::string fmtv=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n";
    1462       75940 :       std::string fmt=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n";
    1463       37970 :       if(dumpfullvirial) {
    1464         353 :         std::fprintf(fp_forces,fmtv.c_str(),virial[0],virial[1],virial[2],virial[3],virial[4],virial[5],virial[6],virial[7],virial[8]);
    1465             :       } else {
    1466       37617 :         std::fprintf(fp_forces,fmt.c_str(),virial[0],virial[4],virial[8]);
    1467             :       }
    1468       37970 :       fmt="X "+fmt;
    1469     4290972 :       for(int i=0; i<natoms; i++) {
    1470     4253002 :         std::fprintf(fp_forces,fmt.c_str(),forces[3*i],forces[3*i+1],forces[3*i+2]);
    1471             :       }
    1472             :     }
    1473      260327 :     if(debugforces.length()>0) {
    1474             :       // Now call the routine to work out the derivatives numerically
    1475          96 :       numder.assign(3*natoms+9,real(0.0));
    1476          96 :       real base=0;
    1477          96 :       p.cmd("getBias",&base);
    1478          96 :       if( std::abs(base)<epsilon ) {
    1479             :         printf("WARNING: bias for configuration appears to be zero so debugging forces is trivial");
    1480             :       }
    1481          96 :       evaluateNumericalDerivatives( step, p, coordinates, masses, charges, cell, base, numder );
    1482             : 
    1483             :       // And output everything to a file
    1484          96 :       fp_dforces.fmtField(" " + dumpforcesFmt);
    1485        6033 :       for(int i=0; i<3*natoms; ++i) {
    1486        5937 :         fp_dforces.printField("parameter",(int)i);
    1487       11874 :         fp_dforces.printField("analytical",forces[i]);
    1488        5937 :         fp_dforces.printField("numerical",-numder[i]);
    1489        5937 :         fp_dforces.printField();
    1490             :       }
    1491             :       // And print the virial
    1492         960 :       for(int i=0; i<9; ++i) {
    1493         864 :         fp_dforces.printField("parameter",3*natoms+i );
    1494         864 :         fp_dforces.printField("analytical",virial[i] );
    1495         864 :         fp_dforces.printField("numerical",-numder[3*natoms+i]);
    1496         864 :         fp_dforces.printField();
    1497             :       }
    1498             :     }
    1499             : 
    1500      260327 :     if(plumedStopCondition) {
    1501             :       break;
    1502             :     }
    1503             : 
    1504      260267 :     step+=stride;
    1505             :   }
    1506         967 :   if(!parseOnly) {
    1507         962 :     p.cmd("runFinalJobs");
    1508             :   }
    1509             : 
    1510             :   return 0;
    1511        3868 : }
    1512             : 
    1513             : template<typename real>
    1514          96 : void Driver<real>::evaluateNumericalDerivatives( const long long int& step, PlumedMain& p, const std::vector<real>& coordinates,
    1515             :     const std::vector<real>& masses, const std::vector<real>& charges,
    1516             :     std::vector<real>& cell, const double& base, std::vector<real>& numder ) {
    1517             : 
    1518          96 :   int natoms = coordinates.size() / 3;
    1519             :   real delta = std::sqrt(epsilon);
    1520          96 :   std::vector<Vector> pos(natoms);
    1521          96 :   real bias=0;
    1522          96 :   std::vector<real> fake_forces( 3*natoms ), fake_virial(9);
    1523        2075 :   for(int i=0; i<natoms; ++i) {
    1524        7916 :     for(unsigned j=0; j<3; ++j) {
    1525        5937 :       pos[i][j]=coordinates[3*i+j];
    1526             :     }
    1527             :   }
    1528             : 
    1529        2075 :   for(int i=0; i<natoms; ++i) {
    1530        7916 :     for(unsigned j=0; j<3; ++j) {
    1531        5937 :       pos[i][j]=pos[i][j]+delta;
    1532        5937 :       p.cmd("setStepLongLong",step);
    1533        5937 :       p.cmd("setPositions",&pos[0][0], {natoms,3});
    1534        5937 :       p.cmd("setForces",&fake_forces[0], {natoms,3});
    1535        5937 :       p.cmd("setMasses",&masses[0], {natoms});
    1536        5937 :       p.cmd("setCharges",&charges[0], {natoms});
    1537        5937 :       p.cmd("setBox",&cell[0], {3,3});
    1538        5937 :       p.cmd("setVirial",&fake_virial[0], {3,3});
    1539        5937 :       p.cmd("prepareCalc");
    1540        5937 :       p.cmd("performCalcNoUpdate");
    1541        5937 :       p.cmd("getBias",&bias);
    1542        5937 :       pos[i][j]=coordinates[3*i+j];
    1543        5937 :       numder[3*i+j] = (bias - base) / delta;
    1544             :     }
    1545             :   }
    1546             : 
    1547             :   // Create the cell
    1548          96 :   Tensor box( cell[0], cell[1], cell[2], cell[3], cell[4], cell[5], cell[6], cell[7], cell[8] );
    1549             :   // And the virial
    1550          96 :   Pbc pbc;
    1551          96 :   pbc.setBox( box );
    1552          96 :   Tensor nvirial;
    1553         384 :   for(unsigned i=0; i<3; i++)
    1554        1152 :     for(unsigned k=0; k<3; k++) {
    1555         864 :       double arg0=box(i,k);
    1556       18675 :       for(int j=0; j<natoms; ++j) {
    1557       17811 :         pos[j]=pbc.realToScaled( pos[j] );
    1558             :       }
    1559         864 :       cell[3*i+k]=box(i,k)=box(i,k)+delta;
    1560         864 :       pbc.setBox(box);
    1561       18675 :       for(int j=0; j<natoms; j++) {
    1562       17811 :         pos[j]=pbc.scaledToReal( pos[j] );
    1563             :       }
    1564         864 :       p.cmd("setStepLongLong",step);
    1565         864 :       p.cmd("setPositions",&pos[0][0], {natoms,3});
    1566         864 :       p.cmd("setForces",&fake_forces[0], {natoms,3});
    1567         864 :       p.cmd("setMasses",&masses[0], {natoms});
    1568         864 :       p.cmd("setCharges",&charges[0], {natoms});
    1569         864 :       p.cmd("setBox",&cell[0], {3,3});
    1570         864 :       p.cmd("setVirial",&fake_virial[0], {3,3});
    1571         864 :       p.cmd("prepareCalc");
    1572         864 :       p.cmd("performCalcNoUpdate");
    1573         864 :       p.cmd("getBias",&bias);
    1574         864 :       cell[3*i+k]=box(i,k)=arg0;
    1575         864 :       pbc.setBox(box);
    1576       18675 :       for(int j=0; j<natoms; j++)
    1577       71244 :         for(unsigned n=0; n<3; ++n) {
    1578       53433 :           pos[j][n]=coordinates[3*j+n];
    1579             :         }
    1580         864 :       nvirial(i,k) = ( bias - base ) / delta;
    1581             :     }
    1582          96 :   nvirial=-matmul(box.transpose(),nvirial);
    1583         384 :   for(unsigned i=0; i<3; i++)
    1584        1152 :     for(unsigned k=0; k<3; k++) {
    1585         864 :       numder[3*natoms+3*i+k] = nvirial(i,k);
    1586             :     }
    1587             : 
    1588          96 : }
    1589             : 
    1590             : }
    1591             : }

Generated by: LCOV version 1.16