/* numberical integrators for MD++, included in md.cpp
 * different ensemble_type's and integrator_type's
 */


/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
#define F02  (3./16.)
#define F12  (251./360.)
#define F32  (11./18.)
#define F42  (1./6.)
#define F52  (1./60.)

void MDFrame::NVE_Gear6()
{
    int i;
    double tmp;
    Matrix33 hinv; Vector3 serr;

    /* initializing memory */
    if(npold!=_NP)
    {
        Realloc(s2,Vector3,_NP);
        Realloc(s3,Vector3,_NP);
        Realloc(s4,Vector3,_NP);
        Realloc(s5,Vector3,_NP);
        Realloc(s2real,Vector3,_NP);
        
        memset(s2,0,sizeof(Vector3)*_NP);
        memset(s3,0,sizeof(Vector3)*_NP);
        memset(s4,0,sizeof(Vector3)*_NP);
        memset(s5,0,sizeof(Vector3)*_NP);
        memset(s2real,0,sizeof(Vector3)*_NP);

        npold=_NP;
    }
    
    /* predictor */
    for(i=0;i<_NP;i++)
    {
        if(fixed[i]) continue;
        _SR[i]+=_VSR[i]+s2[i]+s3[i]+s4[i]+s5[i];
        _VSR[i]+=s2[i]*2.+s3[i]*3.+s4[i]*4.+s5[i]*5.;
        s2[i]+=s3[i]*3.+s4[i]*6.+s5[i]*10.;
        s3[i]+=s4[i]*4.+s5[i]*10.;
        s4[i]+=s5[i]*5.;
    }

    /* evaluator */
    call_potential();
    calcprop();
    
    hinv=_H.inv();

    /* fix me! need to change the unit of velocity to A/ps */
    tmp=0.5*(_TIMESTEP)*(_TIMESTEP)*1e-24  //(ps^2)
        /(_ATOMMASS[0]*1e-3/AVO)*EV/1e-20;     //(A^2)
    
    for(i=0;i<_NP;i++)
    {
        if(fixed[i]) continue;
        if(species[i]==0)
            s2real[i]=hinv*_F[i]*tmp;
        else
            s2real[i]=hinv*_F[i]*tmp *_ATOMMASS[0]/_ATOMMASS[species[i]];
    }

    /* corrector */
    for(i=0;i<_NP;i++)
    {
        if(fixed[i]) continue;
        serr=s2[i]-s2real[i];
        _SR[i]-=serr*F02;
        _VSR[i]-=serr*F12;
        s2[i]-=serr;
        s3[i]-=serr*F32;
        s4[i]-=serr*F42;
        s5[i]-=serr*F52;
    }
}













/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NVT_Gear6()
{
    FATAL("NVT_Gear6 not implemented yet.  Come back soon!");
}











/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NPH_Gear6()
{
    FATAL("NPH_Gear6 not implemented yet.  Come back soon!");
}












/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NPT_Gear6()
{
    FATAL("NPT_Gear6 not implemented yet.  Come back soon!");
}










/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NVE_VVerlet(int nstep)
{
    int i;
    double tmp;
    Matrix33 hinv;
    
    if(npold!=_NP)
    {
        Realloc(s2,Vector3,_NP);
        memset(s2,0,sizeof(Vector3)*_NP);
        npold=_NP;
    }

    if(nstep>0) /* skip this in the very first step */
    {
        /* s2[i] is the acceleration in previous time step (n) */
        for(i=0;i<_NP;i++)
        {
            if(fixed[i]) continue;
            _VSR[i]+=s2[i];        /* p(n+1/2) */
            _SR[i]+=_VSR[i];       /* q(n+1) */
        }
    }
    /* _SR[i] is the position at current step,  q(n+1) */
    /* _VSR[i] is the velocity at half-step,    p(n+1/2) */
    
    /* compute acceleration a(n+1),  s2[i]=0.5*a*(dt)^2 */
    call_potential();
    calcprop();

    hinv=_H.inv();

    /* fix me! need to change the unit of velocity to A/ps */
    tmp=0.5*(_TIMESTEP)*(_TIMESTEP)*1e-24  //(ps^2)
        /(_ATOMMASS[0]*1e-3/AVO)*EV/1e-20; //(A^2)

    for(i=0;i<_NP;i++)
    {
        if(fixed[i]) continue;
        if(species[i]==0)
            s2[i]=hinv*_F[i]*tmp;
        else
            s2[i]=hinv*_F[i]*tmp *_ATOMMASS[0]/_ATOMMASS[species[i]];
    }
        
    /* s2[i] is the acceleration at current step, 0.5*a(n+1)*(dt)^2 */
    
    if(nstep>0) /* skip this in the very first step */
    {
        for(i=0;i<_NP;i++)
        {
            if(fixed[i]) continue;
            _VSR[i]+=s2[i];
        }
    }
    /* _VSR[i] is the velocity at current step, p(n+1) */
}














/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NVT_VVerlet(int nstep)
{
    FATAL("NVT_VVerlet not implemented yet.  Come back soon!");
}

















/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NPH_VVerlet(int nstep)
{
    FATAL("NPH_VVerlet not implemented yet.  Come back soon!");
}














/*******************************************************
 *
 *  NVE ensemble
 *  Gear6 predictor-corrector integrator
 *
 ******************************************************/
void MDFrame::NPT_VVerlet(int nstep)
{
    FATAL("NPT_VVerlet not implemented yet.  Come back soon!");
}
