/*--------------------------------------------------------------------*/
void single_step() {
/*----------------------------------------------------------------------
r & rv are propagated by DeltaT using the velocity-Verlet scheme.
----------------------------------------------------------------------*/
  int i,a;

  half_kick(); /* First half kick to obtain v(t+Dt/2) */
  for (i=0; i<n; i++) /* Update atomic coordinates to r(t+Dt) */
    for (a=0; a<3; a++) r[i][a] = r[i][a] + DeltaT*rv[i][a];
  atom_move();
  atom_copy();
  compute_accel(); /* Computes new accelerations, a(t+Dt) */
  half_kick(); /* Second half kick to obtain v(t+Dt) */
}
/*!

*/
void Md_method::run(Program_options & options, ostream & output)
{

  output.precision(10);


  string logfile=options.runid+".log";
  prop.setLog(logfile, log_label);

  int natoms=sys->nIons();

  Array1 < Array1 <int> > atom_move;
  Array1 < Array2 <doublevar> > displace;

  //Even numbered displacements are in + direction, odd are in 
  // - direction

  if(natoms==2) {
    //For a dimer, assume they are oriented in the z 
    //direction and only move in that direction.
    atom_move.Resize(4);
    displace.Resize(4);
    int count=0;
    for(int at=0; at < natoms; at++) {
      for(int s=0; s< 2; s++) {
        atom_move(count).Resize(1);
        displace(count).Resize(1,3);
        atom_move(count)(0)=at;
        displace(count)=0;
          if(s==0) 
            displace(count)(0,2)=0.00025;
          else
            displace(count)(0,2)=-0.00025;
          count++;
      }
    }
    
  }
  else {
    int ndim=0;
    for(int d=0; d< 3; d++) {
      if(restrict_dimension(d) ==0) ndim++;
    }
    atom_move.Resize(2*ndim*natoms);
    displace.Resize(2*ndim*natoms);
    int count=0;
    for(int at=0; at< natoms; at++) {
      for(int d=0; d< 3; d++) {
        if(!restrict_dimension(d) ) {
        for(int s=0; s< 2; s++) {
          atom_move(count).Resize(1);
          displace(count).Resize(1,3);
          atom_move(count)(0)=at;
          displace(count)=0;
          if(s==0) 
            displace(count)(0,d)=0.00025;
          else
            displace(count)(0,d)=-0.00025;
          count++;
        }
      }
      }
    }
  }
  
  prop.setDisplacement(atom_move, displace);
  Properties_final_average curravg;
  
  string vmcout=options.runid+".embed";
  ofstream vmcoutput;
  if(output) 
	vmcoutput.open(vmcout.c_str());

 
  Array3 <doublevar> ionpos(nstep+2, natoms, 3, 0.0);
  Array1 <doublevar> temppos(3);


  for(int s=0; s< 2; s++) {
    for(int at=0; at< natoms; at++) {
      sys->getIonPos(at, temppos);
      for(int d=0; d< 3; d++) {
        ionpos(s,at,d)=temppos(d);
      }
    }
  }

  if(readcheckfile != "") {
    read_check(ionpos);
  }


  for(int s=0; s< 2; s++) {
    Array2 <doublevar> pos(ionpos(s));
    recenter(pos, atomic_weights);
  }

  for(int step=0; step < nstep; step++) {

    int currt=step+1; //current time

    for(int at=0; at< natoms; at++) {
      for(int d=0; d< 3; d++) {
        temppos(d)=ionpos(currt, at, d);
      }
      sys->setIonPos(at, temppos);
    }

    qmc_avg->runWithVariables(prop, sys, wfdata, pseudo, vmcoutput);
    prop.getFinal(curravg);
    
    if(output) 
      output << "*****Step " << step << endl;
    Array2 <doublevar> force(natoms, 3, 0.0);
    Array2 <doublevar> force_err(natoms, 3, 0.0);

    for(int f=0; f< atom_move.GetDim(0); f+=2 ) {
      for(int m=0; m < atom_move(f).GetDim(0); m++) {
        int at=atom_move(f)(m);
        for(int d=0; d< 3; d++) {
          //Take a finite difference between the two forces
          doublevar prop=fabs(displace(f)(m,d)/curravg.aux_size(f));
          doublevar fin_diff=(curravg.aux_diff(f,0)-curravg.aux_diff(f+1,0))
            /(2*curravg.aux_size(f));
          force(at,d)+= -prop*fin_diff;
          
          force_err(at,d)+=prop*(curravg.aux_differr(f,0)
                                 +curravg.aux_differr(f+1,0))
            /(2*curravg.aux_size(f))/(2*curravg.aux_size(f));
        }
      }
    }


   
    for(int at=0; at< natoms; at++) {
      for(int d=0; d< 3; d++) 
        force_err(at,d)=sqrt(force_err(at,d));
    }


    //Make sure that Newton's laws are actually followed for
    //two atoms; we can do this for more, as well.
    if(natoms==2) {
      doublevar average=(force(0,2)-force(1,2))/2.0;
      force(0,2)=average;
      force(1,2)=-average;
    }
    
    //Verlet algorithm..
    for(int at=0; at< natoms; at++) {
      for(int d=0; d< 3; d++) {
        ionpos(currt+1, at, d)=ionpos(currt, at,d)
          +(1-damp)*(ionpos(currt, at, d)-ionpos(currt-1, at,d))
          +tstep*tstep*force(at,d)/atomic_weights(at);
        //cout << "pos " << ionpos(currt, at,d)  
        //     << "  last " <<  ionpos(currt-1, at,d) 
        //     << "  weight " << atomic_weights(at) << endl;
      }
    }

    Array2 <doublevar> currpos(ionpos(currt+1));
    recenter(currpos, atomic_weights);
    
    doublevar kinen=0;
    int field=output.precision() + 15;
    
    for(int at=0; at < natoms; at++) {
      if(output) 

        output << "position" << at << " " 
             << setw(field)  << ionpos(currt+1, at, 0)
             << setw(field) << ionpos(currt+1, at, 1) 
             << setw(field) << ionpos(currt+1, at, 2) << endl;

      Array1 <doublevar> velocity(3);
      for(int d=0; d< 3; d++) {
        velocity(d)=(ionpos(currt+1, at, d)-ionpos(currt-1, at,d))/(2*tstep);
      }
      
      for(int d=0;d < 3; d++) {
        kinen+=.5*atomic_weights(at)*velocity(d)*velocity(d);
      }
      if(output ) {
        output << "velocity" << at << " "
               << setw(field) << velocity(0) 
               << setw(field) << velocity(1) 
               << setw(field) << velocity(2) << endl;
        
        output << "force" << at << "    "
               << setw(field) << force(at,0) 
               << setw(field) << force(at, 1) 
               << setw(field) << force(at,2) << endl;
        output << "force_err" << at 
               << setw(field) << force_err(at, 0)
               << setw(field) << force_err(at, 1)
               << setw(field) << force_err(at, 2) << endl;
      //output << "force" << at << "z  " << force(at,2) << " +/- "
      //      << force_err(at,2) << endl;
      }

    }
    if(output ) { 
    output << "kinetic_energy " << kinen << endl;
    output << "electronic_energy " << curravg.total_energy(0) << " +/- " 
           << sqrt(curravg.total_energyerr(0)) << endl;

    output << "total_energy " << curravg.total_energy(0)+kinen << " +/- "
           << sqrt(curravg.total_energyerr(0)) <<  endl;

    if(writecheckfile != "") 
      if(output) 
         write_check(ionpos, currt+1);
    }

  }
  if(output) 
    vmcoutput.close();


}