// Quantum1DCrystal.java (C) 2002 by Paul Falstad, www.falstad.com
import java.awt.*;
import java.applet.Applet;
import java.util.Vector;
import java.util.Random;
import java.lang.Math;
import java.awt.event.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import org.netlib.util.*;
import org.netlib.lapack.Dsyevd;
class Quantum1DCrystalCanvas extends Canvas {
Quantum1DCrystalFrame pg;
Quantum1DCrystalCanvas(Quantum1DCrystalFrame p) {
pg = p;
}
public Dimension getPreferredSize() {
return new Dimension(300,400);
}
public void update(Graphics g) {
pg.updateQuantum1DCrystal(g);
}
public void paint(Graphics g) {
pg.updateQuantum1DCrystal(g);
}
};
class Quantum1DCrystalLayout implements LayoutManager {
public Quantum1DCrystalLayout() {}
public void addLayoutComponent(String name, Component c) {}
public void removeLayoutComponent(Component c) {}
public Dimension preferredLayoutSize(Container target) {
return new Dimension(500, 500);
}
public Dimension minimumLayoutSize(Container target) {
return new Dimension(100,100);
}
public void layoutContainer(Container target) {
int barwidth = 0;
int i;
for (i = 1; i < target.getComponentCount(); i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = m.getPreferredSize();
if (d.width > barwidth)
barwidth = d.width;
}
}
Insets insets = target.insets();
int targetw = target.size().width - insets.left - insets.right;
int cw = targetw-barwidth;
int targeth = target.size().height - (insets.top+insets.bottom);
target.getComponent(0).move(insets.left, insets.top);
target.getComponent(0).resize(cw, targeth);
cw += insets.left;
int h = insets.top;
for (i = 1; i < target.getComponentCount(); i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = m.getPreferredSize();
if (m instanceof Scrollbar || m instanceof DecentScrollbar)
d.width = barwidth;
if (m instanceof Choice && d.width > barwidth)
d.width = barwidth;
if (m instanceof Label) {
h += d.height/5;
d.width = barwidth;
}
m.move(cw, h);
m.resize(d.width, d.height);
h += d.height;
}
}
}
};
public class Quantum1DCrystal extends Applet implements ComponentListener {
static Quantum1DCrystalFrame qf;
void destroyFrame() {
if (qf != null)
qf.dispose();
qf = null;
repaint();
}
public static void main(String args[]) {
qf = new Quantum1DCrystalFrame(null);
qf.init();
}
boolean started = false;
public void init() {
addComponentListener(this);
}
void showFrame() {
if (qf == null) {
started = true;
qf = new Quantum1DCrystalFrame(this);
qf.init();
repaint();
}
}
public void paint(Graphics g) {
String s = "Applet is open in a separate window.";
if (!started)
s = "Applet is starting.";
else if (qf == null)
s = "Applet is finished.";
else
qf.show();
g.drawString(s, 10, 30);
}
public void componentHidden(ComponentEvent e){}
public void componentMoved(ComponentEvent e){}
public void componentShown(ComponentEvent e) { showFrame(); }
public void componentResized(ComponentEvent e) {}
public void destroy() {
if (qf != null)
qf.dispose();
qf = null;
repaint();
}
};
class Quantum1DCrystalFrame extends Frame
implements ComponentListener, ActionListener,
MouseMotionListener, MouseListener, ItemListener,
DecentScrollbarListener {
Thread engine = null;
Dimension winSize;
Image dbimage;
Random random;
int stateCount;
int elevelCount;
int maxStateCount = 500;
int sampleCount = 320;
int cellSampleCount = 32;
int potSampleCount = 128;
int pSampleCount;
double modes[][];
double modesLeft[][];
double dispersion[][];
double expecte;
double selectedK;
double potTrans[];
double blochTrans[];
int selectedBand;
public static final double epsilon = .00001;
public static final double epsilon2 = .003;
public static final double phasorBaseEnergy = 1;
public String getAppletInfo() {
return "Quantum1DCrystal by Paul Falstad";
}
Button groundButton;
Checkbox stoppedCheck;
CheckboxMenuItem eCheckItem;
CheckboxMenuItem xCheckItem;
CheckboxMenuItem pCheckItem;
CheckboxMenuItem blochCheckItem;
CheckboxMenuItem dispersionCheckItem;
CheckboxMenuItem expectCheckItem;
CheckboxMenuItem probCheckItem;
CheckboxMenuItem probPhaseCheckItem;
CheckboxMenuItem reImCheckItem;
CheckboxMenuItem magPhaseCheckItem;
CheckboxMenuItem extendedZonesItem;
CheckboxMenuItem reducedZonesItem;
CheckboxMenuItem repeatedZonesItem;
Menu waveFunctionMenu;
Menu zoneMenu;
MenuItem exitItem;
Choice mouseChooser;
Choice setupChooser;
Vector setupList;
Setup setup;
DecentScrollbar forceBar, speedBar, wellCountBar, energyScaleBar;
DecentScrollbar massBar, aux1Bar, aux2Bar, aux3Bar, aux4Bar;
Label aux1Label, aux2Label, aux3Label, aux4Label;
View viewPotential, viewX, viewP, viewDispersion, viewBloch;
View viewList[];
int viewCount;
double elevels[];
double dispmax[];
static final double pi = 3.14159265358979323846;
double step;
double func[];
double funci[];
double blochr[];
double blochi[];
double pdata[], pdatar[], pdatai[];
double pot[];
double mass;
double escale;
int selectedCoef;
int selectedPaneHandle;
int kUpdateState, kUpdateSkip;
static final int stateBuffer = 5;
static final int SEL_NONE = 0;
static final int SEL_POTENTIAL = 1;
static final int SEL_X = 2;
static final int SEL_P = 3;
static final int SEL_STATES = 4;
static final int SEL_HANDLE = 5;
static final int SEL_DISPERSION = 6;
static final int MOUSE_EIGEN = 0;
static final int MOUSE_EDIT = 1;
int selection;
int dragX, dragY;
int xpoints[], ypoints[];
boolean dragging;
boolean startup, selectGround;
boolean levelsChanged, stateChanged;
boolean setupModified;
double t;
int pause;
static final int phaseColorCount = 480;
Color phaseColors[];
FFT fft;
int getrand(int x) {
int q = random.nextInt();
if (q < 0) q = -q;
return q % x;
}
Quantum1DCrystalCanvas cv;
Quantum1DCrystal applet;
NumberFormat showFormat;
Quantum1DCrystalFrame(Quantum1DCrystal a) {
super("1-d Quantum Crystal Applet v1.0c");
applet = a;
}
public void init() {
startup = true;
xpoints = new int[5];
ypoints = new int[5];
setupList = new Vector();
Setup s = new FiniteWellSetup();
while (s != null) {
setupList.addElement(s);
s = s.createNext();
}
selectedCoef = -1;
setLayout(new Quantum1DCrystalLayout());
cv = new Quantum1DCrystalCanvas(this);
cv.addComponentListener(this);
cv.addMouseMotionListener(this);
cv.addMouseListener(this);
add(cv);
MenuBar mb = new MenuBar();
Menu m = new Menu("File");
mb.add(m);
m.add(exitItem = getMenuItem("Exit"));
m = new Menu("View");
mb.add(m);
m.add(eCheckItem = getCheckItem("Energy"));
eCheckItem.setState(true);
m.add(xCheckItem = getCheckItem("Position"));
xCheckItem.setState(true);
m.add(pCheckItem = getCheckItem("Momentum"));
m.add(blochCheckItem = getCheckItem("Bloch Function"));
/*m.add(densityCheckItem = getCheckItem("Density of Levels"));
densityCheckItem.setState(true);*/
m.add(dispersionCheckItem = getCheckItem("Dispersion"));
dispersionCheckItem.setState(true);
m.addSeparator();
/*m.add(expectCheckItem = getCheckItem("Expectation Values"));
expectCheckItem.setState(true);*/
Menu m2 = waveFunctionMenu = new Menu("Wave Function");
m.add(m2);
m2.add(probCheckItem = getCheckItem("Probability"));
m2.add(probPhaseCheckItem = getCheckItem("Probability + Phase"));
probPhaseCheckItem.setState(true);
m2.add(reImCheckItem = getCheckItem("Real + Imaginary Parts"));
m2.add(magPhaseCheckItem = getCheckItem("Magnitude + Phase"));
m = zoneMenu = new Menu("Zones");
mb.add(m);
m.add(extendedZonesItem = getCheckItem("Extended Zone Scheme"));
m.add(reducedZonesItem = getCheckItem("Reduced Zone Scheme"));
reducedZonesItem.setState(true);
m.add(repeatedZonesItem = getCheckItem("Repeated Zone Scheme"));
setMenuBar(mb);
setupChooser = new Choice();
int i;
for (i = 0; i != setupList.size(); i++)
setupChooser.add("Setup: " +
((Setup) setupList.elementAt(i)).getName());
setup = (Setup) setupList.elementAt(0);
setupChooser.addItemListener(this);
add(setupChooser);
mouseChooser = new Choice();
mouseChooser.add("Mouse = Set Eigenstate");
mouseChooser.add("Mouse = Edit Function");
mouseChooser.addItemListener(this);
add(mouseChooser);
mouseChooser.select(MOUSE_EIGEN);
add(groundButton = new Button("Ground State"));
groundButton.addActionListener(this);
stoppedCheck = new Checkbox("Stopped");
stoppedCheck.addItemListener(this);
add(stoppedCheck);
add(new Label("Simulation Speed", Label.CENTER));
add(speedBar = new DecentScrollbar(this, 50, 1, 150));
add(new Label("Particle Mass", Label.CENTER));
add(massBar = new DecentScrollbar(this, 100, 10, 500));
add(new Label("# of Wells Shown", Label.CENTER));
add(wellCountBar = new DecentScrollbar(this, 5, 1, 50));
add(new Label("Energy Scale", Label.CENTER));
add(energyScaleBar = new DecentScrollbar(this, 100, 1, 100));
add(aux1Label = new Label("Aux 1", Label.CENTER));
add(aux1Bar = new DecentScrollbar(this, 50, 1, 100));
add(aux2Label = new Label("Aux 2", Label.CENTER));
add(aux2Bar = new DecentScrollbar(this, 50, 1, 100));
add(aux3Label = new Label("Aux 3", Label.CENTER));
add(aux3Bar = new DecentScrollbar(this, 50, 1, 100));
add(aux4Label = new Label("Aux 4", Label.CENTER));
add(aux4Bar = new DecentScrollbar(this, 50, 1, 100));
try {
String param = applet.getParameter("PAUSE");
if (param != null)
pause = Integer.parseInt(param);
} catch (Exception e) { }
dispmax = new double[maxStateCount];
setResolution();
phaseColors = new Color[phaseColorCount+1];
for (i = 0; i != phaseColorCount; i++) {
int pm = phaseColorCount/6;
int a1 = i % pm;
int a2 = a1*255/pm;
int a3 = 255-a2;
Color c = null;
switch (i/pm) {
case 0: c = new Color(255, a2, 0); break;
case 1: c = new Color(a3, 255, 0); break;
case 2: c = new Color(0, 255, a2); break;
case 3: c = new Color(0, a3, 255); break;
case 4: c = new Color(a2, 0, 255); break;
case 5: c = new Color(255, 0, a3); break;
}
phaseColors[i] = c;
}
phaseColors[phaseColorCount] = phaseColors[0];
random = new Random();
reinit();
cv.setBackground(Color.black);
cv.setForeground(Color.lightGray);
showFormat = DecimalFormat.getInstance();
showFormat.setMaximumFractionDigits(2);
resize(750, 600);
handleResize();
Dimension x = getSize();
Dimension screen = getToolkit().getScreenSize();
setLocation((screen.width - x.width)/2,
(screen.height - x.height)/2);
show();
}
MenuItem getMenuItem(String s) {
MenuItem mi = new MenuItem(s);
mi.addActionListener(this);
return mi;
}
CheckboxMenuItem getCheckItem(String s) {
CheckboxMenuItem mi = new CheckboxMenuItem(s);
mi.addItemListener(this);
return mi;
}
void reinit() {
doSetup();
}
void handleResize() {
Dimension d = winSize = cv.getSize();
if (winSize.width == 0)
return;
int tpad = 20;
int potsize = (viewPotential == null) ? 0 : viewPotential.height+tpad;
int dispsize = (viewDispersion == null) ? 0 : viewDispersion.height+tpad;
viewX = viewP = viewDispersion = viewPotential = viewBloch = null;
viewList = new View[20];
int i = 0;
if (eCheckItem.getState())
viewList[i++] = viewPotential = new View();
if (xCheckItem.getState())
viewList[i++] = viewX = new View();
if (blochCheckItem.getState())
viewList[i++] = viewBloch = new View();
if (pCheckItem.getState())
viewList[i++] = viewP = new View();
if (dispersionCheckItem.getState())
viewList[i++] = viewDispersion = new View();
viewCount = i;
int sizenum = viewCount;
int toth = winSize.height;
// preserve size of potential and state panes if possible
if (potsize > 0 && viewPotential != null) {
sizenum--;
toth -= potsize;
}
if (dispsize > 0 && viewDispersion != null) {
sizenum--;
toth -= dispsize;
}
int cury = 0;
for (i = 0; i != viewCount; i++) {
View v = viewList[i];
int h = toth/sizenum;
if (v == viewPotential && potsize > 0)
h = potsize;
else if (v == viewDispersion && dispsize > 0)
h = dispsize;
v.x = 0;
v.width = winSize.width;
v.y = cury+tpad;
v.height = h-tpad;
v.handle = cury;
cury += h;
}
setGraphLines();
dbimage = createImage(d.width, d.height);
}
void setGraphLines() {
int i;
for (i = 0; i != viewCount; i++) {
View v = viewList[i];
v.mid_y = v.y + v.height/2;
v.ymult = .90*v.height/2;
v.lower_y = (int) (v.mid_y+v.ymult);
v.ymult2 = v.ymult*2;
}
}
void doGround() {
select(0, 0);
}
void doBlank() {
t = 0;
// workaround bug in IE
if (winSize != null && winSize.width > 0)
dbimage = createImage(winSize.width, winSize.height);
}
void centerString(Graphics g, String s, int y) {
FontMetrics fm = g.getFontMetrics();
g.drawString(s, (winSize.width-fm.stringWidth(s))/2, y);
}
public void paint(Graphics g) {
cv.repaint();
}
long lastTime;
public void updateQuantum1DCrystal(Graphics realg) {
Graphics g = dbimage.getGraphics();
if (winSize == null || winSize.width == 0)
return;
boolean allQuiet = true;
double tadd = 0;
if (!stoppedCheck.getState() && !dragging) {
int val = speedBar.getValue();
tadd = Math.exp(val/20.)*(.1/5);
long sysTime = System.currentTimeMillis();
if (lastTime == 0)
lastTime = sysTime;
tadd *= (sysTime-lastTime)*(1/17.);
lastTime = sysTime;
allQuiet = false;
} else
lastTime = 0;
Color gray1 = new Color(76, 76, 76);
Color gray2 = new Color(127, 127, 127);
g.setColor(cv.getBackground());
g.fillRect(0, 0, winSize.width, winSize.height);
g.setColor(cv.getForeground());
int i;
int ox = -1, oy = -1;
for (i = 1; i != viewCount; i++) {
g.setColor(i == selectedPaneHandle ? Color.yellow : Color.gray);
g.drawLine(0, viewList[i].handle, winSize.width, viewList[i].handle);
}
if (levelsChanged || stateChanged) {
cv.setCursor(Cursor.getPredefinedCursor(WAIT_CURSOR));
if (levelsChanged)
genStates();
else
getBands(true, selectedK, selectedBand);
cv.setCursor(null);
levelsChanged = stateChanged = false;
} else {
long tm = System.currentTimeMillis();
// spend 50ms updating K
while (updateK() &&
System.currentTimeMillis() < tm+50)
;
}
ox = -1;
int j;
if (viewPotential != null) {
int mid_y = viewPotential.mid_y;
double ymult = viewPotential.ymult;
g.setColor(Color.gray);
for (i = 0; i < elevelCount; i += 2) {
g.setColor(Color.darkGray);
double dy2 = elevels[i];
double dy1 = elevels[i+1];
int y1 = getEnergyY(dy1, viewPotential);
int y2 = getEnergyY(dy2, viewPotential);
y2 -= y1;
if (y2 <= 0)
y2 = 1;
g.fillRect(0, y1, winSize.width, y2);
}
g.setColor(Color.white);
int wc = wellCountBar.getValue();
double step = winSize.width/((double) potSampleCount*wc);
for (i = 0; i != potSampleCount*wc; i++) {
int x = (int) (step*i);
double dy = pot[i & (potSampleCount-1)];
int y = getEnergyY(dy, viewPotential);
if (ox != -1)
g.drawLine(ox, oy, x, y);
ox = x;
oy = y;
}
int y = getEnergyY(expecte, viewPotential);
g.setColor(Color.red);
g.drawLine(0, y, winSize.width, y);
/*
g.setColor(Color.black);
g.fillRect(0, 0, winSize.width, 20);
viewPotential.drawLabel(g, "Potential");*/
}
ox = -1;
g.setColor(Color.white);
double maxf = 0;
for (i = 0; i != sampleCount; i++) {
int x = winSize.width * i / sampleCount;
double dr = func[i], di = funci[i];
double dy = dr*dr+di*di;
if (dy > maxf)
maxf = dy;
}
// evolve wave function
double speed = (expecte+1)*tadd;
double efr = Math.cos(speed);
double efi = -Math.sin(speed);
for (i = 0; i != sampleCount; i++) {
double fr = func [i];
double fi = funci[i];
func [i] = fr*efr - fi*efi;
funci[i] = fr*efi + fi*efr;
fr = blochr[i];
fi = blochi[i];
blochr[i] = fr*efr - fi*efi;
blochi[i] = fr*efi + fi*efr;
}
if (viewX != null) {
viewX.drawLabel(g, "Wave Function (Position)");
// draw X representation
int mid_y = viewX.mid_y;
double ymult = viewX.ymult;
drawFunction(g, viewX, func, funci, sampleCount, 0);
if (selectedCoef != -1 && !dragging) {
g.setColor(Color.yellow);
ox = -1;
for (i = 0; i != sampleCount; i++) {
int x = winSize.width * i / sampleCount;
double dy = modes[selectedCoef][i]/dispmax[selectedCoef];
int y = mid_y - (int) (ymult * dy);
if (ox != -1)
g.drawLine(ox, oy, x, y);
ox = x;
oy = y;
}
}
}
if (viewP != null) {
viewP.drawLabel(g, "Momentum");
// draw P representation
g.setColor(gray2);
g.drawLine(winSize.width/2, viewP.mid_y-(int) viewP.ymult,
winSize.width/2, viewP.mid_y+(int) viewP.ymult);
for (i = 0; i != pdatar.length; i++)
pdatar[i] = pdatai[i] = 0;
int btlen = blochTrans.length/4;
int btmask = blochTrans.length-1;
// I must have missed a sign somewhere; fix it so that waves
// are going in right direction
int fudge = ((selectedBand & 1) == 1) ? 1 : -1;
int kstep = 8;
kstep *= -fudge;
int pc = pdatar.length/2 + (int) (selectedK*kstep);
btlen = 16;
for (i = 0; i != btlen; i++) {
pdatar[pc+kstep*i] = blochTrans[i*2];
pdatar[pc-kstep*i] = blochTrans[btmask&(-i*2)];
pdatai[pc+kstep*i] = blochTrans[i*2+1];
pdatai[pc-kstep*i] = blochTrans[btmask&(-i*2+1)];
}
for (i = pdatar.length-1; i > 0; i--) {
if (pdatar[i] == 0 && pdatai[i] == 0) {
pdatar[i] = pdatar[i-1]*1e-16;
pdatai[i] = pdatai[i-1]*1e-16;
}
}
int offset = pSampleCount/4;
drawFunction(g, viewP, pdatar, pdatai, pSampleCount/2, offset);
}
if (viewDispersion != null) {
viewDispersion.drawLabel(g, "Dispersion (E vs. k)");
g.setColor(Color.gray);
int mid_y = viewDispersion.mid_y;
double ymult = viewDispersion.ymult;
double e0 = elevels[0]+1;
int top = viewDispersion.y+5;
for (i = 0; i < elevelCount; i += 2) {
g.setColor(Color.darkGray);
double dy2 = elevels[i]-e0;
double dy1 = elevels[i+1]-e0;
int y1 = getEnergyY(dy1, viewDispersion);
int y2 = getEnergyY(dy2, viewDispersion);
if (y2 < top)
continue;
if (y1 < top)
y1 = top;
y2 -= y1;
if (y2 <= 0)
y2 = 1;
g.fillRect(0, y1, winSize.width, y2);
}
g.setColor(Color.white);
if (repeatedZonesItem.getState()) {
viewDispersion.cellw2 = viewDispersion.width/10;
int cells = (viewDispersion.width/2)/viewDispersion.cellw2 + 1;
for (i = 0; i != dispersion.length; i++)
for (j = -cells; j <= cells; j++)
drawDispersion(g, i, j, true, true);
}
if (reducedZonesItem.getState()) {
viewDispersion.cellw2 = viewDispersion.width/3;
for (i = 0; i != dispersion.length; i++)
drawDispersion(g, i, 0, true, true);
}
if (extendedZonesItem.getState()) {
viewDispersion.cellw2 = viewDispersion.width/10;
boolean xp = true;
for (i = 0; i != dispersion.length; i++) {
drawDispersion(g, i, (i+1)/2, xp, !xp);
drawDispersion(g, i, -(i+1)/2, !xp, xp);
xp = !xp;
}
}
int y = getEnergyY(expecte-e0, viewDispersion);
g.setColor(Color.red);
if (y >= viewDispersion.y) {
g.drawLine(0, y, winSize.width, y);
}
int x = (int) (viewDispersion.cellw2*selectedK*2+
viewDispersion.width/2);
if (!extendedZonesItem.getState())
g.drawLine(x, top, x, viewDispersion.y+viewDispersion.height);
}
if (viewBloch != null) {
viewBloch.drawLabel(g, "Bloch Function");
drawFunction(g, viewBloch, blochr, blochi, blochr.length, 0);
}
realg.drawImage(dbimage, 0, 0, this);
if (!stoppedCheck.getState())
cv.repaint(pause);
}
int getEnergyY(double e, View v) {
escale = energyScaleBar.getValue()/100.;
e = (e+1)*escale-1;
return v.mid_y - (int) (v.ymult*e);
}
void drawDispersion(Graphics g, int level, int off, boolean pos, boolean neg) {
int ox = -1;
int oy = -1;
int j;
double e0 = elevels[0]+1;
int cellw2 = viewDispersion.cellw2;
int cellw = cellw2*2;
int top = viewDispersion.y+5;
for (j = 0; j != dispersion[0].length; j++) {
int cx = off*cellw + viewDispersion.width/2;
int x = j*cellw2/(dispersion[0].length-1);
int y = getEnergyY(dispersion[level][j]-e0, viewDispersion);
if (ox != -1 && y > top && oy > top) {
if (pos)
g.drawLine(cx+ox, oy, cx+x, y);
if (neg)
g.drawLine(cx-ox, oy, cx-x, y);
}
ox = x;
oy = y;
}
}
String getUnitText(double v, String u) {
double va = Math.abs(v);
if (va < 1e-17)
return "0 " + u;
if (va < 1e-12)
return showFormat.format(v*1e15) + " f" + u;
if (va < 1e-9)
return showFormat.format(v*1e12) + " p" + u;
if (va < 1e-6)
return showFormat.format(v*1e9) + " n" + u;
if (va < 1e-3)
return showFormat.format(v*1e6) + " u" + u;
if (va < 1)
return showFormat.format(v*1e3) + " m" + u;
if (va < 1e3)
return showFormat.format(v) + " " + u;
if (va < 1e6)
return showFormat.format(v*1e-3) + " k" + u;
if (va < 1e9)
return showFormat.format(v*1e-6) + " M" + u;
if (va < 1e12)
return showFormat.format(v*1e-9) + " G" + u;
if (va < 1e15)
return showFormat.format(v*1e-12) + " T" + u;
return v + " " + u;
}
String getEnergyText(double e, boolean abs) {
return getUnitText(convertEnergy(e, abs), "eV");
}
String getLengthText(double x) {
// getEnergyText() assumes a 4 nm screen width
return getUnitText(pointsToLength(x), "m");
}
double pointsToLength(double x) {
// getEnergyText() assumes a 4 nm screen width
return 4e-9*x/(sampleCount-2.);
}
double convertEnergy(double e, boolean abs) {
// ground state energy for an electron in a 4 nm infinite well (in eV)
// (for 1 Angstrom, it's 37.603)
double base = .023502;
// the calculated ground state energy for a particle of default mass in a
// well the full width of the window is 0.001891. So, if we assume the
// window is 1 angstrom wide, then we multiply the elevels by base/.001891 to
// get eV.
if (abs)
e += setup.getBaseEnergy();
return e*base/.0018801;
}
int stateColSize, stateSize;
void drawFunction(Graphics g, View view, double fr[], double fi[],
int count, int offset) {
int i;
double expectx = 0;
double expectx2 = 0;
double maxsq = 0;
double tot = 0;
int zero = winSize.width/2;
for (i = 0; i != count; i++) {
int x = winSize.width * i / (count-1);
int ii = i+offset;
double dr = fr[ii];
double di = (fi == null) ? 0 : fi[ii];
double dy = dr*dr+di*di;
if (dy > maxsq)
maxsq = dy;
int dev = x-zero;
expectx += dy*dev;
expectx2 += dy*dev*dev;
tot += dy;
}
expectx /= tot;
expectx2 /= tot;
double maxnm = Math.sqrt(maxsq);
double uncert = Math.sqrt(expectx2-expectx*expectx);
int ox = -1, oy = 0;
double bestscale = 0;
if (fi != null &&
(probCheckItem.getState() || probPhaseCheckItem.getState()))
bestscale = 1/maxsq;
else
bestscale = 1/maxnm;
view.scale = bestscale;
/*
if (!adjustingWaveFunc) {
// adjust scale
view.scale *= 1.001;
if (view.scale > bestscale || view.scale == 0)
view.scale = bestscale;
if (view.scale > 1e8)
view.scale = 1e8;
}
*/
g.setColor(Color.gray);
/*
double scaler = 1e-10;
while (scaler*view.scale*view.ymult*600 < view.height)
scaler *= 10;
System.out.print(scaler + "\n");
for (i = 0; i != 20; i++) {
int y = (int) (view.ymult * i * view.scale * scaler * 10);
System.out.print(i + " " + y + "\n");
if (y > view.height/2)
break;
g.drawLine(winSize.width-5, view.mid_y - y,
winSize.width, view.mid_y - y);
}
*/
if ((probCheckItem.getState() || probPhaseCheckItem.getState() ||
magPhaseCheckItem.getState()) && fi != null) {
// draw probability or magnitude
g.setColor(Color.white);
double mult = view.ymult2*view.scale;
for (i = 0; i != count; i++) {
int x = winSize.width * i / (count-1);
double dy = 0;
int ii = i+offset;
if (!magPhaseCheckItem.getState())
dy = (fr[ii]*fr[ii]+fi[ii]*fi[ii]);
else
dy = Math.sqrt(fr[ii]*fr[ii]+fi[ii]*fi[ii]);
if (!probCheckItem.getState()) {
double ang = Math.atan2(fi[ii], fr[ii]);
g.setColor(phaseColors[(int)((ang+pi)*phaseColorCount/(2*pi+.2))]);
}
int y = view.lower_y - (int) (mult * dy);
if (y < view.y)
y = view.y;
if (ox != -1) {
xpoints[0] = ox;
ypoints[0] = view.lower_y+1;
xpoints[1] = ox;
ypoints[1] = oy;
xpoints[2] = x;
ypoints[2] = y;
xpoints[3] = x;
ypoints[3] = view.lower_y+1;
g.fillPolygon(xpoints, ypoints, 4);
}
ox = x;
oy = y;
}
} else {
g.setColor(Color.darkGray);
int mid_y = view.mid_y;
g.drawLine(0, mid_y, winSize.width, mid_y);
double mult = view.ymult*view.scale;
if (fi != null) {
g.setColor(Color.blue);
for (i = 0; i != count; i++) {
int x = winSize.width * i / (count-1);
int ii = i+offset;
int y = mid_y - (int) (mult * fi[ii]);
if (ox != -1)
g.drawLine(ox, oy, x, y);
ox = x;
oy = y;
}
}
g.setColor(Color.white);
ox = -1;
for (i = 0; i != count; i++) {
int x = winSize.width * i / (count-1);
int ii = i+offset;
int y = mid_y - (int) (mult * fr[ii]);
if (ox != -1)
g.drawLine(ox, oy, x, y);
ox = x;
oy = y;
}
}
if (maxsq > 0 && fi != null) {
expectx += zero;
/*if (uncertaintyCheckItem.getState()) {
g.setColor(Color.blue);
g.drawLine((int) (expectx-uncert), view.y,
(int) (expectx-uncert), view.y+view.height);
g.drawLine((int) (expectx+uncert), view.y,
(int) (expectx+uncert), view.y+view.height);
}*/
/*if (expectCheckItem.getState()) {
g.setColor(Color.red);
g.drawLine((int) expectx, view.y,
(int) expectx, view.y+view.height);
}*/
}
}
void edit(MouseEvent e) {
if (selection == SEL_NONE)
return;
int x = e.getX();
int y = e.getY();
switch (selection) {
case SEL_HANDLE: editHandle(y); break;
case SEL_DISPERSION : editDispersion(x, y); break;
default: editFunc(x, y); break;
}
}
void editHandle(int y) {
int dy = y-viewList[selectedPaneHandle].handle;
View upper = viewList[selectedPaneHandle-1];
View lower = viewList[selectedPaneHandle];
int minheight = 10;
if (upper.height+dy < minheight || lower.height-dy < minheight)
return;
upper.height += dy;
lower.height -= dy;
lower.y += dy;
lower.handle += dy;
setGraphLines();
cv.repaint(pause);
}
void editFunc(int x, int y) {
if (mouseChooser.getSelectedIndex() == MOUSE_EIGEN) {
if (selection == SEL_POTENTIAL)
selectStateByEnergy(y);
return;
}
if (dragX == x) {
editFuncPoint(x, y);
dragY = y;
} else {
// need to draw a line from old x,y to new x,y and
// call editFuncPoint for each point on that line. yuck.
int x1 = (x < dragX) ? x : dragX;
int y1 = (x < dragX) ? y : dragY;
int x2 = (x > dragX) ? x : dragX;
int y2 = (x > dragX) ? y : dragY;
dragX = x;
dragY = y;
for (x = x1; x <= x2; x++) {
y = y1+(y2-y1)*(x-x1)/(x2-x1);
editFuncPoint(x, y);
}
}
}
void editFuncPoint(int x, int y) {
if (selection != SEL_POTENTIAL)
return;
View v = (selection == SEL_X) ? viewX : viewPotential;
int wc = wellCountBar.getValue();
int fullx = potSampleCount*wc;
int lox = x * fullx / winSize.width;
int hix = ((x+1) * fullx-1) / winSize.width;
double val = (v.mid_y - y) / v.ymult;
double val2 = (v.lower_y - y) / v.ymult2;
if (val > 1)
val = 1;
if (val < -1)
val = -1;
if (val2 > 1)
val2 = 1;
if (val2 < 0)
val2 = 0;
val = (val +1)/escale-1;
val2 = (val2+1)/escale-1;
if (val > 1)
val = 1;
if (val2 > 1)
val2 = 1;
if (lox < 1)
lox = 1;
if (hix >= sampleCount-1)
hix = sampleCount-2;
for (; lox <= hix; lox++) {
pot[lox % potSampleCount] = val;
setupModified = true;
getPotTrans();
levelsChanged = true;
}
cv.repaint(pause);
}
void editDispersion(int x, int y) {
x -= viewDispersion.width/2;
double k = x*.5/viewDispersion.cellw2;
if (extendedZonesItem.getState()) {
int band = 0;
while (k > .5) {
k -= .5;
band++;
}
while (k < -.5) {
k += .5;
band++;
}
if ((band & 1) != 0)
k = (k >= 0) ? .5-k : -.5-k;
select(k, band);
return;
}
if (repeatedZonesItem.getState()) {
while (k > .5)
k -= 1;
while (k < -.5)
k += 1;
}
if (k > .5)
k = .5;
if (k < -.5)
k = -.5;
int i;
int besty = 1000;
int band = 0;
double e0 = elevels[0]+1;
for (i = 0; i != dispersion.length; i++) {
int ya = getEnergyY(elevels[i*2 ]-e0, viewDispersion);
int yb = getEnergyY(elevels[i*2+1]-e0, viewDispersion);
if (y < ya && y > yb) {
besty = -1;
band = i;
break;
}
int yd = Math.abs(y-ya);
if (yd < besty) {
besty = yd;
band = i;
}
yd = Math.abs(y-yb);
if (yd < besty) {
besty = yd;
band = i;
}
}
select(k, band);
}
void select(double k, int band) {
selectedK = k;
selectedBand = band;
stateChanged = true;
cv.repaint(pause);
}
void getPotTrans() {
potTrans = new double[potSampleCount*2];
int i;
for (i = 0; i != potSampleCount; i++)
potTrans[i*2] = pot[i];
FFT fft = new FFT(potSampleCount);
fft.transform(potTrans, false);
}
double getPState(int x) {
double p = (x * pSampleCount/2 / winSize.width) - pSampleCount/4;
return p*pi/(pSampleCount/2);
}
public void componentHidden(ComponentEvent e){}
public void componentMoved(ComponentEvent e){}
public void componentShown(ComponentEvent e) {
cv.repaint(pause);
}
public void componentResized(ComponentEvent e) {
handleResize();
cv.repaint(pause);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == exitItem) {
applet.destroyFrame();
return;
}
cv.repaint();
if (e.getSource() == groundButton)
doGround();
}
public void scrollbarValueChanged(DecentScrollbar ds) {
System.out.print(ds.getValue() + "\n");
if (ds == massBar)
levelsChanged = true;
if (ds == aux1Bar || ds == aux2Bar || ds == aux3Bar || ds == aux4Bar) {
setup.drawPotential();
getPotTrans();
levelsChanged = true;
}
if (ds == wellCountBar) {
setResolution();
setup.drawPotential();
stateChanged = true;
}
cv.repaint(pause);
}
public void scrollbarFinished(DecentScrollbar ds) {
/*
if (ds == massBar || ds == aux1Bar || ds == aux2Bar || ds == aux3Bar ||
ds == aux4Bar) {
adjustingStates = false;
statesChanged = true;
cv.repaint(pause);
}
*/
}
public boolean handleEvent(Event ev) {
if (ev.id == Event.WINDOW_DESTROY) {
destroyFrame();
return true;
}
return super.handleEvent(ev);
}
void destroyFrame() {
if (applet == null)
dispose();
else
applet.destroyFrame();
}
void setResolution() {
int wc = wellCountBar.getValue();
cellSampleCount = 8;
while (cellSampleCount < 700/wc)
cellSampleCount *= 2;
sampleCount = cellSampleCount * wc;
//sampleCount++;
func = new double[sampleCount];
funci = new double[sampleCount];
blochr = new double[sampleCount];
blochi = new double[sampleCount];
pot = new double[potSampleCount];
stateChanged = true;
pSampleCount = 512;
pdatar = new double[pSampleCount];
pdatai = new double[pSampleCount];
fft = new FFT(pSampleCount);
}
void genStates() {
levelsChanged = false;
if (potTrans == null)
getPotTrans();
double lev1[] = getBands(false, 0, 0);
double lev2[] = getBands(false, .5, 0);
elevelCount = lev1.length*2;
elevels = new double[elevelCount];
stateCount = elevelCount;
// copy levels, and make sure they are in proper order
// (swapp every other pair)
int i;
for (i = 0; i != lev1.length; i++) {
int a = (i & 1);
elevels[i*2+a] = lev1[i];
elevels[i*2+1-a] = lev2[i];
}
// start to calculate the dispersion graph; first get the
// endpoints, k = 0 and k = .5
int dispx = 65;
int ll = lev1.length;
dispersion = new double[ll][dispx];
for (i = 0; i != ll; i++) {
dispersion[i][0] = lev1[i];
dispersion[i][dispx-1] = lev2[i];
// linearly interpolate the middle values for now
int j;
for (j = 1; j < dispx-1; j++) {
double q = j/(dispx-1.);
dispersion[i][j] = lev1[i]*(1-q) + lev2[i]*q;
}
}
// fill in the rest of the dispersion graph later
kUpdateState = dispx/2;
kUpdateSkip = kUpdateState*2;
getBands(true, selectedK, selectedBand);
}
boolean updateK() {
// are we done?
if (kUpdateSkip <= 1)
return false;
// update one k value in the dispersion graph. at the start,
// have the endpoints k = 0 and .5, and then we do .25, and then
// .125 and .375, etc. until it's all done.
int dispx = dispersion[0].length;
double k = kUpdateState/(2.*(dispx-1));
double lev3[] = getBands(false, k, 0);
int j;
for (j = 0; j != lev3.length; j++) {
dispersion[j][kUpdateState] = lev3[j];
int hskip = kUpdateSkip/2;
int m;
// interpolate linearly between the neighbor points that are done
for (m = 1; m < hskip; m++) {
double q = m/(double) hskip;
dispersion[j][kUpdateState-m] =
(1-q)*dispersion[j][kUpdateState] +
q*dispersion[j][kUpdateState-hskip];
dispersion[j][kUpdateState+m] =
(1-q)*dispersion[j][kUpdateState] +
q*dispersion[j][kUpdateState+hskip];
}
}
// skip to the next point
kUpdateState += kUpdateSkip;
if (kUpdateState >= dispx) {
// use a finer grid
kUpdateSkip /= 2;
if (kUpdateSkip == 1)
return false;
kUpdateState = kUpdateSkip/2;
}
return true;
}
int getFourierIndex(int i, int n) {
return (i > n/2) ? n/2-i : i;
}
double [] getBands(boolean getStates, double k, int band) {
//System.out.println("genstates " + k);
// n = number of basis states to use (more = more accurate, slower)
int n = 48;
int n2 = n*2;
double h[] = new double[n2*n2];
int i, j;
mass = massBar.getValue()*.0002;
double m1 = 1./mass;
mass *= .511e6 / .32;
// calculate matrix element of H. The basis functions for the
// H matrix are the momentum eigenfunctions, e^ikx. We
// convert the complex H (n by n) to a real H matrix 2n by 2n, because our
// eigenvalue solver can't handle complex numbers. To set
// H(i,j) to a+bi, we set H(i,j)=H(i+n,j+n)=a, H(i+n,j)=-b,
// H(i,j+n)=b.
for (i = 0; i != n; i++) {
// basis state i = exp(I*ii*x) (I^2 = -1)
int ii = getFourierIndex(i, n);
// p^2/2m matrix has h^2 (ii+k)^2/2m along the diagonal
double iik = ii+k;
h[i+n+n2*(i+n)] = h[i+n2*i] = m1*iik*iik*.01;
for (j = 0; j != n; j++) {
// basis state j = exp(I*jj*x)
int jj = getFourierIndex(j, n);
// V matrix element Vij = (jj-ii)'th element of fourier xform of potential fn
int ij = jj-ii;
if (ij < 0)
ij += potTrans.length/2;
double re = potTrans[ij*2]/potSampleCount;
double im = potTrans[ij*2+1]/potSampleCount;
h[i+n2*j] += re;
h[i+n+n2*(j+n)] += re;
h[i+n+j*n2] -= im;
h[i+n2*(j+n)] += im;
}
}
double work[] = new double[1+5*n2+5*n2*n2];
int iwork[] = new int[3+5*n2];
intW info = new intW(0);
double w[] = new double[n2];
// use LAPACK to find the eigenvalues and eigenvectors
Dsyevd.dsyevd(getStates ? "V" : "N", "U", n2,
h, 0, n2,
w, 0,
work, 0, work.length,
iwork, 0, iwork.length,
info);
//System.out.println(info.val);
double levels[] = new double[n2];
// now get the eigenvalues and sort them
for (i = 0; i != n2; i++)
levels[i] = w[i];
int si, sj;
// sort the elevels
for (si = 1; si < n2; si++) {
double v = levels[si];
sj = si;
while (levels[sj-1] > v) {
levels[sj] = levels[sj-1]; sj--;
if (sj <= 0) break;
}
levels[sj] = v;
}
// get the levels
double levels2[] = new double[20];
for (i = 0; i != 20; i++)
levels2[i] = levels[i*2];
// if we only need the levels, quit now
if (!getStates)
return levels2;
// get an eigenstate by stepping through all them.
int picker = 0;
for (i = 0; i != stateCount; i++) {
for (j = 0; j != n; j++)
if (levels[i] == w[j])
break;
if (j == n) {
System.out.print("can't find elevels! " + i + " " +
levels[i] + "\n");
continue;
}
w[j] = -1;
// is this the eigenstate we want?
if (picker++ < band*2)
continue;
// do an inverse FFT to calculate the bloch function
double q[] = new double[cellSampleCount*2];
int off = n2*j;
blochTrans = new double[cellSampleCount*2];
int norm = (h[off+1] < 0) ? -1 : 1;
for (j = 0; j != n; j++) {
int qo = getFourierIndex(j, n);
if (Math.abs(qo) >= cellSampleCount/2)
continue;
if (qo < 0)
qo += q.length/2;
blochTrans[qo*2] = q[qo*2 ] = norm*h[j+off];
blochTrans[qo*2+1] = q[qo*2+1] = norm*h[j+n+off];
}
FFT fft = new FFT(cellSampleCount);
fft.transform(q, true);
double km = 2*pi*k/cellSampleCount;
// I must have missed a sign somewhere; fix it so that waves
// are going in right direction
int fudge = ((band & 1) == 1) ? 1 : -1;
// multiply by the bloch wave to get the required state over
// multiple wells.
for (j = 0; j != sampleCount; j++) {
int ji = j % cellSampleCount;
double re = q[ji*2];
double im = q[ji*2+1];
double kr = Math.cos(j*km);
double ki = -Math.sin(j*km);
func[j] = re*kr - im*ki;
funci[j] = fudge*(re*ki + im*kr);
blochr[j] = re;
blochi[j] = fudge*im;
}
expecte = levels[band*2];
break;
}
return null;
}
public void mouseDragged(MouseEvent e) {
dragging = true;
edit(e);
}
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
dragX = x; dragY = y;
int oldCoef = selectedCoef;
int oldSelection = selection;
selectedCoef = -1;
selectedPaneHandle = -1;
selection = 0;
int i;
for (i = 1; i != viewCount; i++) {
int dy = y-viewList[i].handle;
if (dy >= -3 && dy <= 3) {
selectedPaneHandle = i;
selection = SEL_HANDLE;
}
}
Cursor cs = null;
if (selection == SEL_HANDLE)
cs = Cursor.getPredefinedCursor(N_RESIZE_CURSOR);
else if (viewX != null && viewX.contains(x, y))
selection = SEL_X;
else if (viewP != null && viewP.contains(x, y)) {
selection = SEL_P;
cv.repaint(pause);
} else if (viewPotential != null && viewPotential.contains(x, y)) {
selection = SEL_POTENTIAL;
} else if (viewDispersion != null && viewDispersion.contains(x, y)) {
selection = SEL_DISPERSION;
}
cv.setCursor(cs);
if (selection != oldSelection || selectedCoef != oldCoef)
cv.repaint(pause);
}
void selectStateByEnergy(int y) {
int band = 0;
double besty = 1000;
int i, j;
double k = 0;
for (i = 0; i != dispersion.length; i++)
for (j = 0; j != dispersion[0].length; j++) {
double ye = getEnergyY(dispersion[i][j], viewPotential);
// subtract out the energy to break ties
ye -= dispersion[i][j]*1e-8;
double yd = Math.abs(y-ye);
if (yd < besty) {
besty = yd;
band = i;
k = j*.5/(dispersion[0].length-1);
}
}
select(k, band);
}
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2 && selectedCoef != -1)
enterSelectedState();
}
void enterSelectedState() {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
if (!dragging) {
if (selectedCoef != -1) {
selectedCoef = -1;
cv.repaint(pause);
}
if (selectedPaneHandle != -1) {
selectedPaneHandle = -1;
cv.repaint(pause);
}
}
}
public void mousePressed(MouseEvent e) {
mouseMoved(e);
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
return;
dragging = true;
edit(e);
}
public void mouseReleased(MouseEvent e) {
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
return;
/*if (mouseChooser.getSelectedIndex() == MOUSE_EDIT &&
selection == SEL_POTENTIAL) {
adjustingStates = false;
statesChanged = true;
}*/
dragging = false;
cv.repaint(pause);
}
public void itemStateChanged(ItemEvent e) {
if (e.getItemSelectable() == stoppedCheck) {
cv.repaint(pause);
return;
}
if (e.getItemSelectable() == setupChooser)
doSetup();
if (e.getItemSelectable() instanceof CheckboxMenuItem) {
CheckboxMenuItem cmi = (CheckboxMenuItem) e.getItemSelectable();
if (!(cmi == extendedZonesItem ||
cmi == reducedZonesItem ||
cmi == repeatedZonesItem))
handleResize();
cv.repaint(pause);
}
int i;
doRadio(waveFunctionMenu, e);
doRadio(zoneMenu, e);
}
void doRadio(Menu menu, ItemEvent e) {
int i, j;
for (i = 0; i != menu.countItems(); i++)
if (e.getItemSelectable() == menu.getItem(i)) {
((CheckboxMenuItem) menu.getItem(i)).setState(true);
for (j = 0; j != menu.countItems(); j++)
if (i != j)
((CheckboxMenuItem) menu.getItem(j)).setState(false);
}
}
void doSetup() {
doBlank();
int i;
for (i = 0; i != potSampleCount; i++)
pot[i] = 0;
setup = (Setup)
setupList.elementAt(setupChooser.getSelectedIndex());
aux1Bar.setValue(100);
aux2Bar.setValue(100);
aux3Bar.setValue(100);
aux4Bar.setValue(100);
selectGround = true;
setup.select();
setup.drawPotential();
getPotTrans();
setupModified = false;
levelsChanged = true;
if (setup.getAuxBarCount() >= 2) {
aux2Label.show();
aux2Bar.show();
} else {
aux2Label.hide();
aux2Bar.hide();
}
if (setup.getAuxBarCount() >= 3) {
aux3Label.show();
aux3Bar.show();
} else {
aux3Label.hide();
aux3Bar.hide();
}
if (setup.getAuxBarCount() >= 4) {
aux4Label.show();
aux4Bar.show();
} else {
aux4Label.hide();
aux4Bar.hide();
}
validate();
selectedCoef = -1;
}
class FFT {
double wtabf[];
double wtabi[];
int size;
FFT(int sz) {
size = sz;
if ((size & (size-1)) != 0)
System.out.println("size must be power of two!");
calcWTable();
}
void calcWTable() {
// calculate table of powers of w
wtabf = new double[size];
wtabi = new double[size];
int i;
for (i = 0; i != size; i += 2) {
double pi = 3.1415926535;
double th = pi*i/size;
wtabf[i ] = Math.cos(th);
wtabf[i+1] = Math.sin(th);
wtabi[i ] = wtabf[i];
wtabi[i+1] = -wtabf[i+1];
}
}
void transform(double data[], boolean inv) {
int i;
int j = 0;
int size2 = size*2;
if ((size & (size-1)) != 0)
System.out.println("size must be power of two!");
// bit-reversal
double q;
int bit;
for (i = 0; i != size2; i += 2) {
if (i > j) {
q = data[i]; data[i] = data[j]; data[j] = q;
q = data[i+1]; data[i+1] = data[j+1]; data[j+1] = q;
}
// increment j by one, from the left side (bit-reversed)
bit = size;
while ((bit & j) != 0) {
j &= ~bit;
bit >>= 1;
}
j |= bit;
}
// amount to skip through w table
int tabskip = size << 1;
double wtab[] = (inv) ? wtabi : wtabf;
int skip1, skip2, ix, j2;
double wr, wi, d1r, d1i, d2r, d2i, d2wr, d2wi;
// unroll the first iteration of the main loop
for (i = 0; i != size2; i += 4) {
d1r = data[i];
d1i = data[i+1];
d2r = data[i+2];
d2i = data[i+3];
data[i ] = d1r+d2r;
data[i+1] = d1i+d2i;
data[i+2] = d1r-d2r;
data[i+3] = d1i-d2i;
}
tabskip >>= 1;
// unroll the second iteration of the main loop
int imult = (inv) ? -1 : 1;
for (i = 0; i != size2; i += 8) {
d1r = data[i];
d1i = data[i+1];
d2r = data[i+4];
d2i = data[i+5];
data[i ] = d1r+d2r;
data[i+1] = d1i+d2i;
data[i+4] = d1r-d2r;
data[i+5] = d1i-d2i;
d1r = data[i+2];
d1i = data[i+3];
d2r = data[i+6]*imult;
d2i = data[i+7]*imult;
data[i+2] = d1r-d2i;
data[i+3] = d1i+d2r;
data[i+6] = d1r+d2i;
data[i+7] = d1i-d2r;
}
tabskip >>= 1;
for (skip1 = 16; skip1 <= size2; skip1 <<= 1) {
// skip2 = length of subarrays we are combining
// skip1 = length of subarray after combination
skip2 = skip1 >> 1;
tabskip >>= 1;
for (i = 0; i != 1000; i++);
// for each subarray
for (i = 0; i < size2; i += skip1) {
ix = 0;
// for each pair of complex numbers (one in each subarray)
for (j = i; j != i+skip2; j += 2, ix += tabskip) {
wr = wtab[ix];
wi = wtab[ix+1];
d1r = data[j];
d1i = data[j+1];
j2 = j+skip2;
d2r = data[j2];
d2i = data[j2+1];
d2wr = d2r*wr - d2i*wi;
d2wi = d2r*wi + d2i*wr;
data[j] = d1r+d2wr;
data[j+1] = d1i+d2wi;
data[j2 ] = d1r-d2wr;
data[j2+1] = d1i-d2wi;
}
}
}
}
}
abstract class Setup {
abstract String getName();
abstract void select();
abstract Setup createNext();
void fudgeLevels() { }
boolean allowLeftRight() { return false; }
abstract void drawPotential();
int getAuxBarCount() { return 2; }
void getInfo(String s[], int offset) { }
double getBaseEnergy() { return -1; }
};
class FiniteWellSetup extends Setup {
String getName() { return "Finite Wells"; }
void select() {
aux1Label.setText("Well Width");
aux1Bar.setValue(98);
aux2Label.setText("Well Depth");
}
int getWidth() {
return (potSampleCount-1)*aux1Bar.getValue()/100;
}
double getTop() {
return -1+(aux2Bar.getValue()-1)/49.5;
}
void drawPotential() {
int i;
int width = getWidth();
double top = getTop();
for (i = 0; i != width; i++)
pot[i] = -1;
for (; i < potSampleCount; i++)
pot[i] = top;
}
/*
void getInfo(String s[], int o) {
s[o] = "Well width = " + getLengthText(potSampleCount-getOffset()*2);
s[o] += ", Well depth = " + getEnergyText(1-getFloor(), false);
}
*/
Setup createNext() { return new FiniteWellPairSetup(); }
}
class FiniteWellPairSetup extends Setup {
String getName() { return "Well Pairs"; }
void select() {
aux1Label.setText("Well Width");
aux2Bar.setValue(80);
aux2Label.setText("Well Separation");
aux2Bar.setValue(100);
aux3Label.setText("Well Depth 1");
aux3Bar.setValue(100);
aux4Label.setText("Well Depth 2");
aux4Bar.setValue(90);
}
int getAuxBarCount() { return 4; }
int getWidth() {
return (aux1Bar.getValue()*3/4)*(potSampleCount/2)/110+1;
}
void drawPotential() {
int i;
int width = getWidth();
// min sep = 1+width; max sep = potSampleCount/2
double sepFrac = aux2Bar.getValue()/100.;
int sep = (int) ((1+width)*(1-sepFrac) + (potSampleCount/2)*sepFrac);
double level1 = 1-aux3Bar.getValue()/50.;
double level2 = 1-aux4Bar.getValue()/50.;
double top = 1;
double space = level1 < level2 ? (level1+1) : (level2+1);
top -= space;
level1 -= space;
level2 -= space;
for (i = 0; i != potSampleCount; i++)
pot[i] = top;
for (i = 0; i != width; i++) {
pot[i] = level1;
pot[i+sep] = level2;
}
}
/*void getInfo(String s[], int o) {
s[o] = "Well width = " + getLengthText(getWidth());
s[o] += ", Well depth = " + getEnergyText(1-getFloor(), false);
s[o+1] = "Well separation = " + getLengthText(getSep()*2);
}*/
Setup createNext() { return new FiniteWellPairCoupledSetup(); }
}
class FiniteWellPairCoupledSetup extends Setup {
String getName() { return "Coupled Well Pairs"; }
void select() {
aux1Label.setText("Well Separation");
aux1Bar.setValue(1);
aux2Label.setText("Wall Potential");
aux2Bar.setValue(50);
}
int getWidth() { return potSampleCount/4; }
double getWallEnergy() { return -1+(aux2Bar.getValue()-1)/50.; }
void drawPotential() {
int i;
int width = getWidth();
// min sep = 1+width; max sep = potSampleCount/2
double sepFrac = aux1Bar.getValue()/100.;
int sep = (int) ((1+width)*(1-sepFrac) + (potSampleCount/2)*sepFrac);
double floor = -1;
double infloor = -1+(aux2Bar.getValue()-1)/49.;
if (infloor > 1)
infloor = 1;
for (i = 0; i != potSampleCount; i++)
pot[i] = 1;
for (i = 0; i != width; i++)
pot[i] = pot[i+sep] = -1;
for (i = width; i != sep; i++)
pot[i] = infloor;
}
/*void getInfo(String s[], int o) {
s[o] = "Well width = " + getLengthText(getWidth());
s[o] += ", Well depth = " + getEnergyText(2, false);
s[o+1] = "Well separation = " + getLengthText(getSep()*2);
s[o+1] += ", Wall potential = " + getEnergyText(getWallEnergy(), true);
}*/
Setup createNext() { return new HarmonicWellSetup(); }
}
class HarmonicWellSetup extends Setup {
String getName() { return "Harmonic"; }
void select() {
aux1Label.setText("Well Width");
aux2Label.setText("Well Depth");
}
int getAuxBarCount() { return 2; }
double getFloor() { return 1-(aux2Bar.getValue())/50.; }
double getTop() { return -1+(aux2Bar.getValue())/50.; }
void drawPotential() {
int i;
double top = getTop();
int width = aux1Bar.getValue()*(potSampleCount-1)/100;
double a = (top+1)/((width/2)*(width/2.));
for (i = 0; i != width; i++) {
double xx = (i-width/2.);
pot[i] = -1+xx*xx*a;
if (pot[i] > top)
pot[i] = top;
}
for (; i < potSampleCount; i++)
pot[i] = top;
}
Setup createNext() { return new CoulombWellArraySetup(); }
}
class CoulombWellArraySetup extends Setup {
String getName() { return "Coulomb-Like"; }
void select() {
aux1Label.setText("Well Width");
aux1Bar.setValue(40);
}
int getAuxBarCount() { return 1; }
void drawPotential() {
int i;
double s = (aux1Bar.getValue())/200.;
int width = potSampleCount;
s *= width/2;
double a = -2*width*s/(2*s-width);
double b = 1+2*a/width;
double add = 1-(b-2*a/(width/2.));
b += add;
for (i = 0; i != potSampleCount; i++) {
double xx = (i-width/2.);
double xx2 = width-Math.abs(xx);
pot[i] = b-a/Math.abs(xx)-a/xx2;
if (pot[i] < -1)
pot[i] = -1;
}
}
Setup createNext() { return new FreeParticleSetup(); }
}
class FreeParticleSetup extends Setup {
String getName() { return "Free Particle"; }
void select() {}
int getAuxBarCount() { return 0; }
void drawPotential() {
int i;
for (i = 0; i != potSampleCount; i++)
pot[i] = -1;
}
Setup createNext() { return new SinusoidalLatticeSetup(); }
}
class SinusoidalLatticeSetup extends Setup {
String getName() { return "Sinusoidal"; }
void select() {
aux1Label.setText("Well Depth");
}
int getAuxBarCount() { return 1; }
void drawPotential() {
double amp = aux1Bar.getValue()/100.;
int buf = potSampleCount/10;
int i;
for (i = 0; i != potSampleCount; i++) {
double xx = i*2*pi/potSampleCount;
pot[i] = -1+amp*(1-Math.cos(xx));
}
}
Setup createNext() { return null; }
}
class View extends Rectangle {
int mid_y, lower_y, handle;
double ymult, ymult2, scale;
int cellw2;
void drawLabel(Graphics g, String str) {
g.setColor(Color.white);
centerString(g, str, y-5);
}
}
};
interface DecentScrollbarListener {
abstract void scrollbarValueChanged(DecentScrollbar ds);
abstract void scrollbarFinished(DecentScrollbar dc);
}
// this is a scrollbar that notifies us when the user is _done_ fiddling
// with the value.
class DecentScrollbar extends Canvas
implements MouseListener, MouseMotionListener {
int value, lo, hi;
DecentScrollbarListener listener;
DecentScrollbar(DecentScrollbarListener parent,
int start, int lo_, int hi_) {
value = start;
lo = lo_;
hi = hi_;
listener = parent;
addMouseListener(this);
addMouseMotionListener(this);
gray1 = new Color(104, 104, 104);
gray2 = new Color(168, 168, 168);
gray3 = new Color(192, 192, 192);
gray4 = new Color(224, 224, 224);
}
Color gray1, gray2, gray3, gray4;
public Dimension getPreferredSize() {
return new Dimension(20,20);
}
static final int tw = 8;
boolean dragging;
int thumbpos, dragoffset;
public void paint(Graphics g) {
Dimension size = getSize();
int w = size.width;
int h = size.height;
int x = thumbpos = (value-lo)*(w-2-tw)/(hi-lo)+1;
g.setColor(gray2);
g.fillRect(0, 0, w, h);
g.setColor(gray3);
g.fillRect(x, 2, tw, h-4);
g.setColor(gray4);
g.drawLine(0, h-1, w, h-1);
g.drawLine(w-1, 1, w-1, h-1);
g.drawLine(x, 1, x+tw-1, 1);
g.drawLine(x, 1, x, h-2);
g.setColor(gray1);
g.drawLine(0, 0, w-1, 0);
g.drawLine(0, 0, 0, h-1);
g.drawLine(x+tw-1, 2, x+tw-1, h-2);
g.drawLine(x+1, h-2, x+tw-1, h-2);
}
int getValue() { return value; }
boolean setValue(int v) {
if (v < lo)
v = lo;
if (v > hi)
v = hi;
if (value == v)
return false;
value = v;
repaint();
return true;
}
public void mousePressed(MouseEvent e) {
if (thumbpos <= e.getX() && thumbpos+tw >= e.getX()) {
dragging = true;
dragoffset = e.getX()-thumbpos;
}
}
public void mouseReleased(MouseEvent e) {
if (dragging)
listener.scrollbarFinished(this);
dragging = false;
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
if (!dragging)
return;
int x = e.getX()-dragoffset;
Dimension size = getSize();
int v = (x-1)*(hi-lo)/(size.width-2-tw)+lo;
if (setValue(v))
listener.scrollbarValueChanged(this);
}
public void mouseMoved(MouseEvent e) {
}
};
A far higher place must be assigned to Judaism among the competitors for the allegiance of Europe. The cosmopolitan importance at one time assumed by this religion has been considerably obscured, owing to the subsequent devolution of its part to Christianity. It is, however, by no means impossible that, but for the diversion created by the Gospel, and the disastrous consequences of their revolt against Rome, the Jews might have won the world to a purified form of their own monotheism. A few significant circumstances are recorded showing how much influence they had acquired, even in Rome, before the first preaching of Christianity. The first of these is to be found in Cicero¡¯s defence of Flaccus. The latter was accused of appropriating part of the annual contributions sent to the temple at Jerusalem; and, in dealing with this charge, Cicero speaks of the Jews, who were naturally prejudiced against his client, as a powerful faction the hostility of which he is anxious not to provoke.330 Some twenty years later, a great advance has been made. Not only must the material interests of the Jews be respected, but a certain conformity to their religious prescriptions is considered a mark of good breeding, In one of his most amusing satires, Horace tells us how, being anxious to shake off a bore, he appeals for help to his friend Aristius Fuscus, and reminds him of217 some private business which they had to discuss together. Fuscus sees his object, and being mischievously determined to defeat it, answers: ¡®Yes, I remember perfectly, but we must wait for some better opportunity; this is the thirtieth Sabbath, do you wish to insult the circumcised Jews?¡¯ ¡®I have no scruples on that point,¡® replies the impatient poet. ¡®But I have,¡¯ rejoins Fuscus,¡ª¡®a little weak-minded, one of the many, you know¡ªexcuse me, another time.¡®331 Nor were the Jews content with the countenance thus freely accorded them. The same poet elsewhere intimates that whenever they found themselves in a majority, they took advantage of their superior strength to make proselytes by force.¡¯332 And they pursued the good work to such purpose that a couple of generations later we find Seneca bitterly complaining that the vanquished had given laws to the victors, and that the customs of this abominable race were established over the whole earth.333 Evidence to the same effect is given by Philo Judaeus and Josephus, who inform us that the Jewish laws and customs were admired, imitated, and obeyed over the whole earth.334 Such assertions might be suspected of exaggeration, were they not, to a certain extent, confirmed by the references already quoted, to which others of the same kind may be added from later writers showing that it was a common practice among the Romans to abstain from work on the Sabbath, and even to celebrate it by praying, fasting, and lighting lamps, to visit the synagogues, to study the law of Moses, and to pay the yearly contribution of two drachmas to the temple at Jerusalem.335 Jeff¡¯s hand was quietly coming down. ¡°What happened to you?¡± begged Sandy. ¡°Something new has come up, sir. I was waiting there by my ship a good while back, and I heard another one cruising and spiraling, shooting the field, I guess, because he came in and set down. My crate, just the way you ordered, was down by the grove, not in plain sight in the middle of the course. But Jeff set his ship down, left the engine running, and went off. I stayed hid to see what would happen, but when he didn¡¯t come back, I thought I¡¯d better go and find you¡ªand see if it meant anything to you.¡± She stood alone, with the sticky, wet knife in her hand, catching her breath, coming out of the madness. Then she stooped, and pushing the branches aside felt about for her pistol. It lay at the root of a tree, and[Pg 80] when she had picked it up and put it back in the holster, there occurred to her for the first time the thought that the shot in the dead stillness must have roused the camp. And now she was sincerely frightened. If she were found here, it would be more than disagreeable for Landor. They must not find her. She started at a swift, long-limbed run, making a wide detour, to avoid the sentries, bending low, and flying silently among the bushes and across the shadowy sands. The year 1756 opened with menaces to England of the most serious nature. The imbecility of the Ministry was beginning to tell in the neglect of its colonies and its defences. France threatened to invade us, and a navy of fifty thousand men was suddenly voted, and an army of thirty-four thousand two hundred and sixty-three of native troops; but as these were not ready, it was agreed to bring over eight thousand Hessians and Hanoverians. To pay for all this it was necessary to grant excessive supplies, and lay on new duties and taxes. In presenting the money bills in the month of May, Speaker Onslow could not avoid remarking that there were two circumstances which tended to create alarm¡ªforeign subsidies and foreign troops introduced, and nothing but their confidence in his Majesty could allay their fears, or give them confidence that their burdens would be soon reduced. There was, in fact, no chance for any such reduction, for wars, troubles, and disgraces were gathering around from various quarters. The first reverse came from the Mediterranean. MUCH to their amazement, the boys waked up the next morning in Nashville, and found that they had passed through the "dark and bloody ground" of Kentucky absolutely without adventure. After drawing and dividing the rations and cartridges. Si gave the boys the necessary instruction about having their things ready so that they could get them in the dark the next morning, and ordered them to disregard the bonfires and mirth-making, and lie down to get all the sleep they could, in preparation for the hard work of the next day. Then, like the rest of the experienced men, who saw that the campaign was at length really on, and this would be the last opportunity for an indefinite while to write, he sat down to write short letters to his mother and to Annabel. "Bully for the Wild Wanderers of the Wabash," Shorty joined in. "They're the boss regiment in the army o' the Cumberland, and the Army o' the Cumberland's the boss army on earth. Hooray for US Co. Le's have a speech. Where's Monty Scruggs?" "Bring a light, do¡ªI can't abide this dark." Albert suddenly began to look uneasy. After all he was not really drunk, only a little fuddled. He walked straight, and his roll was natural to him, while though he was exceedingly cheerful, and often burst into song, his words were not jumbled, and he generally seemed to have a fair idea of what he was saying. "But I heard what the doctor said to you." "A purty accident¡ªwud them stacks no more dry than a ditch. 'Twas a clear case of 'bustion¡ªfireman said so to me; as wicked and tedious a bit o' wark as ever I met in my life." Calverley stept from the shadow of the cliff, and beheld a meteor in the sky, brightening and expanding, as the clouds opened, until it assumed the appearance of a brilliant star, of astonishing magnitude, encircled by dazzling rays, which, in a singular manner, were all inclined in one direction, and pointing to that part of the horizon where lay the rival of England¡ªFrance. The foreman's face assumed a deeper hue than usual: he looked fiercely at the galleyman, but there was a determination in the weather-beaten face that made him pause ere he spoke. "Galleyman," he at length said, "you knew the business before you came: if you be so fond of saving old witches' lives, why didn't you say so, that I might not now be in this dilemma?" "No, no, not the boy," replied Merritt, rather impatiently. HoMEÁíÀàС˵ߣɫ
ENTER NUMBET 0017
www.shakeng.com.cn
www.dutu1.com.cn
xuer7.net.cn
art170.com.cn
www.tiyue0.net.cn
manme8.net.cn
yinzi7.com.cn
1to1liao.org.cn
www.apeiguan.com.cn
lajin2.com.cn