1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2012-2021 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 "CLToolRegister.h"
24 #include "tools/Tools.h"
25 #include "core/PlumedMain.h"
26 #include "tools/Communicator.h"
27 #include "tools/Random.h"
28 #include "tools/Pbc.h"
29 #include <cstdio>
30 #include <cstring>
31 #include <vector>
32 #include <map>
33 #include <memory>
34 #include "tools/Units.h"
35 #include "tools/PDB.h"
36 #include "tools/FileBase.h"
37 #include "tools/IFile.h"
38 
39 // when using molfile plugin
40 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
41 #ifndef __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS
42 /* Use the internal ones. Alternatively:
43  *    ifeq (,$(findstring __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS,$(CPPFLAGS)))
44  *    CPPFLAGS+=-I../molfile
45  */
46 #include "molfile/libmolfile_plugin.h"
47 #include "molfile/molfile_plugin.h"
48 using namespace PLMD::molfile;
49 #else
50 #include <libmolfile_plugin.h>
51 #include <molfile_plugin.h>
52 #endif
53 #endif
54 
55 #ifdef __PLUMED_HAS_XDRFILE
56 #include <xdrfile/xdrfile_trr.h>
57 #include <xdrfile/xdrfile_xtc.h>
58 #endif
59 
60 using namespace std;
61 
62 namespace PLMD {
63 namespace cltools {
64 
65 //+PLUMEDOC TOOLS driver-float
66 /*
67 Equivalent to \ref 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.
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 
178 */
179 //+ENDPLUMEDOC
180 //
181 
182 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
183 static vector<molfile_plugin_t *> plugins;
184 static map <string, unsigned> pluginmap;
register_cb(void * v,vmdplugin_t * p)185 static int register_cb(void *v, vmdplugin_t *p) {
186   //const char *key = p->name;
187   const auto ret = pluginmap.insert ( std::pair<string,unsigned>(string(p->name),plugins.size()) );
188   if (ret.second==false) {
189     //cerr<<"MOLFILE: found duplicate plugin for "<<key<<" : not inserted "<<endl;
190   } else {
191     //cerr<<"MOLFILE: loading plugin "<<key<<" number "<<plugins.size()-1<<endl;
192     plugins.push_back(reinterpret_cast<molfile_plugin_t *>(p));
193   }
194   return VMDPLUGIN_SUCCESS;
195 }
196 #endif
197 
198 template<typename real>
199 class Driver : public CLTool {
200 public:
201   static void registerKeywords( Keywords& keys );
202   explicit Driver(const CLToolOptions& co );
203   int main(FILE* in,FILE*out,Communicator& pc) override;
204   void evaluateNumericalDerivatives( const long int& step, PlumedMain& p, const std::vector<real>& coordinates,
205                                      const std::vector<real>& masses, const std::vector<real>& charges,
206                                      std::vector<real>& cell, const double& base, std::vector<real>& numder );
207   string description()const override;
208 };
209 
210 template<typename real>
registerKeywords(Keywords & keys)211 void Driver<real>::registerKeywords( Keywords& keys ) {
212   CLTool::registerKeywords( keys ); keys.isDriver();
213   keys.addFlag("--help-debug",false,"print special options that can be used to create regtests");
214   keys.add("compulsory","--plumed","plumed.dat","specify the name of the plumed input file");
215   keys.add("compulsory","--timestep","1.0","the timestep that was used in the calculation that produced this trajectory in picoseconds");
216   keys.add("compulsory","--trajectory-stride","1","the frequency with which frames were output to this trajectory during the simulation"
217 #ifdef __PLUMED_HAS_XDRFILE
218            " (0 means that the number of the step is read from the trajectory file,"
219            " currently working only for xtc/trr files read with --ixtc/--trr)"
220 #endif
221           );
222   keys.add("compulsory","--multi","0","set number of replicas for multi environment (needs MPI)");
223   keys.addFlag("--noatoms",false,"don't read in a trajectory.  Just use colvar files as specified in plumed.dat");
224   keys.addFlag("--parse-only",false,"read the plumed input file and stop");
225   keys.add("atoms","--ixyz","the trajectory in xyz format");
226   keys.add("atoms","--igro","the trajectory in gro format");
227   keys.add("atoms","--idlp4","the trajectory in DL_POLY_4 format");
228 #ifdef __PLUMED_HAS_XDRFILE
229   keys.add("atoms","--ixtc","the trajectory in xtc format (xdrfile implementation)");
230   keys.add("atoms","--itrr","the trajectory in trr format (xdrfile implementation)");
231 #endif
232   keys.add("optional","--length-units","units for length, either as a string or a number");
233   keys.add("optional","--mass-units","units for mass in pdb and mc file, either as a string or a number");
234   keys.add("optional","--charge-units","units for charge in pdb and mc file, either as a string or a number");
235   keys.add("optional","--kt","set \\f$k_B T\\f$, it will not be necessary to specify temperature in input file");
236   keys.add("optional","--dump-forces","dump the forces on a file");
237   keys.add("optional","--dump-forces-fmt","( default=%%f ) the format to use to dump the forces");
238   keys.addFlag("--dump-full-virial",false,"with --dump-forces, it dumps the 9 components of the virial");
239   keys.add("optional","--pdb","provides a pdb with masses and charges");
240   keys.add("optional","--mc","provides a file with masses and charges as produced with DUMPMASSCHARGE");
241   keys.add("optional","--box","comma-separated box dimensions (3 for orthorhombic, 9 for generic)");
242   keys.add("optional","--natoms","provides number of atoms - only used if file format does not contain number of atoms");
243   keys.add("optional","--initial-step","provides a number for the initial step, default is 0");
244   keys.add("optional","--debug-forces","output a file containing the forces due to the bias evaluated using numerical derivatives "
245            "and using the analytical derivatives implemented in plumed");
246   keys.add("hidden","--debug-float","[yes/no] turns on the single precision version (to check float interface)");
247   keys.add("hidden","--debug-dd","[yes/no] use a fake domain decomposition");
248   keys.add("hidden","--debug-pd","[yes/no] use a fake particle decomposition");
249   keys.add("hidden","--debug-grex","use a fake gromacs-like replica exchange, specify exchange stride");
250   keys.add("hidden","--debug-grex-log","log file for debug=grex");
251 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
252   MOLFILE_INIT_ALL
253   MOLFILE_REGISTER_ALL(NULL, register_cb)
254   for(unsigned i=0; i<plugins.size(); i++) {
255     string kk="--mf_"+string(plugins[i]->name);
256     string mm=" molfile: the trajectory in "+string(plugins[i]->name)+" format " ;
257     keys.add("atoms",kk,mm);
258   }
259 #endif
260 }
261 template<typename real>
Driver(const CLToolOptions & co)262 Driver<real>::Driver(const CLToolOptions& co ):
263   CLTool(co)
264 {
265   inputdata=commandline;
266 }
267 template<typename real>
description() const268 string Driver<real>::description()const { return "analyze trajectories with plumed"; }
269 
270 template<typename real>
main(FILE * in,FILE * out,Communicator & pc)271 int Driver<real>::main(FILE* in,FILE*out,Communicator& pc) {
272 
273   Units units;
274   PDB pdb;
275 
276 // Parse everything
277   bool printhelpdebug; parseFlag("--help-debug",printhelpdebug);
278   if( printhelpdebug ) {
279     fprintf(out,"%s",
280             "Additional options for debug (only to be used in regtest):\n"
281             "  [--debug-float yes]     : turns on the single precision version (to check float interface)\n"
282             "  [--debug-dd yes]        : use a fake domain decomposition\n"
283             "  [--debug-pd yes]        : use a fake particle decomposition\n"
284            );
285     return 0;
286   }
287   // Are we reading trajectory data
288   bool noatoms; parseFlag("--noatoms",noatoms);
289   bool parseOnly; parseFlag("--parse-only",parseOnly);
290 
291   std::string fakein;
292   bool debug_float=false;
293   fakein="";
294   if(parse("--debug-float",fakein)) {
295     if(fakein=="yes") debug_float=true;
296     else if(fakein=="no") debug_float=false;
297     else error("--debug-float should have argument yes or no");
298   }
299 
300   if(debug_float && sizeof(real)!=sizeof(float)) {
301     auto cl=cltoolRegister().create(CLToolOptions("driver-float"));
302     cl->setInputData(this->getInputData());
303     int ret=cl->main(in,out,pc);
304     return ret;
305   }
306 
307   bool debug_pd=false;
308   fakein="";
309   if(parse("--debug-pd",fakein)) {
310     if(fakein=="yes") debug_pd=true;
311     else if(fakein=="no") debug_pd=false;
312     else error("--debug-pd should have argument yes or no");
313   }
314   if(debug_pd) fprintf(out,"DEBUGGING PARTICLE DECOMPOSITION\n");
315 
316   bool debug_dd=false;
317   fakein="";
318   if(parse("--debug-dd",fakein)) {
319     if(fakein=="yes") debug_dd=true;
320     else if(fakein=="no") debug_dd=false;
321     else error("--debug-dd should have argument yes or no");
322   }
323   if(debug_dd) fprintf(out,"DEBUGGING DOMAIN DECOMPOSITION\n");
324 
325   if( debug_pd || debug_dd ) {
326     if(noatoms) error("cannot debug without atoms");
327   }
328 
329 // set up for multi replica driver:
330   int multi=0;
331   parse("--multi",multi);
332   Communicator intracomm;
333   Communicator intercomm;
334   if(multi) {
335     int ntot=pc.Get_size();
336     int nintra=ntot/multi;
337     if(multi*nintra!=ntot) error("invalid number of processes for multi environment");
338     pc.Split(pc.Get_rank()/nintra,pc.Get_rank(),intracomm);
339     pc.Split(pc.Get_rank()%nintra,pc.Get_rank(),intercomm);
340   } else {
341     intracomm.Set_comm(pc.Get_comm());
342   }
343 
344 // set up for debug replica exchange:
345   bool debug_grex=parse("--debug-grex",fakein);
346   int  grex_stride=0;
347   FILE*grex_log=NULL;
348   if(debug_grex) {
349     if(noatoms) error("must have atoms to debug_grex");
350     if(multi<2)  error("--debug_grex needs --multi with at least two replicas");
351     Tools::convert(fakein,grex_stride);
352     string n; Tools::convert(intercomm.Get_rank(),n);
353     string file;
354     parse("--debug-grex-log",file);
355     if(file.length()>0) {
356       file+="."+n;
357       grex_log=fopen(file.c_str(),"w");
358     }
359   }
360 
361 // Read the plumed input file name
362   string plumedFile; parse("--plumed",plumedFile);
363 // the timestep
364   double t; parse("--timestep",t);
365   real timestep=real(t);
366 // the stride
367   unsigned stride; parse("--trajectory-stride",stride);
368 // are we writing forces
369   string dumpforces(""), debugforces(""), dumpforcesFmt("%f");;
370   bool dumpfullvirial=false;
371   if(!noatoms) {
372     parse("--dump-forces",dumpforces);
373     parse("--debug-forces",debugforces);
374   }
375   if(dumpforces!="" || debugforces!="" ) parse("--dump-forces-fmt",dumpforcesFmt);
376   if(dumpforces!="") parseFlag("--dump-full-virial",dumpfullvirial);
377   if( debugforces!="" && (debug_dd || debug_pd) ) error("cannot debug forces and domain/particle decomposition at same time");
378   if( debugforces!="" && sizeof(real)!=sizeof(double) ) error("cannot debug forces in single precision mode");
379 
380   real kt=-1.0;
381   parse("--kt",kt);
382   string trajectory_fmt;
383 
384   bool use_molfile=false;
385 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
386   molfile_plugin_t *api=NULL;
387   void *h_in=NULL;
388   molfile_timestep_t ts_in; // this is the structure that has the timestep
389 // a std::unique_ptr<float> with the same scope as ts_in
390 // it is necessary in order to store the pointer to ts_in.coords
391   std::unique_ptr<float[]> ts_in_coords;
392   ts_in.coords=ts_in_coords.get();
393   ts_in.velocities=NULL;
394   ts_in.A=-1; // we use this to check whether cell is provided or not
395 #endif
396 
397 // Read in an xyz file
398   string trajectoryFile(""), pdbfile(""), mcfile("");
399   bool pbc_cli_given=false; vector<double> pbc_cli_box(9,0.0);
400   int command_line_natoms=-1;
401 
402   if(!noatoms) {
403     std::string traj_xyz; parse("--ixyz",traj_xyz);
404     std::string traj_gro; parse("--igro",traj_gro);
405     std::string traj_dlp4; parse("--idlp4",traj_dlp4);
406     std::string traj_xtc;
407     std::string traj_trr;
408 #ifdef __PLUMED_HAS_XDRFILE
409     parse("--ixtc",traj_xtc);
410     parse("--itrr",traj_trr);
411 #endif
412 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
413     for(unsigned i=0; i<plugins.size(); i++) {
414       string molfile_key="--mf_"+string(plugins[i]->name);
415       string traj_molfile;
416       parse(molfile_key,traj_molfile);
417       if(traj_molfile.length()>0) {
418         fprintf(out,"\nDRIVER: Found molfile format trajectory %s with name %s\n",plugins[i]->name,traj_molfile.c_str());
419         trajectoryFile=traj_molfile;
420         trajectory_fmt=string(plugins[i]->name);
421         use_molfile=true;
422         api = plugins[i];
423       }
424     }
425 #endif
426     { // check that only one fmt is specified
427       int nn=0;
428       if(traj_xyz.length()>0) nn++;
429       if(traj_gro.length()>0) nn++;
430       if(traj_dlp4.length()>0) nn++;
431       if(traj_xtc.length()>0) nn++;
432       if(traj_trr.length()>0) nn++;
433       if(nn>1) {
434         fprintf(stderr,"ERROR: cannot provide more than one trajectory file\n");
435         if(grex_log)fclose(grex_log);
436         return 1;
437       }
438     }
439     if(traj_xyz.length()>0 && trajectoryFile.length()==0) {
440       trajectoryFile=traj_xyz;
441       trajectory_fmt="xyz";
442     }
443     if(traj_gro.length()>0 && trajectoryFile.length()==0) {
444       trajectoryFile=traj_gro;
445       trajectory_fmt="gro";
446     }
447     if(traj_dlp4.length()>0 && trajectoryFile.length()==0) {
448       trajectoryFile=traj_dlp4;
449       trajectory_fmt="dlp4";
450     }
451     if(traj_xtc.length()>0 && trajectoryFile.length()==0) {
452       trajectoryFile=traj_xtc;
453       trajectory_fmt="xdr-xtc";
454     }
455     if(traj_trr.length()>0 && trajectoryFile.length()==0) {
456       trajectoryFile=traj_trr;
457       trajectory_fmt="xdr-trr";
458     }
459     if(trajectoryFile.length()==0&&!parseOnly) {
460       fprintf(stderr,"ERROR: missing trajectory data\n");
461       if(grex_log)fclose(grex_log);
462       return 1;
463     }
464     string lengthUnits(""); parse("--length-units",lengthUnits);
465     if(lengthUnits.length()>0) units.setLength(lengthUnits);
466     string chargeUnits(""); parse("--charge-units",chargeUnits);
467     if(chargeUnits.length()>0) units.setCharge(chargeUnits);
468     string massUnits(""); parse("--mass-units",massUnits);
469     if(massUnits.length()>0) units.setMass(massUnits);
470 
471     parse("--pdb",pdbfile);
472     if(pdbfile.length()>0) {
473       bool check=pdb.read(pdbfile,false,1.0);
474       if(!check) error("error reading pdb file");
475     }
476 
477     parse("--mc",mcfile);
478 
479     string pbc_cli_list; parse("--box",pbc_cli_list);
480     if(pbc_cli_list.length()>0) {
481       pbc_cli_given=true;
482       vector<string> words=Tools::getWords(pbc_cli_list,",");
483       if(words.size()==3) {
484         for(int i=0; i<3; i++) sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[4*i]));
485       } else if(words.size()==9) {
486         for(int i=0; i<9; i++) sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[i]));
487       } else {
488         string msg="ERROR: cannot parse command-line box "+pbc_cli_list;
489         fprintf(stderr,"%s\n",msg.c_str());
490         return 1;
491       }
492 
493     }
494 
495     parse("--natoms",command_line_natoms);
496 
497   }
498 
499 
500   if(debug_dd && debug_pd) error("cannot use debug-dd and debug-pd at the same time");
501   if(debug_pd || debug_dd) {
502     if( !Communicator::initialized() ) error("needs mpi for debug-pd");
503   }
504 
505   PlumedMain p;
506   int rr=sizeof(real);
507   p.cmd("setRealPrecision",&rr);
508   int checknatoms=-1;
509   long int step=0;
510   parse("--initial-step",step);
511 
512   if(Communicator::initialized()) {
513     if(multi) {
514       if(intracomm.Get_rank()==0) p.cmd("GREX setMPIIntercomm",&intercomm.Get_comm());
515       p.cmd("GREX setMPIIntracomm",&intracomm.Get_comm());
516       p.cmd("GREX init");
517     }
518     p.cmd("setMPIComm",&intracomm.Get_comm());
519   }
520   p.cmd("setMDLengthUnits",&units.getLength());
521   p.cmd("setMDChargeUnits",&units.getCharge());
522   p.cmd("setMDMassUnits",&units.getMass());
523   p.cmd("setMDEngine","driver");
524   p.cmd("setTimestep",&timestep);
525   p.cmd("setPlumedDat",plumedFile.c_str());
526   p.cmd("setLog",out);
527 
528   int natoms;
529   int lvl=0;
530   int pb=1;
531 
532   if(parseOnly) {
533     if(command_line_natoms<0) error("--parseOnly requires setting the number of atoms with --natoms");
534     natoms=command_line_natoms;
535   }
536 
537 
538   FILE* fp=NULL; FILE* fp_forces=NULL; OFile fp_dforces;
539 #ifdef __PLUMED_HAS_XDRFILE
540   XDRFILE* xd=NULL;
541 #endif
542   if(!noatoms&&!parseOnly) {
543     if (trajectoryFile=="-")
544       fp=in;
545     else {
546       if(multi) {
547         string n;
548         Tools::convert(intercomm.Get_rank(),n);
549         std::string testfile=FileBase::appendSuffix(trajectoryFile,"."+n);
550         FILE* tmp_fp=fopen(testfile.c_str(),"r");
551         if(tmp_fp) { fclose(tmp_fp); trajectoryFile=testfile.c_str();}
552       }
553       if(use_molfile==true) {
554 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
555         h_in = api->open_file_read(trajectoryFile.c_str(), trajectory_fmt.c_str(), &natoms);
556         if(natoms==MOLFILE_NUMATOMS_UNKNOWN) {
557           if(command_line_natoms>=0) natoms=command_line_natoms;
558           else error("this file format does not provide number of atoms; use --natoms on the command line");
559         }
560         ts_in_coords.reset(new float [3*natoms]);
561         ts_in.coords = ts_in_coords.get();
562 #endif
563       } else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr") {
564 #ifdef __PLUMED_HAS_XDRFILE
565         xd=xdrfile_open(trajectoryFile.c_str(),"r");
566         if(!xd) {
567           string msg="ERROR: Error opening trajectory file "+trajectoryFile;
568           fprintf(stderr,"%s\n",msg.c_str());
569           return 1;
570         }
571         if(trajectory_fmt=="xdr-xtc") read_xtc_natoms(&trajectoryFile[0],&natoms);
572         if(trajectory_fmt=="xdr-trr") read_trr_natoms(&trajectoryFile[0],&natoms);
573 #endif
574       } else {
575         fp=fopen(trajectoryFile.c_str(),"r");
576         if(!fp) {
577           string msg="ERROR: Error opening trajectory file "+trajectoryFile;
578           fprintf(stderr,"%s\n",msg.c_str());
579           return 1;
580         }
581       }
582     }
583     if(dumpforces.length()>0) {
584       if(Communicator::initialized() && pc.Get_size()>1) {
585         string n;
586         Tools::convert(pc.Get_rank(),n);
587         dumpforces+="."+n;
588       }
589       fp_forces=fopen(dumpforces.c_str(),"w");
590     }
591     if(debugforces.length()>0) {
592       if(Communicator::initialized() && pc.Get_size()>1) {
593         string n;
594         Tools::convert(pc.Get_rank(),n);
595         debugforces+="."+n;
596       }
597       fp_dforces.open(debugforces);
598     }
599   }
600 
601   std::string line;
602   std::vector<real> coordinates;
603   std::vector<real> forces;
604   std::vector<real> masses;
605   std::vector<real> charges;
606   std::vector<real> cell;
607   std::vector<real> virial;
608   std::vector<real> numder;
609 
610 // variables to test particle decomposition
611   int pd_nlocal;
612   int pd_start;
613 // variables to test random decomposition (=domain decomposition)
614   std::vector<int>  dd_gatindex;
615   std::vector<int>  dd_g2l;
616   std::vector<real> dd_masses;
617   std::vector<real> dd_charges;
618   std::vector<real> dd_forces;
619   std::vector<real> dd_coordinates;
620   int dd_nlocal;
621 // random stream to choose decompositions
622   Random rnd;
623 
624   if(trajectory_fmt=="dlp4") {
625     if(!Tools::getline(fp,line)) error("error reading title");
626     if(!Tools::getline(fp,line)) error("error reading atoms");
627     sscanf(line.c_str(),"%d %d %d",&lvl,&pb,&natoms);
628 
629   }
630   bool lstep=true;
631   while(true) {
632     if(!noatoms&&!parseOnly) {
633       if(use_molfile==true) {
634 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
635         int rc;
636         rc = api->read_next_timestep(h_in, natoms, &ts_in);
637         if(rc==MOLFILE_EOF) {
638           break;
639         }
640 #endif
641       } else if(trajectory_fmt=="xyz" || trajectory_fmt=="gro" || trajectory_fmt=="dlp4") {
642         if(!Tools::getline(fp,line)) break;
643       }
644     }
645     bool first_step=false;
646     if(!noatoms&&!parseOnly) {
647       if(use_molfile==false && (trajectory_fmt=="xyz" || trajectory_fmt=="gro")) {
648         if(trajectory_fmt=="gro") if(!Tools::getline(fp,line)) error("premature end of trajectory file");
649         sscanf(line.c_str(),"%100d",&natoms);
650       }
651       if(use_molfile==false && trajectory_fmt=="dlp4") {
652         char xa[9];
653         int xb,xc,xd;
654         double t;
655         sscanf(line.c_str(),"%8s %ld %d %d %d %lf",xa,&step,&xb,&xc,&xd,&t);
656         timestep = real(t);
657         if (lstep) {
658           p.cmd("setTimestep",&timestep);
659           lstep = false;
660         }
661       }
662     }
663     if(checknatoms<0 && !noatoms) {
664       pd_nlocal=natoms;
665       pd_start=0;
666       first_step=true;
667       masses.assign(natoms,std::numeric_limits<real>::quiet_NaN());
668       charges.assign(natoms,std::numeric_limits<real>::quiet_NaN());
669 //case pdb: structure
670       if(pdbfile.length()>0) {
671         for(unsigned i=0; i<pdb.size(); ++i) {
672           AtomNumber an=pdb.getAtomNumbers()[i];
673           unsigned index=an.index();
674           if( index>=unsigned(natoms) ) error("atom index in pdb exceeds the number of atoms in trajectory");
675           masses[index]=pdb.getOccupancy()[i];
676           charges[index]=pdb.getBeta()[i];
677         }
678       }
679       if(mcfile.length()>0) {
680         IFile ifile;
681         ifile.open(mcfile);
682         int index; double mass; double charge;
683         while(ifile.scanField("index",index).scanField("mass",mass).scanField("charge",charge).scanField()) {
684           masses[index]=mass;
685           charges[index]=charge;
686         }
687       }
688     } else if( checknatoms<0 && noatoms ) {
689       natoms=0;
690     }
691     if( checknatoms<0 ) {
692       if(kt>=0) {
693         p.cmd("setKbT",&kt);
694       }
695       checknatoms=natoms;
696       p.cmd("setNatoms",&natoms);
697       p.cmd("init");
698       if(parseOnly) break;
699     }
700     if(checknatoms!=natoms) {
701       std::string stepstr; Tools::convert(step,stepstr);
702       error("number of atoms in frame " + stepstr + " does not match number of atoms in first frame");
703     }
704 
705     coordinates.assign(3*natoms,real(0.0));
706     forces.assign(3*natoms,real(0.0));
707     cell.assign(9,real(0.0));
708     virial.assign(9,real(0.0));
709 
710     if( first_step || rnd.U01()>0.5) {
711       if(debug_pd) {
712         int npe=intracomm.Get_size();
713         vector<int> loc(npe,0);
714         vector<int> start(npe,0);
715         for(int i=0; i<npe-1; i++) {
716           int cc=(natoms*2*rnd.U01())/npe;
717           if(start[i]+cc>natoms) cc=natoms-start[i];
718           loc[i]=cc;
719           start[i+1]=start[i]+loc[i];
720         }
721         loc[npe-1]=natoms-start[npe-1];
722         intracomm.Bcast(loc,0);
723         intracomm.Bcast(start,0);
724         pd_nlocal=loc[intracomm.Get_rank()];
725         pd_start=start[intracomm.Get_rank()];
726         if(intracomm.Get_rank()==0) {
727           fprintf(out,"\nDRIVER: Reassigning particle decomposition\n");
728           fprintf(out,"DRIVER: "); for(int i=0; i<npe; i++) fprintf(out,"%d ",loc[i]); printf("\n");
729           fprintf(out,"DRIVER: "); for(int i=0; i<npe; i++) fprintf(out,"%d ",start[i]); printf("\n");
730         }
731         p.cmd("setAtomsNlocal",&pd_nlocal);
732         p.cmd("setAtomsContiguous",&pd_start);
733       } else if(debug_dd) {
734         int npe=intracomm.Get_size();
735         int rank=intracomm.Get_rank();
736         dd_charges.assign(natoms,0.0);
737         dd_masses.assign(natoms,0.0);
738         dd_gatindex.assign(natoms,-1);
739         dd_g2l.assign(natoms,-1);
740         dd_coordinates.assign(3*natoms,0.0);
741         dd_forces.assign(3*natoms,0.0);
742         dd_nlocal=0;
743         for(int i=0; i<natoms; ++i) {
744           double r=rnd.U01()*npe;
745           int n; for(n=0; n<npe; n++) if(n+1>r)break;
746           plumed_assert(n<npe);
747           if(n==rank) {
748             dd_gatindex[dd_nlocal]=i;
749             dd_g2l[i]=dd_nlocal;
750             dd_charges[dd_nlocal]=charges[i];
751             dd_masses[dd_nlocal]=masses[i];
752             dd_nlocal++;
753           }
754         }
755         if(intracomm.Get_rank()==0) {
756           fprintf(out,"\nDRIVER: Reassigning domain decomposition\n");
757         }
758         p.cmd("setAtomsNlocal",&dd_nlocal);
759         p.cmd("setAtomsGatindex",&dd_gatindex[0]);
760       }
761     }
762 
763     int plumedStopCondition=0;
764     if(!noatoms) {
765       if(use_molfile) {
766 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
767         if(pbc_cli_given==false) {
768           if(ts_in.A>0.0) { // this is negative if molfile does not provide box
769             // info on the cell: convert using pbcset.tcl from pbctools in vmd distribution
770             real cosBC=cos(real(ts_in.alpha)*pi/180.);
771             //double sinBC=sin(ts_in.alpha*pi/180.);
772             real cosAC=cos(real(ts_in.beta)*pi/180.);
773             real cosAB=cos(real(ts_in.gamma)*pi/180.);
774             real sinAB=sin(real(ts_in.gamma)*pi/180.);
775             real Ax=real(ts_in.A);
776             real Bx=real(ts_in.B)*cosAB;
777             real By=real(ts_in.B)*sinAB;
778             real Cx=real(ts_in.C)*cosAC;
779             real Cy=(real(ts_in.C)*real(ts_in.B)*cosBC-Cx*Bx)/By;
780             real Cz=sqrt(real(ts_in.C)*real(ts_in.C)-Cx*Cx-Cy*Cy);
781             cell[0]=Ax/10.; cell[1]=0.; cell[2]=0.;
782             cell[3]=Bx/10.; cell[4]=By/10.; cell[5]=0.;
783             cell[6]=Cx/10.; cell[7]=Cy/10.; cell[8]=Cz/10.;
784           } else {
785             cell[0]=0.0; cell[1]=0.0; cell[2]=0.0;
786             cell[3]=0.0; cell[4]=0.0; cell[5]=0.0;
787             cell[6]=0.0; cell[7]=0.0; cell[8]=0.0;
788           }
789         } else {
790           for(unsigned i=0; i<9; i++)cell[i]=pbc_cli_box[i];
791         }
792         // info on coords
793         // the order is xyzxyz...
794         for(int i=0; i<3*natoms; i++) {
795           coordinates[i]=real(ts_in.coords[i])/real(10.); //convert to nm
796           //cerr<<"COOR "<<coordinates[i]<<endl;
797         }
798 #endif
799       } else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr") {
800 #ifdef __PLUMED_HAS_XDRFILE
801         int localstep;
802         float time;
803         matrix box;
804         std::unique_ptr<rvec[]> pos(new rvec[natoms]);
805         float prec,lambda;
806         int ret=exdrOK;
807         if(trajectory_fmt=="xdr-xtc") ret=read_xtc(xd,natoms,&localstep,&time,box,pos.get(),&prec);
808         if(trajectory_fmt=="xdr-trr") ret=read_trr(xd,natoms,&localstep,&time,&lambda,box,pos.get(),NULL,NULL);
809         if(stride==0) step=localstep;
810         if(ret==exdrENDOFFILE) break;
811         if(ret!=exdrOK) break;
812         for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) cell[3*i+j]=box[i][j];
813         for(int i=0; i<natoms; i++) for(unsigned j=0; j<3; j++)
814             coordinates[3*i+j]=real(pos[i][j]);
815 #endif
816       } else {
817         if(trajectory_fmt=="xyz") {
818           if(!Tools::getline(fp,line)) error("premature end of trajectory file");
819 
820           std::vector<double> celld(9,0.0);
821           if(pbc_cli_given==false) {
822             std::vector<std::string> words;
823             words=Tools::getWords(line);
824             if(words.size()==3) {
825               sscanf(line.c_str(),"%100lf %100lf %100lf",&celld[0],&celld[4],&celld[8]);
826             } else if(words.size()==9) {
827               sscanf(line.c_str(),"%100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf",
828                      &celld[0], &celld[1], &celld[2],
829                      &celld[3], &celld[4], &celld[5],
830                      &celld[6], &celld[7], &celld[8]);
831             } else error("needed box in second line of xyz file");
832           } else {			// from command line
833             celld=pbc_cli_box;
834           }
835           for(unsigned i=0; i<9; i++)cell[i]=real(celld[i]);
836         }
837         if(trajectory_fmt=="dlp4") {
838           std::vector<double> celld(9,0.0);
839           if(pbc_cli_given==false) {
840             if(!Tools::getline(fp,line)) error("error reading vector a of cell");
841             sscanf(line.c_str(),"%lf %lf %lf",&celld[0],&celld[1],&celld[2]);
842             if(!Tools::getline(fp,line)) error("error reading vector b of cell");
843             sscanf(line.c_str(),"%lf %lf %lf",&celld[3],&celld[4],&celld[5]);
844             if(!Tools::getline(fp,line)) error("error reading vector c of cell");
845             sscanf(line.c_str(),"%lf %lf %lf",&celld[6],&celld[7],&celld[8]);
846           } else {
847             celld=pbc_cli_box;
848           }
849           for(auto i=0; i<9; i++)cell[i]=real(celld[i])*0.1;
850         }
851         int ddist=0;
852         // Read coordinates
853         for(int i=0; i<natoms; i++) {
854           bool ok=Tools::getline(fp,line);
855           if(!ok) error("premature end of trajectory file");
856           double cc[3];
857           if(trajectory_fmt=="xyz") {
858             char dummy[1000];
859             int ret=std::sscanf(line.c_str(),"%999s %100lf %100lf %100lf",dummy,&cc[0],&cc[1],&cc[2]);
860             if(ret!=4) error("cannot read line"+line);
861           } else if(trajectory_fmt=="gro") {
862             // do the gromacs way
863             if(!i) {
864               //
865               // calculate the distance between dots (as in gromacs gmxlib/confio.c, routine get_w_conf )
866               //
867               const char      *p1, *p2, *p3;
868               p1 = strchr(line.c_str(), '.');
869               if (p1 == NULL) error("seems there are no coordinates in the gro file");
870               p2 = strchr(&p1[1], '.');
871               if (p2 == NULL) error("seems there is only one coordinates in the gro file");
872               ddist = p2 - p1;
873               p3 = strchr(&p2[1], '.');
874               if (p3 == NULL)error("seems there are only two coordinates in the gro file");
875               if (p3 - p2 != ddist)error("not uniform spacing in fields in the gro file");
876             }
877             Tools::convert(line.substr(20,ddist),cc[0]);
878             Tools::convert(line.substr(20+ddist,ddist),cc[1]);
879             Tools::convert(line.substr(20+ddist+ddist,ddist),cc[2]);
880           } else if(trajectory_fmt=="dlp4") {
881             char dummy[9];
882             int idummy;
883             double m,c;
884             sscanf(line.c_str(),"%8s %d %lf %lf",dummy,&idummy,&m,&c);
885             masses[i]=real(m);
886             charges[i]=real(c);
887             if(!Tools::getline(fp,line)) error("error reading coordinates");
888             sscanf(line.c_str(),"%lf %lf %lf",&cc[0],&cc[1],&cc[2]);
889             cc[0]*=0.1;
890             cc[1]*=0.1;
891             cc[2]*=0.1;
892             if(lvl>0) {
893               if(!Tools::getline(fp,line)) error("error skipping velocities");
894             }
895             if(lvl>1) {
896               if(!Tools::getline(fp,line)) error("error skipping forces");
897             }
898           } else plumed_error();
899           if(!debug_pd || ( i>=pd_start && i<pd_start+pd_nlocal) ) {
900             coordinates[3*i]=real(cc[0]);
901             coordinates[3*i+1]=real(cc[1]);
902             coordinates[3*i+2]=real(cc[2]);
903           }
904         }
905         if(trajectory_fmt=="gro") {
906           if(!Tools::getline(fp,line)) error("premature end of trajectory file");
907           std::vector<string> words=Tools::getWords(line);
908           if(words.size()<3) error("cannot understand box format");
909           Tools::convert(words[0],cell[0]);
910           Tools::convert(words[1],cell[4]);
911           Tools::convert(words[2],cell[8]);
912           if(words.size()>3) Tools::convert(words[3],cell[1]);
913           if(words.size()>4) Tools::convert(words[4],cell[2]);
914           if(words.size()>5) Tools::convert(words[5],cell[3]);
915           if(words.size()>6) Tools::convert(words[6],cell[5]);
916           if(words.size()>7) Tools::convert(words[7],cell[6]);
917           if(words.size()>8) Tools::convert(words[8],cell[7]);
918         }
919 
920       }
921 
922       p.cmd("setStepLong",&step);
923       p.cmd("setStopFlag",&plumedStopCondition);
924 
925       if(debug_dd) {
926         for(int i=0; i<dd_nlocal; ++i) {
927           int kk=dd_gatindex[i];
928           dd_coordinates[3*i+0]=coordinates[3*kk+0];
929           dd_coordinates[3*i+1]=coordinates[3*kk+1];
930           dd_coordinates[3*i+2]=coordinates[3*kk+2];
931         }
932         p.cmd("setForces",&dd_forces[0]);
933         p.cmd("setPositions",&dd_coordinates[0]);
934         p.cmd("setMasses",&dd_masses[0]);
935         p.cmd("setCharges",&dd_charges[0]);
936       } else {
937 // this is required to avoid troubles when the last domain
938 // contains zero atoms
939 // Basically, for empty domains we pass null pointers
940 #define fix_pd(xx) (pd_nlocal!=0?&xx:NULL)
941         p.cmd("setForces",fix_pd(forces[3*pd_start]));
942         p.cmd("setPositions",fix_pd(coordinates[3*pd_start]));
943         p.cmd("setMasses",fix_pd(masses[pd_start]));
944         p.cmd("setCharges",fix_pd(charges[pd_start]));
945       }
946       p.cmd("setBox",&cell[0]);
947       p.cmd("setVirial",&virial[0]);
948     } else {
949       p.cmd("setStepLong",&step);
950       p.cmd("setStopFlag",&plumedStopCondition);
951     }
952     p.cmd("calc");
953     if(debugforces.length()>0) {
954       virial.assign(9,real(0.0));
955       forces.assign(3*natoms,real(0.0));
956       p.cmd("prepareCalc");
957       p.cmd("performCalcNoUpdate");
958     }
959 
960 // this is necessary as only processor zero is adding to the virial:
961     intracomm.Bcast(virial,0);
962     if(debug_pd) intracomm.Sum(forces);
963     if(debug_dd) {
964       for(int i=0; i<dd_nlocal; i++) {
965         forces[3*dd_gatindex[i]+0]=dd_forces[3*i+0];
966         forces[3*dd_gatindex[i]+1]=dd_forces[3*i+1];
967         forces[3*dd_gatindex[i]+2]=dd_forces[3*i+2];
968       }
969       dd_forces.assign(3*natoms,0.0);
970       intracomm.Sum(forces);
971     }
972     if(debug_grex &&step%grex_stride==0) {
973       p.cmd("GREX savePositions");
974       if(intracomm.Get_rank()>0) {
975         p.cmd("GREX prepare");
976       } else {
977         int r=intercomm.Get_rank();
978         int n=intercomm.Get_size();
979         int partner=r+(2*((r+step/grex_stride)%2))-1;
980         if(partner<0)partner=0;
981         if(partner>=n) partner=n-1;
982         p.cmd("GREX setPartner",&partner);
983         p.cmd("GREX calculate");
984         p.cmd("GREX shareAllDeltaBias");
985         for(int i=0; i<n; i++) {
986           string s; Tools::convert(i,s);
987           real a=std::numeric_limits<real>::quiet_NaN(); s="GREX getDeltaBias "+s; p.cmd(s.c_str(),&a);
988           if(grex_log) fprintf(grex_log," %f",a);
989         }
990         if(grex_log) fprintf(grex_log,"\n");
991       }
992     }
993 
994 
995     if(fp_forces) {
996       fprintf(fp_forces,"%d\n",natoms);
997       string fmtv=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n";
998       string fmt=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n";
999       if(dumpfullvirial) {
1000         fprintf(fp_forces,fmtv.c_str(),virial[0],virial[1],virial[2],virial[3],virial[4],virial[5],virial[6],virial[7],virial[8]);
1001       } else {
1002         fprintf(fp_forces,fmt.c_str(),virial[0],virial[4],virial[8]);
1003       }
1004       fmt="X "+fmt;
1005       for(int i=0; i<natoms; i++)
1006         fprintf(fp_forces,fmt.c_str(),forces[3*i],forces[3*i+1],forces[3*i+2]);
1007     }
1008     if(debugforces.length()>0) {
1009       // Now call the routine to work out the derivatives numerically
1010       numder.assign(3*natoms+9,real(0.0)); real base=0;
1011       p.cmd("getBias",&base);
1012       if( fabs(base)<epsilon ) printf("WARNING: bias for configuration appears to be zero so debugging forces is trivial");
1013       evaluateNumericalDerivatives( step, p, coordinates, masses, charges, cell, base, numder );
1014 
1015       // And output everything to a file
1016       fp_dforces.fmtField(" " + dumpforcesFmt);
1017       for(int i=0; i<3*natoms; ++i) {
1018         fp_dforces.printField("parameter",(int)i);
1019         fp_dforces.printField("analytical",forces[i]);
1020         fp_dforces.printField("numerical",-numder[i]);
1021         fp_dforces.printField();
1022       }
1023       // And print the virial
1024       for(int i=0; i<9; ++i) {
1025         fp_dforces.printField("parameter",3*natoms+i );
1026         fp_dforces.printField("analytical",virial[i] );
1027         fp_dforces.printField("numerical",-numder[3*natoms+i]);
1028         fp_dforces.printField();
1029       }
1030     }
1031 
1032     if(plumedStopCondition) break;
1033 
1034     step+=stride;
1035   }
1036   if(!parseOnly) p.cmd("runFinalJobs");
1037 
1038   if(fp_forces) fclose(fp_forces);
1039   if(debugforces.length()>0) fp_dforces.close();
1040   if(fp && fp!=in)fclose(fp);
1041 #ifdef __PLUMED_HAS_XDRFILE
1042   if(xd) xdrfile_close(xd);
1043 #endif
1044 #ifdef __PLUMED_HAS_MOLFILE_PLUGINS
1045   if(h_in) api->close_file_read(h_in);
1046 #endif
1047   if(grex_log) fclose(grex_log);
1048 
1049   return 0;
1050 }
1051 
1052 template<typename real>
evaluateNumericalDerivatives(const long int & step,PlumedMain & p,const std::vector<real> & coordinates,const std::vector<real> & masses,const std::vector<real> & charges,std::vector<real> & cell,const double & base,std::vector<real> & numder)1053 void Driver<real>::evaluateNumericalDerivatives( const long int& step, PlumedMain& p, const std::vector<real>& coordinates,
1054     const std::vector<real>& masses, const std::vector<real>& charges,
1055     std::vector<real>& cell, const double& base, std::vector<real>& numder ) {
1056 
1057   int natoms = coordinates.size() / 3; real delta = sqrt(epsilon);
1058   std::vector<Vector> pos(natoms); real bias=0;
1059   std::vector<real> fake_forces( 3*natoms ), fake_virial(9);
1060   for(int i=0; i<natoms; ++i) {
1061     for(unsigned j=0; j<3; ++j) pos[i][j]=coordinates[3*i+j];
1062   }
1063 
1064   for(int i=0; i<natoms; ++i) {
1065     for(unsigned j=0; j<3; ++j) {
1066       pos[i][j]=pos[i][j]+delta;
1067       p.cmd("setStepLong",&step);
1068       p.cmd("setPositions",&pos[0][0]);
1069       p.cmd("setForces",&fake_forces[0]);
1070       p.cmd("setMasses",&masses[0]);
1071       p.cmd("setCharges",&charges[0]);
1072       p.cmd("setBox",&cell[0]);
1073       p.cmd("setVirial",&fake_virial[0]);
1074       p.cmd("prepareCalc");
1075       p.cmd("performCalcNoUpdate");
1076       p.cmd("getBias",&bias);
1077       pos[i][j]=coordinates[3*i+j];
1078       numder[3*i+j] = (bias - base) / delta;
1079     }
1080   }
1081 
1082   // Create the cell
1083   Tensor box( cell[0], cell[1], cell[2], cell[3], cell[4], cell[5], cell[6], cell[7], cell[8] );
1084   // And the virial
1085   Pbc pbc; pbc.setBox( box ); Tensor nvirial;
1086   for(unsigned i=0; i<3; i++) for(unsigned k=0; k<3; k++) {
1087       double arg0=box(i,k);
1088       for(int j=0; j<natoms; ++j) pos[j]=pbc.realToScaled( pos[j] );
1089       cell[3*i+k]=box(i,k)=box(i,k)+delta; pbc.setBox(box);
1090       for(int j=0; j<natoms; j++) pos[j]=pbc.scaledToReal( pos[j] );
1091       p.cmd("setStepLong",&step);
1092       p.cmd("setPositions",&pos[0][0]);
1093       p.cmd("setForces",&fake_forces[0]);
1094       p.cmd("setMasses",&masses[0]);
1095       p.cmd("setCharges",&charges[0]);
1096       p.cmd("setBox",&cell[0]);
1097       p.cmd("setVirial",&fake_virial[0]);
1098       p.cmd("prepareCalc");
1099       p.cmd("performCalcNoUpdate");
1100       p.cmd("getBias",&bias);
1101       cell[3*i+k]=box(i,k)=arg0; pbc.setBox(box);
1102       for(int j=0; j<natoms; j++) for(unsigned n=0; n<3; ++n) pos[j][n]=coordinates[3*j+n];
1103       nvirial(i,k) = ( bias - base ) / delta;
1104     }
1105   nvirial=-matmul(box.transpose(),nvirial);
1106   for(unsigned i=0; i<3; i++) for(unsigned k=0; k<3; k++)  numder[3*natoms+3*i+k] = nvirial(i,k);
1107 
1108 }
1109 
1110 }
1111 }
1112