/* Simulation program for size effects (surface scattering and grain boundary scattering) in resistivity of metal (Cu, Al, etc) films amd line interconnects; written by Arif Emre Yarimbiyik -- Version 1.0 */ import java.util.*; import java.lang.Math; public class Copper { public final double convertmnm = 10e9; public final static double Ex = 4.0e10 ; // electric field in -x direction; Note: Not used in this version !!! public final static double MFP=39; public final static double MAXTREL=3.1681716e-14; // public final static double MFP=28.86; // public final static double MAXTREL = 2.268e-14; //_ 125C public final static double PI=3.1415926; public static void main(String[]args) { final int N_simel = 500, N_simrange = 30; final double N_fermi = 8.47e28; // number of electrons nearby the Fermi energy per volume final double simulation_scale = N_simel/N_fermi; final double q = 1.6e-19; final double M = 9.035e-31; // C , kg final double Meff = M * 1.3; final double N_step = 2000; final double startBox = N_step * MFP; final double xvalue = 2*startBox ; final double pElastic=0.1; final double pElasticFourthSide=0.1; final double pGBSct=0.7; //1.0; //0.7; final double gStdevRatio=0.0; // Stdev in grain size is not active currently double yvalue=0.0 , zvalue=0.0; double grainSize=0.0; double grainSizeStdev=0.0; double trel=0.0 , totalTrel=0.0 , totalStep=0.0; double conductivity=0.0,resistivity=0.0; double dummy=0.0; int noway; boolean onGB = false; // on a grain boundary ? for (int i=0 ; i=pGBSct ) ) { dummy=simwire.simulateElectron(eIndex) ; totalTrel = totalTrel + dummy ; noway = simwire.getEPosition(eIndex).unallowedDirection(yvalue,zvalue); simwire.getEPosition(eIndex).moveInside(0.00000001,noway); } else totalTrel=totalTrel + 0.0; } } trel = totalTrel / (double) (N_step*N_simel) ; conductivity = calcConductivity(N_fermi,q,Meff,trel); resistivity = 1.0 / conductivity; System.out.println(/*"@@@@@@@@@@@ "+*/ /*yvalue + " " + trel + " st" + " "+*/resistivity); } } public static double smaller(double a,double b) { double small=a; if(bboundOne && qboundTwo ) ) { between = true; } return between; } public Coords getEPosition(int i) { return this.eConfig[i]; } } //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// class Coords { double x; double y; double z; Coords() { double x = 1.0; double y = 1.0; double z = 1.0; } Coords(double xCoord,double yCoord,double zCoord) { x = xCoord; y = yCoord; z = zCoord; } public void setY(double q) { y=q; } public void setXYZ(double p,double q,double r) { x=p; y=q ; z=r; } public double getX() { return x; } public double getY() { return y; } public double getZ() { return z; } public boolean isElastic(double pel,double pelFourth,Coords intersec) { boolean elasticSct=false; boolean sideFour=false; if (isBetween(intersec.getY(),-0.01,0.01)==true) sideFour=true; if (sideFour) { if( Math.random() < pelFourth) elasticSct=true; } else { if( Math.random() < pel) elasticSct=true; } return elasticSct; } public double inelas(Coords initialPosition,double yBound,double zBound) { int noway = 0; double amount = yBound*0.0001; double timeInelas=0.0; noway = initialPosition.unallowedDirection(yBound,zBound); initialPosition.moveInside(amount,noway); this.findIntersect(initialPosition,yBound,zBound); noway = this.unallowedDirection(yBound,zBound); timeInelas = this.timePassed(Copper.MAXTREL,initialPosition); this.moveInside(amount,noway); return timeInelas; } public double elas(Coords initialPosition,double xBound,double yBound,double zBound,double probElas, double probElasFourth,Coords[] grainB,double probGBS) { double timeElas=0.0 , timeInelas=0.0; double timeGBSct=0.0; int noway; Coords symmetric = new Coords(this.getX(),this.getY(),this.getZ()); this.findIntersect(initialPosition,yBound,zBound); double t_elasfirst = this.timePassed(Copper.MAXTREL,initialPosition); double t_elassecond=0.0; initialPosition.setXYZ(this.getX(),this.getY(),this.getZ()); noway = initialPosition.unallowedDirection(yBound,zBound); initialPosition.moveInside(0.00001,noway); this.findElastic(symmetric,yBound,zBound); boolean inside = this.checkifin(yBound,zBound); if(inside) { timeGBSct=this.gbSCT(initialPosition,grainB,probGBS); if(timeGBSct==-1.0) { timeElas = Copper.MAXTREL ; timeInelas = 0.0; } else { timeInelas=timeGBSct; timeElas=t_elasfirst; } } else { Coords newTempSurfacePosition = new Coords(this.getX(),this.getY(),this.getZ()); newTempSurfacePosition.findIntersect(initialPosition,yBound,zBound); timeGBSct=newTempSurfacePosition.gbSCT(initialPosition,grainB,probGBS); if(timeGBSct==-1) { if(isElastic(probElas,probElasFourth,newTempSurfacePosition)==false) { timeInelas = this.inelas(initialPosition,yBound,zBound); timeElas=t_elasfirst; } else // ................ 2nd(++) elas...................... { Coords symmetricTwo = new Coords(this.getX(),this.getY(),this.getZ()); this.setXYZ( newTempSurfacePosition.getX(), newTempSurfacePosition.getY(), newTempSurfacePosition.getZ()); noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); t_elassecond = this.timePassed(Copper.MAXTREL,initialPosition); initialPosition.setXYZ(this.getX(),this.getY(),this.getZ()); this.findElastic(symmetricTwo,yBound,zBound); inside = this.checkifin(yBound,zBound); if(inside) { timeGBSct=this.gbSCT(initialPosition,grainB,probGBS); if(timeGBSct==-1.0) { timeElas = Copper.MAXTREL; timeInelas = 0.0; } else { timeInelas=timeGBSct; timeElas=t_elasfirst + t_elassecond; } inside=this.checkifin(yBound,zBound); } else // 2nd elas out .. { Coords nTempSurfPosTwo = new Coords(this.getX(),this.getY(),this.getZ()); Coords checky = new Coords(this.getX(),this.getY(),this.getZ()); noway = initialPosition.unallowedDirection(yBound,zBound); initialPosition.moveInside(0.00001,noway); nTempSurfPosTwo.findIntersect(initialPosition,yBound,zBound); noway = nTempSurfPosTwo.unallowedDirection(yBound,zBound); nTempSurfPosTwo.moveInside(0.00001,noway); timeGBSct=nTempSurfPosTwo.gbSCT(initialPosition,grainB,probGBS); if(timeGBSct!=-1) { this.setXYZ(nTempSurfPosTwo.x,nTempSurfPosTwo.y,nTempSurfPosTwo.z); timeElas=t_elasfirst+t_elassecond; timeInelas=timeGBSct; // here newTempSurfacePosition is actually the position on the GB noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); inside=this.checkifin(yBound,zBound); } else { if(isElastic(probElas,probElasFourth,nTempSurfPosTwo)==false) { timeInelas = this.inelas(initialPosition,yBound,zBound); noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); timeElas=t_elasfirst+t_elassecond; inside=this.checkifin(yBound,zBound); } else // ................ 3rd elas...................... { double t_elasthird=0.0; inside=initialPosition.checkifin(yBound,zBound); // 3rd elas starts ///////////////////////////////////////////////////////////////////////////////////// Coords symmetricThree = new Coords(this.getX(),this.getY(),this.getZ()); this.findIntersect(initialPosition,yBound,zBound); noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); t_elasthird = this.timePassed(Copper.MAXTREL,initialPosition); initialPosition.setXYZ(this.getX(),this.getY(),this.getZ()); this.findElastic(symmetricThree,yBound,zBound); inside = this.checkifin(yBound,zBound); if(inside) { timeGBSct=0.0; timeGBSct=this.gbSCT(initialPosition,grainB,probGBS); if(timeGBSct==-1.0) { timeElas = Copper.MAXTREL; timeInelas = 0.0; } else { timeInelas=timeGBSct; timeElas=t_elasfirst + t_elassecond + t_elasthird; } inside=this.checkifin(yBound,zBound); } else // 3rd elas out .. { Coords nTSPThree = new Coords(this.getX(),this.getY(),this.getZ()); noway = initialPosition.unallowedDirection(yBound,zBound); initialPosition.moveInside(0.00001,noway); nTSPThree.findIntersect(initialPosition,yBound,zBound); noway = nTSPThree.unallowedDirection(yBound,zBound); nTSPThree.moveInside(0.00001,noway); timeGBSct=nTSPThree.gbSCT(initialPosition,grainB,probGBS); if(timeGBSct!=-1) { this.setXYZ(nTSPThree.x,nTSPThree.y,nTSPThree.z); timeElas = t_elasfirst + t_elassecond + t_elasthird; timeInelas=timeGBSct; noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); inside=this.checkifin(yBound,zBound); } else { if(isElastic(probElas,probElasFourth,nTSPThree)==false) { timeInelas = this.inelas(initialPosition,yBound,zBound); noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); timeElas=t_elasfirst+t_elassecond+t_elasthird; inside=this.checkifin(yBound,zBound); } else // ................ !!! NO 4th(and ++) elas ALLOWED !!! ...... { timeInelas = this.inelas(initialPosition,yBound,zBound); noway = this.unallowedDirection(yBound,zBound); this.moveInside(0.00001,noway); timeElas=t_elasfirst+t_elassecond+t_elasthird; inside=this.checkifin(yBound,zBound); } } } // 3rd elas ends //////////////////////////////////////////////////////////////////////////////////////// } } } } } else { this.setXYZ(newTempSurfacePosition.x,newTempSurfacePosition.y,newTempSurfacePosition.z); timeElas=t_elasfirst; timeInelas=timeGBSct; // here newTempSurfacePosition is actually the position on the GB inside=this.checkifin(yBound,zBound); } } return timeElas+timeInelas; } public void findElastic(Coords sym , double yBound , double zBound) { Coords middle = new Coords(); double eps=0.01; if(isBetween(this.z,zBound-eps,zBound+eps) ) { middle.z = zBound; middle.y = sym.y; } if(isBetween(this.z,0.0-eps,0.0+eps)) { middle.z = 0.0; middle.y = sym.y; } if(isBetween(this.y,yBound-eps,yBound+eps) ) { middle.y = yBound; middle.z = sym.z; } if(isBetween(this.y,0.0-eps,0.0+eps) ) { middle.y = 0.0; middle.z = sym.z; } this.y = 2.0 * middle.y - sym.y ; this.z = 2.0 * middle.z - sym.z ; this.x = sym.x ; } public double distanceFrom(Coords second) { //finds the distance between 2 points in 3-D space double dist; dist=Math.sqrt( Math.pow((this.x-second.x),2.0)+Math.pow((this.y-second.y),2.0)+ Math.pow((this.z-second.z),2.0) ); return dist; } public void move(double E_field) { // move sph.shell without direction restrictions Coords onsphere = new Coords(); double theta,phi,convert = Copper.PI/180.0 ; theta = ( (Math.random()*100000) % 360) * convert; phi = ( (Math.random()*100000) % 180) * convert; onsphere.x = Copper.MFP * Math.sin(phi) * Math.cos(theta); onsphere.y = Copper.MFP * Math.sin(phi) * Math.sin(theta); onsphere.z = Copper.MFP * Math.cos(phi); this.x = this.x + onsphere.x; this.y = this.y + onsphere.y; this.z = this.z + onsphere.z; } public boolean checkifin(double yBound,double zBound) { boolean in = false; Coords eCheck = this; if ( eCheck.y >= 0.0 && eCheck.z >= 0.0 && eCheck.y <= yBound && eCheck.z <= zBound ) { in = true; } return in; } int unallowedDirection(double yBound,double zBound) { // noway=1 no east noway=-1 no west // noway=2 no north noway=-2 no south // noway=0 all directions allowed int noway=0; double eps=0.0001; if ( this.isBetween('z',zBound-eps,zBound+eps) ) noway = 1; else if( this.isBetween('z',0.0-eps,0.0+eps) ) noway =-1; else if( this.isBetween('y',yBound-eps,yBound+eps) ) noway = 2; else if( this.isBetween('y',0.0-eps,0.0+eps) ) noway =-2; return noway; } boolean isBetween(char side, double boundOne,double boundTwo) { boolean between = false; double q = 0.0; if(side=='y') q = this.y; else if(side=='z') q= this.z; if ( ( q>boundOne && qboundTwo ) ) { between = true; } return between; } boolean isBetween(double q, double boundOne,double boundTwo) { boolean between = false; if ( ( q>boundOne && qboundTwo ) ) { between = true; } return between; } public void moveInside(double amountin,int noway) { if (noway==1) this.z = this.z - amountin; else if(noway==-1) this.z = this.z + amountin; else if(noway== 2) this.y = this.y - amountin; else if(noway==-2) this.y = this.y + amountin; } double line3D(double c,double b1,double b2,double c1,double c2) { /* Finds the needed coordinate of a point (of which one coordinate is known) on a 3D line Evaluates y-y1 z = -------- (z2-z1) + z1 y2-y1 for line3D(intersection.y,zone,ztwo,yone,ytwo); // z = line3D(intersection.y,zone,ztwo,yone,ytwo); // a b1 b2 c1 c2 */ double bSeeked; bSeeked = ( (c-c1)/(c2-c1) ) * (b2-b1) + b1; return bSeeked; } public void findIntersect(Coords initPos,double yBound,double zBound) { /* Assumption: Projection of electron's trajectory is a line in 3D Its projection on yz plane is a line that starts at (y1,z1) and ends at (y2,z2) y = a*z + b (= z=(y-b)/a y2-y1 where a = ------- and b = y1-a*z1 z2-z1 Our wire is in rectengular prism shape. Intersections of the trajectory with the lines y=0 , z=0 , y=maxY and z=maxZ are found. Then, the intersection point which is actually on the boundaries of the rectengular prism is determined */ double yone = initPos.y , zone = initPos.z , ytwo = this.y , ztwo = this.z; double xone = initPos.x , xtwo = this.x; double maxY = yBound , maxZ = zBound; double a,b; double solnUp= -1.0,solnDown=-1.0,solnLeft=-1.0,solnRight=-1.0; // z;y=maxY z;y=0 y;z=0 y;z=maxZ a = (ytwo-yone) / (ztwo-zone); b = yone-a*zone; if ( (ytwo-yone) != 0.0) { // z=(y-b)/a solnUp = (maxY-b)/a; solnDown = -b/a; } if ( (ztwo-zone) != 0.0) { // y=a*z+b solnRight = a*maxZ+b; solnLeft = b; } if( isBetween(solnUp,0.0,maxZ) && isBetween(solnUp,zone,ztwo) ) { this.z = solnUp; this.y = line3D(this.z,yone,ytwo,zone,ztwo); this.x = line3D(this.z,xone,xtwo,zone,ztwo); } else if( isBetween(solnDown,0.0,maxZ) && isBetween(solnDown,zone,ztwo) ) { this.z = solnDown; this.y = line3D(this.z,yone,ytwo,zone,ztwo); this.x = line3D(this.z,xone,xtwo,zone,ztwo); } else if( isBetween(solnRight,0.0,maxY) && isBetween(solnRight,yone,ytwo) ) { this.y = solnRight; this.z = line3D(this.y,zone,ztwo,yone,ytwo); this.x = line3D(this.y,xone,xtwo,yone,ytwo); } else if( isBetween(solnLeft,0.0,maxY) && isBetween(solnLeft,yone,ytwo) ) { this.y = solnLeft; this.z = line3D(this.y,zone,ztwo,yone,ytwo); this.x = line3D(this.y,xone,xtwo,yone,ytwo); } if ( Math.abs(this.y)<0.0000001 ) this.y = 0.0; if ( Math.abs(this.z)<0.0000001 ) this.z = 0.0; } public double timePassed(double tmax,Coords second) { // finds the time passed till an e's path intersects with the boundary // first 1 ; last 2 ; intersect 3 // computes the relaxation time for the electrons // that are inelastically scattered from the surface double ratio = 1.0; double way = 0.0; way = this.distanceFrom(second); ratio = way / Copper.MFP; return tmax * ratio; } public boolean isGrainbndScattered(double pGbSct) { boolean gbSct=false; if( Math.random() < pGbSct) gbSct=true; return gbSct; } public boolean checkGrain(Coords initPos,Coords[] grainB) { boolean gInBetween=false; int i; for(i=0;i grainB[i].getX() && initPos.getX() < grainB[i].getX() ) || ( this.x < grainB[i].getX() && initPos.getX() > grainB[i].getX() ) ) { gInBetween=true; break; } } return gInBetween; } public double grainSct(Coords initPos,Coords[] grainB) { // first find the intersection(the point which the carrier is scattered on the grain boundary) // then compute time passed double timeTillSct,tmax; int i; double xCoordIntersect,yCoordIntersect,zCoordIntersect; Coords pointOnGb=new Coords(0.0,0.0,0.0); for(i=0;i grainB[i].getX() && initPos.getX() < grainB[i].getX() ) || ( this.x < grainB[i].getX() && initPos.getX() > grainB[i].getX() ) ) { xCoordIntersect = grainB[i].x; yCoordIntersect = this.y + ((xCoordIntersect-this.x) / ((this.x-initPos.x) / (this.y-initPos.y))); zCoordIntersect = this.z + ((xCoordIntersect-this.x) / ((this.x-initPos.x) / (this.z-initPos.z))); pointOnGb = new Coords(xCoordIntersect,yCoordIntersect,zCoordIntersect); break; } } tmax=Copper.MAXTREL; timeTillSct = Math.abs(initPos.timePassed(tmax,pointOnGb)); this.x=pointOnGb.x; this.y=pointOnGb.y; this.z=pointOnGb.z; return timeTillSct; } public double gbSCT(Coords initPos,Coords[] grainB,double pGBS) { double timeTillSct,tmax; int i; double xCoordIntersect,yCoordIntersect,zCoordIntersect; boolean gbScattered=false; int randDirection=0; Coords pointOnGb=new Coords(0.0,0.0,0.0); for(i=0;i grainB[i].getX() && initPos.getX() < grainB[i].getX() ) || ( this.x < grainB[i].getX() && initPos.getX() > grainB[i].getX() ) ) { if(isGrainbndScattered(pGBS)==true) { xCoordIntersect = grainB[i].x; yCoordIntersect = this.y + ((xCoordIntersect-this.x) / ((this.x-initPos.x) / (this.y-initPos.y))); zCoordIntersect = this.z + ((xCoordIntersect-this.x) / ((this.x-initPos.x) / (this.z-initPos.z))); pointOnGb = new Coords(xCoordIntersect,yCoordIntersect,zCoordIntersect); gbScattered=true; break; } } } if(gbScattered==false) return -1.0; else { tmax=Copper.MAXTREL; timeTillSct = Math.abs(initPos.timePassed(tmax,pointOnGb)); this.x=pointOnGb.x; this.y=pointOnGb.y; this.z=pointOnGb.z; return timeTillSct; } } public boolean isOnGB(Coords[] gbs) { boolean onaGB=false; for(int i=0; i