LCOV - code coverage report
Current view: top level - cltools - Driver.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 575 615 93.5 %
Date: 2026-11-05 10:19:04 Functions: 8 9 88.9 %

          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 "tools/TrajectoryParser.h"
      43             : 
      44             : namespace PLMD {
      45             : namespace cltools {
      46             : 
      47             : //+PLUMEDOC TOOLS driver-float
      48             : /*
      49             : A tool that does the same as driver, but using single precision reals.
      50             : 
      51             : We recommend always using [driver](driver.md) to postprocess your trajectories. However,
      52             : if you want to test what PLUMED does when linked from a single precision code you can use
      53             : this version of driver. The documentation for this command line tool is identical to that for
      54             : [driver](driver.md).
      55             : 
      56             : ## Examples
      57             : 
      58             : ```plumed
      59             : plumed driver-float --plumed plumed.dat --ixyz trajectory.xyz
      60             : ```
      61             : 
      62             : For more examples see the documentation for [driver](driver.md).
      63             : 
      64             : */
      65             : //+ENDPLUMEDOC
      66             : //
      67             : 
      68             : 
      69             : //+PLUMEDOC TOOLS driver
      70             : /*
      71             : driver is a tool that allows one to use plumed to post-process an existing trajectory.
      72             : 
      73             : The input to driver is specified using the command line arguments described below.
      74             : 
      75             : In addition, you can use the special [READ](READ.md) command inside your plumed input
      76             : to read in colvar files that were generated during your MD simulation.  The values
      77             : read in from the file can then be treated like calculated colvars.
      78             : 
      79             : !!! warning "masses and chages"
      80             : 
      81             :     Notice that by default the driver has no knowledge about the masses and charges
      82             :     of your atoms! Thus, if you want to compute quantities that depend on charges (e.g. [DHENERGY](DHENERGY.md))
      83             :     or masses (e.g. [COM](COM.md)) you need to pass masses and charges to driver.
      84             :     You can do this by either using --pdb option or the --mc option. The latter
      85             :     will read a file produced by [DUMPMASSCHARGE](DUMPMASSCHARGE.md).
      86             : 
      87             : 
      88             : ## Examples
      89             : 
      90             : The following command tells plumed to post process the trajectory contained in `trajectory.xyz`
      91             :  by performing the actions described in the input file `plumed.dat`.  If an action that takes the
      92             : stride keyword is given a stride equal to $n$ then it will be performed only on every $n$th
      93             : frame in the trajectory file.
      94             : 
      95             : ```plumed
      96             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz
      97             : ```
      98             : 
      99             : Notice that `xyz` files are expected to be in the internal PLUMED unit of nm.
     100             : You can change this behavior by using the `--length-units` option as shown below
     101             : 
     102             : ```plumed
     103             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz --length-units A
     104             : ```
     105             : 
     106             : The strings accepted by the `--length-units` options are the same ones accepted by the [UNITS](UNITS.md) action.
     107             : Other file formats typically have their default coordinates (e.g., `gro` files are always in nm)
     108             : and it thus should not be necessary to use the `--length-units` option. Additionally,
     109             : consider that the units used by the `driver` might be different by the units used in the PLUMED input
     110             : file `plumed.dat`. For instance consider the command:
     111             : 
     112             : ```plumed
     113             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz --length-units A
     114             : ```
     115             : 
     116             : which uses the following `plumed.dat` file
     117             : 
     118             : ```plumed
     119             : # no explicit UNITS action here
     120             : d: DISTANCE ATOMS=1,2
     121             : PRINT ARG=d FILE=colvar
     122             : ```
     123             : 
     124             : In this case, the driver reads the `xyz` file assuming it to contain coordinates in Angstroms.
     125             : However, the resulting `colvar` file contains a distance expressed in nm.
     126             : 
     127             : The following command tells plumed to post process the trajectory contained in trajectory.xyz.
     128             :  by performing the actions described in the input file plumed.dat.
     129             : 
     130             : ```plumed
     131             : plumed driver --plumed plumed.dat --ixyz trajectory.xyz --trajectory-stride 100 --timestep 0.001
     132             : ```
     133             : 
     134             : Here though
     135             : `--trajectory-stride` is set equal to the frequency with which frames were output during the trajectory
     136             : and the `--timestep` is equal to the simulation timestep.  As such the `STRIDE` parameters in the `plumed.dat`
     137             : files are referred to the original timestep and any files output resemble those that would have been generated
     138             : had we run the calculation we are running with driver when the MD simulation was running.
     139             : 
     140             : PLUMED can read xyz files (in PLUMED units) and gro files (in nm). In addition,
     141             : PLUMED includes support for a
     142             : subset of the trajectory file formats supported by VMD, e.g. xtc and dcd:
     143             : 
     144             : ```plumed
     145             : plumed driver --plumed plumed.dat --pdb diala.pdb --mf_xtc traj.xtc --trajectory-stride 100 --timestep 0.001
     146             : ```
     147             : 
     148             : where `--mf_` prefixes the extension of one of the accepted molfile plugin format.
     149             : If PLUMED has been installed with full molfile support, other formats will be available.
     150             : Just type `plumed driver --help` to see which file formats you can use.
     151             : 
     152             : Molfile plugin requires the periodic cell to be triangular (i.e. the first vector oriented along x and
     153             : second vector in xy plane). This is true for many MD codes. However, it could be false
     154             : if you rotate the coordinates in your trajectory before reading them in the driver.
     155             : Also notice that some formats (e.g. amber crd) do not specify the total number of atoms. In this case you can use
     156             : the `--natoms` option as shown below
     157             : 
     158             : ```plumed
     159             : plumed driver --plumed plumed.dat --mf_crd trajectory.crd --natoms 128
     160             : ```
     161             : 
     162             : Check the available molfile plugins and limitations at [this link](http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/).
     163             : 
     164             : You can also use the xdrfile implementation of xtc and trr with plumed driver. If you want to do so you just
     165             : download and install properly the xdrfile library (see [this link](http://www.gromacs.org/Developer_Zone/Programming_Guide/XTC_Library)).
     166             : If the xdrfile library is installed properly the PLUMED configure script should be able to
     167             : detect it and enable it.
     168             : Notice that the xdrfile implementation of xtc and trr
     169             : is more robust than the molfile one, since it provides support for generic cell shapes.
     170             : In addition, if you install xdrfile you can then use the [DUMPATOMS](DUMPATOMS.md) command to write compressed xtc files.
     171             : 
     172             : ## Multiple replicas
     173             : 
     174             : When PLUMED is compiled with MPI support, you can emulate a multi-simulation setup with `driver` by providing the `--multi`
     175             : option with the appropriate number of ranks. This allows you to use the ref special-replica-syntax that is discussed [here](parsing.md) to analyze multiple
     176             : trajectories (see [this tutorial](https://www.plumed-tutorials.org/lessons/21/005/data/NAVIGATION.html)). PLUMED will also automatically append a numbered suffix to output files
     177             : (e.g. `COLVAR.0`, `COLVAR.1`, …) as discussed [here](Files.md). Similarly, each replica will search for the corresponding suffixed input file (e.g. `traj.0.xtc`, …)
     178             : or default to the unsuffixed one.
     179             : 
     180             : */
     181             : //+ENDPLUMEDOC
     182             : //
     183             : 
     184             : template<typename real>
     185             : class Driver : public CLTool {
     186             : public:
     187             :   static void registerKeywords( Keywords& keys );
     188             :   explicit Driver(const CLToolOptions& co );
     189             :   int main(FILE* in,FILE*out,Communicator& pc) override;
     190             :   void evaluateNumericalDerivatives( const long long int& step, PlumedMain& p, const std::vector<real>& coordinates,
     191             :                                      const std::vector<real>& masses, const std::vector<real>& charges,
     192             :                                      std::vector<real>& cell, const double& base, std::vector<real>& numder );
     193             :   std::string description()const override;
     194             : };
     195             : 
     196             : template<typename real>
     197       14642 : void Driver<real>::registerKeywords( Keywords& keys ) {
     198       14642 :   CLTool::registerKeywords( keys );
     199             :   keys.isDriver();
     200       14642 :   keys.addFlag("--help-debug",false,"print special options that can be used to create regtests");
     201       14642 :   keys.add("compulsory","--plumed","plumed.dat","specify the name of the plumed input file");
     202       14642 :   keys.add("compulsory","--timestep","1.0","the timestep that was used in the calculation that produced this trajectory in picoseconds");
     203       14642 :   keys.add("compulsory","--trajectory-stride","1","the frequency with which frames were output to this trajectory during the simulation"
     204             :            " (0 means that the number of the step is read from the trajectory file,"
     205             :            " currently working only for xtc/trr files read with --ixtc/--trr)"
     206             :           );
     207       14642 :   keys.add("compulsory","--multi","0","set number of replicas for multi environment (needs MPI)");
     208       14642 :   keys.addFlag("--noatoms",false,"don't read in a trajectory.  Just use colvar files as specified in plumed.dat");
     209       14642 :   keys.addFlag("--parse-only",false,"read the plumed input file and stop");
     210       14642 :   keys.addFlag("--restart",false,"makes driver behave as if restarting");
     211       14642 :   TrajectoryParser::registerKeywords(keys);
     212       14642 :   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");
     213       14642 :   keys.add("optional","--valuedict-ofile","output a dictionary giving information about each value in the input file");
     214       14642 :   keys.add("optional","--length-units","units for length, either as a string or a number");
     215       14642 :   keys.add("optional","--mass-units","units for mass in pdb and mc file, either as a string or a number");
     216       14642 :   keys.add("optional","--charge-units","units for charge in pdb and mc file, either as a string or a number");
     217       14642 :   keys.add("optional","--kt","set kT it will not be necessary to specify temperature in input file");
     218       14642 :   keys.add("optional","--dump-forces","dump the forces on a file");
     219       14642 :   keys.add("optional","--dump-forces-fmt","( default=%%f ) the format to use to dump the forces");
     220       14642 :   keys.addFlag("--dump-full-virial",false,"with --dump-forces, it dumps the 9 components of the virial");
     221       14642 :   keys.add("optional","--pdb","provides a pdb with masses and charges");
     222       14642 :   keys.add("optional","--mc","provides a file with masses and charges as produced with DUMPMASSCHARGE");
     223       14642 :   keys.add("optional","--box","comma-separated box dimensions (3 for orthorhombic, 9 for generic)");
     224       14642 :   keys.add("optional","--natoms","provides number of atoms - only used if file format does not contain number of atoms");
     225       14642 :   keys.add("optional","--initial-step","provides a number for the initial step, default is 0");
     226       14642 :   keys.add("optional","--debug-forces","output a file containing the forces due to the bias evaluated using numerical derivatives "
     227             :            "and using the analytical derivatives implemented in plumed");
     228       14642 :   keys.add("hidden","--debug-float","[yes/no] turns on the single precision version (to check float interface)");
     229       14642 :   keys.add("hidden","--debug-dd","[yes/no] use a fake domain decomposition");
     230       14642 :   keys.add("hidden","--debug-pd","[yes/no] use a fake particle decomposition");
     231       14642 :   keys.add("hidden","--debug-grex","use a fake gromacs-like replica exchange, specify exchange stride");
     232       14642 :   keys.add("hidden","--debug-grex-log","log file for debug=grex");
     233       14642 : }
     234             : template<typename real>
     235        1345 : Driver<real>::Driver(const CLToolOptions& co ):
     236        1345 :   CLTool(co) {
     237        1345 :   inputdata=inputType::commandline;
     238        1345 : }
     239             : template<typename real>
     240           7 : std::string Driver<real>::description()const {
     241           7 :   return "analyze trajectories with plumed";
     242             : }
     243             : 
     244             : template<typename real>
     245        1331 : int Driver<real>::main(FILE* in,FILE*out,Communicator& pc) {
     246             : 
     247        1331 :   Units units;
     248        1331 :   PDB pdb;
     249             : 
     250             : // Parse everything
     251             :   bool printhelpdebug;
     252        1331 :   parseFlag("--help-debug",printhelpdebug);
     253        1331 :   if( printhelpdebug ) {
     254             :     std::fprintf(out,"%s",
     255             :                  "Additional options for debug (only to be used in regtest):\n"
     256             :                  "  [--debug-float yes]     : turns on the single precision version (to check float interface)\n"
     257             :                  "  [--debug-dd yes]        : use a fake domain decomposition\n"
     258             :                  "  [--debug-pd yes]        : use a fake particle decomposition\n"
     259             :                 );
     260             :     return 0;
     261             :   }
     262             :   // Are we reading trajectory data
     263             :   bool noatoms;
     264        1331 :   parseFlag("--noatoms",noatoms);
     265             :   bool parseOnly;
     266        2662 :   parseFlag("--parse-only",parseOnly);
     267             :   std::string full_outputfile;
     268        2732 :   parse("--shortcut-ofile",full_outputfile);
     269             :   std::string valuedict_file;
     270        1331 :   parse("--valuedict-ofile",valuedict_file);
     271             :   bool restart;
     272        2732 :   parseFlag("--restart",restart);
     273             : 
     274             :   std::string fakein;
     275             :   bool debug_float=false;
     276             :   fakein="";
     277        2662 :   if(parse("--debug-float",fakein)) {
     278           2 :     if(fakein=="yes") {
     279             :       debug_float=true;
     280           0 :     } else if(fakein=="no") {
     281             :       debug_float=false;
     282             :     } else {
     283           0 :       error("--debug-float should have argument yes or no");
     284             :     }
     285             :   }
     286             : 
     287             :   if(debug_float && sizeof(real)!=sizeof(float)) {
     288           2 :     auto cl=cltoolRegister().create(CLToolOptions("driver-float"));
     289             :     cl->setInputData(this->getInputData());
     290           1 :     int ret=cl->main(in,out,pc);
     291             :     return ret;
     292           1 :   }
     293             : 
     294             :   bool debug_pd=false;
     295             :   fakein="";
     296        2660 :   if(parse("--debug-pd",fakein)) {
     297          12 :     if(fakein=="yes") {
     298             :       debug_pd=true;
     299           0 :     } else if(fakein=="no") {
     300             :       debug_pd=false;
     301             :     } else {
     302           0 :       error("--debug-pd should have argument yes or no");
     303             :     }
     304             :   }
     305             :   if(debug_pd) {
     306             :     std::fprintf(out,"DEBUGGING PARTICLE DECOMPOSITION\n");
     307             :   }
     308             : 
     309             :   bool debug_dd=false;
     310             :   fakein="";
     311        2660 :   if(parse("--debug-dd",fakein)) {
     312          92 :     if(fakein=="yes") {
     313             :       debug_dd=true;
     314           0 :     } else if(fakein=="no") {
     315             :       debug_dd=false;
     316             :     } else {
     317           0 :       error("--debug-dd should have argument yes or no");
     318             :     }
     319             :   }
     320             :   if(debug_dd) {
     321             :     std::fprintf(out,"DEBUGGING DOMAIN DECOMPOSITION\n");
     322             :   }
     323             : 
     324        1330 :   if( debug_pd || debug_dd ) {
     325         104 :     if(noatoms) {
     326           0 :       error("cannot debug without atoms");
     327             :     }
     328             :   }
     329             : 
     330             : // set up for multi replica driver:
     331        1330 :   int multi=0;
     332        1400 :   parse("--multi",multi);
     333        1330 :   Communicator intracomm;
     334        1330 :   Communicator intercomm;
     335        1330 :   if(multi) {
     336         300 :     int ntot=pc.Get_size();
     337         300 :     int nintra=ntot/multi;
     338         300 :     if(multi*nintra!=ntot) {
     339           0 :       error("invalid number of processes for multi environment");
     340             :     }
     341         300 :     pc.Split(pc.Get_rank()/nintra,pc.Get_rank(),intracomm);
     342         300 :     pc.Split(pc.Get_rank()%nintra,pc.Get_rank(),intercomm);
     343             :   } else {
     344        1030 :     intracomm.Set_comm(pc.Get_comm());
     345             :   }
     346             : 
     347             : // set up for debug replica exchange:
     348        1330 :   bool debug_grex=parse("--debug-grex",fakein);
     349        1330 :   int  grex_stride=0;
     350             :   FILE*grex_log=NULL;
     351             : // call fclose when fp goes out of scope
     352         724 :   auto deleter=[](auto f) {
     353             :     if(f) {
     354         724 :       std::fclose(f);
     355             :     }
     356             :   };
     357             :   std::unique_ptr<FILE,decltype(deleter)> grex_log_deleter(grex_log,deleter);
     358             : 
     359        1330 :   if(debug_grex) {
     360          30 :     if(noatoms) {
     361           0 :       error("must have atoms to debug_grex");
     362             :     }
     363          30 :     if(multi<2) {
     364           0 :       error("--debug_grex needs --multi with at least two replicas");
     365             :     }
     366          30 :     if(!Tools::convertNoexcept(fakein,grex_stride) || grex_stride<=0) {
     367          70 :       error("--debug-grex should be a positive integer");
     368             :     }
     369             :     std::string n;
     370          30 :     Tools::convert(intercomm.Get_rank(),n);
     371             :     std::string file;
     372          60 :     parse("--debug-grex-log",file);
     373          30 :     if(file.length()>0) {
     374          30 :       file+="."+n;
     375          30 :       grex_log=std::fopen(file.c_str(),"w");
     376             :       grex_log_deleter.reset(grex_log);
     377             :     }
     378             :   }
     379             : 
     380             : // Read the plumed input file name
     381             :   std::string plumedFile;
     382        1330 :   parse("--plumed",plumedFile);
     383             : // the timestep
     384             :   double t;
     385        1330 :   parse("--timestep",t);
     386        1330 :   real timestep=real(t);
     387             : // the stride
     388             :   unsigned stride;
     389        1330 :   parse("--trajectory-stride",stride);
     390             : // are we writing forces
     391        1540 :   std::string dumpforces(""), debugforces(""), dumpforcesFmt("%f");;
     392        1330 :   bool dumpfullvirial=false;
     393        1330 :   if(!noatoms) {
     394        1273 :     parse("--dump-forces",dumpforces);
     395        2546 :     parse("--debug-forces",debugforces);
     396             :   }
     397        1330 :   if(dumpforces!="" || debugforces!="" ) {
     398        1414 :     parse("--dump-forces-fmt",dumpforcesFmt);
     399             :   }
     400        1330 :   if(dumpforces!="") {
     401        1390 :     parseFlag("--dump-full-virial",dumpfullvirial);
     402             :   }
     403        1330 :   if( debugforces!="" && (debug_dd || debug_pd) ) {
     404           0 :     error("cannot debug forces and domain/particle decomposition at same time");
     405             :   }
     406           1 :   if( debugforces!="" && sizeof(real)!=sizeof(double) ) {
     407           0 :     error("cannot debug forces in single precision mode");
     408             :   }
     409             : 
     410        1330 :   real kt=-1.0;
     411        2730 :   parse("--kt",kt);
     412             :   std::string trajectory_fmt;
     413             : 
     414             :   bool use_molfile=false;
     415             : 
     416             :   // Read in an xyz file
     417        1540 :   std::string trajectoryFile(""), pdbfile(""), mcfile("");
     418             :   bool pbc_cli_given=false;
     419        1400 :   std::vector<double> pbc_cli_box(9,0.0);
     420        1330 :   int command_line_natoms=-1;
     421             : 
     422        1330 :   TrajectoryParser parser;
     423        1330 :   if(!noatoms) {
     424             :     int nn=0;
     425             :     trajectory_fmt="";
     426        8911 :     for (const auto & trj_type : TrajectoryParser::trajectoryOptions()) {
     427             :       std::string tmp;
     428       12730 :       parse("--i"+trj_type, tmp);
     429        6365 :       if (tmp.length()>0) {
     430             :         trajectory_fmt=trj_type;
     431         898 :         ++nn;
     432             :         trajectoryFile=tmp;
     433             :       }
     434             :     }
     435             : #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
     436             :     {
     437        1273 :       auto plugins_names=TrajectoryParser::getMolfilePluginsnames() ;
     438       12730 :       for(unsigned i=0; i<plugins_names.size(); i++) {
     439       11457 :         std::string molfile_key="--mf_"+plugins_names[i];
     440             :         std::string traj_molfile;
     441       11457 :         parse(molfile_key,traj_molfile);
     442       11457 :         if(traj_molfile.length()>0) {
     443         358 :           ++nn;
     444             :           std::fprintf(out,"\nDRIVER: Found molfile format trajectory %s with name %s\n",plugins_names[i].c_str(),traj_molfile.c_str());
     445             :           trajectoryFile=traj_molfile;
     446             :           trajectory_fmt=plugins_names[i];
     447             :           use_molfile=true;
     448             :         }
     449             :       }
     450        1273 :     }
     451             : #endif
     452             :     {
     453             : 
     454        1273 :       if(nn>1) {
     455           0 :         std::fprintf(stderr,"ERROR: cannot provide more than one trajectory file\n");
     456           1 :         return 1;
     457             :       }
     458             :     }
     459             : 
     460        1273 :     if(trajectoryFile.length()==0&&!parseOnly) {
     461           0 :       std::fprintf(stderr,"ERROR: missing trajectory data\n");
     462             :       return 1;
     463             :     }
     464        1273 :     std::string lengthUnits("");
     465        2546 :     parse("--length-units",lengthUnits);
     466        1273 :     if(lengthUnits.length()>0) {
     467          31 :       units.setLength(lengthUnits);
     468             :     }
     469        1274 :     std::string chargeUnits("");
     470        2546 :     parse("--charge-units",chargeUnits);
     471        1273 :     if(chargeUnits.length()>0) {
     472           1 :       units.setCharge(chargeUnits);
     473             :     }
     474        1274 :     std::string massUnits("");
     475        2546 :     parse("--mass-units",massUnits);
     476        1273 :     if(massUnits.length()>0) {
     477           1 :       units.setMass(massUnits);
     478             :     }
     479             : 
     480        2546 :     parse("--pdb",pdbfile);
     481        1273 :     if(pdbfile.length()>0) {
     482          80 :       bool check=pdb.read(pdbfile,false,1.0);
     483          80 :       if(!check) {
     484           0 :         error("error reading pdb file");
     485             :       }
     486             :     }
     487             : 
     488        2547 :     parse("--mc",mcfile);
     489             : 
     490             :     std::string pbc_cli_list;
     491        2546 :     parse("--box",pbc_cli_list);
     492        1273 :     if(pbc_cli_list.length()>0) {
     493             :       pbc_cli_given=true;
     494          52 :       std::vector<std::string> words=Tools::getWords(pbc_cli_list,",");
     495          52 :       if(words.size()==3 || words.size()==9) {
     496         221 :         for(unsigned i=0; i<words.size(); i++) {
     497             :           // with 3 numbers, they are the diagonal elements
     498         171 :           if(!Tools::convertNoexcept(words[i],pbc_cli_box[words.size()==3?4*i:i])) {
     499           1 :             error("cannot parse command-line box "+pbc_cli_list);
     500             :           }
     501             :         }
     502             :       } else {
     503           1 :         std::string msg="ERROR: cannot parse command-line box "+pbc_cli_list;
     504           1 :         std::fprintf(stderr,"%s\n",msg.c_str());
     505             :         return 1;
     506             :       }
     507             : 
     508          52 :     }
     509             : 
     510        2543 :     parse("--natoms",command_line_natoms);
     511             : 
     512             :   } // if(!noatoms)
     513             : 
     514        1328 :   if(debug_dd && debug_pd) {
     515           0 :     error("cannot use debug-dd and debug-pd at the same time");
     516             :   }
     517        1328 :   if(debug_pd || debug_dd) {
     518         104 :     if( !Communicator::initialized() ) {
     519           0 :       error("needs mpi for debug-pd");
     520             :     }
     521             :   }
     522             : 
     523        1328 :   PlumedMain p;
     524        1328 :   if( parseOnly ) {
     525          17 :     p.activateParseOnlyMode();
     526             :   }
     527        1328 :   p.cmd("setRealPrecision",(int)sizeof(real));
     528             :   int checknatoms=-1;
     529        1328 :   long long int step=0;
     530        1328 :   parse("--initial-step",step);
     531             : 
     532        1328 :   if(restart) {
     533           2 :     p.cmd("setRestart",1);
     534             :   }
     535             : 
     536        1328 :   if(Communicator::initialized()) {
     537         483 :     if(multi) {
     538         300 :       if(intracomm.Get_rank()==0) {
     539         412 :         p.cmd("GREX setMPIIntercomm",&intercomm.Get_comm());
     540             :       }
     541         600 :       p.cmd("GREX setMPIIntracomm",&intracomm.Get_comm());
     542         300 :       p.cmd("GREX init");
     543             :     }
     544         966 :     p.cmd("setMPIComm",&intracomm.Get_comm());
     545             :   }
     546        1328 :   p.cmd("setLog",out);
     547             :   // the units should be passed with the same precision as the other real numbers
     548        1328 :   p.cmd("setMDLengthUnits",real(units.getLength()));
     549        1328 :   p.cmd("setMDChargeUnits",real(units.getCharge()));
     550        1328 :   p.cmd("setMDMassUnits",real(units.getMass()));
     551        1328 :   p.cmd("setMDEngine","driver");
     552        1328 :   p.cmd("setTimestep",timestep);
     553        1328 :   if( !parseOnly || full_outputfile.length()==0 ) {
     554        1323 :     p.cmd("setPlumedDat",plumedFile.c_str());
     555             :   }
     556             : 
     557             :   int natoms=0;
     558             : 
     559        1328 :   if(parseOnly) {
     560          17 :     if(command_line_natoms<0) {
     561           0 :       error("--parseOnly requires setting the number of atoms with --natoms");
     562             :     }
     563             :     natoms=command_line_natoms;
     564             :   }
     565             : 
     566             : 
     567             :   FILE* fp_forces=NULL;
     568        1328 :   OFile fp_dforces;
     569             : 
     570             :   std::unique_ptr<FILE,decltype(deleter)> fp_forces_deleter(fp_forces,deleter);
     571             : 
     572        1328 :   if(!noatoms&&!parseOnly) {
     573        1254 :     if (trajectoryFile=="-") {
     574           1 :       auto errormessage=parser.init(trajectory_fmt, in);
     575           0 :       if(errormessage) {
     576           0 :         error(*errormessage);
     577             :       }
     578             :     } else {
     579        1253 :       if(multi) {
     580             :         std::string n;
     581         300 :         Tools::convert(intercomm.Get_rank(),n);
     582         600 :         std::string testfile=FileBase::appendSuffix(trajectoryFile,"."+n);
     583         300 :         FILE* tmp_fp=std::fopen(testfile.c_str(),"r");
     584             :         // no exceptions here
     585         300 :         if(tmp_fp) {
     586         235 :           std::fclose(tmp_fp);
     587             :           trajectoryFile=testfile;
     588             :         }
     589             :       }
     590        1253 :       auto errormessage=parser.init(trajectory_fmt,trajectoryFile,use_molfile,command_line_natoms);
     591        1253 :       if(errormessage) {
     592           1 :         error(*errormessage);
     593             :       }
     594        1252 :       natoms = parser.nOfAtoms();
     595             :     }
     596        1252 :     if(dumpforces.length()>0) {
     597         695 :       if(Communicator::initialized() && pc.Get_size()>1) {
     598             :         std::string n;
     599         282 :         Tools::convert(pc.Get_rank(),n);
     600         564 :         dumpforces+="."+n;
     601             :       }
     602         695 :       fp_forces=std::fopen(dumpforces.c_str(),"w");
     603         695 :       if(!fp_forces) {
     604          71 :         error("cannot open file "+dumpforces+" for writing");
     605             :       }
     606             :       fp_forces_deleter.reset(fp_forces);
     607             :     }
     608        1251 :     if(debugforces.length()>0) {
     609          19 :       if(Communicator::initialized() && pc.Get_size()>1) {
     610             :         std::string n;
     611           6 :         Tools::convert(pc.Get_rank(),n);
     612          12 :         debugforces+="."+n;
     613             :       }
     614          19 :       fp_dforces.open(debugforces);
     615             :     }
     616             :   }
     617             : 
     618             :   std::string line;
     619        1325 :   std::vector<real> coordinates;
     620        1325 :   std::vector<real> forces;
     621        1325 :   std::vector<real> masses;
     622        1325 :   std::vector<real> charges;
     623        1325 :   std::vector<real> cell;
     624        1325 :   std::vector<real> virial;
     625        1325 :   std::vector<real> numder;
     626             : 
     627             : // variables to test particle decomposition
     628             :   int pd_nlocal=0;
     629             :   int pd_start=0;
     630             : // variables to test random decomposition (=domain decomposition)
     631        1325 :   std::vector<int>  dd_gatindex;
     632        1325 :   std::vector<int>  dd_g2l;
     633        1325 :   std::vector<real> dd_masses;
     634        1325 :   std::vector<real> dd_charges;
     635        1325 :   std::vector<real> dd_forces;
     636        1325 :   std::vector<real> dd_coordinates;
     637             :   int dd_nlocal=0;
     638             : // random stream to choose decompositions
     639        1325 :   Random rnd;
     640             : 
     641             : 
     642             :   bool lstep=true;
     643      277988 :   while(true) {
     644             :     bool first_step=false;
     645      279313 :     if(!noatoms&&!parseOnly) {
     646             : 
     647       78711 :       real timeStep=-1.0;
     648             : 
     649       78711 :       auto errormessage=parser.readHeader(step,timeStep);
     650             : 
     651       78711 :       if (errormessage) {
     652        1182 :         if (*errormessage =="EOF") {
     653             :           break;
     654             :         } else {
     655           0 :           error(*errormessage);
     656             :         }
     657             :       }
     658       77529 :       if (lstep && timeStep>0.0) {
     659           2 :         p.cmd("setTimestep",real(timeStep));
     660             :         lstep = false;
     661             :       }
     662       77529 :       natoms=parser.nOfAtoms();
     663             :     }
     664      278131 :     if(checknatoms<0 && !noatoms) {
     665             :       pd_nlocal=natoms;
     666             :       pd_start=0;
     667             :       first_step=true;
     668        1268 :       masses.assign(natoms,std::numeric_limits<real>::quiet_NaN());
     669        1268 :       charges.assign(natoms,std::numeric_limits<real>::quiet_NaN());
     670             : //case pdb: structure
     671        1268 :       if(pdbfile.length()>0) {
     672      150997 :         for(unsigned i=0; i<pdb.size(); ++i) {
     673      150917 :           AtomNumber an=pdb.getAtomNumbers()[i];
     674             :           unsigned index=an.index();
     675      150917 :           if( index>=unsigned(natoms) ) {
     676          66 :             error("atom index in pdb exceeds the number of atoms in trajectory");
     677             :           }
     678      150917 :           masses[index]=pdb.getOccupancy()[i];
     679      150917 :           charges[index]=pdb.getBeta()[i];
     680             :         }
     681             :       }
     682        1268 :       if(mcfile.length()>0) {
     683          17 :         IFile ifile;
     684          17 :         ifile.open(mcfile);
     685             :         int index;
     686             :         double mass;
     687             :         double charge;
     688      495756 :         while(ifile.scanField("index",index).scanField("mass",mass).scanField("charge",charge).scanField()) {
     689      247862 :           if( index<0 || index>=natoms ) {
     690           2 :             error("atom index in file " + mcfile + " is not between 0 and the number of atoms in trajectory minus one");
     691             :           }
     692      247861 :           masses[index]=mass;
     693      247861 :           charges[index]=charge;
     694             :         }
     695          17 :       }
     696             :     } else if( checknatoms<0 && noatoms ) {
     697             :       natoms=0;
     698             :     }
     699             : 
     700      278130 :     if( checknatoms<0 ) {
     701        1324 :       if(kt>=0) {
     702           5 :         p.cmd("setKbT",kt);
     703             :       }
     704             :       checknatoms=natoms;
     705        1324 :       p.cmd("setNatoms",natoms);
     706        1324 :       p.cmd("init");
     707             :       // Check if we have been asked to output the long version of the input and if there are shortcuts
     708        1264 :       if( parseOnly && full_outputfile.length()>0 ) {
     709             : 
     710             :         // Read in the plumed input file and store what is in there
     711             :         std::map<std::string,std::vector<std::string> > data;
     712           5 :         IFile ifile;
     713           5 :         ifile.open(plumedFile);
     714           5 :         std::vector<std::string> words;
     715          34 :         while( Tools::getParsedLine(ifile,words) && !p.getEndPlumed() ) {
     716          24 :           p.readInputWords(words,false);
     717             :           Action* aa=p.getActionSet()[p.getActionSet().size()-1].get();
     718          24 :           plumed_assert(aa); // needed for following calls, see #1046
     719          24 :           ActionWithValue* av=aa->castToActionWithValue();
     720          32 :           if( av && aa->getDefaultString().length()>0 ) {
     721           3 :             std::vector<std::string> def;
     722           6 :             def.push_back( "defaults " + aa->getDefaultString() );
     723           3 :             data[ aa->getLabel() ] = def;
     724           3 :           }
     725          24 :           ActionShortcut* as=aa->castToActionShortcut();
     726          24 :           if( as ) {
     727          20 :             if( aa->getDefaultString().length()>0 ) {
     728           5 :               std::vector<std::string> def;
     729           5 :               def.push_back( "defaults " + aa->getDefaultString() );
     730           5 :               data[ as->getShortcutLabel() ] = def;
     731           5 :             }
     732          20 :             const auto & shortcut_commands = as->getSavedInputLines();
     733          20 :             if( shortcut_commands.size()==0 ) {
     734          14 :               continue;
     735             :             }
     736          12 :             if( data.find( as->getShortcutLabel() )!=data.end() ) {
     737          16 :               for(unsigned i=0; i<shortcut_commands.size(); ++i) {
     738          14 :                 data[ as->getShortcutLabel() ].push_back( shortcut_commands[i] );
     739             :               }
     740             :             } else {
     741           4 :               data[ as->getShortcutLabel() ] = shortcut_commands;
     742             :             }
     743             :           }
     744             :         }
     745           5 :         ifile.close();
     746             :         // Only output the full version of the input file if there are shortcuts
     747           5 :         if( data.size()>0 && intracomm.Get_rank()==0 && intercomm.Get_rank()==0 ) {
     748           5 :           OFile long_file;
     749           5 :           long_file.open( full_outputfile );
     750           5 :           long_file.printf("{\n");
     751             :           bool firstpass=true;
     752          17 :           for(auto& x : data ) {
     753          12 :             if( !firstpass ) {
     754           7 :               long_file.printf("   },\n");
     755             :             }
     756          12 :             long_file.printf("   \"%s\" : {\n", x.first.c_str() );
     757          12 :             plumed_assert( x.second.size()>0 );
     758             :             unsigned sstart=0;
     759          12 :             if( x.second[0].find("defaults")!=std::string::npos ) {
     760             :               sstart=1;
     761          16 :               long_file.printf("      \"defaults\" : \"%s\"", x.second[0].substr( 9 ).c_str() );
     762           8 :               if( x.second.size()>1 ) {
     763           2 :                 long_file.printf(",\n");
     764             :               } else {
     765           6 :                 long_file.printf("\n");
     766             :               }
     767             :             }
     768          12 :             if( x.second.size()>sstart ) {
     769             :               {
     770           6 :                 std::string cmnd=Tools::convertRegexForJson(x.second[sstart]);
     771           6 :                 long_file.printf("      \"expansion\" : \"%s", cmnd.c_str() );
     772             :               }
     773          36 :               for(unsigned j=sstart+1; j<x.second.size(); ++j) {
     774             :                 //reinitializing it to RVO the string
     775          30 :                 std::string cmnd=Tools::convertRegexForJson(x.second[j]);
     776          30 :                 long_file.printf("\\n%s", cmnd.c_str() );
     777             :               }
     778           6 :               long_file.printf("\"\n");
     779             :             }
     780             :             firstpass=false;
     781             :           }
     782           5 :           long_file.printf("   }\n}\n");
     783           5 :           long_file.close();
     784           5 :         }
     785           5 :       }
     786        1264 :       if( valuedict_file.length()>0 && intracomm.Get_rank()==0 && intercomm.Get_rank()==0 ) {
     787           5 :         OFile valuefile;
     788           5 :         valuefile.open( valuedict_file );
     789           5 :         valuefile.printf("{\n");
     790             :         bool firsta=true;
     791         149 :         for(const auto & pp : p.getActionSet()) {
     792         144 :           if( pp.get()->getName()=="CENTER" ) {
     793           3 :             continue ;
     794             :           }
     795         141 :           ActionWithVirtualAtom* avv=dynamic_cast<ActionWithVirtualAtom*>(pp.get());
     796         141 :           if( avv ||  pp.get()->getName()=="GROUP" || pp.get()->getName()=="DENSITY" ) {
     797             :             Action* actionBase=pp.get();
     798           6 :             if( firsta ) {
     799           0 :               valuefile.printf("  \"%s\" : {\n    \"action\" : \"%s\"",
     800             :                                actionBase->getLabel().c_str(),
     801             :                                actionBase->getName().c_str() );
     802             :               firsta=false;
     803             :             } else {
     804           6 :               valuefile.printf(",\n  \"%s\" : {\n    \"action\" : \"%s\"",
     805             :                                actionBase->getLabel().c_str(),
     806             :                                actionBase->getName().c_str() );
     807             :             }
     808           6 :             if( avv ) {
     809           3 :               valuefile.printf(",\n    \"%s\" : { \"type\": \"atoms\","
     810             :                                " \"description\": \"virtual atom calculated by %s action\" }",
     811             :                                avv->getLabel().c_str(),
     812           3 :                                avv->getName().c_str() );
     813             :             } else {
     814           3 :               valuefile.printf(",\n    \"%s\" : { \"type\": \"atoms\","
     815             :                                " \"description\": \"indices of atoms specified in GROUP\" }",
     816             :                                actionBase->getLabel().c_str() );
     817             :             }
     818           6 :             valuefile.printf("\n  }");
     819           6 :             continue;
     820           6 :           }
     821         135 :           ActionWithValue* av=dynamic_cast<ActionWithValue*>(pp.get());
     822         135 :           if( av && av->getNumberOfComponents()>0 ) {
     823          89 :             Keywords keys;
     824          89 :             p.getKeywordsForAction( av->getName(), keys );
     825          89 :             if( firsta ) {
     826          10 :               valuefile.printf("  \"%s\" : {\n    \"action\" : \"%s\"",
     827           5 :                                av->getLabel().c_str(),
     828             :                                keys.getDisplayName().c_str() );
     829             :               firsta=false;
     830             :             } else {
     831         168 :               valuefile.printf(",\n  \"%s\" : {\n    \"action\" : \"%s\"",
     832          84 :                                av->getLabel().c_str(),
     833             :                                keys.getDisplayName().c_str() );
     834             :             }
     835         207 :             for(unsigned i=0; i<av->getNumberOfComponents(); ++i) {
     836         118 :               Value* myval = av->copyOutput(i);
     837         118 :               std::string compname = myval->getName(), description;
     838         118 :               if( av->getLabel()==compname ) {
     839         150 :                 description = keys.getOutputComponentDescription(".#!value");
     840             :               } else {
     841          43 :                 std::size_t dot=compname.find(av->getLabel() + ".");
     842          43 :                 std::string cname = compname.substr(dot + av->getLabel().length() + 1);
     843          86 :                 description = av->getOutputComponentDescription( cname, keys );
     844             :               }
     845         118 :               if( description.find("\\")!=std::string::npos ) {
     846           0 :                 error("found invalid backslash character in documentation for component " + compname + " in action " + av->getName() + " with label " + av->getLabel() );
     847             :               }
     848         236 :               valuefile.printf(",\n    \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
     849             :             }
     850          89 :             valuefile.printf("\n  }");
     851          89 :           }
     852         135 :           ActionShortcut* as=pp->castToActionShortcut();
     853         135 :           if( as ) {
     854          41 :             const auto & cnames = as->getSavedOutputs();
     855          41 :             if( cnames.size()==0 ) {
     856          34 :               continue ;
     857             :             }
     858             : 
     859           7 :             if( firsta ) {
     860           0 :               valuefile.printf("  \"shortcut_%s\" : {\n    \"action\" : \"%s\"", as->getShortcutLabel().c_str(), as->getName().c_str() );
     861             :               firsta=false;
     862             :             } else {
     863           7 :               valuefile.printf(",\n  \"shortcut_%s\" : {\n    \"action\" : \"%s\"", as->getShortcutLabel().c_str(), as->getName().c_str() );
     864             :             }
     865           7 :             Keywords keys;
     866           7 :             p.getKeywordsForAction( as->getName(), keys );
     867          18 :             for(unsigned i=0; i<cnames.size(); ++i) {
     868          11 :               ActionWithValue* av2=p.getActionSet().selectWithLabel<ActionWithValue*>( cnames[i] );
     869          11 :               if( !av2 ) {
     870           0 :                 plumed_merror("could not find value created by shortcut with name " + cnames[i] );
     871             :               }
     872          11 :               if( av2->getNumberOfComponents()==1 ) {
     873          11 :                 Value* myval = av2->copyOutput(0);
     874          11 :                 std::string compname = myval->getName(), description;
     875          11 :                 if( compname==as->getShortcutLabel() ) {
     876          14 :                   description = keys.getOutputComponentDescription(".#!value");
     877             :                 } else {
     878           4 :                   std::size_t shortcutPos=compname.find(as->getShortcutLabel());
     879           8 :                   description = keys.getOutputComponentDescription(
     880           4 :                                   compname.substr(shortcutPos+as->getShortcutLabel().length()+1) );
     881             :                 }
     882          11 :                 if( description.find("\\")!=std::string::npos ) {
     883           0 :                   error("found invalid backslash character in documentation for component " + compname + " in action " + as->getName() + " with label " + as->getLabel() );
     884             :                 }
     885          22 :                 valuefile.printf(",\n    \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }",
     886             :                                  myval->getName().c_str(),
     887             :                                  myval->getValueType().c_str(),
     888             :                                  description.c_str() );
     889             :               } else {
     890           0 :                 for(unsigned j=0; j<av2->getNumberOfComponents(); ++j) {
     891           0 :                   Value* myval = av2->copyOutput(j);
     892           0 :                   std::string compname = myval->getName(), description;
     893           0 :                   if( av2->getLabel()==compname ) {
     894           0 :                     plumed_merror("should not be outputting description of value from action when using shortcuts");
     895             :                   } else {
     896           0 :                     std::size_t dot=compname.find(av2->getLabel() + ".");
     897           0 :                     std::string cname = compname.substr(dot+av2->getLabel().length() + 1);
     898           0 :                     description = av2->getOutputComponentDescription( cname, keys );
     899             :                   }
     900           0 :                   if( description.find("\\")!=std::string::npos ) {
     901           0 :                     error("found invalid backslash character in documentation for component " + compname + " in action " + av2->getName() + " with label " + av2->getLabel() );
     902             :                   }
     903           0 :                   valuefile.printf(",\n    \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
     904             :                 }
     905             :               }
     906             :             }
     907           7 :             valuefile.printf("\n  }");
     908           7 :           }
     909             :         }
     910           5 :         valuefile.printf("\n}\n");
     911           5 :         valuefile.close();
     912           5 :       }
     913        1264 :       if(parseOnly) {
     914             :         break;
     915             :       }
     916             :     }
     917      278064 :     if(checknatoms!=natoms) {
     918             :       std::string stepstr;
     919           0 :       Tools::convert(step,stepstr);
     920           0 :       error("number of atoms in frame " + stepstr + " does not match number of atoms in first frame");
     921             :     }
     922             : 
     923      278064 :     coordinates.assign(3*natoms,real(0.0));
     924      278064 :     forces.assign(3*natoms,real(0.0));
     925      278064 :     cell.assign(9,real(0.0));
     926      278064 :     virial.assign(9,real(0.0));
     927             : 
     928      278064 :     if( first_step || rnd.U01()>0.5) {
     929      141084 :       if(debug_pd) {
     930         152 :         int npe=intracomm.Get_size();
     931         152 :         std::vector<int> loc(npe,0);
     932         152 :         std::vector<int> start(npe,0);
     933         608 :         for(int i=0; i<npe-1; i++) {
     934         456 :           int cc=(natoms*2*rnd.U01())/npe;
     935         456 :           if(start[i]+cc>natoms) {
     936          16 :             cc=natoms-start[i];
     937             :           }
     938         456 :           loc[i]=cc;
     939         456 :           start[i+1]=start[i]+loc[i];
     940             :         }
     941         152 :         loc[npe-1]=natoms-start[npe-1];
     942         152 :         intracomm.Bcast(loc,0);
     943         152 :         intracomm.Bcast(start,0);
     944         152 :         pd_nlocal=loc[intracomm.Get_rank()];
     945         152 :         pd_start=start[intracomm.Get_rank()];
     946         152 :         if(intracomm.Get_rank()==0) {
     947             :           std::fprintf(out,"\nDRIVER: Reassigning particle decomposition\n");
     948             :           std::fprintf(out,"DRIVER: ");
     949         190 :           for(int i=0; i<npe; i++) {
     950         152 :             std::fprintf(out,"%d ",loc[i]);
     951             :           }
     952             :           std::fprintf(out,"\n");
     953             :           std::fprintf(out,"DRIVER: ");
     954         190 :           for(int i=0; i<npe; i++) {
     955         152 :             std::fprintf(out,"%d ",start[i]);
     956             :           }
     957             :           std::fprintf(out,"\n");
     958             :         }
     959         152 :         p.cmd("setAtomsNlocal",pd_nlocal);
     960         152 :         p.cmd("setAtomsContiguous",pd_start);
     961      141084 :       } else if(debug_dd) {
     962        1100 :         int npe=intracomm.Get_size();
     963        1100 :         int rank=intracomm.Get_rank();
     964        1100 :         dd_charges.assign(natoms,0.0);
     965        1100 :         dd_masses.assign(natoms,0.0);
     966        1100 :         dd_gatindex.assign(natoms,-1);
     967        1100 :         dd_g2l.assign(natoms,-1);
     968        1100 :         dd_coordinates.assign(3*natoms,0.0);
     969        1100 :         dd_forces.assign(3*natoms,0.0);
     970             :         dd_nlocal=0;
     971       56098 :         for(int i=0; i<natoms; ++i) {
     972       54998 :           double r=rnd.U01()*npe;
     973             :           int n;
     974      115728 :           for(n=0; n<npe; n++)
     975      115728 :             if(n+1>r) {
     976             :               break;
     977             :             }
     978       54998 :           plumed_assert(n<npe);
     979       54998 :           if(n==rank) {
     980       20911 :             dd_gatindex[dd_nlocal]=i;
     981       20911 :             dd_g2l[i]=dd_nlocal;
     982       20911 :             dd_charges[dd_nlocal]=charges[i];
     983       20911 :             dd_masses[dd_nlocal]=masses[i];
     984       20911 :             dd_nlocal++;
     985             :           }
     986             :         }
     987        1100 :         if(intracomm.Get_rank()==0) {
     988             :           std::fprintf(out,"\nDRIVER: Reassigning domain decomposition\n");
     989             :         }
     990        1100 :         p.cmd("setAtomsNlocal",dd_nlocal);
     991        1100 :         p.cmd("setAtomsGatindex",&dd_gatindex[0], {dd_nlocal});
     992             :       }
     993             :     }
     994             : 
     995      278064 :     int plumedStopCondition=0;
     996      278064 :     if(!noatoms) {
     997       77479 :       auto errormessage=parser.readAtoms(
     998             :                           stride,
     999             :                           pbc_cli_given,
    1000             :                           debug_pd,
    1001             :                           pd_start,
    1002             :                           pd_nlocal,
    1003             :                           step,
    1004             :                           masses.data(),
    1005             :                           charges.data(),
    1006             :                           coordinates.data(),
    1007             :                           cell.data()
    1008             :                         );
    1009             : 
    1010       77479 :       if (errormessage) {
    1011          11 :         if (*errormessage =="EOF") {
    1012             :           break;
    1013             :         } else {
    1014           0 :           error(*errormessage);
    1015             :         }
    1016             :       }
    1017             : 
    1018       77468 :       if(pbc_cli_given) {
    1019        4270 :         for(unsigned i=0; i<9; i++) {
    1020        3843 :           cell[i]=real(pbc_cli_box[i]);
    1021             :         }
    1022             :       }
    1023       77468 :       p.cmd("setStepLongLong",step);
    1024       77468 :       p.cmd("setStopFlag",&plumedStopCondition);
    1025             : 
    1026       77468 :       if(debug_dd) {
    1027       40880 :         for(int i=0; i<dd_nlocal; ++i) {
    1028       38856 :           int kk=dd_gatindex[i];
    1029       38856 :           dd_coordinates[3*i+0]=coordinates[3*kk+0];
    1030       38856 :           dd_coordinates[3*i+1]=coordinates[3*kk+1];
    1031       38856 :           dd_coordinates[3*i+2]=coordinates[3*kk+2];
    1032             :           // masses and charges might have been read in readAtoms (e.g., dlp4)
    1033       38856 :           dd_masses[i]=masses[kk];
    1034       38856 :           dd_charges[i]=charges[kk];
    1035             :         }
    1036        2024 :         p.cmd("setForces",&dd_forces[0], {dd_nlocal,3});
    1037        2024 :         p.cmd("setPositions",&dd_coordinates[0], {dd_nlocal,3});
    1038        2024 :         p.cmd("setMasses",&dd_masses[0], {dd_nlocal});
    1039        2024 :         p.cmd("setCharges",&dd_charges[0], {dd_nlocal});
    1040             :       } else {
    1041             : // this is required to avoid troubles when the last domain
    1042             : // contains zero atoms
    1043             : // Basically, for empty domains we pass null pointers
    1044             : #define fix_pd(xx) (pd_nlocal!=0?&xx:NULL)
    1045      150888 :         p.cmd("setForces",fix_pd(forces[3*pd_start]), {pd_nlocal,3});
    1046      150888 :         p.cmd("setPositions",fix_pd(coordinates[3*pd_start]), {pd_nlocal,3});
    1047      150888 :         p.cmd("setMasses",fix_pd(masses[pd_start]), {pd_nlocal});
    1048      150888 :         p.cmd("setCharges",fix_pd(charges[pd_start]), {pd_nlocal});
    1049             :       }
    1050       77468 :       p.cmd("setBox",cell.data(), {3,3});
    1051       77468 :       p.cmd("setVirial",virial.data(), {3,3});
    1052             :     } else {
    1053      200585 :       p.cmd("setStepLongLong",step);
    1054      200585 :       p.cmd("setStopFlag",&plumedStopCondition);
    1055             :     }
    1056      278053 :     p.cmd("calc");
    1057      278049 :     if(debugforces.length()>0) {
    1058         163 :       virial.assign(9,real(0.0));
    1059         163 :       forces.assign(3*natoms,real(0.0));
    1060         163 :       p.cmd("prepareCalc");
    1061         163 :       p.cmd("performCalcNoUpdate");
    1062             :     }
    1063             : 
    1064             : // this is necessary as only processor zero is adding to the virial:
    1065      278049 :     intracomm.Bcast(virial,0);
    1066      278049 :     if(debug_pd) {
    1067         240 :       intracomm.Sum(forces);
    1068             :     }
    1069      278049 :     if(debug_dd) {
    1070       40880 :       for(int i=0; i<dd_nlocal; i++) {
    1071       38856 :         forces[3*dd_gatindex[i]+0]=dd_forces[3*i+0];
    1072       38856 :         forces[3*dd_gatindex[i]+1]=dd_forces[3*i+1];
    1073       38856 :         forces[3*dd_gatindex[i]+2]=dd_forces[3*i+2];
    1074             :       }
    1075        2024 :       dd_forces.assign(3*natoms,0.0);
    1076        2024 :       intracomm.Sum(forces);
    1077             :     }
    1078      278049 :     if(debug_grex &&step%grex_stride==0) {
    1079         114 :       p.cmd("GREX savePositions");
    1080         114 :       if(intracomm.Get_rank()>0) {
    1081          57 :         p.cmd("GREX prepare");
    1082             :       } else {
    1083          57 :         int r=intercomm.Get_rank();
    1084          57 :         int n=intercomm.Get_size();
    1085          57 :         int partner=r+(2*((r+step/grex_stride)%2))-1;
    1086          57 :         if(partner<0) {
    1087             :           partner=0;
    1088             :         }
    1089          57 :         if(partner>=n) {
    1090           8 :           partner=n-1;
    1091             :         }
    1092          57 :         p.cmd("GREX setPartner",partner);
    1093          57 :         p.cmd("GREX calculate");
    1094          57 :         p.cmd("GREX shareAllDeltaBias");
    1095         228 :         for(int i=0; i<n; i++) {
    1096             :           std::string s;
    1097         171 :           Tools::convert(i,s);
    1098         171 :           real a=std::numeric_limits<real>::quiet_NaN();
    1099         342 :           s="GREX getDeltaBias "+s;
    1100         171 :           p.cmd(s,&a);
    1101         171 :           if(grex_log) {
    1102         171 :             std::fprintf(grex_log," %f",a);
    1103             :           }
    1104             :         }
    1105          57 :         if(grex_log) {
    1106             :           std::fprintf(grex_log,"\n");
    1107             :         }
    1108             :       }
    1109             :     }
    1110             : 
    1111             : 
    1112      278049 :     if(fp_forces) {
    1113             :       std::fprintf(fp_forces,"%d\n",natoms);
    1114      321880 :       std::string fmtv=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n";
    1115       80470 :       std::string fmt=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n";
    1116       40235 :       if(dumpfullvirial) {
    1117         441 :         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]);
    1118             :       } else {
    1119       39794 :         std::fprintf(fp_forces,fmt.c_str(),virial[0],virial[4],virial[8]);
    1120             :       }
    1121       40235 :       fmt="X "+fmt;
    1122     5088484 :       for(int i=0; i<natoms; i++) {
    1123     5048249 :         std::fprintf(fp_forces,fmt.c_str(),forces[3*i],forces[3*i+1],forces[3*i+2]);
    1124             :       }
    1125             :     }
    1126      278049 :     if(debugforces.length()>0) {
    1127             :       // Now call the routine to work out the derivatives numerically
    1128         163 :       numder.assign(3*natoms+9,real(0.0));
    1129         163 :       real base=0;
    1130         163 :       p.cmd("getBias",&base);
    1131         163 :       if( std::abs(base)<epsilon ) {
    1132             :         std::fprintf(out,"WARNING: bias for configuration appears to be zero so debugging forces is trivial\n");
    1133             :       }
    1134         163 :       evaluateNumericalDerivatives( step, p, coordinates, masses, charges, cell, base, numder );
    1135             : 
    1136             :       // And output everything to a file
    1137         163 :       fp_dforces.fmtField(" " + dumpforcesFmt);
    1138        9772 :       for(int i=0; i<3*natoms; ++i) {
    1139        9609 :         fp_dforces.printField("parameter",(int)i);
    1140       19218 :         fp_dforces.printField("analytical",forces[i]);
    1141        9609 :         fp_dforces.printField("numerical",-numder[i]);
    1142        9609 :         fp_dforces.printField();
    1143             :       }
    1144             :       // And print the virial
    1145        1630 :       for(int i=0; i<9; ++i) {
    1146        1467 :         fp_dforces.printField("parameter",3*natoms+i );
    1147        1467 :         fp_dforces.printField("analytical",virial[i] );
    1148        1467 :         fp_dforces.printField("numerical",-numder[3*natoms+i]);
    1149        1467 :         fp_dforces.printField();
    1150             :       }
    1151             :     }
    1152             : 
    1153      278049 :     if(plumedStopCondition) {
    1154             :       break;
    1155             :     }
    1156             : 
    1157      277988 :     step+=stride;
    1158             :   }
    1159        1260 :   if(!parseOnly) {
    1160        1319 :     p.cmd("runFinalJobs");
    1161             :   }
    1162             : 
    1163             :   return 0;
    1164        5690 : }
    1165             : 
    1166             : template<typename real>
    1167         163 : void Driver<real>::evaluateNumericalDerivatives( const long long int& step, PlumedMain& p, const std::vector<real>& coordinates,
    1168             :     const std::vector<real>& masses, const std::vector<real>& charges,
    1169             :     std::vector<real>& cell, const double& base, std::vector<real>& numder ) {
    1170             : 
    1171         163 :   int natoms = coordinates.size() / 3;
    1172             :   real delta = std::sqrt(epsilon);
    1173         163 :   std::vector<Vector> pos(natoms);
    1174         163 :   real bias=0;
    1175         163 :   std::vector<real> fake_forces( 3*natoms ), fake_virial(9);
    1176        3366 :   for(int i=0; i<natoms; ++i) {
    1177       12812 :     for(unsigned j=0; j<3; ++j) {
    1178        9609 :       pos[i][j]=coordinates[3*i+j];
    1179             :     }
    1180             :   }
    1181             : 
    1182        3366 :   for(int i=0; i<natoms; ++i) {
    1183       12812 :     for(unsigned j=0; j<3; ++j) {
    1184        9609 :       pos[i][j]=pos[i][j]+delta;
    1185        9609 :       p.cmd("setStepLongLong",step);
    1186        9609 :       p.cmd("setPositions",&pos[0][0], {natoms,3});
    1187        9609 :       p.cmd("setForces",&fake_forces[0], {natoms,3});
    1188        9609 :       p.cmd("setMasses",&masses[0], {natoms});
    1189        9609 :       p.cmd("setCharges",&charges[0], {natoms});
    1190        9609 :       p.cmd("setBox",&cell[0], {3,3});
    1191        9609 :       p.cmd("setVirial",&fake_virial[0], {3,3});
    1192        9609 :       p.cmd("prepareCalc");
    1193        9609 :       p.cmd("performCalcNoUpdate");
    1194        9609 :       p.cmd("getBias",&bias);
    1195        9609 :       pos[i][j]=coordinates[3*i+j];
    1196        9609 :       numder[3*i+j] = (bias - base) / delta;
    1197             :     }
    1198             :   }
    1199             : 
    1200             :   // Create the cell
    1201         163 :   Tensor box( cell[0], cell[1], cell[2], cell[3], cell[4], cell[5], cell[6], cell[7], cell[8] );
    1202             :   // And the virial
    1203         163 :   Pbc pbc;
    1204         163 :   pbc.setBox( box );
    1205         163 :   Tensor nvirial;
    1206         652 :   for(unsigned i=0; i<3; i++)
    1207        1956 :     for(unsigned k=0; k<3; k++) {
    1208        1467 :       double arg0=box(i,k);
    1209       30294 :       for(int j=0; j<natoms; ++j) {
    1210       28827 :         pos[j]=pbc.realToScaled( pos[j] );
    1211             :       }
    1212        1467 :       cell[3*i+k]=box(i,k)=box(i,k)+delta;
    1213        1467 :       pbc.setBox(box);
    1214       30294 :       for(int j=0; j<natoms; j++) {
    1215       28827 :         pos[j]=pbc.scaledToReal( pos[j] );
    1216             :       }
    1217        1467 :       p.cmd("setStepLongLong",step);
    1218        1467 :       p.cmd("setPositions",&pos[0][0], {natoms,3});
    1219        1467 :       p.cmd("setForces",&fake_forces[0], {natoms,3});
    1220        1467 :       p.cmd("setMasses",&masses[0], {natoms});
    1221        1467 :       p.cmd("setCharges",&charges[0], {natoms});
    1222        1467 :       p.cmd("setBox",&cell[0], {3,3});
    1223        1467 :       p.cmd("setVirial",&fake_virial[0], {3,3});
    1224        1467 :       p.cmd("prepareCalc");
    1225        1467 :       p.cmd("performCalcNoUpdate");
    1226        1467 :       p.cmd("getBias",&bias);
    1227        1467 :       cell[3*i+k]=box(i,k)=arg0;
    1228        1467 :       pbc.setBox(box);
    1229       30294 :       for(int j=0; j<natoms; j++)
    1230      115308 :         for(unsigned n=0; n<3; ++n) {
    1231       86481 :           pos[j][n]=coordinates[3*j+n];
    1232             :         }
    1233        1467 :       nvirial(i,k) = ( bias - base ) / delta;
    1234             :     }
    1235         163 :   nvirial=-matmul(box.transpose(),nvirial);
    1236         652 :   for(unsigned i=0; i<3; i++)
    1237        1956 :     for(unsigned k=0; k<3; k++) {
    1238        1467 :       numder[3*natoms+3*i+k] = nvirial(i,k);
    1239             :     }
    1240             : 
    1241         163 : }
    1242             : 
    1243             : }
    1244             : }

Generated by: LCOV version 1.16