
// Monte Carlo simulation with the
// Metropolis scheme for spinodal decomposition

import java.lang.*;
import java.util.*;
import java.io.*;
import java.awt.*;  // uses the abstract windowing toolkit

public class Exchang {
// change the following globals to suit your fancy:
  static int maxSize = 200;      // width of window in pixels
  static int dim = 100;          // lattice size; can be any divisor of maxSize
  static int squareWidth = maxSize / dim;
  static Graphics g;  // the frame's graphics object, for drawing into
  static int frameTop, frameLeft;  // platform-dependent width of frame's top and left edges    
  static Color upColor = new Color(00,160,60);
  static Color downColor = new Color(255,245,220);
  	
  static int seed;	
  static int ic; //counter for the current iteration
  static final int nsize = 10000;
  static final int nskip = 10000;
  static final int pskip = 100;  //replot lattice after pskip iterations
  static final int ntotal = nsize*nskip; //total number of iterations
  static final int neq = 0;	    //# of iterations for equilibriation
  static final int lx = dim;	//dimensions of lattice
  static final int ly = dim;	//dimensions of lattice
  static int iaccept = 0;	// counter for calculating the acceptance rate of attempted jumps
  static int at;
  static double r1, r2;
  static double fn = 0.5; //fraction of negative spin sites
  static double fp = 1 - fn; //fraction of positive spin sites
  static int a[][] = new int[lx][ly]; // array that stores the spins in the lattice
  static int nb[][] = new int[lx][ly]; //# of B atoms on lattice sites nearest to site (i,j) 
  static Random r = new Random();
  static int rmax = dim/2 + 1; // maximum correlation length
  static double Teq = 1.0;	//for equilibriation at temperature Teq before final simulations
  static double T1 = 1.5; //temperature at which simulation is to be done
  static double T;
  static double jaa = 30;
  static double jbb = 30;
  static double jab = 28; 
  
  
  public static void main(String argv[]) {
  // initialize window and graphics:
    Frame gWin = new Frame("Exchang Model");
    gWin.setLocation(50,50);  // screen coordinates of top left corner
    gWin.setResizable(false);
    gWin.setVisible(true);  // show it!
    Insets theInsets = gWin.getInsets();
    gWin.setSize(maxSize+theInsets.left+theInsets.right,maxSize+theInsets.top+theInsets.bottom);
    frameTop = theInsets.top;
    frameLeft = theInsets.left;
    long resumeTime = System.currentTimeMillis() + 1000;
    do {} while (System.currentTimeMillis() < resumeTime);  // wait for frame to get initialized
    g = gWin.getGraphics();  // stick graphics object into a global so we can draw from anywhere!
  	
  	FileOutputStream out;
    PrintStream p;
  	// Initiate the seed from the current time
    GregorianCalendar t = new GregorianCalendar();
    int t1 = t.get(Calendar.SECOND);
    int t2 = t.get(Calendar.MINUTE);
    int t3 = t.get(Calendar.HOUR_OF_DAY);
    int t4 = t.get(Calendar.DAY_OF_MONTH);
    int t5 = t.get(Calendar.MONTH) + 1;
    int t6 = t.get(Calendar.YEAR);
	seed = t6+70*(t5+12*(t4+31*(t3+23*(t2+59*t1))));

    if((seed%2) == 0) seed = seed-1;
    
  	initial(a);			//initializes spins 
  	
  	System.out.println("\n" + "Initial spins: ");
  	//create new files for writing output
	
	try{
		out = new FileOutputStream("corExchang.dat",false);
       	p = new PrintStream(out);             
       	p.print("\n");
       	p.close();
    }
	catch(Exception e){
       	System.err.println("Error in printing to file");
    }	     

  	double accept = 0;
  	//Equilibriate at temperature T;
    //System.out.println(accept + " " + i);
  	for(int i=0; i<neq; ++i){
  		iaccept = 0;
  		T = Teq;
   		exchange();  //exchange of spins between neighbours
  		accept = i*accept + iaccept*100.0/(lx*ly);
  		accept /= i+1;
  	}
 
 	//append results to files
    System.out.println("\n" + "After " + neq + " exchanges: ");
	
    double cr[] = new double[rmax+1];
    System.out.println("Accept rate = " + accept + "%");
    
    for(ic=0; ic<=ntotal; ++ic) {
    	iaccept = 0;
    	T = T1;
        exchange();
            		
   		accept = (neq+ic)*accept + iaccept*100.0/(lx*ly);
  		accept /= neq+ic+1;
  		
        if(ic%nskip == 0){
      		System.out.println("\n" + "ic = " + ic);  
			cr = correl();
			try{
		       out = new FileOutputStream("corExchang.dat",true);
		       p = new PrintStream(out);             
		       p.print("\n");
		       p.println("ic = " + ic);
		       for(int r=0; r<rmax; ++r){
		       	   p.println(r + " " + cr[r]);
		       } 
		       p.println();   
		       p.close();
		     }
		     catch(Exception e){
		           System.err.println("Error in printing to file");
		     }
		
      		 System.out.println("Accept rate = " + accept + "%");
        }
        
        
        if(ic%pskip==0){
        	for(int i=0; i<lx; ++i)
	        	for(int j=0; j<ly; ++j)
        			colorSquare(i,j);     		
        }
    }

  	at = 0;
  	for(int i=0; i<lx; ++i)
  		for(int j=0; j<ly; ++j)
  			at += a[i][j];
  			
    int es = lx*ly/2-at;
          
  }

////////////////////////////////////////////////////////////////////////////////  
//Initialize the spins
  public static void initial(int a[][]){
  	int i1, i2, j1, j2;
  	for(int i=0; i<lx; ++i)
  		for(int j=0; j<ly; ++j){
  			r1 = ranf();
  			if(r1<=fn)	//if randomn # < fraction of negative spin
  			   a[i][j] = 0; // 0 --> negative spin
  			else
  			   a[i][j] = 1; // 1 --> positive spin
  		}
  	
  	at = 0;
  	for(int i=0; i<lx; ++i)
  		for(int j=0; j<ly; ++j)
  			at += a[i][j];
  			
    int es = lx*ly/2-at;
  	
  	System.out.println("Excess spin = " + es );

 
 // # of B in nearest sites	
  	for(int i=0; i<lx; ++i)
    	for(int j=0; j<ly; ++j){
    	   i1 = (lx+i-1)%lx;	//%lx taken for periodic boundary contion/
    	   i2 = (i+1)%lx;
    	   j1 = (ly+j-1)%ly;	//%ly taken for periodic boundary contion
    	   j2 = (j+1)%ly;
    	   nb[i][j] = a[i1][j]+a[i2][j]+a[i][j1]+a[i][j2];
    	   colorSquare(i,j);
    	}
    	
  }
	
////////////////////////////////////////////////////////////////////////////////	
	

//Exchange spin
 public static void exchange(){
   int swp = 0;
   int i1=0, i2=0, j1=0, j2=0;
   int i3=0, i4=0, j3=0, j4=0;
 
   double delH = 0;
   double kB = 1;
   double p; 
   int xA=0, xB=0, yA=0, yB=0;
   int daa=0, dbb=0, dab=0;

   iaccept = 0;
 //Exchange of spins 
   for(int i=0; i<lx; ++i)
 	  for(int j=0; j<ly; ++j){ 	
 	     i = (int) (lx*ranf());
 	     j = (int) (ly*ranf());     
 	     i1 = (lx+i-1)%lx;
 	     i2 = (i+1)%lx;
 	     i3 = (lx+i-2)%lx;
 	     i4 = (i+2)%lx;
	     j1 = (ly+j-1)%ly;	     
	     j2 = (j+1)%ly;	     
	     j3 = (ly+j-2)%ly;         
         j4 = (j+2)%ly;

   	     int t1 = (int) (4.*ranf());
   	     r1 = ranf();
         if(t1==0){
       	   if(a[i1][j]==a[i][j]);
       	   if(a[i1][j]!=a[i][j]){
       	   	 if(a[i][j]==0){ //a[i][j] = A, a[i-1][j] = B
       	 	   xA = 4 - nb[i][j]; //# A nearest neighbours to ij
   	 		   yB = nb[i1][j];	 //# B nearest neighbours to (i-1)j
       	 	   daa = 3 - xA - yB; //change in # AA bonds
       	 	   dbb = daa;   //change in # BB bonds
       	 	   dab = -2*daa; //change in # AB bonds
       	     }
       	 	 if(a[i][j]==1){ //a[i][j] = B, a[i-1][j] = A
       	 		xB = nb[i][j]; //# B nearest neighbours to ij
    	 		yA = 4 - nb[i1][j]; //# A nearest neighbours to (i-1)j
       	 		daa = 3 - xB - yA;
       	 		dbb = daa;
       	 		dab = -2*daa;       	 	
       	 	 }
       	 	 delH = -(daa*jaa+dbb*jbb+dab*jab);
       	 	 p = Math.exp(-delH/(kB*T));
		     if(p>=ranf()){
		       nb[i][j] += -a[i1][j] + a[i][j];	   
		       nb[i2][j] += -a[i][j] + a[i1][j]; 
		       nb[i][j2] += -a[i][j] + a[i1][j]; 
		       nb[i][j1] += -a[i][j] + a[i1][j]; 
		       nb[i1][j] += -a[i][j] + a[i1][j];
		       nb[i3][j] += -a[i1][j] + a[i][j]; 
		       nb[i1][j2] += -a[i1][j] + a[i][j];
		       nb[i1][j1] += -a[i1][j] + a[i][j];
		       swp = a[i][j];
		       a[i][j] = a[i1][j];
		       a[i1][j] = swp;  
		       iaccept += 1;
		     } 		        
       	   } 
       	         
         }
         
	   		
	   		
         if(t1==1){
       	   if(a[i2][j]==a[i][j]);
       	   if(a[i2][j]!=a[i][j]){
       	 	 if(a[i][j]==0){ //a[i][j] = A, a[i+1][j] = B
       	 		xA = 4 - nb[i][j]; //# A nearest neighbours to ij
       	 		yB = nb[i2][j];  //# B nearest neighbours to (i+1)j
       	 		daa = 3 - xA - yB;
       	 		dbb = daa;
       	 		dab = -2*daa;
       	 	 }
       	 	 if(a[i][j]==1){ //a[i][j] = B, a[i+1][j] = A
       	 		xB = nb[i][j]; //# B nearest neighbours to ij
       	 		yA = 4 - nb[i2][j]; //# A nearest neighbours to (i+1)j
       	 		daa = 3- xB - yA;
       	 		dbb = daa;
       	 		dab = -2*daa;
       	 	 }
       	 	 delH = -(daa*jaa+dbb*jbb+dab*jab);
       	 	 p = Math.exp(-delH/(kB*T));
		     if(p>=ranf()){
		        nb[i][j] += -a[i2][j]+a[i][j];
		        nb[i1][j] += -a[i][j] + a[i2][j]; 
		        nb[i][j2] += -a[i][j] + a[i2][j]; 
		        nb[i][j1] += -a[i][j] + a[i2][j];
		        nb[i2][j] += -a[i][j] + a[i2][j];
		        nb[i4][j] += -a[i2][j] + a[i][j]; 
		        nb[i2][j2] += -a[i2][j] + a[i][j];
		        nb[i2][j1] += -a[i2][j] + a[i][j];
		        swp = a[i][j];
		        a[i][j] = a[i2][j];
		        a[i2][j] = swp;  
		        iaccept += 1;
		     }   
       	   }        	           
         }
         
       
         if(t1==2){
       	   if(a[i][j1]==a[i][j]);
       	   if(a[i][j1]!=a[i][j]){
       	 	 if(a[i][j]==0){ //a[i][j] = A, a[i][j-1] = B
       	 		xA = 4 - nb[i][j]; //# A nearest neighbours to ij
       	 		yB = nb[i][j1];  //# B nearest neighbours to i(j-1)
       	 		daa = 3 - xA -yB; 
       	 		dbb = daa;
       	 		dab = -2*daa;
       	 	 }
       	 	 if(a[i][j]==1){ //a[i][j] = B, a[i][j-1] = A
       	 		xB = nb[i][j];  //# B nearest neighbours to ij
       	 		yA = 4 - nb[i][j1]; //# A nearest neighbours to i(j-1)
       	 		daa = 3- xB - yA;
       	 		dbb = daa;
       	 		dab = -2*daa;
       	 	 }
       	 	 delH = -(daa*jaa+dbb*jbb+dab*jab);
       	 	 p = Math.exp(-delH/(kB*T));
		     if(p>=ranf()){
		        nb[i][j] += -a[i][j1]+a[i][j];
	     	    nb[i][j2] += -a[i][j] + a[i][j1]; 
		        nb[i2][j] += -a[i][j] + a[i][j1]; 
		        nb[i1][j] += -a[i][j] + a[i][j1]; 
		        nb[i][j1] += -a[i][j]+a[i][j1];
		        nb[i][j3] += -a[i][j1] + a[i][j]; 
		        nb[i2][j1] += -a[i][j1] + a[i][j]; 
		        nb[i1][j1] += -a[i][j1] + a[i][j];
		        swp = a[i][j];
		        a[i][j] = a[i][j1];
		        a[i][j1] = swp;  			
		        iaccept += 1;	
		     }  
       	   }       	               
         }
         
       
         if(t1==3){
       	   if(a[i][j2]==a[i][j]);
       	   if(a[i][j2]!=a[i][j]){
       	 	 if(a[i][j]==0){ //a[i][j] = A, a[i][j+1] = B
       	 		xA = 4 - nb[i][j]; //# A nearest neighbours to ij
       	 		yB = nb[i][j2]; //# B nearest neighbours to i(j+1)
       	 		daa = 3 - xA -yB;
       	 		dbb = daa;
       	 		dab = -2*daa;
       	 	 }
       	 	 if(a[i][j]==1){ //a[i][j] = B, a[i][j+1] = A
       	 		xB = nb[i][j]; //# B nearest neighbours to ij
       	 		yA = 4 - nb[i][j2]; //# A nearest neighbours to i(j+1)
       	 		daa = 3 - xB - yA;
       	 		dbb = daa;
       	 		dab = -2*daa;
       	 	 }
       	 	 delH = -(daa*jaa+dbb*jbb+dab*jab);
       	 	 p = Math.exp(-delH/(kB*T));
		     if(p>=ranf()){
		        nb[i][j] += -a[i][j2]+a[i][j];
		        nb[i][j1] += -a[i][j] + a[i][j2]; 
		        nb[i2][j] += -a[i][j] + a[i][j2]; 
		        nb[i1][j] += -a[i][j] + a[i][j2]; 
		        nb[i][j2] += -a[i][j]+a[i][j2];
		        nb[i][j4] += -a[i][j2] + a[i][j]; 
		        nb[i2][j2] += -a[i][j2] + a[i][j]; 
		        nb[i1][j2] += -a[i][j2] + a[i][j]; 
		        swp = a[i][j];
		        a[i][j] = a[i][j2];
		        a[i][j2] = swp;  
		        iaccept += 1;	
		     }     
       	   }            
       	 }
      }
 }
 
////////////////////////////////////////////////////////////////////////////////
 // Method to generate a uniform random number in [0,1]
// following x(i+1)=a*x(i) mod c with a=pow(7,5) and
// c=pow(2,31)-1.  Here the seed is a global variable.

  public static double ranf() {
    final int a = 16807, c = 2147483647, q = 127773,
      r = 2836;
    final double cd = c;
    int h = seed/q;
    int l = seed%q;
    int t = a*l-r*h;
    if (t > 0) seed = t;
    else seed = c+t;
    return seed/cd;
  }
 
////////////////////////////////////////////////////////////////////////////////
//Method to calculate the correlation function
  public static double[] correl() {
 	double cr[] = new double[rmax+1]; 
 	double temp = 0.0;
 	double b[][] = new double[lx][ly];
 	for(int i=0; i<lx; ++i)
	    for(int j=0; j<ly; ++j){
	     	if(a[i][j]==0) b[i][j] = -1;
	    	if(a[i][j]==1) b[i][j] = 1;	
	    }
	   
 	for(int r=0; r<=rmax; ++r){ 	
 	    cr[r] = 0.0;
	    for(int i=0; i<lx; ++i)
	    	for(int j=0; j<ly; ++j){
	    		if(r==0) cr[0] += b[i][j]*b[i][j];
	    		if(r!=0){
	    			temp = b[(i+r)%lx][j] + b[i][(j+r)%ly];
	    			cr[r] += b[i][j]*temp/2.0;	    			
	    		}   		 
	    	}
	    
	}
	for(int r=0; r<=rmax; ++r)
		cr[r] /= lx*ly;
	
    return cr;
 }
 ///////////////////////////////////////////////////////////////////////////////
 // given a lattice site, color that square according to the current s value:
    private static void colorSquare(int i, int j) {
        if (a[i][j] == 1) g.setColor(upColor); else g.setColor(downColor);
        g.fillRect(squareWidth*i + frameLeft, squareWidth*j + frameTop, squareWidth, squareWidth);
    }
   
}

