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