/*
  ffs.cpp
  by Seunghwa Ryu, shryu@stanford.edu
  Last Modified : Mon Sep  8 17:16:38 2008

  FUNCTION  :  Foward Flux Sampling for rare transition events

  To Do:
      1.  calcrystalorder() needs to be improved

  Note:
      This file is included by md.cpp.  This file cannot be compiled by itself.
*/

/********************************************************************/
/* Forward Flux Sampling (FFS) function (Seunghwa Ryu)              */
/********************************************************************/
void MDFrame::calcrystalorder()
{
    int i, j, jpt, m, M, Nb, Nc_i;
    Vector3 sij, rij;
    double rrij, xij, yij, zij, r_l;
    double metric[30];

    int N_cluster, Size_cluster[_NP];    
    int k0;
    //INFO("calcrys");

    /* Initialize Nc_i */
    Nc_i = 0;

    M = 2*L_for_QLM + 2;
    N_solid_P = 0;
    N_skin_P = 0;
    N_lgst_cluster = 0;
    N_lgst_skin = 0;
    N_cluster = 0;

//	printf ("debug\n");
    if (L_for_QLM==3)
    {
        metric[0]=5.0;
	metric[1]=metric[0];
	metric[2]=30.0;
	metric[3]=metric[2];
	metric[4]=3.0;
	metric[5]=metric[4];
	metric[6]=2.0;
    }
     else if (L_for_QLM==6)
    {
	metric[0] = 231.0;
	metric[1] = metric[0];
	metric[2] = 2772.0;
	metric[3] = metric[2];
	metric[4] = 126.0;
	metric[5] = metric[4];
	metric[6] = 420.0;
	metric[7] = metric[6];
	metric[8] = 105.0;
	metric[9] = metric[8];
	metric[10]= 168.0;
	metric[11]= metric[10];
	metric[12]= 2.0;
    }
    else
    {
        ERROR("calcrystalorder(): L = "<<L_for_QLM<<" is not implemented");
        return;
    }
//	INFO("calcry1 \n");
    /* initialize QLM and QL to zero */
    for(i=0 ; i < _NP ; i++)
    {
	QLM_mark[i]=0;
        QLM_solid[i]=0;
	Size_cluster[i]=0;
        _QL[i]=0;
        for(m=0;m<M;m++)
            _QLM[i*M+m]=0;
    }
//	INFO("calcry1.5\n");
    for(i=0;i<_NP;i++)
    {
        Nb=0;
        for(j=0;j<nn[i];j++)
        {
            jpt=nindex[i][j];
            if(jpt==i) continue;
            sij=_SR[jpt]-_SR[i]; sij.subint();
            rij=_H*sij; rrij=rij.norm();

            if(rrij > Rc_for_QLM) continue;
	    xij=rij.x;
	    yij=rij.y;
	    zij=rij.z;
	    r_l=pow(rrij,(double)L_for_QLM);

            /* rij.x, rij.y, rij.z
             * rij[0], rij[1], rij[2]
             */
	    Nb++;
	    if (L_for_QLM == 3)
            {	
                 _QLM[i*M+ 0 ] += ( pow(xij,3.0) - 3.0*xij*pow(yij,2.0) )/r_l;
		 _QLM[i*M+ 1 ] += ( pow(yij,3.0) - 3.0*yij*pow(xij,2.0) )/r_l;
		 _QLM[i*M+ 2 ] += ( pow(xij,2.0) - pow(yij,2.0) )*zij/r_l;
		 _QLM[i*M+ 3 ] += -2.0*xij*yij*zij/r_l;
		 _QLM[i*M+ 4 ] += (4.0*zij*zij-xij*xij-yij*yij)*xij/r_l;
		 _QLM[i*M+ 5 ] += -(4.0*zij*zij-xij*xij-yij*yij)*yij/r_l;
		 _QLM[i*M+ 6 ] += zij*(2.0*zij*zij-3.0*xij*xij-3.0*yij*yij)/r_l;            }
            else if (L_for_QLM ==6)
	    {
		_QLM[i*M+ 0 ] += (pow(xij,6.0)-15*pow(xij,4.0)*pow(yij,2.0)+15*pow(xij,2.0)*pow(yij,4.0)-pow(yij,6.0))/r_l;
		_QLM[i*M+ 1 ] += 2*xij*yij*(3*pow(xij,4.0)-10*pow(xij,2.0)*pow(yij,2.0)+3*pow(yij,4.0))/r_l;
		_QLM[i*M+ 2 ] += xij*zij*(pow(xij,4.0)-10*pow(xij,2.0)*pow(yij,2.0)+5*pow(yij,4.0))/r_l;
		_QLM[i*M+ 3 ] += yij*zij*(5*pow(xij,4.0)-10*pow(xij,2.0)*pow(yij,2.0)+pow(yij,4.0))/r_l;
		_QLM[i*M+ 4 ] += -(-10*pow(xij,4.0)*pow(zij,2.0)+pow(xij,6.0)-5*pow(xij,4.0)*pow(yij,2.0)+60*pow(xij*yij*zij,2.0)-5*pow(xij,2.0)*pow(yij,4.0)-10*pow(yij,4.0)*pow(zij,2.0)+pow(yij,6.0))/r_l;
		_QLM[i*M+ 5 ] += -4*(-10*pow(zij,2.0)+xij*xij+yij*yij)*xij*yij*(xij*xij-yij*yij)/r_l;
		_QLM[i*M+ 6 ] += -xij*zij*(-8*pow(xij,2.0)*pow(zij,2.0)+3*pow(xij,4.0)-6*pow(xij,2.0)*pow(yij,2.0)+24*pow(yij,2.0)*pow(zij,2.0)-9*pow(yij,4.0))/r_l;
		_QLM[i*M+ 7 ] += -zij*(-8*pow(zij,2.0)+3*xij*xij+3*yij*yij)*yij*(3*xij*xij-yij*yij)/r_l;
		_QLM[i*M+ 8 ] += (16*pow(xij,2.0)*pow(zij,4.0)-16*pow(xij,4.0)*pow(zij,2.0)+pow(xij,6.0)+pow(xij,4.0)*pow(yij,2.0)-pow(xij,2.0)*pow(yij,4.0)-16*pow(yij,2.0)*pow(zij,4.0)+16*pow(yij,4.0)*pow(zij,2.0)-pow(yij,6.0))/r_l;
		_QLM[i*M+ 9 ] += 2*(16*pow(zij,4.0)-16*pow(xij,2.0)*pow(zij,2.0)-16*pow(yij,2.0)*pow(zij,2.0)+pow(xij,4.0)+2*pow(xij*yij,2.0)+pow(yij,4.0))*xij*yij/r_l;
		_QLM[i*M+ 10] += xij*zij*(8*pow(zij,4.0)-20*pow(xij*zij,2.0)-20*pow(yij*zij,2.0)+5*pow(xij,4.0)+10*pow(xij*yij,2.0)+5*pow(yij,4.0))/r_l;
		_QLM[i*M+ 11] += yij*zij*(8*pow(zij,4.0)-20*pow(xij*zij,2.0)-20*pow(yij*zij,2.0)+5*pow(xij,4.0)+10*pow(xij*yij,2.0)+5*pow(yij,4.0))/r_l;
		_QLM[i*M+ 12] += -(-16*pow(zij,6.0)+120*pow(xij,2.0)*pow(zij,4.0)+120*pow(yij,2.0)*pow(zij,4.0)-90*pow(xij,4.0)*pow(zij,2.0)-180*pow(xij*yij*zij,2.0)-90*pow(yij,4.0)*pow(zij,2.0)+5*pow(xij,6.0)+15*pow(xij,4.0)*pow(yij,2.0)+15*pow(xij,2.0)*pow(yij,4.0)+5*pow(yij,6.0))/r_l;
	    }
        }
        /* the last entry is the magnitude of the vector */
	for (m=0;m<M-1;m++)
	    _QLM[i*M+M-1] += metric[m]*_QLM[i*M+m]*_QLM[i*M+m];
	_QLM[i*M+M-1]=sqrt(_QLM[i*M+M-1]);
//        printf("%d %f\n",Nb,_QLM[i*M+M-1]);
    }

//	INFO("calcry2\n");
    for(i=0;i<_NP;i++)
    {
        Nb=0;
        for(j=0;j<nn[i];j++)
        {
            jpt=nindex[i][j];
            if(jpt==i) continue;
            sij=_SR[jpt]-_SR[i]; sij.subint();
            rij=_H*sij; rrij=rij.norm();  
            if(rrij > Rc_for_QLM) continue;
	    Nb++; 
            for(m=0;m<M-1;m++)
            {
                _QL[i] += _QLM[i*M+m] * _QLM[jpt*M+m] * metric[m] / _QLM[jpt*M+M-1];
            }
        }
        if (Nb>0)
	{
	_QL[i]/= fabs((_QLM[i*M+M-1]*Nb));
		if (L_for_QLM==6)
			_QL[i]=-_QL[i];
	}
        else
        _QL[i] = 2; 
//        printf("%d %f\n",Nb,_QL[i]);

        /* put results in TOPOL array for visualization */
	_TOPOL[i] = _QL[i];
	if (_QL[i] <= QLM_cutoff )
	{
		N_solid_P++;
		QLM_solid[i]=1;
	}

//	_TOPOL[i] = _QLM[i*M+M-1];	
    }
//    INFO("calcry3");
    k0=0;
    for (i=0;i<_NP;i++)
    {
	if ( QLM_mark[i]==0 && QLM_solid[i]==1 )
	{
	    N_cluster++;
	    N_cluster_temp = 0;
	    if (N_cluster == 1)
		Nc_i=i;
 	    if (wSKIN>0) DFS1(i,0,0,0);
	    else DFS(i,0,0);
	    Size_cluster[N_cluster]=N_cluster_temp;
            if (N_cluster_temp > N_lgst_cluster)
            {
		N_lgst_cluster = N_cluster_temp;
 	        Nc_i=i;
            }
//	    printf("Size_cluster = %d\n", N_cluster_temp);
//	    printf("N_largest_cluster = %d\n", N_lgst_cluster);	    
/*********************************************/
	    if (YES_UMB==1 && UMB_K < 0 && N_cluster_temp > 0 )
	    {
		for (j=0;j<=2*delta_n;j++) if (Narray[j]==N_cluster_temp) {
		if ( UMB_curstep > UMB_equilstep ) {
		    Occurence[j]++;
		    Probability[j]++;
		}
		}
	    }
/*********************************************/
	}
}
/*********************************************/    
    if ( YES_UMB == 1 && UMB_K < 0 )
    {   
        k0=_NP-N_solid_P;
	for (j=0;j<=2*delta_n;j++) if (Narray[j]==0) {
	if (UMB_curstep > UMB_equilstep ) {
	    Occurence[j]=Occurence[j]+k0;
	    Probability[j]=Probability[j]+k0;
	}
	} 
    }
/*********************************************/    
    if ( N_lgst_index != 0 )
    {
//        N_lgst_cluster = 0;
	for (i=0;i<_NP;i++)
	    QLM_mark[i]=0;
	if (wSKIN >0 )
	    DFS1(Nc_i,1,N_lgst_index,N_lgst_skin_index);
	else
	    DFS(Nc_i,1,N_lgst_index);
    }
//    printf("N_solid_P = %d\n",N_solid_P);
//    printf("N_skin_P = %d\n",N_skin_P);
//    printf("N_largest_cluster = %d\n",N_lgst_cluster);
}

void MDFrame::caldislocationorder()
{
//    printf("babo 0 \n");
    int i, Nc_i, j, jpt;
    int N_cluster, Size_cluster[_NP],nn_rc, N_bulk;
    Vector3 sij0, sij, rij0, rij;
    double rrij0, rrij, temp;

    /* Initialize Nc_i */
    Nc_i = 0;

    N_cluster = 0;
    N_lgst_cluster = 0;
    N_solid_P = 0;
    for (i=0;i< _NP;i++)
    {
        QLM_mark[i]=0;
        QLM_solid[i]=0;
        Size_cluster[i]=0;
	_QL[i]=0;
    }

//    printf("babo 1\n");
//    calcentralsymmetry();
    if (_SR2==NULL)
    {
 	FATAL("cal_dislocation_order: _SR2 == NULL");
	return;
    }
    N_bulk = _NP;
    for (i=0;i< _NP;i++)
    {
        nn_rc = 0;
	for (j=0;j<nn[i];j++)
	{
//            printf("%d %f\n",nn[i],nn_ave); 
	    jpt = nindex[i][j];
	    if (jpt == i ) continue;

	    sij0 = _SR2[jpt]-_SR2[i]; sij0.subint();
            rij0 = _H*sij0; rrij0=rij0.norm();

            sij  = _SR[jpt] - _SR[i]; sij.subint();
	    rij = _H*sij; rrij=rij.norm();

//	printf("i=%d j=%d SRi=%f SRj=%f \n",i,j,_SR[jpt][1],_SR2[jpt][1]);
	    temp = fabs(rrij0-rrij);
	    if (rrij > Rc_for_QLM) continue;
            nn_rc ++;
	    if (temp > _QL[i]) _QL[i]=temp;
	}
//        printf("nn_rc =%d",nn_rc); 
//        printf("i=%d, temp = %f\n",i,temp);
        if (nn_rc < 10 ) 
        {
            _QL[i]=0;
            N_bulk--;
        } 
        _TOPOL[i]=_QL[i];
        if ( _QL[i] > QLM_cutoff )
        {
//	        printf("i=%d QL=%f",i,_QL[i]); 
                N_solid_P++;
                QLM_solid[i]=1;
        }
    }
  
//    printf("N_bulk=%d\n",N_bulk);
    for (i=0;i<_NP;i++)
    {
        if ( QLM_mark[i]==0 && QLM_solid[i]==1 )
        {
	    N_cluster++;
	    N_cluster_temp = 0;
	    if (N_cluster == 1)
	 	Nc_i = i;
	    DFS(i,0,0);
	    Size_cluster[N_cluster] = N_cluster_temp;
	    if (N_cluster_temp > N_lgst_cluster)
	    {
		N_lgst_cluster = N_cluster_temp;
		Nc_i=i;
	    }
	}
    }
//    printf("N_solid = %d\n",N_solid_P);
//    printf("N_lgst_cluster = %d\n\n",N_lgst_cluster);
    if (N_lgst_index !=0)
    {
	for(i=0;i<_NP;i++)
	    QLM_mark[i]=0;
	DFS(i,1,N_lgst_index);
    }
}
void MDFrame::DFS(int i, int On_Off, double index )
{
    int j, jpt;
    double rrij;
    Vector3 sij, rij;

    if (QLM_mark[i]==1 || QLM_solid[i]==0)
	return;
    else
    {
//	printf("QLM_mark=%d , QLM_solid=%d, i = %d \n",QLM_mark[i],QLM_solid[i],i);
	QLM_mark[i]=1;
	if ( On_Off > 0 ) 
	{
	    _QL[i]=index;
	    _TOPOL[i]=_QL[i];
        }
	N_cluster_temp++;
	for (j=0;j<nn[i];j++)
	{
	    jpt = nindex[i][j];
	    if ( jpt == i || QLM_solid[jpt] == 0 || QLM_mark[jpt] == 1)
		continue;
	    sij=_SR[jpt]-_SR[i]; sij.subint();
	    rij=_H*sij; rrij=rij.norm();
	   
	    if (rrij > Rc_for_QLM) continue;
	    DFS(jpt, On_Off, index);
        }
    }
}

void MDFrame::DFS1(int i, int On_Off, double index, double index1 )
{
    int j, jpt;
    double rrij;
    Vector3 sij, rij;

    if (QLM_mark[i]==1 && QLM_solid[i]==0)
	return;
    else if (QLM_mark[i]==0 && QLM_solid[i]==0)
    {
        QLM_mark[i]=1;
	if (On_Off > 0 )
	{
	    _QL[i]=index1;
	    _TOPOL[i]=_QL[i];
	    N_lgst_skin++;
	}
//        _QL[i]=-1.5;
//        _TOPOL[i]=_QL[i];
        N_skin_P++;
        N_cluster_temp++;
        return; 
    }
    else
    {
//	printf("QLM_mark=%d , QLM_solid=%d, i = %d \n",QLM_mark[i],QLM_solid[i],i);
	QLM_mark[i]=1;
	if ( On_Off > 0 )
	{
	    _QL[i]=index;
	    _TOPOL[i]=_QL[i];
	}
	N_cluster_temp++;
	for (j=0;j<nn[i];j++)
	{
	    jpt = nindex[i][j];
	    if ( jpt == i || QLM_mark[jpt] == 1)
		continue;
	    sij=_SR[jpt]-_SR[i]; sij.subint();
	    rij=_H*sij; rrij=rij.norm();
	   
	    if (rrij > Rc_for_QLM) continue;
	    DFS1(jpt, On_Off, index, index1);
        }
    }
}

void MDFrame::allocQLM()
{
    int size;

    if (L_for_QLM < 0)
    {
        ERROR("L_for_QLM = "<<L_for_QLM<<" skip allocQLM");
        return;
    }
    if (_NP <= 0)
    {
        ERROR("NP = "<<_NP<<" skip allocQLM");
        return;
    }
    size = (2*L_for_QLM + 2)*_NP;

    Realloc(_QLM,double,size);
   
    Realloc(QLM_solid,int,_NP);

    Realloc(QLM_mark,int,_NP);

    Realloc(_QL,double,_NP);

}

void MDFrame::assign_Lam()
{
    int i, n;
    n = (int)input[0];
    Realloc(_Lam_array,int,n);
    Realloc(_Lam_check,int,n);
    for (i=1;i<=n;i++)
    {
	_Lam_array[i-1]=(int)input[i];
	_Lam_check[i-1]=0;
    }
    FFS0_check=1;
}

int MDFrame::FFSprocess()
{
    int i,Ntemp;
    if (FFSautoend==1) {
	Ntemp = (int) _Lam_array[FFSoption*2];
	_Lam_array[FFSoption]=Ntemp;
    } 
    if (FFSoption==0) 
    {
	if (N_lgst_cluster >= _Lam_array[0] && FFS0_check == 0 )
	{
	    FFScn.write(this,zipfiles,true);
	    FFS0_check=1;
	}
	if (FFS0_check==1 && N_lgst_cluster <= lambda_A )
	    FFS0_check=0;
        return 0;
    }
    else
    {
	if (N_lgst_cluster >= _Lam_array[FFSoption])
	{
	    FFS0_check = 1;
	    FFScn.write(this,zipfiles,true);
	    return 1;
	}
	
	if ( FFSpruning > 0 )
	{
	    for (i=FFSoption;i>1;i--)
	    {
		if ( N_lgst_cluster<=_Lam_array[i-2] && _Lam_check[i-2]==0 )
		{
		    if (drand48()>FFS_Pp)
		    {
			FFScn_weight=FFScn_weight/(1-FFS_Pp);
			_Lam_check[i-2]=1;
		    }
		    else
		    {
		 	FFS0_check = -1;
		    }
		}
		if ( N_lgst_cluster <= lambda_A ) FFS0_check=-1;
	    }
	    if ( N_lgst_cluster <= lambda_A ) FFS0_check=-1;
	}
	else
	{
	    if ( FFScurstep > step0 + totalsteps || N_lgst_cluster <= lambda_A )
		FFS0_check = -1;
	}
   	
	if (FFS0_check<0) return 1;
	else return 0;
    }
}

void MDFrame::initUMB()
{
    allocUMB();
    setconfig4();
    copyStoS4();
    refreshneighborlist(); 
    calcrystalorder();
    N_lgst_temp = N_lgst_cluster;
    kinetic_flag = 0;
}

void MDFrame::allocUMB()
{
    int i, no;
    no = (int) ceil(1.0*Kinetic_Time/savepropfreq+1);
    Realloc(Narray,int,2*delta_n+1);
    Realloc(Occurence,int,2*delta_n+1);
    Realloc(Probability,double,2*delta_n+1);
    Realloc(time_array,double,no+1);
    Realloc(n_array,int,no+1);
    for (i=0;i<2*delta_n+1;i++)
    {
	Narray[i]=n_center-delta_n+i;
	Occurence[i]=0;
	Probability[i]=0;
    }
    for (i=0;i<no+1;i++)
    {
	time_array[i]=1.0*i*savepropfreq*_TIMESTEP;
	n_array[i]=0;
    }
}

void MDFrame::UMBprocess()
{
    double umb_temp,R;
    int umb_deltan;
INFO_Printf("babo\n");
    if ( UMB_K==0 ) {
	if ( N_lgst_cluster < Narray[0] )
	{
	    copyS4toS();
	    Occurence[0]++;
	    Probability[0]++;
	}
	else if ( N_lgst_cluster > Narray[2*delta_n])
	{
	    copyS4toS();
	    Occurence[2*delta_n]++;
	    Probability[2*delta_n]++;
	}
	else
	{
	    umb_deltan=N_lgst_cluster-Narray[0];
	    Occurence[umb_deltan]++;
	    Probability[umb_deltan]++;
	    copyStoS4();
	    N_lgst_temp=N_lgst_cluster;
	}
    }

    if ( UMB_K > 0 && kinetic_flag == 0 )
    {
	umb_temp=(N_lgst_cluster-N_lgst_temp)*(N_lgst_cluster+N_lgst_temp-2*n_center);
	R=exp(-0.5*UMB_K*(umb_temp)/_TDES);
//        INFO("check");
        INFO_Printf("R=%f, umb_temp=%f, n_center=%d N_lgst=%d, N_lgst_temp=%d\n",R,umb_temp,n_center,N_lgst_cluster,N_lgst_temp);
	acc_UMB = (drand48()<=R);
	if (acc_UMB) {
	    umb_deltan=(N_lgst_cluster-Narray[0]);
	    umb_temp=exp(0.5*UMB_K*pow((N_lgst_cluster-n_center),2)/_TDES);
	    if (YES_HMC!=1) copyStoS4();
	    else 
	    {
		if (acc_HMC==1) copyStoS4();
	    }		
	    if (umb_deltan>=0 && umb_deltan <2*delta_n && Kinetic < 1 && curstep > UMB_equilstep) {
	        Occurence[umb_deltan]++;
	        Probability[umb_deltan]+=umb_temp;
	    }
            INFO_Printf("UMB accepted\n");
//            INFO_Printf("R=%f, umb_temp=%f, _TDES=%f \n",R,umb_temp,_TDES);
//            INFO_Printf("N_lgst=%d, N_lgst_temp=%d \n",N_lgst_cluster,N_lgst_temp);
	    N_lgst_temp=N_lgst_cluster;
//            perturbevelocity();
    	}
	else
	{
	    umb_deltan=(N_lgst_temp-Narray[0]);
	    umb_temp=exp(0.5*UMB_K*pow((N_lgst_temp-n_center),2)/_TDES);
	    copyS4toS();
//            initvelocity();
//            input=30.0;
            perturbevelocity();
	    if (umb_deltan >=0 && umb_deltan <= 2*delta_n && Kinetic < 1 && curstep > UMB_equilstep ) {
	    	Occurence[umb_deltan]++;
		Probability[umb_deltan]+=umb_temp;
	    }
            INFO_Printf("UMB rejected\n");
   	}
    } 

    if ( Kinetic == 1 && kinetic_flag == 1 ) {
	kinetic0++;
	n_array[kinetic0]=n_array[kinetic0]+(N_lgst_cluster-n_center)*(N_lgst_cluster-n_center);
	if ( kinetic0 > (int) 1.0*Kinetic_Time/savepropfreq ) kinetic_flag = 0;
    }

    if ( Kinetic == 1 && N_lgst_cluster == n_center && kinetic_flag == 0 && curstep < totalsteps - Kinetic_Time - 1)
    {
	kinetic_flag=1;
	Kinetic_Swip++;
	kinetic0=0;
    }
}

void MDFrame::setconfig4()
{
    Realloc(_SR4,Vector3,_NP);
    Realloc(_R4,Vector3,_NP);
    Realloc(_VSR4,Vector3,_NP);
    Realloc(_VR4,Vector3,_NP);
}

void MDFrame::copyStoS4()
{
    memcpy(_SR4,_SR,sizeof(Vector3)*_NP);
    memcpy(_R4,_R,sizeof(Vector3)*_NP);
    memcpy(_VSR4,_VSR,sizeof(Vector3)*_NP);
    memcpy(_VR4,_VR,sizeof(Vector3)*_NP);
    _H4=_H;
}

void MDFrame::copyS4toS()
{
    memcpy(_SR,_SR4,sizeof(Vector3)*_NP);
    memcpy(_R,_R4,sizeof(Vector3)*_NP);
    memcpy(_VSR,_VSR4,sizeof(Vector3)*_NP);
    memcpy(_VR,_VR4,sizeof(Vector3)*_NP);
    _H=_H4;
}

void MDFrame::printhist()
{
    FILE *fp, *fp1, *fp2;
    int i;
    fp  = fopen("Narray.txt","w");  
    fp1 = fopen("Freq.txt","w");
    fp2 = fopen("Prob.txt","w");
    for (i=0;i<2*delta_n+1;i++)
    {
	fprintf(fp,"%d\n",Narray[i]);
	if (UMB_K >= 0 ) {
	fprintf(fp1,"%d\n",Occurence[i]);
	fprintf(fp2,"%f\n",Probability[i]);
	} else {
	fprintf(fp1,"%f\n",Probability[i]);
	fprintf(fp2,"%f\n",Probability[i]);
	}
    }
    fclose(fp);
    fclose(fp1);
    fclose(fp2);
}

void MDFrame::kineticprint()
{
    FILE *fp, *fp1, *fp2;
    int i;
    fp = fopen("time_array.txt","w");
    fp1= fopen("n_array.txt","w");
    fp2= fopen("tot_swip.txt","w");
    for (i=0;i<(int) 1.0*Kinetic_Time/savepropfreq+2;i++) {
	fprintf(fp,"%f\n",time_array[i]);
	fprintf(fp1,"%d\n",n_array[i]);
    }
	fprintf(fp2,"%d %d\n",_NP,Kinetic_Swip);
    fclose(fp);fclose(fp1);fclose(fp2);
}

void MDFrame::HMCprocess()
{
    double tmp,R, Hamil_now, Hamil_pre;
    Hamil_pre=EPOT_temp+KATOM_temp;
    Hamil_now=_EPOT+_KATOM;
    tmp=( (Hamil_pre) - (Hamil_now) )/(KB*_TDES);
    R=exp(tmp);
INFO_Printf("EPOT_pre=%e, EPOT_now=%e\n",EPOT_temp,_EPOT);
INFO_Printf("KATOM_pre=%e, KATOM_now=%e\n",KATOM_temp,_KATOM);
INFO_Printf("T_HMC    =%f, T_inst   =%f\n",T_HMC,_T);
INFO_Printf("Hamil_pre=%e, Hamil_now=%e, R=%e\n",Hamil_pre,_HELM,R);
    if (tmp<-40) acc_HMC=0;
    else
    {
	if (drand48() < R)
	    acc_HMC=1;
	else
	    acc_HMC=0;
    }
    if (acc_HMC)
    {
	INFO("HMC accepted");
        if (YES_UMB==0)
	{
	    copyStoS4();
            EPOT_temp=_EPOT;
            T_HMC=_TDES;
            perturbevelocity();
            KATOM_temp=_KATOM;
	}
        else if (YES_UMB==1)
	{
	    UMBprocess();
	    if (acc_UMB || UMB_K==-1 )
	    {
		EPOT_temp=_EPOT;
                INFO("HMC&UMB accepted");
                T_HMC=_TDES;
	    }
            perturbevelocity();
	    KATOM_temp=_KATOM;
	}
    }
    else
    {
   	INFO("HMC rejected");
	copyS4toS();
        perturbevelocity();
//        initvelocity();
        if (YES_UMB==1)
	{
	N_lgst_cluster=N_lgst_temp;
	UMBprocess();
	}
        KATOM_temp=_KATOM;
    }
}

void MDFrame::initHMC()
{
    setconfig4();
    copyStoS4();
    call_potential();
    calcprop();
    EPOT_temp=_EPOT;
    KATOM_temp=_KATOM;
    T_HMC=_TDES;
}
