24 #include "tools/Tools.h"
25 #include "wrapper/Plumed.h"
26 #include "tools/Communicator.h"
27 #include "tools/Random.h"
31 #include "tools/Units.h"
32 #include "tools/PDB.h"
72 template<
typename real>
75 static void registerKeywords(
Keywords& keys );
78 string description()
const;
81 template<
typename real>
83 CLTool::registerKeywords( keys );
84 keys.
addFlag(
"--help-debug",
false,
"print special options that can be used to create regtests");
85 keys.
add(
"compulsory",
"--plumed",
"plumed.dat",
"specify the name of the plumed input file");
86 keys.
add(
"compulsory",
"--timestep",
"1.0",
"the timestep that was used in the calculation that produced this trajectory in picoseconds");
87 keys.
add(
"compulsory",
"--trajectory-stride",
"1",
"the frequency with which frames were output to this trajectory during the simulation");
88 keys.
add(
"compulsory",
"--multi",
"0",
"set number of replicas for multi environment (needs mpi)");
89 keys.
addFlag(
"--noatoms",
false,
"don't read in a trajectory. Just use colvar files as specified in plumed.dat");
90 keys.
add(
"atoms",
"--ixyz",
"the trajectory in xyz format");
91 keys.
add(
"atoms",
"--igro",
"the trajectory in gro format");
92 keys.
add(
"optional",
"--length-units",
"units for length, either as a string or a number");
93 keys.
add(
"optional",
"--dump-forces",
"dump the forces on a file");
94 keys.
add(
"optional",
"--dump-forces-fmt",
"( default=%%f ) the format to use to dump the forces");
95 keys.
add(
"optional",
"--pdb",
"provides a pdb with masses and charges");
96 keys.
add(
"optional",
"--box",
"comma-separated box dimensions (3 for orthorombic, 9 for generic)");
97 keys.
add(
"hidden",
"--debug-float",
"turns on the single precision version (to check float interface)");
98 keys.
add(
"hidden",
"--debug-dd",
"use a fake domain decomposition");
99 keys.
add(
"hidden",
"--debug-pd",
"use a fake particle decomposition");
100 keys.
add(
"hidden",
"--debug-grex",
"use a fake gromacs-like replica exchange, specify exchange stride");
101 keys.
add(
"hidden",
"--debug-grex-log",
"log file for debug=grex");
104 template<
typename real>
111 template<
typename real>
114 template<
typename real>
121 bool printhelpdebug; parseFlag(
"--help-debug",printhelpdebug);
122 if( printhelpdebug ){
124 "Additional options for debug (only to be used in regtest):\n"
125 " [--debug-float] : turns on the single precision version (to check float interface)\n"
126 " [--debug-dd] : use a fake domain decomposition\n"
127 " [--debug-pd] : use a fake particle decomposition\n"
132 bool noatoms; parseFlag(
"--noatoms",noatoms);
135 bool debugfloat=parse(
"--debug-float",fakein);
136 if(debugfloat &&
sizeof(real)!=
sizeof(
float)){
139 int ret=cl->
main(in,out,pc);
144 bool debug_pd=parse(
"--debug-pd",fakein);
145 bool debug_dd=parse(
"--debug-dd",fakein);
146 if( debug_pd || debug_dd ){
147 if(noatoms) error(
"cannot debug without atoms");
152 parse(
"--multi",multi);
157 int nintra=ntot/multi;
158 if(multi*nintra!=ntot) error(
"invalid number of processes for multi environment");
166 bool debug_grex=parse(
"--debug-grex",fakein);
170 if(noatoms) error(
"must have atoms to debug_grex");
171 if(multi<2) error(
"--debug_grex needs --multi with at least two replicas");
175 parse(
"--debug-grex-log",file);
178 grex_log=fopen(file.c_str(),
"w");
183 string plumedFile; parse(
"--plumed",plumedFile);
185 double t; parse(
"--timestep",t);
186 real timestep=real(t);
188 unsigned stride; parse(
"--trajectory-stride",stride);
190 string dumpforces(
""), dumpforcesFmt(
"%f");;
191 if(!noatoms) parse(
"--dump-forces",dumpforces);
192 if(dumpforces!=
"") parse(
"--dump-forces-fmt",dumpforcesFmt);
194 string trajectory_fmt;
197 string trajectoryFile(
""), pdbfile(
"");
198 bool pbc_cli_given=
false; vector<double> pbc_cli_box(9,0.0);
200 std::string traj_xyz; parse(
"--ixyz",traj_xyz);
201 std::string traj_gro; parse(
"--igro",traj_gro);
202 if(traj_xyz.length()>0 && traj_gro.length()>0){
203 fprintf(stderr,
"ERROR: cannot provide more than one trajectory file\n");
204 if(grex_log)fclose(grex_log);
207 if(traj_xyz.length()>0 && trajectoryFile.length()==0){
208 trajectoryFile=traj_xyz;
209 trajectory_fmt=
"xyz";
211 if(traj_gro.length()>0 && trajectoryFile.length()==0){
212 trajectoryFile=traj_gro;
213 trajectory_fmt=
"gro";
215 if(trajectoryFile.length()==0){
216 fprintf(stderr,
"ERROR: missing trajectory data\n");
217 if(grex_log)fclose(grex_log);
220 string lengthUnits(
""); parse(
"--length-units",lengthUnits);
221 if(lengthUnits.length()>0) units.
setLength(lengthUnits);
223 parse(
"--pdb",pdbfile);
224 if(pdbfile.length()>0){
225 bool check=pdb.
read(pdbfile,
false,1.0);
226 if(!check) error(
"error reading pdb file");
229 string pbc_cli_list; parse(
"--box",pbc_cli_list);
230 if(pbc_cli_list.length()>0) {
234 for(
int i=0;i<3;i++) sscanf(words[i].c_str(),
"%100lf",&(pbc_cli_box[4*i]));
235 }
else if(words.size()==9) {
236 for(
int i=0;i<9;i++) sscanf(words[i].c_str(),
"%100lf",&(pbc_cli_box[i]));
238 string msg=
"ERROR: cannot parse command-line box "+pbc_cli_list;
239 fprintf(stderr,
"%s\n",msg.c_str());
246 if( debug_dd && debug_pd ) error(
"cannot use debug-dd and debug-pd at the same time");
247 if(debug_pd || debug_dd){
253 p.
cmd(
"setRealPrecision",&rr);
259 p.
cmd(
"GREX setMPIIntracomm",&intracomm.
Get_comm());
265 p.
cmd(
"setMDEngine",
"driver");
266 p.
cmd(
"setTimestep",×tep);
267 p.
cmd(
"setPlumedDat",plumedFile.c_str());
273 trajectoryFile+=
"."+
n;
276 FILE* fp=NULL; FILE* fp_forces=NULL;
278 if (trajectoryFile==
"-")
281 fp=fopen(trajectoryFile.c_str(),
"r");
283 string msg=
"ERROR: Error opening XYZ file "+trajectoryFile;
284 fprintf(stderr,
"%s\n",msg.c_str());
289 if(dumpforces.length()>0){
295 fp_forces=fopen(dumpforces.c_str(),
"w");
300 std::vector<real> coordinates;
301 std::vector<real> forces;
302 std::vector<real> masses;
303 std::vector<real> charges;
304 std::vector<real> cell;
305 std::vector<real> virial;
311 std::vector<int> dd_gatindex;
312 std::vector<int> dd_g2l;
313 std::vector<real> dd_masses;
314 std::vector<real> dd_charges;
315 std::vector<real> dd_forces;
316 std::vector<real> dd_coordinates;
327 bool first_step=
false;
329 if(trajectory_fmt==
"gro")
if(!
Tools::getline(fp,line)) error(
"premature end of trajectory file");
330 sscanf(line.c_str(),
"%100d",&natoms);
332 if(checknatoms<0 && !noatoms){
336 masses.assign(natoms,real(1.0));
337 charges.assign(natoms,real(0.0));
338 if(pdbfile.length()>0){
339 for(
unsigned i=0;i<pdb.
size();++i){
341 unsigned index=an.
index();
342 if( index>=
unsigned(natoms) ) error(
"atom index in pdb exceeds the number of atoms in trajectory");
344 charges[index]=pdb.
getBeta()[i];
347 }
else if( checknatoms<0 && noatoms ){
352 p.
cmd(
"setNatoms",&natoms);
355 if(checknatoms!=natoms){
357 error(
"number of atoms in frame " + stepstr +
" does not match number of atoms in first frame");
360 coordinates.assign(3*natoms,real(0.0));
361 forces.assign(3*natoms,real(0.0));
362 cell.assign(9,real(0.0));
363 virial.assign(9,real(0.0));
365 if( first_step || rnd.
U01()>0.5){
368 vector<int> loc(npe,0);
369 vector<int> start(npe,0);
370 for(
int i=0;i<npe-1;i++){
371 int cc=(natoms*2*rnd.
U01())/npe;
372 if(start[i]+cc>natoms) cc=natoms-start[i];
374 start[i+1]=start[i]+loc[i];
376 loc[npe-1]=natoms-start[npe-1];
377 intracomm.
Bcast(&loc[0],npe,0);
378 intracomm.
Bcast(&start[0],npe,0);
379 pd_nlocal=loc[intracomm.
Get_rank()];
380 pd_start=start[intracomm.
Get_rank()];
382 fprintf(out,
"\nDRIVER: Reassigning particle decomposition\n");
383 fprintf(out,
"DRIVER: ");
for(
int i=0;i<npe;i++) fprintf(out,
"%d ",loc[i]); printf(
"\n");
384 fprintf(out,
"DRIVER: ");
for(
int i=0;i<npe;i++) fprintf(out,
"%d ",start[i]); printf(
"\n");
386 p.
cmd(
"setAtomsNlocal",&pd_nlocal);
387 p.
cmd(
"setAtomsContiguous",&pd_start);
391 dd_charges.assign(natoms,0.0);
392 dd_masses.assign(natoms,0.0);
393 dd_gatindex.assign(natoms,-1);
394 dd_g2l.assign(natoms,-1);
395 dd_coordinates.assign(3*natoms,0.0);
396 dd_forces.assign(3*natoms,0.0);
398 for(
int i=0;i<natoms;++i){
399 double r=rnd.
U01()*npe;
400 int n;
for(n=0;n<npe;n++) if(n+1>r)
break;
401 plumed_assert(n<npe);
403 dd_gatindex[dd_nlocal]=i;
405 dd_charges[dd_nlocal]=charges[i];
406 dd_masses[dd_nlocal]=masses[i];
411 fprintf(out,
"\nDRIVER: Reassigning particle decomposition\n");
413 p.
cmd(
"setAtomsNlocal",&dd_nlocal);
414 p.
cmd(
"setAtomsGatindex",&dd_gatindex[0]);
418 int plumedStopCondition=0;
419 p.
cmd(
"setStep",&step);
420 p.
cmd(
"setStopFlag",&plumedStopCondition);
422 if(trajectory_fmt==
"xyz"){
423 if(!
Tools::getline(fp,line)) error(
"premature end of trajectory file");
425 std::vector<double> celld(9,0.0);
426 if(pbc_cli_given==
false) {
427 std::vector<std::string> words;
430 sscanf(line.c_str(),
"%100lf %100lf %100lf",&celld[0],&celld[4],&celld[8]);
431 }
else if(words.size()==9){
432 sscanf(line.c_str(),
"%100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf",
433 &celld[0], &celld[1], &celld[2],
434 &celld[3], &celld[4], &celld[5],
435 &celld[6], &celld[7], &celld[8]);
436 }
else error(
"needed box in second line of xyz file");
440 for(
unsigned i=0;i<9;i++)cell[i]=real(celld[i]);
444 for(
int i=0;i<natoms;i++){
446 if(!ok) error(
"premature end of trajectory file");
448 if(trajectory_fmt==
"xyz"){
450 int ret=std::sscanf(line.c_str(),
"%999s %100lf %100lf %100lf",
dummy,&cc[0],&cc[1],&cc[2]);
451 if(ret!=4) error(
"cannot read line"+line);
452 }
else if(trajectory_fmt==
"gro"){
458 const char *p1, *p2, *p3;
459 p1 = strchr(line.c_str(),
'.');
460 if (p1 == NULL) error(
"seems there are no coordinates in the gro file");
461 p2 = strchr(&p1[1],
'.');
462 if (p2 == NULL) error(
"seems there is only one coordinates in the gro file");
464 p3 = strchr(&p2[1],
'.');
465 if (p3 == NULL)error(
"seems there are only two coordinates in the gro file");
466 if (p3 - p2 != ddist)error(
"not uniform spacing in fields in the gro file");
471 }
else plumed_error();
472 if(!debug_pd || ( i>=pd_start && i<pd_start+pd_nlocal) ){
473 coordinates[3*i]=real(cc[0]);
474 coordinates[3*i+1]=real(cc[1]);
475 coordinates[3*i+2]=real(cc[2]);
478 if(trajectory_fmt==
"gro"){
479 if(!
Tools::getline(fp,line)) error(
"premature end of trajectory file");
481 if(words.size()<3) error(
"cannot understand box format");
494 for(
int i=0;i<dd_nlocal;++i){
495 int kk=dd_gatindex[i];
496 dd_coordinates[3*i+0]=coordinates[3*kk+0];
497 dd_coordinates[3*i+1]=coordinates[3*kk+1];
498 dd_coordinates[3*i+2]=coordinates[3*kk+2];
500 p.
cmd(
"setForces",&dd_forces[0]);
501 p.
cmd(
"setPositions",&dd_coordinates[0]);
502 p.
cmd(
"setMasses",&dd_masses[0]);
503 p.
cmd(
"setCharges",&dd_charges[0]);
505 p.
cmd(
"setForces",&forces[3*pd_start]);
506 p.
cmd(
"setPositions",&coordinates[3*pd_start]);
507 p.
cmd(
"setMasses",&masses[pd_start]);
508 p.
cmd(
"setCharges",&charges[pd_start]);
510 p.
cmd(
"setBox",&cell[0]);
511 p.
cmd(
"setVirial",&virial[0]);
516 intracomm.
Bcast(&virial[0],9,0);
517 if(debug_pd) intracomm.
Sum(&forces[0],natoms*3);
519 for(
int i=0;i<dd_nlocal;i++){
520 forces[3*dd_gatindex[i]+0]=dd_forces[3*i+0];
521 forces[3*dd_gatindex[i]+1]=dd_forces[3*i+1];
522 forces[3*dd_gatindex[i]+2]=dd_forces[3*i+2];
524 dd_forces.assign(3*natoms,0.0);
525 intracomm.
Sum(&forces[0],natoms*3);
527 if(debug_grex &&step%grex_stride==0){
528 p.
cmd(
"GREX savePositions");
530 p.
cmd(
"GREX prepare");
534 int partner=r+(2*((r+step/grex_stride)%2))-1;
535 if(partner<0)partner=0;
536 if(partner>=n) partner=n-1;
537 p.
cmd(
"GREX setPartner",&partner);
538 p.
cmd(
"GREX calculate");
539 p.
cmd(
"GREX shareAllDeltaBias");
540 for(
int i=0;i<
n;i++){
542 real
a; s=
"GREX getDeltaBias "+s; p.
cmd(s.c_str(),&
a);
543 if(grex_log) fprintf(grex_log,
" %f",a);
545 if(grex_log) fprintf(grex_log,
"\n");
551 fprintf(fp_forces,
"%d\n",natoms);
552 string fmt=dumpforcesFmt+
" "+dumpforcesFmt+
" "+dumpforcesFmt+
"\n";
553 fprintf(fp_forces,fmt.c_str(),virial[0],virial[4],virial[8]);
555 for(
int i=0;i<natoms;i++)
556 fprintf(fp_forces,fmt.c_str(),forces[3*i],forces[3*i+1],forces[3*i+2]);
559 if(noatoms && plumedStopCondition)
break;
563 p.
cmd(
"runFinalJobs");
565 if(fp_forces) fclose(fp_forces);
566 if(fp && fp!=in)fclose(fp);
567 if(grex_log) fclose(grex_log);
Simple class to store the index of an atom.
void cmd(const char *key, const void *val=NULL)
Send a command to this plumed object.
void Split(int, int, Communicator &) const
Wrapper to MPI_Comm_split.
bool read(const std::string &file, bool naturalUnits, double scale)
Read the pdb from a file, scaling positions by a factor scale.
static bool initialized()
Tests if MPI library is initialized.
int main(int argc, char **argv)
This main uses only the interface published in Plumed.h.
void Bcast(T *, int, int)
MPI_Comm & Get_comm()
Reference to MPI communicator.
void setLength(const std::string &)
Set lengh units from string.
Class containing wrappers to MPI.
void add(const std::string &t, const std::string &k, const std::string &d)
Add a new keyword of type t with name k and description d.
This class holds the keywords and their documentation.
const std::vector< double > & getBeta() const
Access to the beta array.
Small utility class that contains information about units.
int Get_rank() const
Obtain the rank of the present process.
const std::vector< double > & getOccupancy() const
Access to the occupancy array.
unsigned index() const
Returns the index number.
CLToolRegister & cltoolRegister()
const double & getLength() const
Get length units as double.
void Set_comm(MPI_Comm)
Set from a real MPI communicator.
unsigned size() const
Returns the number of atoms.
const std::vector< AtomNumber > & getAtomNumbers() const
Access to the indexes.
int Get_size() const
Obtain the number of processes.
void Sum(T *, int)
Wrapper for MPI_Allreduce with MPI_SUM.
void addFlag(const std::string &k, const bool def, const std::string &d)
Add a falg with name k that is by default on if def is true and off if def is false. d should provide a description of the flag.