/** applet No. 1015 * * hetero crystal growth - kinetic Monte Carlo Method 2D Model * * Created by Ikeuchi Mitsuru on September 10 2006. * Copyright (c) 2006-2007 Ikeuchi Mitsuru. All rights reserved. * * ver 0.0.1 2006.09.10 created * ver 0.0.2 2007.06.08 improved code * */ import java.awt.*; import java.awt.event.*; import java.applet.*; public class heteroXtalGrowth2dKMC extends Applet implements ItemListener, ActionListener, AdjustmentListener, Runnable { // ------------------------------------ preset field ----------- Thread th = null; // for run()-paint() thread // for event Choice ch_view; Button bt_reset, bt_startStop; Scrollbar sc_add, sc_qqhop, sc_qqaa, sc_qqbb, sc_qqab, sc_kT; // for off-paint buffer Dimension dim; Image imgOff; Graphics gOff; // KMC double t = 0.0; double dt = 1.0; int resetSW = 0; int started = 1; int changeFlag = 1; double qqHopping = 0.2; double qqAANeighbor = 0.3; double qqBBNeighbor = 0.3; double qqABNeighbor = 0.5; double kT = 0.06; double addingRate = 0.02; double totalRate = 1.0e15; int NNx = 64; int NNy = 64; int NNa = 1000; int maxNNa = 2000; int NNN = 20000; int lattice[][] = new int[NNx][NNy]; int atom[][] = new int[NNN][2]; int kind[] = new int[NNN]; double transition[] = new double[NNN*4]; double transitionAtom[] = new double[NNN]; // display int dispWidth = 630; int dispHeight = 420; int sleepTime = 50; int dispMode = 0; // ------------------------------ applet main thread ----------- public void init() { resize(dispWidth,dispHeight); setBackground(Color.white); dim = getSize(); imgOff = createImage(dim.width,dim.height); gOff = imgOff.getGraphics(); ch_view = new Choice(); ch_view.add("0 yellow"); ch_view.add("1 magenta"); ch_view.add("2 green"); ch_view.addItemListener(this); ch_view.select("1 magenta"); bt_reset= new Button("reset"); bt_reset.addActionListener(this); bt_startStop= new Button("start/stop"); bt_startStop.addActionListener(this); sc_add= new Scrollbar(Scrollbar.HORIZONTAL,20,10,5,110); sc_add.addAdjustmentListener(this); sc_qqhop= new Scrollbar(Scrollbar.HORIZONTAL,20,10,0,110); sc_qqhop.addAdjustmentListener(this); sc_qqaa= new Scrollbar(Scrollbar.HORIZONTAL,30,10,0,110); sc_qqaa.addAdjustmentListener(this); sc_qqbb= new Scrollbar(Scrollbar.HORIZONTAL,30,10,0,110); sc_qqbb.addAdjustmentListener(this); sc_qqab= new Scrollbar(Scrollbar.HORIZONTAL,50,10,0,110); sc_qqab.addAdjustmentListener(this); sc_kT= new Scrollbar(Scrollbar.HORIZONTAL,60,10,25,210); sc_kT.addAdjustmentListener(this); setLayout(new BorderLayout()); Panel pnl = new Panel(); pnl.setLayout(new GridLayout(2,6,5,0)); //pnl.add(new Label(" ")); pnl.add(bt_reset); pnl.add(bt_startStop); pnl.add(new Label(" ")); pnl.add(new Label(" ")); pnl.add(new Label(" adding rate R"));; pnl.add(new Label(" temp")); pnl.add(sc_qqhop); pnl.add(sc_qqaa); pnl.add(sc_qqbb); pnl.add(sc_qqab); pnl.add(sc_add); pnl.add(sc_kT); add(pnl,"North"); setInitialCondition(); } public void start() { if (th == null) { th = new Thread(this); th.start(); } } public void stop() { if (th != null) th = null; } // ---------------------------------- event listener ----------- public void itemStateChanged(ItemEvent ev){ if (ev.getSource() == ch_view) { dispMode = ch_view.getSelectedIndex(); } } public void actionPerformed(ActionEvent ev){ if(ev.getSource() == bt_reset){ resetSW = 1; } else if (ev.getSource() == bt_startStop){ if (started==0) { started = 1; } else { started = 0; } } } public void adjustmentValueChanged(AdjustmentEvent ev){ if (ev.getSource() == sc_add) { addingRate = 0.001*(double)(sc_add.getValue()); changeFlag = 1; } else if (ev.getSource() == sc_qqhop) { qqHopping = 0.01*(double)(sc_qqhop.getValue()); changeFlag = 1; } else if (ev.getSource() == sc_qqaa) { qqAANeighbor = 0.01*(double)(sc_qqaa.getValue()); changeFlag = 1; } else if (ev.getSource() == sc_qqbb) { qqBBNeighbor = 0.01*(double)(sc_qqbb.getValue()); changeFlag = 1; } else if (ev.getSource() == sc_qqab) { qqABNeighbor = 0.01*(double)(sc_qqab.getValue()); changeFlag = 1; } else if (ev.getSource() == sc_kT) { kT = 0.001*(double)(sc_kT.getValue()); changeFlag = 1; } } // ========================= run() - paint() loop ============== public void run() { while (th != null) { timeEvolution(); offPaint(); repaint(); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { } } } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { g.drawImage(imgOff,0,0,this); } // ---------------------------------------- offPaint ----------- private void offPaint() { int gbx = 400; gOff.setColor(Color.white); gOff.fillRect(0,0,dim.width,dim.height); if (dispMode==0) { dispLattice(30, 80, 5); } else if (dispMode==1) { ; } else if (dispMode==2) { ; } gOff.setColor(Color.gray); gOff.drawRect(30,80,5*NNx,5*NNy); gOff.setColor(Color.black); gOff.drawString("Qhop="+(int)(qqHopping*100.0+0.5)/100.0+" eV",dispWidth/6*0+10,70); gOff.setColor(Color.getHSBColor(0.1f,0.8f,0.8f)); gOff.drawString("QAA="+(int)(qqAANeighbor*100.0+0.5)/100.0+" eV",dispWidth/6*1+10,70); gOff.setColor(Color.getHSBColor(0.6f,0.8f,0.8f)); gOff.drawString("QBB="+(int)(qqBBNeighbor*100.0+0.5)/100.0+" eV",dispWidth/6*2+10,70); gOff.setColor(Color.getHSBColor(0.3f,0.8f,0.8f)); gOff.drawString("QAB="+(int)(qqABNeighbor*100.0+0.5)/100.0+" eV",dispWidth/6*3+10,70); gOff.setColor(Color.black); gOff.drawString("add rate="+(int)(addingRate*1000.0+0.5)/1000.0+"",dispWidth/6*4+10,70); gOff.drawString("kT="+(int)(kT*1000+0.5)/1000.0+" eV",dispWidth/6*5+10,70); gOff.drawString(" ="+(int)(kT*11600+0.5)+" K",dispWidth/6*5+10,90); gOff.setColor(Color.blue); gOff.drawString("t="+(int)(t*1e12+0.5)/1000.0+" ns",gbx,120); if (started==0) { gOff.drawString("stopped",gbx,140); } else { gOff.drawString("started",gbx,140); } gOff.drawString("N="+NNa+"",gbx,160); //gOff.drawString("nn="+numberOfAtom()+"",gbx,160); } // ------------------------------------ plot methods ----------- private void dispLattice(int gx, int gy, int span) { int i,j,ir; double col; ir = span; for(i=0;i=0) { if (kind[lattice[i][j]]==0) { gOff.setColor(Color.getHSBColor(0.1f,0.6f,0.8f)); } else if (kind[lattice[i][j]]==1) { gOff.setColor(Color.getHSBColor(0.6f,0.6f,0.8f)); } gOff.fillRect(gx+span*i,gy+span*j, ir, ir); } } } } // ================ kinetic Monte-Carlo Method 2D ============== // set initial condition private void setInitialCondition() { int ia; t = 0.0; initLattice(); setCrystal(15, 15, 30, 30); addAnAtom(maxNNa); addAnAtom(maxNNa); addAnAtom(maxNNa); setAllTransition(); changeFlag = 0; } private void initLattice() { int i,j; for(i=0;i= 0); atom[ia][0] = i; atom[ia][1] = j; lattice[i][j] = ia; } // add an atom private void addAnAtom(int mxNNa) { int ia; if (NNa1000) nn = 1000; nn=50; for(i=0;i=0) { rt = 0.0; } else { ee1 = energyOfNeighbor(kind[ia], ii, jj) - qqap(kind[ia],kind[ia]); if (ee>=ee1) { rt = transitionRate(qqHopping); } else { rt = transitionRate(qqHopping+(ee1-ee)); } } return(rt); } private double energyOfNeighbor(int ka, int i, int j) { int ip; double ee; ee = 0.0; ip = lattice[(i+1)%NNx][j]; if (ip>=0) ee += qqap(ka, kind[ip]); ip = lattice[(i-1+NNx)%NNx][j]; if (ip>=0) ee += qqap(ka, kind[ip]); ip = lattice[i][(j+1)%NNy]; if (ip>=0) ee += qqap(ka, kind[ip]); ip = lattice[i][(j-1+NNy)%NNy]; if (ip>=0) ee += qqap(ka, kind[ip]); return( ee ); } private double qqap(int ka, int kp) { double eap; eap = 0.0; if (ka==0 && kp==0) eap = -qqAANeighbor; if (ka==0 && kp==1) eap = -qqABNeighbor; if (ka==1 && kp==0) eap = -qqABNeighbor; if (ka==1 && kp==1) eap = -qqBBNeighbor; return( eap ); } private double transitionRate(double energy) { double h,nue0; h = 6.626e-34; nue0 = kT*1.602e-19/h; return( nue0*Math.exp(-energy/kT) ); } /* ----- hermonic transition state theory ----- private double transitionRate(double energy) { double m,r,omega,nue,rate; m = 137.0*1.67e-27; r = 0.3*1.0e-9; omega = Math.sqrt(energy*1.6e-19/(m*r*r)); nue = omega/(2.0*3.1416);//s rate = nue*Math.exp(-energy/kT); return( rate ); } */ // select transion private int selectTransion(double rsum) { int ia,iap; double rnd; rnd = rsum*Math.random(); for (ia=0; ia0.0) { ia = ip/4; id = ip%4; i = atom[ia][0]; j = atom[ia][1]; lattice[i][j] = -1; if (id==0) i = (i+1)%NNx; if (id==1) i = (i-1+NNx)%NNx; if (id==2) j = (j+1)%NNy; if (id==3) j = (j-1+NNy)%NNy; atom[ia][0] = i; atom[ia][1] = j; lattice[i][j] = ia; rs0 = rateAround(i,j); rs1 = setRateAround(i,j); totalRate = totalRate - rs0 + rs1; } } private double setRateAround(int i0, int j0) { int i,j,ii,jj; double srate; srate = 0.0; for (i=i0-2; i<=i0+2; i++) { ii = (i+NNx)%NNx; for (j=j0-2; j<=j0+2; j++) { jj = (j+NNy)%NNy; if (lattice[ii][jj]>=0) { srate += setTransition(lattice[ii][jj]); } } } return ( srate ); } private double rateAround(int i0, int j0) { int i,j,ii,jj; double srate; srate = 0.0; for (i=i0-2; i<=i0+2; i++) { ii = (i+NNx)%NNx; for (j=j0-2; j<=j0+2; j++) { jj = (j+NNy)%NNy; if (lattice[ii][jj]>=0) { srate += transitionAtom[lattice[ii][jj]]; } } } return ( srate ); } // --------------------------------------- utilities ----------- int numberOfAtom() { int i,j,n; n = 0; for(i=0;i=0) n += 1; } } return(n); } } /* ----- kinetic Monte-Carlo algorithm ----- * ( or the Bortz-Kalos-Liebowitz (BKL) algorithm ) * * i-th transition rate in the system : ri * total transition rate : RN = sum(ri, {i=1,2,...,N}) * * 1) t = 0 * * 2) select i : randomly (proportional to ri/RN) * calculate R(i) = sum(rj, {j=1,2,...,i}) * get a uniform random number u in [0,1] * find i R(i-1) < u RN <= R(i) * * 3) execute i-th transition * * 4) update the time * get a uniform random numner u in (0,1] * dt = -log(u)/R * t = t + dt * * 5) goto 2) * * ---------- transition state ----- * * transion rate k * k = nue0*exp(-dE/kT) * nue0 = kT/h , h: Plank constant * * * ----- hermonic transition state theory ----- * * oscillation in hermonic potential * U(x) = k x^2, k = V/r^2 (<- U(r) = V) * * motion equation m a = - kx * omega = sqrt(k/m) = sqrt( V/(m*r^2) ) * * transion rate = (omega/(2 pai))*exp(-V/kT) * * m = 137*1.67e-27; // Ba * V = 0.3eV = 0.3*1.6e-19; * r = 0.3e-9; * * omega/(2 pai) = 2.4e11 (1/s) * * */