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",×tep);
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",×tep);
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