/** applet No. 1178 * * crystallization - kinetic Monte-Carlo Method 3D * * Created by Ikeuchi Mitsuru on June 03 2007. * Copyright (c) 2007 Ikeuchi Mitsuru. All rights reserved. * * ver 0.0.1 2007.06.03 created * */ import java.awt.*; import java.awt.event.*; import java.applet.*; public class crystallizationMtKMC3D extends Applet implements MouseListener, MouseMotionListener, ItemListener, ActionListener, AdjustmentListener, Runnable { // ------------------------------------ preset field ----------- Thread th = null; // for run()-paint() thread KMC3D kmc = null; // for event Choice ch_view; Button bt_reset, bt_startStop; Scrollbar sc_nn, sc_add, sc_qqhop, sc_qqnb, sc_kT; // for off-paint buffer Dimension dim; Image imgOff; Graphics gOff; // KMC field variable copy int NNx = 36; int NNy = 36; int NNz = 36; int NNa = 0; double ddh = 1.0e-9; double xMax = ddh*NNx; double yMax = ddh*NNy; double zMax = ddh*NNz; // control 3D int dgX, dgY, dgXb, dgYb; double cx = 0.5*xMax; double cy = 0.5*yMax; double cz = 0.5*zMax; double theta = -20.0*3.14/180.0; double fai = 10.0*3.14/180.0; double dtheta = 0.0*3.14/180.0; double pai = 3.1415926536; // display 3D int dispWidth = 630; int dispHeight = 420; int sleepTime = 50; int dispMode = 1; double dispScale = (240.0/xMax); double viewScale = 1.0; int NNN = 20000; int srtz[][] = new int[2][NNN]; double px[] = new double[NNN]; double py[] = new double[NNN]; double pz[] = new double[NNN]; double wkx[] = new double[8]; double wky[] = new double[8]; double wkz[] = new double[8]; double pwkx[] = new double[8]; double pwky[] = new double[8]; double pwkz[] = new double[8]; int boxp[][] = { {0,1},{0,2},{0,4},{1,3},{1,5},{2,3},{2,6},{4,5},{4,6},{3,7},{5,7},{6,7} }; int thCount = 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_nn= new Scrollbar(Scrollbar.HORIZONTAL,100,10,1,210); sc_nn.addAdjustmentListener(this); sc_add= new Scrollbar(Scrollbar.HORIZONTAL,50,10,0,210); sc_add.addAdjustmentListener(this); sc_qqhop= new Scrollbar(Scrollbar.HORIZONTAL,20,10,0,110); sc_qqhop.addAdjustmentListener(this); sc_qqnb= new Scrollbar(Scrollbar.HORIZONTAL,30,10,0,110); sc_qqnb.addAdjustmentListener(this); sc_kT= new Scrollbar(Scrollbar.HORIZONTAL,60,10,25,210); sc_kT.addAdjustmentListener(this); addMouseListener(this); addMouseMotionListener(this); setLayout(new BorderLayout()); Panel pnl = new Panel(); pnl.setLayout(new GridLayout(1,6,5,0)); //pnl.add(new Label(" ")); pnl.add(bt_reset); pnl.add(bt_startStop); pnl.add(sc_add); pnl.add(sc_qqhop); pnl.add(sc_qqnb); pnl.add(sc_kT); add(pnl,"North"); } public void start() { if (kmc == null) { kmc = new KMC3D(); kmc.start(); } if (th == null) { th = new Thread(this); th.start(); } } public void stop() { if (th != null) th = null; if (kmc != null) kmc = 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){ kmc.reset(); thCount = 0; } else if (ev.getSource() == bt_startStop){ if (kmc.getStartSW()==0) { kmc.setStartSW(1); } else { kmc.setStartSW(0); } } } public void adjustmentValueChanged(AdjustmentEvent ev){ if (ev.getSource() == sc_add) { kmc.setAddingRate( 0.001*(double)(sc_add.getValue()) ); } else if (ev.getSource() == sc_qqhop) { kmc.setQHopping( 0.01*(double)(sc_qqhop.getValue()) ); } else if (ev.getSource() == sc_qqnb) { kmc.setQNeighbor( 0.01*(double)(sc_qqnb.getValue()) ); } else if (ev.getSource() == sc_kT) { kmc.setKT( 0.001*(double)(sc_kT.getValue()) ); } } public void mousePressed(MouseEvent ev){ } public void mouseReleased(MouseEvent ev){ dgXb = 0; dgYb = 0; dgX = 0; dgY = 0; } public void mouseClicked(MouseEvent ev){ } public void mouseEntered(MouseEvent ev){ } public void mouseExited (MouseEvent ev){ } public void mouseMoved (MouseEvent ev){ } public void mouseDragged(MouseEvent ev){ dgXb = dgX; dgYb = dgY; dgX=ev.getX(); dgY=ev.getY(); if (dgXb==0 && dgYb==0) { dgXb = dgX; dgYb = dgY; } theta += 0.5*3.14/180.0*(dgX-dgXb); fai += 0.5*3.14/180.0*(dgY-dgYb); } // ========================= run() - paint() loop ============== public void run() { while (th != null) { thCount += 1; if (kmc != null) 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); } // --------------------------------------- off-paint ----------- private void offPaint() { gOff.setColor(Color.white); gOff.fillRect(0,0,dim.width,dim.height); NNa = kmc.getNNa(); NNx = kmc.getNNx(); NNy = kmc.getNNy(); NNz = kmc.getNNz(); ddh = kmc.getddh(); xMax = ddh*NNx; yMax = ddh*NNy; zMax = ddh*NNz; if (dispMode==0) { dispLattice(30, 80, 5); gOff.setColor(Color.black); gOff.drawRect(30,80,5*NNx,5*NNy); } else if (dispMode==1) { ball3dPlot(80, 100); } else if (dispMode==2) { ; } gOff.setColor(Color.black); gOff.drawString("t="+(int)(kmc.getTime()*1e14+0.5)/100.0+" ps",10,40); if (kmc.getStartSW()==0) { gOff.drawString("stopped",dispWidth/6*1+10,40); } else { gOff.drawString("started",dispWidth/6*1+10,40); } gOff.drawString("add rate="+(int)(kmc.getAddingRate()*1000.0+0.5)/1000.0+"",dispWidth/6*2,40); gOff.drawString("N="+NNa+"",dispWidth/6*2+10,60); gOff.drawString("Qhop="+(int)(kmc.getQHopping()*100.0+0.5)/100.0+" eV",dispWidth/6*3+10,40); gOff.drawString("Qnbr="+(int)(kmc.getQNeighbor()*100.0+0.5)/100.0+" eV",dispWidth/6*4+10,40); gOff.drawString("kT="+(int)(kmc.getKT()*1000+0.5)/1000.0+" eV",dispWidth/6*5+10,40); gOff.drawString(" ="+(int)(kmc.getKT()*11600+0.5)+" K",dispWidth/6*5+10,60); //gOff.setColor(Color.blue); //gOff.drawString("nn="+numberOfAdatom()+"",dispWidth/6*2+10,60); gOff.setColor(Color.black); gOff.drawString("thread KMC = "+kmc.getCount()+" ",400,380); gOff.drawString("thread disp = "+thCount+" ",400,400); } // ------------------------------------ plot methods ----------- private void dispLattice(int gx, int gy, int span) { int i,j,ir, ia; double col; ir = span; for(i=0;i=0) { if (kmc.getKind(ia)==0) { gOff.setColor(Color.getHSBColor(0.1f,0.6f,0.8f)); } else { gOff.setColor(Color.getHSBColor(0.05f,0.6f,0.8f)); } gOff.fillRect(gx+span*i,gy+span*j, ir, ir); } } } } // private void ball3dPlot(int gbx, int gby) { int i,j,gx,gy,gz; double sc,sz; setWaku(); rotate(theta,fai); zSort(); drawWaku(gbx,gby,0); sc = dispScale*viewScale; for (i=0; i=srtz[1][p]) p = i; k = qSortPartition(i,j,srtz[1][p]); qSort(i,k-1); qSort(k,j); } } private int qSortPartition(int i,int j, int x) { int l,r,w; l = i; r = j; while (l<=r) { while (l<=j && srtz[1][l]=i && srtz[1][r]>=x) r--; if (l>r) break; w = srtz[0][l]; srtz[0][l] = srtz[0][r]; srtz[0][r] = w; w = srtz[1][l]; srtz[1][l] = srtz[1][r]; srtz[1][r] = w; l++; r--; } return ( l ); } } // ================== kinetic Monte-Carlo Method 2D ============== class KMC3D extends Thread { private double t = 0.0; private double dt = 1.0; private double ddh = 1.0e-9; private double qqHopping = 0.2; private double qqNeighbor = 0.3; private double kT = 0.06; private double addingRate = 0.05; private double totalRate = 1.0e15; private int NNx = 36; private int NNy = 36; private int NNz = 36; private int NNa = 0; private int maxNNa = 2000; private double xMax = ddh*NNx; private double yMax = ddh*NNy; private double zMax = ddh*NNz; private int NNN = 20000; private int lattice[][][] = new int[NNx][NNy][NNz]; private int atom[][] = new int[NNN][3]; private int kind[] = new int[NNN]; private double transition[] = new double[NNN*6]; private double transitionAtom[] = new double[NNN]; private double rate[] = new double[8]; private int resetSW = 0; private int startSW = 1; private int stepSW = 1; private int changeFlag = 1; private int sleepTime = 1; private int stopSleepTime = 100; private int count = 0; // ------------------------------- class constructor ----------- KMC3D() { setInitialCondition(); } // -------------------------------------- thread run ----------- public void run() { while (true) { count += 1; timeEvolution(); if (sleepTime>0) { try { Thread.sleep(sleepTime); } catch (InterruptedException e) { } } } } // --------------------------- set initial condition ----------- private void setInitialCondition() { int ia; t = 0.0; count = 0; initLattice(); //setCrystal(10, 10, 10, 15, 15, 15); NNa = 0; for(ia=0;ia<100;ia++) { addAnAtom(maxNNa); } setAllTransition(); changeFlag = 0; } private void initLattice() { int i,j,k; for(i=0;i= 0); atom[ia][0] = i; atom[ia][1] = j; atom[ia][2] = k; lattice[i][j][k] = ia; } // private void addAnAtom(int mxNNa) { int ia; if (NNa1000) nn = 1000; nn=50; for(i=0;i=0) { rt = 0.0; } else { nb1 = noOfNeighbor(ii,jj,kk)-1; if (nb<=nb1) { rt = rate[0]; } else { rt = rate[nb-nb1]; } } return(rt); } private int noOfNeighbor(int i, int j, int k) { int nb; nb = 0; if (lattice[(i+1)%NNx][j][k]>=0) nb += 1; if (lattice[(i-1+NNx)%NNx][j][k]>=0) nb += 1; if (lattice[i][(j+1)%NNy][k]>=0) nb += 1; if (lattice[i][(j-1+NNy)%NNy][k]>=0) nb += 1; if (lattice[i][j][(k+1)%NNz]>=0) nb += 1; if (lattice[i][j][(k-1+NNz)%NNz]>=0) nb += 1; return( nb ); } private void setRate() { rate[0] = transitionRate(qqHopping); rate[1] = transitionRate(qqHopping + qqNeighbor); rate[2] = transitionRate(qqHopping + 2.0*qqNeighbor); rate[3] = transitionRate(qqHopping + 3.0*qqNeighbor); rate[4] = transitionRate(qqHopping + 4.0*qqNeighbor); rate[5] = transitionRate(qqHopping + 5.0*qqNeighbor); rate[6] = transitionRate(qqHopping + 6.0*qqNeighbor); } 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/6; id = ip%6; i = atom[ia][0]; j = atom[ia][1]; k = atom[ia][2]; lattice[i][j][k] = -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; if (id==4) k = (k+1)%NNz; if (id==5) k = (k-1+NNz)%NNz; atom[ia][0] = i; atom[ia][1] = j; atom[ia][2] = k; lattice[i][j][k] = ia; rs0 = rateAround(i,j,k); rs1 = setRateAround(i,j,k); totalRate = totalRate - rs0 + rs1; } } private double setRateAround(int i0, int j0, int k0) { int i,j,k,ii,jj,kk; 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; for (k=k0-2; k<=k0+2; k++) { kk = (k+NNz)%NNz; if (lattice[ii][jj][kk]>=0) { srate += setTransition(lattice[ii][jj][kk]); } } } } return ( srate ); } private double rateAround(int i0, int j0, int k0) { int i,j,k,ii,jj,kk; 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; for (k=k0-2; k<=k0+2; k++) { kk = (k+NNz)%NNz; if (lattice[ii][jj][kk]>=0) { srate += transitionAtom[lattice[ii][jj][kk]]; } } } } return ( srate ); } // --------------------------------------- utilities ----------- private int numberOfAtom() { int i,j,k,n; n = 0; for(i=0;i=0) n += 1; } } } return(n); } // ------------------------------------- I/O methods ----------- // control public void reset() { resetSW = 1; } public void setStartSW(int sw) { startSW = sw; } public int getStartSW() { return startSW; } public void setStepSW() { stepSW = 1; } public int getCount() { return count; } public void setAddingRate(double ar) { addingRate = ar; changeFlag = 1; } public double getAddingRate() { return addingRate; } public void setQHopping(double qh) { qqHopping = qh; changeFlag = 1; } public double getQHopping() { return qqHopping; } public void setQNeighbor(double qn) { qqNeighbor = qn; changeFlag = 1; } public double getQNeighbor() { return qqNeighbor; } public void setKT(double ev) { kT = ev; changeFlag = 1; } public double getKT() { return kT; } // get data public int getNNa() { return NNa; } public int getNNx() { return NNx; } public int getNNy() { return NNy; } public int getNNz() { return NNz; } public double getddh() { return ddh; } public double getTime() { return t; } public int getNumberOfAtom() { return numberOfAtom(); } public int getLattice(int i, int j, int k) { return lattice[i][j][k]; } public int getAtom(int ia, int d) { return atom[ia][d]; } public int getKind(int ia) { return kind[ia]; } } /* ----- 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) * * */