LCOV - code coverage report
Current view: top level - cltools - SimpleMD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 258 277 93.1 %
Date: 2021-11-18 15:22:58 Functions: 21 23 91.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2020 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 "core/PlumedMain.h"
      25             : #include "tools/Vector.h"
      26             : #include "tools/Random.h"
      27             : #include <string>
      28             : #include <cstdio>
      29             : #include <cmath>
      30             : #include <vector>
      31             : #include <memory>
      32             : 
      33             : using namespace std;
      34             : 
      35             : namespace PLMD {
      36             : namespace cltools {
      37             : 
      38             : //+PLUMEDOC TOOLS simplemd
      39             : /*
      40             : simplemd allows one to do molecular dynamics on systems of Lennard-Jones atoms.
      41             : 
      42             : The input to simplemd is specified in an input file. Configurations are input and
      43             : output in xyz format. The input file should contain one directive per line.
      44             : The directives available are as follows:
      45             : 
      46             : \par Examples
      47             : 
      48             : You run an MD simulation using simplemd with the following command:
      49             : \verbatim
      50             : plumed simplemd < in
      51             : \endverbatim
      52             : 
      53             : The following is an example of an input file for a simplemd calculation. This file
      54             : instructs simplemd to do 50 steps of MD at a temperature of 0.722
      55             : \verbatim
      56             : nputfile input.xyz
      57             : outputfile output.xyz
      58             : temperature 0.722
      59             : tstep 0.005
      60             : friction 1
      61             : forcecutoff 2.5
      62             : listcutoff  3.0
      63             : nstep 50
      64             : nconfig 10 trajectory.xyz
      65             : nstat   10 energies.dat
      66             : \endverbatim
      67             : 
      68             : If you run the following a description of all the directives that can be used in the
      69             : input file will be output.
      70             : \verbatim
      71             : plumed simplemd --help
      72             : \endverbatim
      73             : 
      74             : */
      75             : //+ENDPLUMEDOC
      76             : 
      77           9 : class SimpleMD:
      78             :   public PLMD::CLTool
      79             : {
      80           0 :   string description()const {
      81           0 :     return "run lj code";
      82             :   }
      83             : 
      84             :   bool write_positions_first;
      85             :   bool write_statistics_first;
      86             :   int write_statistics_last_time_reopened;
      87             :   FILE* write_statistics_fp;
      88             : 
      89             : 
      90             : public:
      91        1839 :   static void registerKeywords( Keywords& keys ) {
      92        7356 :     keys.add("compulsory","nstep","The number of steps of dynamics you want to run");
      93        9195 :     keys.add("compulsory","temperature","NVE","the temperature at which you wish to run the simulation in LJ units");
      94        9195 :     keys.add("compulsory","friction","off","The friction (in LJ units) for the Langevin thermostat that is used to keep the temperature constant");
      95        9195 :     keys.add("compulsory","tstep","0.005","the integration timestep in LJ units");
      96        7356 :     keys.add("compulsory","inputfile","An xyz file containing the initial configuration of the system");
      97        9195 :     keys.add("compulsory","forcecutoff","2.5","");
      98        9195 :     keys.add("compulsory","listcutoff","3.0","");
      99        7356 :     keys.add("compulsory","outputfile","An output xyz file containing the final configuration of the system");
     100        9195 :     keys.add("compulsory","nconfig","10","The frequency with which to write configurations to the trajectory file followed by the name of the trajectory file");
     101        9195 :     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");
     102        9195 :     keys.add("compulsory","maxneighbours","10000","The maximum number of neighbors an atom can have");
     103        9195 :     keys.add("compulsory","idum","0","The random number seed");
     104        9195 :     keys.add("compulsory","ndim","3","The dimensionality of the system (some interesting LJ clusters are two dimensional)");
     105        9195 :     keys.add("compulsory","wrapatoms","false","If true, atomic coordinates are written wrapped in minimal cell");
     106        1839 :   }
     107             : 
     108           9 :   explicit SimpleMD( const CLToolOptions& co ) :
     109             :     CLTool(co),
     110             :     write_positions_first(true),
     111             :     write_statistics_first(true),
     112             :     write_statistics_last_time_reopened(0),
     113           9 :     write_statistics_fp(NULL)
     114             :   {
     115           9 :     inputdata=ifile;
     116             :   }
     117             : 
     118             : private:
     119             : 
     120             :   void
     121           9 :   read_input(double& temperature,
     122             :              double& tstep,
     123             :              double& friction,
     124             :              double& forcecutoff,
     125             :              double& listcutoff,
     126             :              int&    nstep,
     127             :              int&    nconfig,
     128             :              int&    nstat,
     129             :              bool&   wrapatoms,
     130             :              string& inputfile,
     131             :              string& outputfile,
     132             :              string& trajfile,
     133             :              string& statfile,
     134             :              int&    maxneighbours,
     135             :              int&    ndim,
     136             :              int&    idum)
     137             :   {
     138             : 
     139             :     // Read everything from input file
     140             :     char buffer1[256];
     141          18 :     std::string tempstr; parse("temperature",tempstr);
     142           9 :     if( tempstr!="NVE" ) Tools::convert(tempstr,temperature);
     143          18 :     parse("tstep",tstep);
     144          18 :     std::string frictionstr; parse("friction",frictionstr);
     145           9 :     if( tempstr!="NVE" ) {
     146           9 :       if(frictionstr=="off") { fprintf(stderr,"Specify friction for thermostat\n"); exit(1); }
     147           9 :       Tools::convert(frictionstr,friction);
     148             :     }
     149          18 :     parse("forcecutoff",forcecutoff);
     150          18 :     parse("listcutoff",listcutoff);
     151          18 :     parse("nstep",nstep);
     152          18 :     parse("maxneighbours",maxneighbours);
     153          18 :     parse("idum",idum);
     154             : 
     155             :     // Read in stuff with sanity checks
     156          18 :     parse("inputfile",inputfile);
     157           9 :     if(inputfile.length()==0) {
     158           0 :       fprintf(stderr,"Specify input file\n");
     159           0 :       exit(1);
     160             :     }
     161          18 :     parse("outputfile",outputfile);
     162           9 :     if(outputfile.length()==0) {
     163           0 :       fprintf(stderr,"Specify output file\n");
     164           0 :       exit(1);
     165             :     }
     166          18 :     std::string nconfstr; parse("nconfig",nconfstr);
     167           9 :     sscanf(nconfstr.c_str(),"%100d %255s",&nconfig,buffer1);
     168             :     trajfile=buffer1;
     169           9 :     if(trajfile.length()==0) {
     170           0 :       fprintf(stderr,"Specify traj file\n");
     171           0 :       exit(1);
     172             :     }
     173          18 :     std::string nstatstr; parse("nstat",nstatstr);
     174           9 :     sscanf(nstatstr.c_str(),"%100d %255s",&nstat,buffer1);
     175             :     statfile=buffer1;
     176           9 :     if(statfile.length()==0) {
     177           0 :       fprintf(stderr,"Specify stat file\n");
     178           0 :       exit(1);
     179             :     }
     180          18 :     parse("ndim",ndim);
     181           9 :     if(ndim<1 || ndim>3) {
     182           0 :       fprintf(stderr,"ndim should be 1,2 or 3\n");
     183           0 :       exit(1);
     184             :     }
     185             :     std::string w;
     186          18 :     parse("wrapatoms",w);
     187           9 :     wrapatoms=false;
     188          18 :     if(w.length()>0 && (w[0]=='T' || w[0]=='t')) wrapatoms=true;
     189           9 :   }
     190             : 
     191           9 :   void read_natoms(const string & inputfile,int & natoms) {
     192             : // read the number of atoms in file "input.xyz"
     193           9 :     FILE* fp=fopen(inputfile.c_str(),"r");
     194           9 :     if(!fp) {
     195           0 :       fprintf(stderr,"ERROR: file %s not found\n",inputfile.c_str());
     196           0 :       exit(1);
     197             :     }
     198           9 :     fscanf(fp,"%1000d",&natoms);
     199           9 :     fclose(fp);
     200           9 :   }
     201             : 
     202           9 :   void read_positions(const string& inputfile,int natoms,vector<Vector>& positions,double cell[3]) {
     203             : // read positions and cell from a file called inputfile
     204             : // natoms (input variable) and number of atoms in the file should be consistent
     205           9 :     FILE* fp=fopen(inputfile.c_str(),"r");
     206           9 :     if(!fp) {
     207           0 :       fprintf(stderr,"ERROR: file %s not found\n",inputfile.c_str());
     208           0 :       exit(1);
     209             :     }
     210             :     char buffer[256];
     211             :     char atomname[256];
     212             :     fgets(buffer,256,fp);
     213           9 :     fscanf(fp,"%1000lf %1000lf %1000lf",&cell[0],&cell[1],&cell[2]);
     214        1549 :     for(int i=0; i<natoms; i++) {
     215        1540 :       fscanf(fp,"%255s %1000lf %1000lf %1000lf",atomname,&positions[i][0],&positions[i][1],&positions[i][2]);
     216             : // note: atomname is read but not used
     217             :     }
     218           9 :     fclose(fp);
     219           9 :   }
     220             : 
     221           9 :   void randomize_velocities(const int natoms,const int ndim,const double temperature,const vector<double>&masses,vector<Vector>& velocities,Random&random) {
     222             : // randomize the velocities according to the temperature
     223        3075 :     for(int iatom=0; iatom<natoms; iatom++) for(int i=0; i<ndim; i++)
     224        6888 :         velocities[iatom][i]=sqrt(temperature/masses[iatom])*random.Gaussian();
     225           9 :   }
     226             : 
     227     9982883 :   void pbc(const double cell[3],const Vector & vin,Vector & vout) {
     228             : // apply periodic boundary condition to a vector
     229    69880181 :     for(int i=0; i<3; i++) {
     230    29948649 :       vout[i]=vin[i]-floor(vin[i]/cell[i]+0.5)*cell[i];
     231             :     }
     232     9982883 :   }
     233             : 
     234        5700 :   void check_list(const int natoms,const vector<Vector>& positions,const vector<Vector>&positions0,const double listcutoff,
     235             :                   const double forcecutoff,bool & recompute)
     236             :   {
     237             : // check if the neighbour list have to be recomputed
     238        5700 :     Vector displacement;  // displacement from positions0 to positions
     239             :     double delta2;        // square of the 'skin' thickness
     240        5700 :     recompute=false;
     241        5700 :     delta2=(0.5*(listcutoff-forcecutoff))*(0.5*(listcutoff-forcecutoff));
     242             : // if ANY atom moved more than half of the skin thickness, recompute is set to .true.
     243      428900 :     for(int iatom=0; iatom<natoms; iatom++) {
     244     2116000 :       for(int k=0; k<3; k++) displacement[k]=positions[iatom][k]-positions0[iatom][k];
     245             :       double s=0.0;
     246      846400 :       for(int k=0; k<3; k++) s+=displacement[k]*displacement[k];
     247      211600 :       if(s>delta2) recompute=true;
     248             :     }
     249        5700 :   }
     250             : 
     251             : 
     252         458 :   void compute_list(const int natoms,const int listsize,const vector<Vector>& positions,const double cell[3],const double listcutoff,
     253             :                     vector<int>& point,vector<int>& list) {
     254             : // see Allen-Tildesey for a definition of point and list
     255         458 :     Vector distance;     // distance of the two atoms
     256         458 :     Vector distance_pbc; // minimum-image distance of the two atoms
     257             :     double listcutoff2;  // squared list cutoff
     258         458 :     listcutoff2=listcutoff*listcutoff;
     259         458 :     point[0]=0;
     260       44616 :     for(int iatom=0; iatom<natoms-1; iatom++) {
     261      132474 :       point[iatom+1]=point[iatom];
     262     4784134 :       for(int jatom=iatom+1; jatom<natoms; jatom++) {
     263    23699880 :         for(int k=0; k<3; k++) distance[k]=positions[iatom][k]-positions[jatom][k];
     264     2369988 :         pbc(cell,distance,distance_pbc);
     265             : // if the interparticle distance is larger than the cutoff, skip
     266     9479952 :         double d2=0; for(int k=0; k<3; k++) d2+=distance_pbc[k]*distance_pbc[k];
     267     2369988 :         if(d2>listcutoff2)continue;
     268     1807791 :         if(point[iatom+1]>listsize) {
     269             : // too many neighbours
     270           0 :           fprintf(stderr,"%s","Verlet list size exceeded\n");
     271           0 :           fprintf(stderr,"%s","Increase maxneighbours\n");
     272           0 :           exit(1);
     273             :         }
     274     3615582 :         list[point[iatom+1]]=jatom;
     275     1807791 :         point[iatom+1]++;
     276             :       }
     277             :     }
     278         458 :   }
     279             : 
     280        5709 :   void compute_forces(const int natoms,const int listsize,const vector<Vector>& positions,const double cell[3],
     281             :                       double forcecutoff,const vector<int>& point,const vector<int>& list,vector<Vector>& forces,double & engconf)
     282             :   {
     283        5709 :     Vector distance;        // distance of the two atoms
     284        5709 :     Vector distance_pbc;    // minimum-image distance of the two atoms
     285             :     double distance_pbc2;   // squared minimum-image distance
     286             :     double forcecutoff2;    // squared force cutoff
     287        5709 :     Vector f;               // force
     288             :     double engcorrection;   // energy necessary shift the potential avoiding discontinuities
     289             : 
     290        5709 :     forcecutoff2=forcecutoff*forcecutoff;
     291        5709 :     engconf=0.0;
     292      855189 :     for(int i=0; i<natoms; i++)for(int k=0; k<3; k++) forces[i][k]=0.0;
     293       11418 :     engcorrection=4.0*(1.0/pow(forcecutoff2,6.0)-1.0/pow(forcecutoff2,3));
     294      212370 :     for(int iatom=0; iatom<natoms-1; iatom++) {
     295    15843181 :       for(int jlist=point[iatom]; jlist<point[iatom+1]; jlist++) {
     296    15223198 :         int jatom=list[jlist];
     297    76115990 :         for(int k=0; k<3; k++) distance[k]=positions[iatom][k]-positions[jatom][k];
     298     7611599 :         pbc(cell,distance,distance_pbc);
     299    30446396 :         distance_pbc2=0.0; for(int k=0; k<3; k++) distance_pbc2+=distance_pbc[k]*distance_pbc[k];
     300             : // if the interparticle distance is larger than the cutoff, skip
     301     7611599 :         if(distance_pbc2>forcecutoff2) continue;
     302     5139281 :         double distance_pbc6=distance_pbc2*distance_pbc2*distance_pbc2;
     303     5139281 :         double distance_pbc8=distance_pbc6*distance_pbc2;
     304     5139281 :         double distance_pbc12=distance_pbc6*distance_pbc6;
     305     5139281 :         double distance_pbc14=distance_pbc12*distance_pbc2;
     306     5139281 :         engconf+=4.0*(1.0/distance_pbc12 - 1.0/distance_pbc6) - engcorrection;
     307    20557124 :         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             : // same force on the two atoms, with opposite sign:
     309    35974967 :         for(int k=0; k<3; k++) forces[iatom][k]+=f[k];
     310    35974967 :         for(int k=0; k<3; k++) forces[jatom][k]-=f[k];
     311             :       }
     312             :     }
     313        5709 :   }
     314             : 
     315        5700 :   void compute_engkin(const int natoms,const vector<double>& masses,const vector<Vector>& velocities,double & engkin)
     316             :   {
     317             : // calculate the kinetic energy from the velocities
     318        5700 :     engkin=0.0;
     319      852100 :     for(int iatom=0; iatom<natoms; iatom++)for(int k=0; k<3; k++) {
     320     1904400 :         engkin+=0.5*masses[iatom]*velocities[iatom][k]*velocities[iatom][k];
     321             :       }
     322        5700 :   }
     323             : 
     324             : 
     325       11400 :   void thermostat(const int natoms,const int ndim,const vector<double>& masses,const double dt,const double friction,
     326             :                   const double temperature,vector<Vector>& velocities,double & engint,Random & random) {
     327             : // Langevin thermostat, implemented as decribed in Bussi and Parrinello, Phys. Rev. E (2007)
     328             : // it is a linear combination of old velocities and new, randomly chosen, velocity,
     329             : // with proper coefficients
     330       11400 :     double c1=exp(-friction*dt);
     331      857800 :     for(int iatom=0; iatom<natoms; iatom++) {
     332      846400 :       double c2=sqrt((1.0-c1*c1)*temperature/masses[iatom]);
     333     2850400 :       for(int i=0; i<ndim; i++) {
     334     2427200 :         engint+=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i];
     335     2427200 :         velocities[iatom][i]=c1*velocities[iatom][i]+c2*random.Gaussian();
     336     2427200 :         engint-=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i];
     337             :       }
     338             :     }
     339       11400 :   }
     340             : 
     341          39 :   void write_positions(const string& trajfile,int natoms,const vector<Vector>& positions,const double cell[3],const bool wrapatoms)
     342             :   {
     343             : // write positions on file trajfile
     344             : // positions are appended at the end of the file
     345          39 :     Vector pos;
     346             :     FILE*fp;
     347          39 :     if(write_positions_first) {
     348           9 :       fp=fopen(trajfile.c_str(),"w");
     349           9 :       write_positions_first=false;
     350             :     } else {
     351          30 :       fp=fopen(trajfile.c_str(),"a");
     352             :     }
     353             :     fprintf(fp,"%d\n",natoms);
     354          39 :     fprintf(fp,"%f %f %f\n",cell[0],cell[1],cell[2]);
     355        7655 :     for(int iatom=0; iatom<natoms; iatom++) {
     356             : // usually, it is better not to apply pbc here, so that diffusion
     357             : // is more easily calculated from a trajectory file:
     358        4888 :       if(wrapatoms) pbc(cell,positions[iatom],pos);
     359       19096 :       else for(int k=0; k<3; k++) pos[k]=positions[iatom][k];
     360        3808 :       fprintf(fp,"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]);
     361             :     }
     362          39 :     fclose(fp);
     363          39 :   }
     364             : 
     365           9 :   void write_final_positions(const string& outputfile,int natoms,const vector<Vector>& positions,const double cell[3],const bool wrapatoms)
     366             :   {
     367             : // write positions on file outputfile
     368           9 :     Vector pos;
     369             :     FILE*fp;
     370           9 :     fp=fopen(outputfile.c_str(),"w");
     371             :     fprintf(fp,"%d\n",natoms);
     372           9 :     fprintf(fp,"%f %f %f\n",cell[0],cell[1],cell[2]);
     373        1549 :     for(int iatom=0; iatom<natoms; iatom++) {
     374             : // usually, it is better not to apply pbc here, so that diffusion
     375             : // is more easily calculated from a trajectory file:
     376         986 :       if(wrapatoms) pbc(cell,positions[iatom],pos);
     377        3878 :       else for(int k=0; k<3; k++) pos[k]=positions[iatom][k];
     378         770 :       fprintf(fp,"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]);
     379             :     }
     380           9 :     fclose(fp);
     381           9 :   }
     382             : 
     383             : 
     384         174 :   void write_statistics(const string & statfile,const int istep,const double tstep,
     385             :                         const int natoms,const int ndim,const double engkin,const double engconf,const double engint) {
     386             : // write statistics on file statfile
     387         174 :     if(write_statistics_first) {
     388             : // first time this routine is called, open the file
     389           9 :       write_statistics_fp=fopen(statfile.c_str(),"w");
     390           9 :       write_statistics_first=false;
     391             :     }
     392         174 :     if(istep-write_statistics_last_time_reopened>100) {
     393             : // every 100 steps, reopen the file to flush the buffer
     394          16 :       fclose(write_statistics_fp);
     395          16 :       write_statistics_fp=fopen(statfile.c_str(),"a");
     396          16 :       write_statistics_last_time_reopened=istep;
     397             :     }
     398         174 :     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);
     399         174 :   }
     400             : 
     401             : 
     402             : 
     403           9 :   virtual int main(FILE* in,FILE*out,PLMD::Communicator& pc) {
     404             :     int            natoms;       // number of atoms
     405             :     vector<Vector> positions;    // atomic positions
     406             :     vector<Vector> velocities;   // velocities
     407             :     vector<double> masses;       // masses
     408             :     vector<Vector> forces;       // forces
     409             :     double         cell[3];      // cell size
     410             :     double         cell9[3][3];  // cell size
     411             : 
     412             : // neighbour list variables
     413             : // see Allen and Tildesey book for details
     414             :     int            listsize;     // size of the list array
     415             :     vector<int>    list;         // neighbour list
     416             :     vector<int>    point;        // pointer to neighbour list
     417             :     vector<Vector> positions0;   // reference atomic positions, i.e. positions when the neighbour list
     418             : 
     419             : // input parameters
     420             : // all of them have a reasonable default value, set in read_input()
     421             :     double      tstep;             // simulation timestep
     422             :     double      temperature;       // temperature
     423             :     double      friction;          // friction for Langevin dynamics (for NVE, use 0)
     424             :     double      listcutoff;        // cutoff for neighbour list
     425             :     double      forcecutoff;       // cutoff for forces
     426             :     int         nstep;             // number of steps
     427             :     int         nconfig;           // stride for output of configurations
     428             :     int         nstat;             // stride for output of statistics
     429             :     int         maxneighbour;      // maximum average number of neighbours per atom
     430             :     int         ndim;              // dimensionality of the system (1, 2, or 3)
     431             :     int         idum;              // seed
     432             :     int         plumedWantsToStop; // stop flag
     433             :     bool        wrapatoms;         // if true, atomic coordinates are written wrapped in minimal cell
     434             :     string      inputfile;         // name of file with starting configuration (xyz)
     435             :     string      outputfile;        // name of file with final configuration (xyz)
     436             :     string      trajfile;          // name of the trajectory file (xyz)
     437             :     string      statfile;          // name of the file with statistics
     438             : 
     439             :     double engkin;                 // kinetic energy
     440             :     double engconf;                // configurational energy
     441             :     double engint;                 // integral for conserved energy in Langevin dynamics
     442             : 
     443             :     bool recompute_list;           // control if the neighbour list have to be recomputed
     444             : 
     445           9 :     Random random;                 // random numbers stream
     446             : 
     447             :     std::unique_ptr<PlumedMain> plumed;
     448             : 
     449             : // Commenting the next line it is possible to switch-off plumed
     450           9 :     plumed.reset(new PLMD::PlumedMain);
     451             : 
     452           9 :     if(plumed) {
     453           9 :       int s=sizeof(double);
     454          18 :       plumed->cmd("setRealPrecision",&s);
     455             :     }
     456             : 
     457           9 :     read_input(temperature,tstep,friction,forcecutoff,
     458             :                listcutoff,nstep,nconfig,nstat,
     459             :                wrapatoms,inputfile,outputfile,trajfile,statfile,
     460             :                maxneighbour,ndim,idum);
     461             : 
     462             : // number of atoms is read from file inputfile
     463           9 :     read_natoms(inputfile,natoms);
     464             : 
     465             : // write the parameters in output so they can be checked
     466             :     fprintf(out,"%s %s\n","Starting configuration           :",inputfile.c_str());
     467             :     fprintf(out,"%s %s\n","Final configuration              :",outputfile.c_str());
     468           9 :     fprintf(out,"%s %d\n","Number of atoms                  :",natoms);
     469           9 :     fprintf(out,"%s %f\n","Temperature                      :",temperature);
     470           9 :     fprintf(out,"%s %f\n","Time step                        :",tstep);
     471           9 :     fprintf(out,"%s %f\n","Friction                         :",friction);
     472           9 :     fprintf(out,"%s %f\n","Cutoff for forces                :",forcecutoff);
     473           9 :     fprintf(out,"%s %f\n","Cutoff for neighbour list        :",listcutoff);
     474           9 :     fprintf(out,"%s %d\n","Number of steps                  :",nstep);
     475           9 :     fprintf(out,"%s %d\n","Stride for trajectory            :",nconfig);
     476             :     fprintf(out,"%s %s\n","Trajectory file                  :",trajfile.c_str());
     477           9 :     fprintf(out,"%s %d\n","Stride for statistics            :",nstat);
     478             :     fprintf(out,"%s %s\n","Statistics file                  :",statfile.c_str());
     479           9 :     fprintf(out,"%s %d\n","Max average number of neighbours :",maxneighbour);
     480           9 :     fprintf(out,"%s %d\n","Dimensionality                   :",ndim);
     481           9 :     fprintf(out,"%s %d\n","Seed                             :",idum);
     482           9 :     fprintf(out,"%s %s\n","Are atoms wrapped on output?     :",(wrapatoms?"T":"F"));
     483             : 
     484             : // Setting the seed
     485           9 :     random.setSeed(idum);
     486             : 
     487             : // Since each atom pair is counted once, the total number of pairs
     488             : // will be half of the number of neighbours times the number of atoms
     489           9 :     listsize=maxneighbour*natoms/2;
     490             : 
     491             : // allocation of dynamical arrays
     492           9 :     positions.resize(natoms);
     493           9 :     positions0.resize(natoms);
     494           9 :     velocities.resize(natoms);
     495           9 :     forces.resize(natoms);
     496           9 :     masses.resize(natoms);
     497           9 :     point.resize(natoms);
     498           9 :     list.resize(listsize);
     499             : 
     500             : // masses are hard-coded to 1
     501        1549 :     for(int i=0; i<natoms; ++i) masses[i]=1.0;
     502             : 
     503             : // energy integral initialized to 0
     504           9 :     engint=0.0;
     505             : 
     506             : // positions are read from file inputfile
     507           9 :     read_positions(inputfile,natoms,positions,cell);
     508             : 
     509             : // velocities are randomized according to temperature
     510           9 :     randomize_velocities(natoms,ndim,temperature,masses,velocities,random);
     511             : 
     512           9 :     if(plumed) {
     513          18 :       plumed->cmd("setNoVirial");
     514          18 :       plumed->cmd("setNatoms",&natoms);
     515          18 :       plumed->cmd("setMDEngine","simpleMD");
     516          18 :       plumed->cmd("setTimestep",&tstep);
     517          18 :       plumed->cmd("setPlumedDat","plumed.dat");
     518           9 :       int pversion=0;
     519          18 :       plumed->cmd("getApiVersion",&pversion);
     520             : // setting kbT is only implemented with api>1
     521             : // even if not necessary in principle in SimpleMD (which is part of plumed)
     522             : // we leave the check here as a reference
     523           9 :       if(pversion>1) {
     524          18 :         plumed->cmd("setKbT",&temperature);
     525             :       }
     526          18 :       plumed->cmd("init");
     527             :     }
     528             : 
     529             : // neighbour list are computed, and reference positions are saved
     530           9 :     compute_list(natoms,listsize,positions,cell,listcutoff,point,list);
     531             : 
     532          18 :     fprintf(out,"List size: %d\n",point[natoms-1]);
     533        5399 :     for(int iatom=0; iatom<natoms; ++iatom) for(int k=0; k<3; ++k) positions0[iatom][k]=positions[iatom][k];
     534             : 
     535             : // forces are computed before starting md
     536           9 :     compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf);
     537             : 
     538             : // remove forces if ndim<3
     539           9 :     if(ndim<3)
     540          30 :       for(int iatom=0; iatom<natoms; ++iatom) for(int k=ndim; k<3; ++k) forces[iatom][k]=0.0;
     541             : 
     542             : // here is the main md loop
     543             : // Langevin thermostat is applied before and after a velocity-Verlet integrator
     544             : // the overall structure is:
     545             : //   thermostat
     546             : //   update velocities
     547             : //   update positions
     548             : //   (eventually recompute neighbour list)
     549             : //   compute forces
     550             : //   update velocities
     551             : //   thermostat
     552             : //   (eventually dump output informations)
     553        5709 :     for(int istep=0; istep<nstep; istep++) {
     554        5700 :       thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random);
     555             : 
     556      852100 :       for(int iatom=0; iatom<natoms; iatom++) for(int k=0; k<3; k++)
     557     2539200 :           velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom];
     558             : 
     559      852100 :       for(int iatom=0; iatom<natoms; iatom++) for(int k=0; k<3; k++)
     560     1904400 :           positions[iatom][k]+=velocities[iatom][k]*tstep;
     561             : 
     562             : // a check is performed to decide whether to recalculate the neighbour list
     563        5700 :       check_list(natoms,positions,positions0,listcutoff,forcecutoff,recompute_list);
     564        5700 :       if(recompute_list) {
     565         449 :         compute_list(natoms,listsize,positions,cell,listcutoff,point,list);
     566      307371 :         for(int iatom=0; iatom<natoms; ++iatom) for(int k=0; k<3; ++k) positions0[iatom][k]=positions[iatom][k];
     567             :         fprintf(out,"Neighbour list recomputed at step %d\n",istep);
     568         898 :         fprintf(out,"List size: %d\n",point[natoms-1]);
     569             :       }
     570             : 
     571        5700 :       compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf);
     572             : 
     573        5700 :       if(plumed) {
     574        5700 :         int istepplusone=istep+1;
     575        5700 :         plumedWantsToStop=0;
     576       22800 :         for(int i=0; i<3; i++)for(int k=0; k<3; k++) cell9[i][k]=0.0;
     577       22800 :         for(int i=0; i<3; i++) cell9[i][i]=cell[i];
     578       11400 :         plumed->cmd("setStep",&istepplusone);
     579       17100 :         plumed->cmd("setMasses",&masses[0]);
     580       17100 :         plumed->cmd("setForces",&forces[0]);
     581       11400 :         plumed->cmd("setEnergy",&engconf);
     582       17100 :         plumed->cmd("setPositions",&positions[0]);
     583       11400 :         plumed->cmd("setBox",cell9);
     584       11400 :         plumed->cmd("setStopFlag",&plumedWantsToStop);
     585       11400 :         plumed->cmd("calc");
     586        5700 :         if(plumedWantsToStop) nstep=istep;
     587             :       }
     588             : // remove forces if ndim<3
     589        5700 :       if(ndim<3)
     590       60000 :         for(int iatom=0; iatom<natoms; ++iatom) for(int k=ndim; k<3; ++k) forces[iatom][k]=0.0;
     591             : 
     592      852100 :       for(int iatom=0; iatom<natoms; iatom++) for(int k=0; k<3; k++)
     593     2539200 :           velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom];
     594             : 
     595        5700 :       thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random);
     596             : 
     597             : // kinetic energy is calculated
     598        5700 :       compute_engkin(natoms,masses,velocities,engkin);
     599             : 
     600             : // eventually, write positions and statistics
     601        5700 :       if((istep+1)%nconfig==0) write_positions(trajfile,natoms,positions,cell,wrapatoms);
     602        5700 :       if((istep+1)%nstat==0)   write_statistics(statfile,istep+1,tstep,natoms,ndim,engkin,engconf,engint);
     603             : 
     604             :     }
     605             : 
     606             : // call final plumed jobs
     607          18 :     plumed->cmd("runFinalJobs");
     608             : 
     609             : // write final positions
     610           9 :     write_final_positions(outputfile,natoms,positions,cell,wrapatoms);
     611             : 
     612             : // close the statistic file if it was open:
     613           9 :     if(write_statistics_fp) fclose(write_statistics_fp);
     614             : 
     615           9 :     return 0;
     616             :   }
     617             : 
     618             : 
     619             : };
     620             : 
     621        7374 : PLUMED_REGISTER_CLTOOL(SimpleMD,"simplemd")
     622             : 
     623             : }
     624        5517 : }
     625             : 
     626             : 
     627             : 
     628             : 

Generated by: LCOV version 1.14