24 #include "wrapper/Plumed.h"
25 #include "tools/Vector.h"
26 #include "tools/Random.h"
91 keys.
add(
"compulsory",
"nstep",
"The number of steps of dynamics you want to run");
92 keys.
add(
"compulsory",
"temperature",
"NVE",
"the temperature at which you wish to run the simulation in LJ units");
93 keys.
add(
"compulsory",
"friction",
"off",
"The friction (in LJ units) for the langevin thermostat that is used to keep the temperature constant");
94 keys.
add(
"compulsory",
"tstep",
"0.005",
"the integration timestep in LJ units");
95 keys.
add(
"compulsory",
"inputfile",
"An xyz file containing the initial configuration of the system");
96 keys.
add(
"compulsory",
"forcecutoff",
"2.5",
"");
97 keys.
add(
"compulsory",
"listcutoff",
"3.0",
"");
98 keys.
add(
"compulsory",
"outputfile",
"An output xyz file containing the final configuration of the system");
99 keys.
add(
"compulsory",
"nconfig",
"10",
"The frequency with which to write configurations to the trajectory file followed by the name of the trajectory file");
100 keys.
add(
"compulsory",
"nstat",
"1",
"The frequency with which to write the statistics to the statistics file followed by the name of the statistics file");
101 keys.
add(
"compulsory",
"maxneighbours",
"10000",
"The maximum number of neighbours an atom can have");
102 keys.
add(
"compulsory",
"idum",
"0",
"The random number seed");
103 keys.
add(
"compulsory",
"ndim",
"3",
"The dimensionality of the system (some interesting LJ clusters are two dimensional)");
104 keys.
add(
"compulsory",
"wrapatoms",
"false",
"If true, atomic coordinates are written wrapped in minimal cell");
109 write_positions_first(true),
110 write_statistics_first(true),
111 write_statistics_last_time_reopened(0),
112 write_statistics_fp(NULL)
140 std::string tempstr; parse(
"temperature",tempstr);
141 if( tempstr!=
"NVE" ) Tools::convert(tempstr,temperature);
142 parse(
"tstep",tstep);
143 std::string frictionstr; parse(
"friction",frictionstr);
144 if( tempstr!=
"NVE" ){
145 if(frictionstr==
"off"){ fprintf(stderr,
"Specify friction for thermostat\n"); exit(1); }
146 Tools::convert(frictionstr,friction);
148 parse(
"forcecutoff",forcecutoff);
149 parse(
"listcutoff",listcutoff);
150 parse(
"nstep",nstep);
151 parse(
"maxneighbours",maxneighbours);
155 parse(
"inputfile",inputfile);
156 if(inputfile.length()==0){
157 fprintf(stderr,
"Specify input file\n");
160 parse(
"outputfile",outputfile);
161 if(outputfile.length()==0){
162 fprintf(stderr,
"Specify output file\n");
165 std::string nconfstr; parse(
"nconfig",nconfstr);
166 sscanf(nconfstr.c_str(),
"%100d %255s",&nconfig,buffer1);
168 if(trajfile.length()==0){
169 fprintf(stderr,
"Specify traj file\n");
172 std::string nstatstr; parse(
"nstat",nstatstr);
173 sscanf(nstatstr.c_str(),
"%100d %255s",&nstat,buffer1);
175 if(statfile.length()==0){
176 fprintf(stderr,
"Specify stat file\n");
180 if(ndim<1 || ndim>3){
181 fprintf(stderr,
"ndim should be 1,2 or 3\n");
185 parse(
"wrapatoms",w);
187 if(w.length()>0 && (w[0]==
'T' || w[0]==
't')) wrapatoms=
true;
192 FILE* fp=fopen(inputfile.c_str(),
"r");
194 fprintf(stderr,
"ERROR: file %s not found\n",inputfile.c_str());
197 fscanf(fp,
"%1000d",&natoms);
201 void read_positions(
const string& inputfile,
int natoms,vector<Vector>& positions,
double cell[3]){
204 FILE* fp=fopen(inputfile.c_str(),
"r");
206 fprintf(stderr,
"ERROR: file %s not found\n",inputfile.c_str());
211 fgets(buffer,256,fp);
212 fscanf(fp,
"%1000lf %1000lf %1000lf",&cell[0],&cell[1],&cell[2]);
213 for(
int i=0;i<natoms;i++){
214 fscanf(fp,
"%255s %1000lf %1000lf %1000lf",atomname,&positions[i][0],&positions[i][1],&positions[i][2]);
220 void randomize_velocities(
const int natoms,
const int ndim,
const double temperature,
const vector<double>&masses,vector<Vector>& velocities,
Random&random){
222 for(
int iatom=0;iatom<natoms;iatom++)
for(
int i=0;i<ndim;i++)
223 velocities[iatom][i]=sqrt(temperature/masses[iatom])*random.
Gaussian();
228 for(
int i=0;i<3;i++){
229 vout[i]=vin[i]-floor(vin[i]/cell[i]+0.5)*cell[i];
233 void check_list(
const int natoms,
const vector<Vector>& positions,
const vector<Vector>&positions0,
const double listcutoff,
234 const double forcecutoff,
bool & recompute)
240 delta2=(0.5*(listcutoff-forcecutoff))*(0.5*(listcutoff-forcecutoff));
242 for(
int iatom=0;iatom<natoms;iatom++){
243 for(
int k=0;k<3;k++) displacement[k]=positions[iatom][k]-positions0[iatom][k];
245 for(
int k=0;k<3;k++) s+=displacement[k]*displacement[k];
246 if(s>delta2) recompute=
true;
251 void compute_list(
const int natoms,
const int listsize,
const vector<Vector>& positions,
const double cell[3],
const double listcutoff,
252 vector<int>& point,vector<int>& list){
257 listcutoff2=listcutoff*listcutoff;
259 for(
int iatom=0;iatom<natoms-1;iatom++){
260 point[iatom+1]=point[iatom];
261 for(
int jatom=iatom+1;jatom<natoms;jatom++){
262 for(
int k=0;k<3;k++) distance[k]=positions[iatom][k]-positions[jatom][k];
263 pbc(cell,distance,distance_pbc);
265 double d2=0;
for(
int k=0;k<3;k++) d2+=distance_pbc[k]*distance_pbc[k];
266 if(d2>listcutoff2)
continue;
267 if(point[iatom+1]>listsize){
269 fprintf(stderr,
"%s",
"Verlet list size exceeded\n");
270 fprintf(stderr,
"%s",
"Increase maxneighbours\n");
273 list[point[iatom+1]]=jatom;
279 void compute_forces(
const int natoms,
const int listsize,
const vector<Vector>& positions,
const double cell[3],
280 double forcecutoff,
const vector<int>& point,
const vector<int>& list,vector<Vector>& forces,
double & engconf)
284 double distance_pbc2;
287 double engcorrection;
289 forcecutoff2=forcecutoff*forcecutoff;
291 for(
int i=0;i<natoms;i++)
for(
int k=0;k<3;k++) forces[i][k]=0.0;
292 engcorrection=4.0*(1.0/pow(forcecutoff2,6.0)-1.0/pow(forcecutoff2,3));
293 for(
int iatom=0;iatom<natoms-1;iatom++){
294 for(
int jlist=point[iatom];jlist<point[iatom+1];jlist++){
295 int jatom=list[jlist];
296 for(
int k=0;k<3;k++) distance[k]=positions[iatom][k]-positions[jatom][k];
297 pbc(cell,distance,distance_pbc);
298 distance_pbc2=0.0;
for(
int k=0;k<3;k++) distance_pbc2+=distance_pbc[k]*distance_pbc[k];
300 if(distance_pbc2>forcecutoff2)
continue;
301 double distance_pbc6=distance_pbc2*distance_pbc2*distance_pbc2;
302 double distance_pbc8=distance_pbc6*distance_pbc2;
303 double distance_pbc12=distance_pbc6*distance_pbc6;
304 double distance_pbc14=distance_pbc12*distance_pbc2;
305 engconf+=4.0*(1.0/distance_pbc12 - 1.0/distance_pbc6) - engcorrection;
306 for(
int k=0;k<3;k++) f[k]=2.0*distance_pbc[k]*4.0*(6.0/distance_pbc14-3.0/distance_pbc8);
308 for(
int k=0;k<3;k++) forces[iatom][k]+=f[k];
309 for(
int k=0;k<3;k++) forces[jatom][k]-=f[k];
314 void compute_engkin(
const int natoms,
const vector<double>& masses,
const vector<Vector>& velocities,
double & engkin)
318 for(
int iatom=0;iatom<natoms;iatom++)
for(
int k=0;k<3;k++){
319 engkin+=0.5*masses[iatom]*velocities[iatom][k]*velocities[iatom][k];
324 void thermostat(
const int natoms,
const int ndim,
const vector<double>& masses,
const double dt,
const double friction,
325 const double temperature,vector<Vector>& velocities,
double & engint,
Random & random){
330 c1=exp(-friction*dt);
331 for(
int iatom=0;iatom<natoms;iatom++){
332 c2=sqrt((1.0-c1*c1)*temperature/masses[iatom]);
333 for(
int i=0;i<ndim;i++){
334 engint+=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i];
335 velocities[iatom][i]=c1*velocities[iatom][i]+c2*random.
Gaussian();
336 engint-=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i];
341 void write_positions(
const string& trajfile,
int natoms,
const vector<Vector>& positions,
const double cell[3],
const bool wrapatoms)
347 if(write_positions_first){
348 fp=fopen(trajfile.c_str(),
"w");
349 write_positions_first=
false;
351 fp=fopen(trajfile.c_str(),
"a");
353 fprintf(fp,
"%d\n",natoms);
354 fprintf(fp,
"%f %f %f\n",cell[0],cell[1],cell[2]);
355 for(
int iatom=0;iatom<natoms;iatom++){
358 if(wrapatoms) pbc(cell,positions[iatom],pos);
359 else for(
int k=0;k<3;k++) pos[k]=positions[iatom][k];
360 fprintf(fp,
"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]);
365 void write_final_positions(
const string& outputfile,
int natoms,
const vector<Vector>& positions,
const double cell[3],
const bool wrapatoms)
370 fp=fopen(outputfile.c_str(),
"w");
371 fprintf(fp,
"%d\n",natoms);
372 fprintf(fp,
"%f %f %f\n",cell[0],cell[1],cell[2]);
373 for(
int iatom=0;iatom<natoms;iatom++){
376 if(wrapatoms) pbc(cell,positions[iatom],pos);
377 else for(
int k=0;k<3;k++) pos[k]=positions[iatom][k];
378 fprintf(fp,
"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]);
385 const int natoms,
const int ndim,
const double engkin,
const double engconf,
const double engint){
387 if(write_statistics_first){
389 write_statistics_fp=fopen(statfile.c_str(),
"w");
390 write_statistics_first=
false;
392 if(istep-write_statistics_last_time_reopened>100){
394 fclose(write_statistics_fp);
395 write_statistics_fp=fopen(statfile.c_str(),
"a");
396 write_statistics_last_time_reopened=istep;
398 fprintf(write_statistics_fp,
"%d %f %f %f %f %f\n",istep,istep*tstep,2.0*engkin/
double(ndim*natoms),engconf,engkin+engconf,engkin+engconf+engint);
405 vector<Vector> positions;
406 vector<Vector> velocities;
407 vector<double> masses;
408 vector<Vector> forces;
417 vector<Vector> positions0;
453 int s=
sizeof(double);
454 plumed->
cmd(
"setRealPrecision",&s);
457 read_input(temperature,tstep,friction,forcecutoff,
458 listcutoff,nstep,nconfig,nstat,
459 wrapatoms,inputfile,outputfile,trajfile,statfile,
460 maxneighbour,ndim,idum);
463 read_natoms(inputfile,natoms);
466 fprintf(out,
"%s %s\n",
"Starting configuration :",inputfile.c_str());
467 fprintf(out,
"%s %s\n",
"Final configuration :",outputfile.c_str());
468 fprintf(out,
"%s %d\n",
"Number of atoms :",natoms);
469 fprintf(out,
"%s %f\n",
"Temperature :",temperature);
470 fprintf(out,
"%s %f\n",
"Time step :",tstep);
471 fprintf(out,
"%s %f\n",
"Friction :",friction);
472 fprintf(out,
"%s %f\n",
"Cutoff for forces :",forcecutoff);
473 fprintf(out,
"%s %f\n",
"Cutoff for neighbour list :",listcutoff);
474 fprintf(out,
"%s %d\n",
"Number of steps :",nstep);
475 fprintf(out,
"%s %d\n",
"Stride for trajectory :",nconfig);
476 fprintf(out,
"%s %s\n",
"Trajectory file :",trajfile.c_str());
477 fprintf(out,
"%s %d\n",
"Stride for statistics :",nstat);
478 fprintf(out,
"%s %s\n",
"Statistics file :",statfile.c_str());
479 fprintf(out,
"%s %d\n",
"Max average number of neighbours :",maxneighbour);
480 fprintf(out,
"%s %d\n",
"Dimensionality :",ndim);
481 fprintf(out,
"%s %d\n",
"Seed :",idum);
482 fprintf(out,
"%s %s\n",
"Are atoms wrapped on output? :",(wrapatoms?
"T":
"F"));
489 listsize=maxneighbour*natoms/2;
492 positions.resize(natoms);
493 positions0.resize(natoms);
494 velocities.resize(natoms);
495 forces.resize(natoms);
496 masses.resize(natoms);
497 point.resize(natoms);
498 list.resize(listsize);
501 for(
unsigned i=0;i<natoms;++i) masses[i]=1.0;
507 read_positions(inputfile,natoms,positions,cell);
510 randomize_velocities(natoms,ndim,temperature,masses,velocities,random);
513 plumed->
cmd(
"setNoVirial");
514 plumed->
cmd(
"setNatoms",&natoms);
515 plumed->
cmd(
"setMDEngine",
"simpleMD");
516 plumed->
cmd(
"setTimestep",&tstep);
517 plumed->
cmd(
"setPlumedDat",
"plumed.dat");
522 compute_list(natoms,listsize,positions,cell,listcutoff,point,list);
524 fprintf(out,
"List size: %d\n",point[natoms-1]);
525 for(
int iatom=0;iatom<natoms;++iatom)
for(
int k=0;k<3;++k) positions0[iatom][k]=positions[iatom][k];
528 compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf);
532 for(
int iatom=0;iatom<natoms;++iatom)
for(
int k=ndim;k<3;++k) forces[iatom][k]=0.0;
545 for(
int istep=0;istep<nstep;istep++){
546 thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random);
548 for(
int iatom=0;iatom<natoms;iatom++)
for(
int k=0;k<3;k++)
549 velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom];
551 for(
int iatom=0;iatom<natoms;iatom++)
for(
int k=0;k<3;k++)
552 positions[iatom][k]+=velocities[iatom][k]*tstep;
555 check_list(natoms,positions,positions0,listcutoff,forcecutoff,recompute_list);
557 compute_list(natoms,listsize,positions,cell,listcutoff,point,list);
558 for(
int iatom=0;iatom<natoms;++iatom)
for(
int k=0;k<3;++k) positions0[iatom][k]=positions[iatom][k];
559 fprintf(out,
"Neighbour list recomputed at step %d\n",istep);
560 fprintf(out,
"List size: %d\n",point[natoms-1]);
563 compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf);
566 int istepplusone=istep+1;
567 for(
int i=0;i<3;i++)
for(
int k=0;k<3;k++) cell9[i][k]=0.0;
568 for(
int i=0;i<3;i++) cell9[i][i]=cell[i];
569 plumed->
cmd(
"setStep",&istepplusone);
570 plumed->
cmd(
"setMasses",&masses[0]);
571 plumed->
cmd(
"setForces",&forces[0]);
572 plumed->
cmd(
"setEnergy",&engconf);
573 plumed->
cmd(
"setPositions",&positions[0]);
574 plumed->
cmd(
"setBox",cell9);
579 for(
int iatom=0;iatom<natoms;++iatom)
for(
int k=ndim;k<3;++k) forces[iatom][k]=0.0;
581 for(
int iatom=0;iatom<natoms;iatom++)
for(
int k=0;k<3;k++)
582 velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom];
584 thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random);
587 compute_engkin(natoms,masses,velocities,engkin);
590 if((istep+1)%nconfig==0) write_positions(trajfile,natoms,positions,cell,wrapatoms);
591 if((istep+1)%nstat==0) write_statistics(statfile,istep+1,tstep,natoms,ndim,engkin,engconf,engint);
596 write_final_positions(outputfile,natoms,positions,cell,wrapatoms);
599 if(write_statistics_fp) fclose(write_statistics_fp);
601 if(plumed)
delete plumed;
609 PLUMED_REGISTER_CLTOOL(SimpleMD,
"simplemd")
void cmd(const char *key, const void *val=NULL)
Send a command to this plumed object.
Class implementing fixed size vectors of doubles.
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.