/*
  md.h
  by Wei Cai  caiwei@stanford.edu
  Last Modified : Sun Sep 10 23:20:37 2006

  FUNCTION  :  Easy-to-use MD simulation Framefork

  Featuring :  1. Scripting input
               2. X-window display
               3. automatic simulation log
               4. convenient configuration and output file handle
               5. perfect lattice and dislocation config creator
               6. conjugate-gradient relaxation
               7. NVT MD simulation
               8. Cell-Verlist combined neighbor list
               
  This is a single CPU code.
  Previous shared-memory option removed.
  May implment MPI parallelization in the future.
*/


#ifndef _MD_H
#define _MD_H

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "general.h"
#include "organizer.h"
#include "display.h"
#include "linalg3.h"
#include "relax.h"

/* Internal units
   Energy:  eV
   Length:  A
   Stress:  eV/A^3

   Stored Internal Variables
   Position:     r               (in A)
   Velocity:     v*TIMESTEP      (in A)
   Accelaration: a*TIMESTEP^2/2  (in A)
*/

/* Physical constants */
#define AVO  6.0221367E+23
#define EV   1.6021772E-19     /* (J)    */
#define BOLZ 1.380658E-23      /* (J/K)  */
#define KB   0.8617336E-4      /* (eV/K) */
#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif

#define MAXSPECIES 10          /* maximum number of species */
#define MAXCOLORS  10          /* maximum number of colors in display */
#define MAXCONSTRAINATOMS 1001 /* maximum number of atoms in constrained minimization */

/* Random number generator for platforms not supporting drand48 (e.g. cygwin) */
#ifdef _NODRAND48
#define drand48 (1.0/RAND_MAX)*rand
#endif

#define MP_Sync() {}
#define MP_BeginMasterOnly() {}
#define MP_EndMasterOnly() {}
#define MP_Free(s) free(s)
#define MP_cpu() 0
#define MP_ncpu() 1

#define Realloc(p,t,s) {p=(t *)realloc(p,sizeof(t)*s);}
#define bindcommand_sync bindcommand



/* Input/output files */
class CNFile : public AUXFile /* configuration(cn) file */
{
public:
    CNFile(int t):AUXFile(t){};
    virtual char * describe();
private:
    virtual int writeblock(void *p);
    virtual int readblock(void *p);
};

class POSCARFile : public AUXFile /* POSCAR (vasp) file */
{
public:
    POSCARFile(int t):AUXFile(t){};
    virtual char * describe();
private:
    virtual int writeblock(void *p);
    virtual int readblock(void *p);
};

class MDCASKconFile : public AUXFile /* MDCASK configuration file */
{
public:
    MDCASKconFile(int t):AUXFile(t){};
    virtual char * describe();
private:
    virtual int writeblock(void *p);
    virtual int readblock(void *p);
};

class MDCASKinputFile : public AUXFile /* MDCASK input file */
{
public:
    MDCASKinputFile(int t):AUXFile(t){};
    virtual char * describe();
private:
    virtual int writeblock(void *p);
    virtual int readblock(void *p);
};

class PropFile : public AUXFile/* Output property file */
{
public:
    PropFile(int t):AUXFile(t){};
    virtual char * describe();
    virtual int writeentry(void *p);
};


/* MD simulation framework */
class MDFrame : public Organizer
{
public:
    int _SAVEMEMORY;    /* controls how much memory is allocated per atom */
    int _NP;            /* total number of atoms */

    class Vector3 *_R, *_SR;   /* real and scaled coordinates of atoms */
    class Vector3 *_VR, *_VSR; /* real and scaled velocities of atoms */
    class Vector3 *_F, *_F0;   /* force on atoms */
    class Vector3 *_R0;        /* place to save old coordinates of atoms */
    class Vector3 *_Fext;      /* external force on atoms */

    int *fixed;                /* 1 if atom is fixed */
    int *image;                /* image atom */
    int *species;              /* species type of atom */
    int *group;                /* group ID */
    int nspecies;              /* number of atom species */
    char element[MAXSPECIES][10]; /* species names */

    class Matrix33 _H, _H0;     /* simulation box vectors and copy */
    class Matrix33 _VIRIAL, _VH;/* Virial stress, and velocity of H */
    double _EPOT, *_EPOT_IND;   /* total potential energy and contribution per atom */
    double _EPOT0;              /* potential energy from previous step */
    double *_TOPOL;             /* atomic environment, e.g. central symmetry parameter */

    /* Molecular Dynamics parameters */
    double _ESTRAIN;             /* box strain energy (in eV) */
    double _KATOM, _KBOX;        /* kinetic energies (in eV) */
    double _ATOMMASS[MAXSPECIES], _WALLMASS; /* in (g/mol) */
    double _TIMESTEP;            /* in picosecond (ps) */
    double _TDES,_T;             /* desired and current temperature */
    int _DOUBLET;                /* 1: if initialize T double desired temperature */
    double _ATOMTCPL,_BOXTCPL;   /* temperature coupling constants */
    double zeta,zetav,zetaa,vt2; /* nose hoover thermal stat */
    double _HELM,_HELMP;         /* Helmholtz free energy and a conserved var */
    int usenosehoover;           /* 1: if use nose hoover thermostat */
    int scalevelocity;           /* 1: if scale velocity for temperature control */
    int applyshear;              /* apply constant shear deformation */
    double extforce[100];        /* external forces on different atom groups */
    double forcemul;             /* a multiplication factor for extforce */
    Matrix33 _SHEARRATE;         /* shear deformation rate, if applyshear==1 */

    /* Neighbor list */
    double _RLIST,_SKIN;        /* potential cut off radius (in A) */
    int _NIC;                   /* maximum number of atoms per cell */
    int _NNM;                   /* maximum number of neighbors per atom */
    int *nn;                    /* nn[i]: number of neighbors of atom i */
    int **nindex;               /* nindex[i][j]: the jth neighbor of atom i */
    int ****celllist;
    char *cell_mem, *nindex_mem;
    bool firsttime;

    /* Numerical integrator */
    Vector3 *s2, *s3, *s4, *s5, *s2real; /* Gear 6th predictor-corrector */
    Matrix33 h2,h3,h4,h5,h2real;
    double zeta2,zeta3,zeta4,zeta5;      /* for Nose-Hoover thermal stat */
    int npold;
                                         /* Velocity Verlet ? */
 
    /* Internal and applied stresses */
    Matrix33 _PSTRESS;          /* stress due to momenta (in eV/A^3) */
    Matrix33 _TOTSTRESS;        /* total stress (_PSTRESS+_VIRIAL) */
    Matrix33 _EXTSTRESS;        /* external applied stress */
    double _EXTSTRESSMUL;       /* multiplier of applied stress */
    double _EXTPRESSADD;        /* addition of hydrostatic pressure, not affected by ESTSTRESSMUL */
    double _VACUUMRATIO;        /* stress correction factor when medium is smaller than simulation box */
   
    /* Conjugate gradient relaxation */   
    int conj_itmax,conj_fevalmax,conj_fixbox,conj_fixshape,
        conj_fixatoms,conj_step,conj_ier,conj_fixdir;
    Matrix33 conj_fixboxvec;
    double conj_dfpred,conj_f,conj_ftol;
    double *conj_space;
    double _HPRECOND;                     /* preconditioner for H */
    double _XPRECOND,_YPRECOND,_ZPRECOND; /* preconditioner for x,y,z */
    Matrix33 _SIGMA;                      /* stress term in Parilleno-Raman */

    /* Conjugate gradient relaxation with constraints */
    double constrainS, constrain_dist;
    int constrainatoms[MAXCONSTRAINATOMS];
    
    /* Molecular Dynamics simulation */
    int totalsteps, equilsteps, curstep;  /* simulation steps */
    int integrator_type;
    
    /* Monte Carlo simulation */
    int MC_atom, MC_accept, MC_accept_tot, MC_switchoffatoms[10];
    double MC_accept_ratio;
    Vector3 MC_dr;

    /* Free energy calculations */
    double _LAMBDA0, _LAMBDA1, dEdlambda, _ECOH;
    int _SWITCHFREQ, _RANDSEED, _CHAINLENGTH, _SWITCHFUNC, _REFPOTENTIAL;
    int heslen, *hesind; double *hes; /* Hessian matrix */
    double _ECSPRING;                 /* spring constant of Einstein crystal */

    /* Nudged-Elastic-Band (NEB) method for saddle point search */
    class Vector3 *_SR1, *_SR2, *_SR3; 
    class Vector3 **_Rc, **_Fc; /* atom positions and forces along a chain of states */
    int nebspec[10];
    double annealspec[10];
    
    /* Configuration manipulation */
    class Vector3 *storedr;         /* atomic displacements */
    class Matrix33 dH;              /* change of matrix H (cell size) */
    char  crystalstructure[30];     /* crystal structure for makecrystal() */
    double latticeconst[3];         /* lattice constant  for makecrystal() */
    double latticesize[3][4];       /* lattice size for makecrystal() */
    double torquespec[3];           /* torsion specification */
    
    /* File input and output */
    double input[20000];                     /* general input variable in script file */
    class CNFile initcn,intercn,finalcn;    /* configuration file objects */
    class PropFile pf;                      /* property file objects */
    char incnfile[200], finalcnfile[200];   /* configuration file name */
    char intercnfile[200];                  /* configuration file name */
    char outpropfile[200];                  /* property file name */
    char myname[200];                       /* name of the simulation */
    char potfile[100];                      /* name of potential file */    
    char command[1000]; int ncom;           /* shell command */
    int  savecn, savecnfreq;                /* frequency of saving cn files */
    int  saveprop, savepropfreq;            /* frequency of saving prop files */
    int  printfreq;                         /* frequency of printing on scren */
    int  filecounter;                       /* number of current file */
    int allocmultiple;                      /* allocate more memory than current number of atoms */
    int writevelocity;                      /* write velocity into cn file */
    int writeall;                           /* write "sx,sy,sz,vx,vy,vz,pot,fixed" into cn file */
    int fixedatomenergypartition;           /* 1: disregard energy contribution from fixed atoms */    

    /* Interface to Fortran code (Relax) */
    char fortranpath[100], fortranexe[100];

    /* Interface to AtomEye and other viewers */
    char atomeyepath[100], atomeyeexe[100];
    int atomeyerepeat[4];

    /* Interface to VASP */
    class POSCARFile initposcar,finalposcar;

    /* Interface to MDCASK */
    class MDCASKconFile initmdcaskcon,finalmdcaskcon;
    class MDCASKinputFile initmdcaskinput,finalmdcaskinput;
    char MDCASKpot[50];
        
    /* Visualization */
    YWindow *win;                   /* Display window object */

    int win_width, win_height;      /* size of the window */
    double rotateangles[5];         /* rotation angles and scaling parameter */
    int plotfreq;                   /* frequency of re-plotting */
    double atomradius[MAXSPECIES];  /* size of atoms */
    double bondradius, bondlength;  /* thickness and length of bonds */

    char atomcolor[MAXSPECIES][30]; /* color of atom species */
    char bondcolor[30];             /* color of bonds */    
    char fixatomcolor[30];          /* color of fixed atoms, fixed[i]=1 */
    char highlightcolor[30];        /* color of highlighted atoms */
    char backgroundcolor[30];       /* background color of window */
    char colornames[MAXCOLORS][30]; /* names of allocated colors */
    unsigned colors[MAXCOLORS+15];  /* value of allocated colors */

    int plot_highlight_atoms[10000];/* indices of atoms to be highlighed */    
    double plot_limits[10];         /* set x,y,z, limits of plotting regime */
    int    plot_atom_info;          /* print information when atom is clicked */
    int    plot_map_pbc;            /* map all atoms in primary cell when plotting */
    double plot_color_windows[100]; /* only plot atoms whose properties fall into specified windows */
    double plot_color_bar[10];      /* how to color atoms according to their properties */
    int    plot_color_axis;          /* which atomic property specifies color */

    int autowritegiffreq;           /* frequency of outputing .GIF graphics file */
    double *color_ind;              /* property linked to atom color */
    int NCS;                        /* number of neighbors for central symmetry parameter comp. */

    /* Constructor (set initial values of member variables) */
    MDFrame(): _SAVEMEMORY(0),_NP(0),

               _R(0),_SR(0),_VR(0),_VSR(0),_F(0),_R0(0),_Fext(0),

               fixed(0),species(0),group(0),nspecies(1),
               _EPOT(0),_EPOT_IND(0),_EPOT0(0),_TOPOL(0),

               /* Molecular Dynamics parameters */
               _ESTRAIN(0),_KATOM(0),_KBOX(0),_WALLMASS(1),
               _TIMESTEP(1e-3),_TDES(0),_T(0),_DOUBLET(0),
               _ATOMTCPL(100),_BOXTCPL(100),
               zeta(0),zetav(0),zetaa(0),vt2(0.25),_HELM(0),_HELMP(0),
               usenosehoover(0),scalevelocity(0),applyshear(0),
               forcemul(1),

               /* Neighbor list */
               _RLIST(0),_SKIN(0),_NIC(100),_NNM(60),nn(0),nindex(0),
               celllist(0), cell_mem(0), nindex_mem(0), firsttime(true),

               /* Numerical integrator */
               s2(0),s3(0),s4(0),s5(0),s2real(0), /* Gear 6th predictor-corrector */
               zeta2(0),zeta3(0),zeta4(0),zeta5(0),
               npold(0),

               /* Internal and applied stresses */
               _EXTSTRESSMUL(0),_EXTPRESSADD(0),_VACUUMRATIO(0),

               /* Conjugate gradient relaxation */
               conj_itmax(1000),conj_fevalmax(10000),conj_fixbox(0),
               conj_fixshape(0),conj_fixatoms(0),conj_step(0),conj_ier(0),conj_fixdir(0),
               conj_dfpred(1e-3),conj_f(0),conj_ftol(1e-8),conj_space(0),
               _HPRECOND(1),_XPRECOND(1),_YPRECOND(1),_ZPRECOND(1),

               /* Conjugate gradient relxation with constrains */
               constrainS(0),constrain_dist(0),
               
               /* Molecular Dynamics simulation steps */
               totalsteps(100), equilsteps(0), curstep(0), integrator_type(0),

               /* Monte Carlo simulation */
               MC_atom(0),MC_accept(0),MC_accept_tot(0), MC_accept_ratio(0),

               /* Free energy calculations */
               _LAMBDA0(0),_LAMBDA1(1),dEdlambda(0),_ECOH(0),_SWITCHFREQ(1),
               _RANDSEED(12345),_CHAINLENGTH(0),_SWITCHFUNC(0),_REFPOTENTIAL(0),
               heslen(0), hesind(0), hes(0),
    
               /* Nudged-Elastic-Band (NEB) method */
               _SR1(0),_SR2(0),_SR3(0),_Rc(0),_Fc(0),
        
               /* Configuration manipulation */
               storedr(0),

               /* File input and output */
               initcn(AUXFile::BLOCK),intercn(AUXFile::SERIES),
               finalcn(AUXFile::BLOCK),pf(AUXFile::ENTRIES),
               ncom(0),savecn(0),savecnfreq(100),saveprop(0),savepropfreq(100),
               printfreq(100),filecounter(1),allocmultiple(1),
               writevelocity(0),writeall(0),fixedatomenergypartition(0),

               /* Interface to VASP */
               initposcar(AUXFile::BLOCK),finalposcar(AUXFile::BLOCK),

               /* Interface to MDCASK */
               initmdcaskcon(AUXFile::BLOCK),finalmdcaskcon(AUXFile::BLOCK),
               initmdcaskinput(AUXFile::BLOCK),finalmdcaskinput(AUXFile::BLOCK),

               /* Visualization */
               win(0),win_width(350),win_height(350),
               plotfreq(1),bondradius(0.1),bondlength(0),plot_atom_info(1),plot_map_pbc(0),
               plot_color_axis(0),autowritegiffreq(0),color_ind(0),NCS(12)
               
    {
        /* Input/output control */
        input[0]=0;
        _ATOMMASS[0]=1;
        
        /* Configuration manipulation */
        latticeconst[0]=latticeconst[1]=latticeconst[2]=1.0;
        sprintf(crystalstructure,"simple-cubic");

        /* Workspace for Monte Carlo simulation */
        MC_switchoffatoms[0]=0;

        /* Plot settings */
        plot_highlight_atoms[0]=0;
        plot_limits[0]=0;
        plot_color_windows[0]=0;
        plot_color_bar[0]=0;

        
    };

    virtual ~MDFrame() { delete(win);}
            
    /* Parser */    
    virtual void initparser();
    virtual int exec(char *name);            
    virtual void initvars();
    void runcommand();        /* run shell command */    

    /* Coordinate transformation */
    void SHtoR();
    void RHtoS();
    void RtoR0();
    void R0toR();
    bool Bond(int I, int J) const;
    
    virtual void Alloc();

    /* Potentials */    
    virtual void potential();
    virtual void potential_energyonly();
    virtual double potential_energyonly(int iatom);
    void ECpotential();            /* Harmonic potential of Einstein crystal */
    void ECpotential_energyonly();
    double ECpotential_energyonly(int iatom);
    void HApotential_energyonly(); /* Harmonic potential based on Hessian matrix */
    void SWITCHpotential_energyonly(double lambda); /* for adiabatic switching */

    /* Neighbor list */
    void NbrList_reconstruct();  /* use cell list combined with Verlist */
    void NbrList_print();        /* for debug use */
    bool NbrList_needrefresh();
    void NbrList_init(int, int);
    void NbrList_initcell(int,int,int,int);
    void NbrList_free();
    void NbrList_freecell();
    void NbrList_refresh();
#define refreshneighborlist NbrList_refresh
    
    /* Numerical integrator */
    void Gear6_step();            /* Gear 6th order predictor-corrector */
    void Gear6_init();
    void Gear6_free();
    void Gear6_predictor();
    void Gear6_evaluator();
    void Gear6_corrector();

    void VVerlet_step(int n);     /* Velocity Verlet ? */
    void VVerlet_init();
    void VVerlet_free();

    
    /* Conjugate gradient relaxation */
    int relax();           /* CG relax */
    int constrainedrelax();/* CG relax with constraints */
    static void potential_wrapper(int *n,double x[],double *f,double df[]);
    static void potential_wrapper_c(int n,double x[],double *f,double df[]);
    static void cstr_potential_wrapper(int *n,double x[],double *f,double df[]);
    static void cstr_potential_wrapper_c(int n,double x[],double *f,double df[]);
    
    /* Molecular Dynamics simulation */
    virtual void integrator();       /* MD integrator */

    virtual void run();              /* run the simulation */
    virtual void calcprop();         /* calculate physical properties */
    void calcentralsymmetry();       /* calculate central symmetry deviation */
    void calHessian();               /* numerical calculation of Hessian matrix */
    void readHessian();              /* read Hessian matrix from file */
    void calphonondisp();            /* calculate phonon dispersion relation */
    void calmisfit();                /* calculate misfit potential */
    void testpotential();            /* test consistency between force and energy */
    void findcore();                 /* find center of mass of defect core atoms */

    void initvelocity();
    void randomposition();
    void velscaler();
    void multiplyvelocity();
    void step();
    void eval();
    void multieval();                /* for testing/timing purposes */

    /* Monte Carlo simulation */
    int runMC();                    /* Metropolis Monte Carlo */
    int runTAMC();                  /* temperature accelerated Monte Carlo */
    int MCstep();
    int runMCSWITCH();
    int MCSWITCHstep(double lambda);
    
    /* Nudged-Elastic-Band relaxation */
    void AllocChain();
    void initRchain();
    int readRchain();
    int writeRchain();
    void nebrelax();   
    void annealpath();       /* simulated annealing of paths */
    void cutpath();
    int statedistance();     /* compute distance between two states _SR1 and _SR */

    /* Configuration manipulation */
    void makecrystal();         /* create perfect crystal structure */
    void makecut();             /* create cut surfaces in lattice */
    void makedipole();          /* create dislocation dipole structure */
    void makedislocation();     /* create an arbitrarily oriented dislocation line */
    void makecylinder();        /* cut a cylinder out of the crystal */
    void setfixbufferatoms();   /* fix atoms around a cylinder */
    void makedislcylinder();    /* create a single dislocation in a cylinder */
    
    void makedisloop();         /* create dislocation loop */
    void calloopdisp            /* compute the displacement field */
         (Vector3 *,double,double,Vector3 *,Vector3 *,Vector3 *);
    void makegrainboundary();   /* create grain boundary */
    void makewave();            /* initiate wave form */
    void maketorquehandle();    /* prepare for torque application */
    
    void scaleH();              /* hydrostatic scale of simulation box */
    void setH();
    void saveH();
    void restoreH();            /* restore H from H0 */
    
    void shiftbox();            /* shift PBC box */
    void redefinepbc();
    void applystrain();         /* apply homogeneous strain */
    void extendbox();           /* make multiple copies of the box*/

    void cutslice();            /* cut a portion from box, inverse of extendbox */
    void splicecn();            /* put two configurations together */
    void cutpastecn();          /* cut and paste a region of the config */

    void setconfig1();          /* copy current _SR to _SR1 */
    void setconfig2();          /* copy current _SR to _SR2 */
    void switchconfig();        /* R - R1 + R2 */
    void replacefreeatom();     /* replace free (not fixed) atoms from another config */
    void relabelatom();
    
    void moveatom();
    void addtorque();
    void printatoms_in_sphere();/* print the indices of all atoms in a sphere */
    void pbcshiftatom();        /* shift atoms in PBC box */
    
    void fixatoms_by_ID();      /* fix a set of atoms whose ID are specified */
    void fixatoms_by_position();/* fix all atoms whose position falls within a specified regime */
    void fixatoms_by_pos_topol();/* fix atoms whose position and TOPOL value are in a specified regime */
    void freeallatoms();
    void reversefixedatoms();

    void setfixedatomsspecies();
    void setfixedatomsgroup();
    void reversespecies();      /* species: 0->1 , 1->0 */
    void movefixedatoms();      /* move atoms that are marked as fixed */
    void removefixedatoms();    /* remove atoms that are marked as fixed */
    void markremovefixedatoms();/* mark fixed atoms for removal (fix=-1) */
    void removeellipsoid();     /* remove all atoms within an ellipsoid */    
    void removerectbox();       /* remove all atoms within a parallelpepid */
    void removeoverlapatoms();  /* remove atoms that are too close to each other*/
    
    /* File input and output */
    virtual void saveintercn(int);   /* save intermediate cn files */
    int readcn();
    int readPOSCAR();
    int readMDCASK();
    int readMDCASKJAIME();
    int convertXDATCAR();
    int setfilecounter();
    int openintercnfile();
    int openpropfile();
        
    int writefinalcnfile(int zip=1,bool bg=true);
    int writePOSCAR();
    int writeMDCASK();
    void writePINYMD(char *fname);
    int writeintercnfile(int zip=1,bool bg=false);

    /* Interface with Fortran code (Relax) */
    void writefortraninifile(char *fname);
    void fortranrelax();

    /* Interface with AtomEye and other viewers */
    void writeatomeyecfgfile(char *fname);
    void convertCNtoCFG();
    void atomeye();
    void writepovray(char *fname);
    void writeMDCASKXYZ(char *fname);
    void writeRASMOLXYZ(char *fname);
    void readRASMOLXYZ(char *fname);
    void writeatomtv(char *fname);
    
    /* Print out energies of current configuration */
    void writeENERGY(char *fname);
    void writeFORCE(char *fname);
    void writePOSITION(char *fname);
    void GnuPlotHistogram();

    /* Visualization */
    virtual void winplot();        
    virtual void winplot(int);
    virtual void openwin();
    virtual void plot();
    int     openwindow(int w,int h,const char *n);
    void    closewindow();
    void    wintogglepause();
    void    alloccolors();
    void    alloccolorsX();
    void    rotate();
    void    saverot();
    
};    


#endif //_MD_H
