/*Applet to Illustrate Band Formation in Semiconductors*/ import java.applet.*; import java.awt.*; import java.awt.event.*; import java.lang.*; public class EnergyLevelDiagrams extends Applet implements ItemListener, MouseListener { Graphics g ; private Font myFont = new Font(Font.SERIF,Font.BOLD,12); private Font mySmallerFont = new Font(Font.SERIF,Font.PLAIN,10); private Font plainFont = new Font(Font.SERIF,Font.PLAIN,12); private Scrollbar internuclearDistanceSlider = new Scrollbar(Scrollbar.HORIZONTAL,100,5,25,380); private int internuclearDistance = 100; private int internuclearDistanceLineStart, internuclearDistanceLine = 165; private Image orbitalImages, morseCurves, energyLevelDiagram; private Graphics orbitalImages_g, morseCurves_g, energyLevelDiagram_g; private Choice numberOfAtomsChoice = new Choice(); private Choice bandOccupancyChoice = new Choice(); private double[][] curve = new double[376][1001]; private int numberOfAtoms = 2; private int level[] = new int[1001]; private int bandOccupancyIndex = 0; private int[] densityOfStatesCount = new int[330]; private Color[] densityOfStatesColor = new Color[330]; private double[][] psi = new double[95][95]; private int levelSelected = 0; @Override public void init() { orbitalImages = createImage(1000,100); orbitalImages_g = orbitalImages.getGraphics(); morseCurves = createImage(430,330); morseCurves_g = morseCurves.getGraphics(); energyLevelDiagram = createImage(430,330); energyLevelDiagram_g = energyLevelDiagram.getGraphics(); internuclearDistanceSlider.addMouseListener(this); this.addMouseListener(this); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); setLayout(gbl); gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.ipadx = 350; gbc.insets = new Insets(135,65,0,0); gbc.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gbl.setConstraints(internuclearDistanceSlider,gbc); add(internuclearDistanceSlider); gbc.ipadx = 20; gbc.insets = new Insets(132,0,0,0); gbl.setConstraints(numberOfAtomsChoice,gbc); add(numberOfAtomsChoice); gbc.ipadx = 35; gbc.gridwidth = GridBagConstraints.REMAINDER; gbl.setConstraints(bandOccupancyChoice,gbc); add(bandOccupancyChoice); numberOfAtomsChoice.addItemListener(this); bandOccupancyChoice.addItemListener(this); numberOfAtomsChoice.addItem("2 atoms"); numberOfAtomsChoice.addItem("3 atoms"); numberOfAtomsChoice.addItem("4 atoms"); numberOfAtomsChoice.addItem("5 atoms"); numberOfAtomsChoice.addItem("10 atoms"); numberOfAtomsChoice.addItem("25 atoms"); numberOfAtomsChoice.addItem("50 atoms"); numberOfAtomsChoice.addItem("100 atoms"); numberOfAtomsChoice.addItem("1000 atoms"); bandOccupancyChoice.addItem("Empty band"); bandOccupancyChoice.addItem("Half-filled band"); bandOccupancyChoice.addItem("Filled band"); makeCurves(); if (numberOfAtoms <= 10) calculatePsi(); drawOrbitalBox(); drawMorseCurves(); drawEnergyLevelBox(); } void makeCurves(){ //calculate all the curves double internuclearDistance; double a, b; int j = numberOfAtoms - 1; for (int i = 0; i <= 375; i++){ //the boundary ones first internuclearDistance = ((float)(i))/100.0; curve[i][0] = (1.0 - Math.exp(-(internuclearDistance - 0.74)/0.74)); //most bonding curve[i][0] = curve[i][0]*curve[i][0]; curve[i][j] = (1.0 + Math.exp(-internuclearDistance)); //most antibonding curve[i][j] = curve[i][j]*curve[i][j]; } for (j = 1; j < numberOfAtoms-1; j++){//System.out.println("Averaging loop j = "+Integer.toString(j)); a = Math.pow((float)(numberOfAtoms - j-1),0.7); b = Math.pow((float)(j),0.7); for (int i = 0; i<= 375; i++){ curve[i][j] = (a*curve[i][0] + b*curve[i][numberOfAtoms-1])/(a + b); } } } void drawOrbitalBox(){ orbitalImages_g.setColor(Color.BLACK); orbitalImages_g.fillRect(0, 0, 999, 99); orbitalImages_g.setColor(Color.RED); orbitalImages_g.drawRect(0, 0, 998, 98); orbitalImages_g.drawRect(1, 1, 996, 96); } void calculatePsi(){ double r; for (int i = 0; i < 95; i++){ for (int j = 0; j < 95; j++){ r = Math.sqrt((float)((i-47)*(i-47) + (j-47)*(j-47))); psi[i][j] = Math.exp(-(r*0.030)*(r*0.030)); //use Gaussian curves? } } } void plotOrbitals() { double coeffs[][] = {{0.0,0.0},{0.0,0.0}}; //dummy initialization int pix = 0; switch (numberOfAtoms){ //Coefficients are from Hyperchem (but scaled) case 2: //2 atoms double H2coeffs[][] = { {1.0, 1.0}, {-1.0, 1.0}}; coeffs = H2coeffs; break; case 3: //3 atoms double H3coeffs[][] = { {0.8069,1.0000,0.8069}, {1.0000,0.0000,-1.0000}, {0.6196,-1.0000,0.6196}}; coeffs = H3coeffs; break; case 4: //4 atoms double H4coeffs[][] = { {0.7274,1.0000,1.0000,0.7274}, {-1.0000,-0.5158,0.5158,1.0000}, {1.0000,-0.7274,-0.7274,1.0000}, {0.5158,-1.0000,1.0000,-0.5158}}; coeffs = H4coeffs; break; case 5: //5 atoms double H5coeffs[][] = { {0.6154,0.8960,1.0000,0.8960,0.6154}, {-1.0000,-0.8242,0.0000,0.8242,1.0000}, {1.0000,-0.1302,-0.9975,-0.1302,1.0000}, {0.8242,-1.0000,0.0000,1.0000,-0.8242}, {0.3911,-0.8267,1.0000,-0.8267,0.3911}}; coeffs = H5coeffs; break; case 10: //10 atoms double H10coeffs[][] = { {0.3768,0.6034,0.7942,0.9297,1.0000,1.0000,0.9297,0.7942,0.6034,0.3768}, {-0.7113,-0.9856,-1.0000,-0.7380,-0.2711,0.2711,0.7380,1.0000,0.9856,0.7113}, {0.9632,1.0000,0.4474,-0.3772,-0.9710,-0.9710,-0.3772,0.4474,1.0000,0.9632}, {-1.0000,-0.5790,0.4237,0.9785,0.5026,-0.5026,-0.9785,-0.4237,0.5790,1.0000}, {1.0000,0.0370,-0.9495,-0.4389,0.7630,0.7630,-0.4389,-0.9495,0.0370,1.0000}, {1.0000,-0.5497,-0.8801,0.6746,0.7851,-0.7851,-0.6746,0.8801,0.5497,-1.0000}, {-0.8065,0.9155,0.1196,-1.0000,0.5863,0.5863,-1.0000,0.1196,0.9155,-0.8065}, {-0.5995,1.0000,-0.6563,-0.1984,0.8986,-0.8986,0.1984,0.6563,-1.0000,0.5995}, {-0.4008,0.8404,-1.0000,0.7960,-0.3020,-0.3020,0.7960,-1.0000,0.8404,-0.4008}, {-0.2021,0.4801,-0.7270,0.9061,-1.0000,1.0000,-0.9061,0.7270,-0.4801,0.2021}}; coeffs = H10coeffs; break; default: break; } int dim = 95; int lev = levelSelected; int overlap = dim-internuclearDistance; int i[] = new int[11]; int len = internuclearDistance*numberOfAtoms + (dim-internuclearDistance); for (int j = 0; j < dim; j++){ //Steps down the orbital graphics box // int j = 46; //left here for debugging int k = 0; int n = 0; int n1, n2, n3 = 0, n4 = 0; for (int m = 0; m <= numberOfAtoms; m++) i[m] = 0; //System.out.println("Begin l loop"); for (int l = 0; l < len; l++){ //Steps across the orbital graphics box if (k > internuclearDistance-1) {k = 0; n++;} //n is the current atom # if (n == 0) i[n]++; else {i[n-1]++; i[n]++;} //is this the first atom? if (i[n] > dim) { //gap between atoms? //No atom here //System.out.println(" l , "+Integer.toString(l)+"no atom here"); } else if (n == 0) { //First atom here (lhs)? // System.out.println("One atom here - beginning (lhs) "+Integer.toString(l)); //System.out.print(" l , "+Integer.toString(l)+", n1 , "+Integer.toString(i[0])+", pix-beginning , "); pix = (int)(coeffs[lev][n]*255.0*psi[i[0]-1][j]); //System.out.println("p1 , "+Double.toString(coeffs[lev][n]*255.0*psi[i[0]-1][j])); if (pix < 0){orbitalImages_g.setColor(new Color(0,-pix,0)); } else { orbitalImages_g.setColor(new Color(pix,0,0));} orbitalImages_g.drawLine(l+10,j+2,l+10,j+2); } else if (n >= numberOfAtoms) { //Last atom here? // System.out.println("One atom here - ending (rhs) "+Integer.toString(l)); //System.out.print(" l , "+Integer.toString(l)+", n1 , "+Integer.toString(i[n-1]-1)+", pix-ending , "); pix = (int)(coeffs[lev][n-1]*255.0*psi[i[n-1]-1][j]); //System.out.println("p1 , "+Double.toString(coeffs[lev][n-1]*255.0*psi[i[n-1]-1][j])); if (pix < 0){orbitalImages_g.setColor(new Color(0,-pix,0)); } else { orbitalImages_g.setColor(new Color(pix,0,0));} orbitalImages_g.drawLine(l+10,j+2,l+10,j+2); } else if (n > 0) { //Atoms n-1 and n overlapping? if (i[n-1] <= dim & i[n] > 0) { //System.out.println("Two atoms overlapping here "+Integer.toString(l)); n1 = i[n-1]-1; n2 = i[n]-1; if (n2 == 0) {n3 = n1; n4 = dim-1;} //System.out.print(" l , "+Integer.toString(l)+", n1 , "+Integer.toString(n1)+", n2 , "+Integer.toString(n2) //+", n3 , "+Integer.toString(n3)+", n4 , "+Integer.toString(n4)); pix = (int)(255.0*(coeffs[lev][n-1]*psi[n1][j]+coeffs[lev][n]*psi[n2][j] -(coeffs[lev][n-1]*psi[n4][j]- // interpolation (coeffs[lev][n-1]*psi[n4][j]-coeffs[lev][n]*psi[0][j])* (n4 - n1)/(n4 - n3)))); if (pix > 255) pix = 255; if (pix < -255) pix = -255; //System.out.println(", pix , "+Integer.toString(pix)+", p1 , "+Double.toString(255.0*coeffs[lev][n-1]*psi[n1][j]) // +", p2 , "+Double.toString(255.0*coeffs[lev][n]*psi[n2][j])); if (pix < 0){orbitalImages_g.setColor(new Color(0,-pix,0)); } else { orbitalImages_g.setColor(new Color(pix,0,0));} orbitalImages_g.drawLine(l+10,j+2,l+10,j+2); } else { //Isolated atom - not first or last //System.out.println("One isolated atom here (not overlapped) "+Integer.toString(l)); //System.out.print(" l , "+Integer.toString(l)+", n1 , "+Integer.toString(i[n]-1)+", pix-not overlapped , "); pix = (int)(coeffs[lev][n]*255.0*psi[i[n]-1][j]); //System.out.println("p1 , "+Double.toString(coeffs[lev][n]*255.0*psi[i[n]-1][j])); if (pix < 0){orbitalImages_g.setColor(new Color(0,-pix,0)); } else { orbitalImages_g.setColor(new Color(pix,0,0));} orbitalImages_g.drawLine(l+10,j+2,l+10,j+2); } } k++; } } //j loop - remove } for debugging orbitalImages_g.setColor(Color.YELLOW); for (int n = 0; n < numberOfAtoms; n++){ //Draw nuclei orbitalImages_g.fillOval(58+n*internuclearDistance-1, 49, 3, 3); } if((numberOfAtoms-1)*internuclearDistance > 900) { //All atoms shown? orbitalImages_g.setColor(Color.WHITE); orbitalImages_g.drawString("This orbital extends outside the window (to the right)", 710,20); } } void drawMorseCurves(){ morseCurves_g.setColor(Color.WHITE); morseCurves_g.fillRect(0, 0, 429, 329); morseCurves_g.setColor(Color.RED); morseCurves_g.drawRect(0, 0, 428, 328); morseCurves_g.drawRect(1, 1, 426, 326); morseCurves_g.setColor(Color.BLUE); morseCurves_g.drawLine(25,25,25,305); // add axes morseCurves_g.drawLine(25,305,400,305); for (int i = 25; i <= 400; i = i + 25){ //add x-ticks morseCurves_g.drawLine(i,302,i,308); } morseCurves_g.drawLine(22,25,27,25); //Add y-axis ticks morseCurves_g.drawLine(22,165,27,165); morseCurves_g.drawLine(22,305,27,305); morseCurves_g.setColor(Color.BLACK); morseCurves_g.setFont(plainFont); morseCurves_g.drawString("Internuclear distance (tickmarks every 25 pm)",80,325); morseCurves_g.setColor(new Color(220,220,220)); //Add connecting lines for (int j = 0; j < numberOfAtoms; j++){ level[j] = (int)(90.0*curve[internuclearDistance][j]); morseCurves_g.drawLine(internuclearDistanceLine-37,290-level[j],426,290-level[j]); } morseCurves_g.setColor(new Color(132,22,0)); //draw curves for (int j = 0; j < numberOfAtoms; j++){ for (int i = 0; i <= 374; i++){ morseCurves_g.drawLine(i+26, 290-(int)(90.0*curve[i][j]), i+27, 290-(int)(90.0*curve[i+1][j])); } } } void drawEnergyLevelBox(){ energyLevelDiagram_g.setColor(Color.WHITE); energyLevelDiagram_g.fillRect(0, 0, 429, 329); energyLevelDiagram_g.setColor(Color.RED); energyLevelDiagram_g.drawRect(0, 0, 428, 328); energyLevelDiagram_g.drawRect(1, 1, 426, 326); energyLevelDiagram_g.setColor(Color.BLACK); } @Override public void paint(Graphics g) { drawOrbitalBox(); if (numberOfAtoms <= 10) plotOrbitals(); else { orbitalImages_g.setColor(Color.WHITE); orbitalImages_g.drawString("Display of the orbitals with more than 10 atoms is not available",100,50); } g.drawImage(orbitalImages, 5, 5, null); g.drawImage(morseCurves, 40, 160, null); g.drawImage(energyLevelDiagram, 545, 160, null); g.setColor(Color.MAGENTA); g.drawLine(internuclearDistanceLine,162,internuclearDistanceLine,464); g.setColor(new Color(220,220,220)); for (int j = 0; j < numberOfAtoms; j++){ //extend connecting lines level[j] = (int)Math.round(90.0*curve[internuclearDistance][j]); g.drawLine(467,450-level[j],690,450-level[j]); g.drawLine(650,359,690,450-level[j]); } g.setColor(Color.BLACK); g.drawString("Energy", 487,200); g.drawLine(505,220,505,300); g.drawLine(505,220,500,225); g.drawLine(505,220,510,225); for (int k = 0; k < 330; k++){ densityOfStatesCount[k] = 0; } for (int j = 0; j < numberOfAtoms; j++) { //calculate energy levels level[j] = (int)Math.round(90.0*curve[internuclearDistance][j]); } for (int j = 0; j < numberOfAtoms; j++){ //count the levels set their colour densityOfStatesCount[level[j]] = densityOfStatesCount[level[j]]+2; densityOfStatesColor[level[j]] = Color.RED; } g.setColor(Color.GREEN.darker()); switch (bandOccupancyIndex) { //draw energy levels case 0: //all unoccupied for (int j = 0; j < numberOfAtoms; j++){ g.drawLine(690,450-level[j],800,450-level[j]); } break; case 1: //half occupied if(numberOfAtoms - (numberOfAtoms/2)*2 == 1){ //odd number of atoms g.setColor(Color.BLUE.darker()); //filled ones for (int j = 0; j < numberOfAtoms/2; j++){ g.drawLine(690,450-level[j],800,450-level[j]); densityOfStatesColor[level[j]] = Color.BLUE; } g.drawLine(690,450-level[numberOfAtoms/2],745,450-level[numberOfAtoms/2]); //middle one densityOfStatesColor[level[numberOfAtoms/2]] = null; g.setColor(Color.GREEN.darker()); g.drawLine(745,450-level[numberOfAtoms/2],800,450-level[numberOfAtoms/2]); for (int j = (numberOfAtoms/2+1); j < numberOfAtoms; j++){ //empty ones g.drawLine(690,450-level[j],800,450-level[j]); densityOfStatesColor[level[j]] = Color.GREEN.darker(); } } else{ //even number of atoms g.setColor(Color.BLUE.darker()); //filled ones for (int j = 0; j < numberOfAtoms/2; j++){ g.drawLine(690,450-level[j],800,450-level[j]); densityOfStatesColor[level[j]] = Color.BLUE.darker(); } g.setColor(Color.GREEN.darker()); //empty ones for (int j = (numberOfAtoms/2); j < numberOfAtoms; j++){ g.drawLine(690,450-level[j],800,450-level[j]); densityOfStatesColor[level[j]] = Color.GREEN.darker(); } } break; case 2: //all filled g.setColor(Color.BLUE.darker()); for (int j = 0; j < numberOfAtoms; j++){ g.drawLine(690,450-level[j],800,450-level[j]); } } g.setColor(new Color(132,22,0)); g.drawLine(575, 359, 650, 359); if (numberOfAtoms == 2){ //H2 case - show internuclearDistancearate 1s levels (left and right). g.drawLine(840, 359, 915, 359); g.setColor(new Color(220,220,220)); g.drawLine(800, 450-level[0], 840, 359); g.drawLine(800, 450-level[numberOfAtoms-1], 840, 359); g.setColor(Color.BLACK); g.drawString("H", 610, 465); g.drawString("H", 740, 465); g.drawString("H", 875, 465); g.setFont(mySmallerFont); g.drawString("2", 750, 469); g.setFont(plainFont); g.drawString("(Energy levels at "+Integer.toString(internuclearDistance)+ " pm)", 675, 485); } else { //If more than just H2, construct density of states histogram g.setColor(Color.RED); g.drawLine(834,162,834,487); g.drawLine(835,162,835,487); g.setColor(Color.BLACK); g.drawString(Integer.toString(numberOfAtoms)+ " H",600, 465); g.drawString("H",740, 465); g.setFont(mySmallerFont); g.drawString(Integer.toString(numberOfAtoms), 750, 469); g.setFont(plainFont); g.drawString("(Energy levels at H-H = "+Integer.toString(internuclearDistance)+ " pm)", 670, 485); g.drawLine(849,180,849,470); g.drawLine(849,470,950,470); g.drawString("Density of States", 855, 485); switch (bandOccupancyIndex) { case 0: //all unoccupied g.setColor(Color.GREEN.darker()); for (int j = 0; j < 330; j++){ if (!(densityOfStatesCount[j] == 0)){ g.drawLine(850, 450-j, 850 + densityOfStatesCount[j], 450-j); } } break; case 1: //half-occupied for (int j = 0; j < 330; j++){ g.setColor(densityOfStatesColor[j]); if (!(densityOfStatesCount[j] == 0)){ if (densityOfStatesColor[j] == null){ g.setColor(Color.BLUE.darker()); g.drawLine(850, 450-j, 850 + densityOfStatesCount[j]/2, 450-j); g.setColor(Color.GREEN.darker()); g.drawLine(850 + densityOfStatesCount[j]/2, 450-j, 850 + densityOfStatesCount[j], 450-j); } else { g.drawLine(850, 450-j, 850 + densityOfStatesCount[j], 450-j); } } } break; case 2: //all occupied g.setColor(Color.BLUE.darker()); for (int j = 0; j < 330; j++){ if (!(densityOfStatesCount[j] == 0)){ g.drawLine(850, 450-j, 850 + densityOfStatesCount[j], 450-j); } } } } if (numberOfAtoms < 25) { g.setColor(Color.RED); g.drawString("Click on a level to draw the orbital", 560,180); } g.setColor(Color.BLACK); g.setFont(myFont); g.drawString("Adjust the internuclear distance with the slider",135,125); g.drawString("Choose number of atoms", 550, 125); g.drawString("Choose an occupancy", 785, 125); g.setFont(mySmallerFont); g.drawString("Copyright: P.H. Bird, 2012",850,505); } // @Override // public void adjustmentValueChanged(AdjustmentEvent evt){ @Override public void mouseReleased(MouseEvent evt) { //read distance slider Object source = evt.getSource(); if (source == internuclearDistanceSlider) { internuclearDistance = internuclearDistanceSlider.getValue(); internuclearDistanceLine = internuclearDistance + internuclearDistanceLineStart + 65; if (internuclearDistance < 48){ internuclearDistance = 48; internuclearDistanceSlider.setValue(48); internuclearDistanceLine = internuclearDistance + internuclearDistanceLineStart + 65; morseCurves_g.setColor(Color.RED); morseCurves_g.drawString("Sorry,distances less than 48 pm cannot be handled", 80,20); repaint(); return; } drawEnergyLevelBox(); drawMorseCurves(); repaint(); } } @Override public void mouseClicked(MouseEvent evt){ //Detect orbital choice if (numberOfAtoms > 10) return; int xLoc = evt.getX(); int yLoc = evt.getY(); if (xLoc > 670 & xLoc < 800 & yLoc > 162 & yLoc < 485){ for (int j = 0; j < numberOfAtoms; j++){ if (yLoc >= 448-level[j] & yLoc <= 452-level[j]){ levelSelected = j; repaint(); } } } } @Override public void mouseExited(MouseEvent evt){} @Override public void mousePressed(MouseEvent evt){} @Override public void mouseEntered(MouseEvent evt){} @Override public void itemStateChanged(ItemEvent evt){ Object source = evt.getSource(); int atomCountIndex; if (source == numberOfAtomsChoice) { levelSelected = 0; atomCountIndex = numberOfAtomsChoice.getSelectedIndex(); switch (atomCountIndex) { case 0: numberOfAtoms = 2; break; case 1: numberOfAtoms = 3; break; case 2: numberOfAtoms = 4; break; case 3: numberOfAtoms = 5; break; case 4: numberOfAtoms = 10; break; case 5: numberOfAtoms = 25; break; case 6: numberOfAtoms = 50; break; case 7: numberOfAtoms = 100; break; case 8: numberOfAtoms = 1000; } } if (source == bandOccupancyChoice){ bandOccupancyIndex = bandOccupancyChoice.getSelectedIndex(); } makeCurves(); drawMorseCurves(); drawEnergyLevelBox(); repaint(); } @Override public String getAppletInfo() { return "Name: Bands\r\n" + "Author: Dr. P. Bird\r\n" + "Copyright: April 2012\r\n" + "Created with NetBeans IDE 7.1.2"; } }