// QuantumCirc.java (C) 2001 by Paul Falstad, www.falstad.com import java.io.InputStream; import java.awt.*; import java.awt.image.ImageProducer; import java.applet.Applet; import java.applet.AudioClip; import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration; import java.io.File; import java.net.URL; import java.util.Random; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.awt.image.*; import java.lang.Math; import java.awt.event.*; class QuantumCircCanvas extends Canvas { QuantumCircFrame pg; QuantumCircCanvas(QuantumCircFrame p) { pg = p; } public Dimension getPreferredSize() { return new Dimension(300,400); } public void update(Graphics g) { pg.updateQuantumCirc(g); } public void paint(Graphics g) { pg.updateQuantumCirc(g); } }; class QuantumCircLayout implements LayoutManager { public QuantumCircLayout() {} 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) { Insets insets = target.insets(); int targetw = target.size().width - insets.left - insets.right; int cw = targetw* 7/10; int targeth = target.size().height - (insets.top+insets.bottom); target.getComponent(0).move(insets.left, insets.top); target.getComponent(0).resize(cw, targeth); int barwidth = targetw - cw; cw += insets.left; int i; 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) d.width = barwidth; if (m instanceof Choice) 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 QuantumCirc extends Applet implements ComponentListener { static QuantumCircFrame ogf; void destroyFrame() { if (ogf != null) ogf.dispose(); ogf = null; repaint(); } boolean started = false; public void init() { addComponentListener(this); } public static void main(String args[]) { ogf = new QuantumCircFrame(null); ogf.init(); } void showFrame() { if (ogf == null) { started = true; ogf = new QuantumCircFrame(this); ogf.init(); repaint(); } } public void paint(Graphics g) { String s = "Applet is open in a separate window."; if (!started) s = "Applet is starting."; else if (ogf == null) s = "Applet is finished."; else ogf.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 (ogf != null) ogf.dispose(); ogf = null; repaint(); } }; class QuantumCircFrame extends Frame implements ComponentListener, ActionListener, AdjustmentListener, MouseMotionListener, MouseListener, ItemListener { Thread engine = null; Dimension winSize; Image dbimage; Random random; int maxSampleCount = 70; int maxDispPhasorsR = 10; int maxDispPhasorsTh = 21; int sampleCountR, sampleCountTh; int modeCountR, modeCountTh, modeCountM; FFT fftTh; public static final double epsilon = .00001; public static final double epsilon2 = .003; static final int panePad = 4; public String getAppletInfo() { return "QuantumCirc Series by Paul Falstad"; } Button groundButton; Button blankButton; Button normalizeButton; Button maximizeButton; Checkbox stoppedCheck; CheckboxMenuItem eCheckItem; CheckboxMenuItem xCheckItem; CheckboxMenuItem pCheckItem; CheckboxMenuItem lCheckItem; CheckboxMenuItem statesCheckItem; CheckboxMenuItem expectCheckItem; CheckboxMenuItem uncertaintyCheckItem; CheckboxMenuItem probCheckItem; CheckboxMenuItem probPhaseCheckItem; CheckboxMenuItem magPhaseCheckItem; CheckboxMenuItem alwaysNormItem; CheckboxMenuItem alwaysMaxItem; Menu waveFunctionMenu; MenuItem measureEItem; MenuItem measureLItem; MenuItem exitItem; Choice mouseChooser; Checkbox colorCheck; Scrollbar brightnessBar; Scrollbar speedBar; Scrollbar forceBar; Scrollbar resBar; Scrollbar phasorBar; Scrollbar pZoomBar; int pZoomBarValue; View viewPotential, viewX, viewP, viewStates, viewXMap, viewPMap, viewStatesMap, viewL; View viewList[]; int viewCount; boolean editingFunc; boolean dragStop; double magcoef[][]; double phasecoef[][]; double phasecoefcos[][]; double phasecoefsin[][]; double phasecoefadj[][]; double angle1SinTab[]; double angle1CosTab[]; double angle2SinTab[]; double angle2CosTab[]; double elevels[][]; double xformbuf[]; double lzspectrum[]; static final double pi = 3.14159265358979323846; double step; double func[][]; double funci[][]; double pfunc[][]; double pfunci[][]; PhaseColor phaseColors[][]; PhaseColor whitePhaseColor; Color grayLevels[]; static final int phaseColorCount = 50; int xpoints[]; int ypoints[]; int floorValues[]; double xStates[][][]; double pStates[][][]; int selectedCoefX, selectedCoefY; double selectedGridX, selectedGridY; int selectedPaneHandle; static final int SEL_NONE = 0; static final int SEL_POTENTIAL = 1; static final int SEL_X = 2; static final int SEL_STATES = 3; static final int SEL_L = 4; static final int SEL_HANDLE = 5; static final int MOUSE_GAUSS = 0; static final int MOUSE_GAUSSP = 1; static final int MOUSE_ROTATE = 2; int selection; int dragX, dragY; int dragStartX, dragStartY; boolean dragSet, dragClear; double viewZoom = 1, viewZoomDragStart; double scaleHeight = 6; double viewHeight = -14, viewHeightDragStart; double viewDistance; double magDragStart; boolean dragging; double t; int pause; double scalex, scaley; int centerX3d; int centerY3d; double topz = 3; double brightmult; int getrand(int x) { int q = random.nextInt(); if (q < 0) q = -q; return q % x; } QuantumCircCanvas cv; QuantumCirc applet; QuantumCircFrame(QuantumCirc a) { super("Quantum Circular Box Applet v1.5a"); applet = a; } boolean useBufferedImage = false; public void init() { String jv = System.getProperty("java.class.version"); double jvf = new Double(jv).doubleValue(); if (jvf >= 48) useBufferedImage = true; selectedCoefX = selectedCoefY = -1; setLayout(new QuantumCircLayout()); cv = new QuantumCircCanvas(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); xCheckItem.disable(); m.add(pCheckItem = getCheckItem("Linear Momentum")); m.add(lCheckItem = getCheckItem("Angular Momentum")); m.add(statesCheckItem = getCheckItem("State Phasors")); statesCheckItem.setState(true); m.addSeparator(); m.add(expectCheckItem = getCheckItem("Expectation Values")); m.add(uncertaintyCheckItem = getCheckItem("Uncertainties")); Menu m2 = waveFunctionMenu = new Menu("Wave Function"); m.add(m2); m2.add(probCheckItem = getCheckItem("Probability")); m2.add(probPhaseCheckItem = getCheckItem("Probability + Phase")); m2.add(magPhaseCheckItem = getCheckItem("Magnitude + Phase")); magPhaseCheckItem.setState(true); m = new Menu("Measure"); mb.add(m); m.add(measureEItem = getMenuItem("Measure Energy")); m.add(measureLItem = getMenuItem("Measure Angular Momentum")); setMenuBar(mb); m = new Menu("Options"); mb.add(m); m.add(alwaysNormItem = getCheckItem("Always Normalize")); m.add(alwaysMaxItem = getCheckItem("Always Maximize")); alwaysMaxItem.setState(true); setMenuBar(mb); mouseChooser = new Choice(); mouseChooser.add("Mouse = Create Gaussian"); mouseChooser.add("Mouse = Gaussian w/ Momentum"); mouseChooser.add("Mouse = Rotate Function"); mouseChooser.addItemListener(this); add(mouseChooser); mouseChooser.select(MOUSE_GAUSS); add(blankButton = new Button("Clear")); blankButton.addActionListener(this); add(normalizeButton = new Button("Normalize")); normalizeButton.addActionListener(this); add(maximizeButton = new Button("Maximize")); maximizeButton.addActionListener(this); 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 Scrollbar(Scrollbar.HORIZONTAL, 105, 1, 1, 300)); speedBar.addAdjustmentListener(this); add(new Label("Brightness", Label.CENTER)); add(brightnessBar = new Scrollbar(Scrollbar.HORIZONTAL, 980, 1, 700, 2000)); brightnessBar.addAdjustmentListener(this); add(new Label("Resolution", Label.CENTER)); add(resBar = new Scrollbar(Scrollbar.HORIZONTAL, 16, 1, 2, maxSampleCount/2)); resBar.addAdjustmentListener(this); add(new Label("Momentum Zoom", Label.CENTER)); add(pZoomBar = new Scrollbar(Scrollbar.HORIZONTAL, 166, 1, 45, 260)); pZoomBar.addAdjustmentListener(this); add(new Label("Phasor Count", Label.CENTER)); add(phasorBar = new Scrollbar(Scrollbar.HORIZONTAL, 10, 1, 5, maxSampleCount/2)); phasorBar.addAdjustmentListener(this); setResolution(); try { String param = applet.getParameter("PAUSE"); if (param != null) pause = Integer.parseInt(param); } catch (Exception e) { } int i, j; phaseColors = new PhaseColor[8][phaseColorCount+1]; for (i = 0; i != 8; i++) for (j = 0; j <= phaseColorCount; j++) { double ang = java.lang.Math.atan(j/(double) phaseColorCount); phaseColors[i][j] = genPhaseColor(i, ang); } whitePhaseColor = new PhaseColor(1, 1, 1); grayLevels = new Color[256]; for (i = 0; i != 256; i++) grayLevels[i] = new Color(i, i, i); random = new Random(); reinit(); cv.setBackground(Color.black); cv.setForeground(Color.lightGray); resize(640, 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; } PhaseColor genPhaseColor(int sec, double ang) { // convert to 0 .. 2*pi angle ang += sec*pi/4; // convert to 0 .. 6 ang *= 3/pi; int hsec = (int) ang; double a2 = ang % 1; double a3 = 1.-a2; PhaseColor c = null; switch (hsec) { case 6: case 0: c = new PhaseColor(1, a2, 0); break; case 1: c = new PhaseColor(a3, 1, 0); break; case 2: c = new PhaseColor(0, 1, a2); break; case 3: c = new PhaseColor(0, a3, 1); break; case 4: c = new PhaseColor(a2, 0, 1); break; case 5: c = new PhaseColor(1, 0, a3); break; } return c; } void reinit() { doBlank(); magcoef[1][0] = 1; } void handleResize() { Dimension d = winSize = cv.getSize(); if (winSize.width == 0) return; dbimage = createImage(d.width, d.height); setupDisplay(); } void setupDisplay() { if (winSize == null) return; int potsize = (viewPotential == null) ? 50 : viewPotential.height; int statesize = (viewStates == null) ? 150 : viewStates.height; viewX = viewL = viewP = viewPotential = viewStates = null; viewList = new View[10]; int i = 0; if (eCheckItem.getState()) viewList[i++] = viewPotential = new View(); if (xCheckItem.getState()) viewList[i++] = viewX = new View(); if (pCheckItem.getState()) viewList[i++] = viewP = new View(); if (lCheckItem.getState()) viewList[i++] = viewL = new View(); if (statesCheckItem.getState()) viewList[i++] = viewStates = 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 (statesize > 0 && viewStates != null) { sizenum--; toth -= statesize; } toth -= panePad*2*(viewCount-1); 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 == viewStates && statesize > 0) h = statesize; v.paneY = cury; if (cury > 0) cury += panePad; v.x = 0; v.width = winSize.width; v.y = cury; v.height = h; cury += h+panePad; } setSubViews(); } void setSubViews() { viewXMap = null; viewStatesMap = null; if (viewStates != null) { viewStatesMap = new View(viewStates); double a = viewStates.width / (double) viewStates.height; double a2 = modeCountTh / (double) modeCountR; int w, h; if (a2 > a) w = viewStates.width-2; else w = (int) ((viewStates.height-2)*a2); viewStatesMap.x += (viewStatesMap.width -w)/2 + 1; viewStatesMap.width = w; } if (viewX != null) { viewXMap = new View(viewX); processMap(viewXMap); } if (viewP != null) { viewPMap = new View(viewP); processMap(viewPMap); } if (viewL != null) { View v = viewL; 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; } floorValues = null; } void processMap(View v) { double a = v.width / (double) v.height; int w, h; if (1 > a) w = h = v.width-2; else w = h = v.height-2; v.x += (v.width -w)/2 + 1; v.y += (v.height-h)/2 + 1; v.width = w; v.height = h; if (useBufferedImage) { try { /* simulate the following code using reflection: dbimage = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_RGB); DataBuffer db = (DataBuffer)(((BufferedImage)memimage). getRaster().getDataBuffer()); DataBufferInt dbi = (DataBufferInt) db; pixels = dbi.getData(); */ Class biclass = Class.forName("java.awt.image.BufferedImage"); Class dbiclass = Class.forName("java.awt.image.DataBufferInt"); Class rasclass = Class.forName("java.awt.image.Raster"); Constructor cstr = biclass.getConstructor( new Class[] { int.class, int.class, int.class }); v.memimage = (Image) cstr.newInstance(new Object[] { new Integer(v.width), new Integer(v.height), new Integer(1)}); // BufferedImage.TYPE_INT_RGB)}); Method m = biclass.getMethod("getRaster", null); Object ras = m.invoke(v.memimage, null); Object db = rasclass.getMethod("getDataBuffer", null). invoke(ras, null); v.pixels = (int[]) dbiclass.getMethod("getData", null).invoke(db, null); } catch (Exception ee) { // ee.printStackTrace(); System.out.println("BufferedImage failed"); } } if (v.pixels == null) { v.pixels = new int[v.width*v.height]; int i; for (i = 0; i != v.width*v.height; i++) v.pixels[i] = 0xFF000000; v.imageSource = new MemoryImageSource(v.width, v.height, v.pixels, 0, v.width); v.imageSource.setAnimated(true); v.imageSource.setFullBufferUpdates(true); v.memimage = cv.createImage(v.imageSource); } } int min(int x, int y) { return (x < y) ? x : y; } /*if (viewFreq != null) { viewFreq.x = (winSize.width-viewFreq.height)/2; viewFreq.width -= viewFreq.x*2; int tw = getTermWidth(); int h = tw*(modeCountR+1); int pad = viewFreq.height-h; if (pad > 0) { viewFreq.y += pad; viewFreq.height -= pad; if (view3d != null) view3d.height += pad; if (view2d != null) view2d.height += pad; } }*/ void doGround() { doBlank(); magcoef[0][0] = 1; t = 0; } void normalize() { double norm = 0; int i, j; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) norm += magcoef[i][j]*magcoef[i][j]; if (norm == 0) return; double normmult = 1/java.lang.Math.sqrt(norm); for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) magcoef[i][j] *= normmult; cv.repaint(pause); } void maximize() { int i, j; double maxm = 0; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) if (java.lang.Math.abs(magcoef[i][j]) > maxm) maxm = java.lang.Math.abs(magcoef[i][j]); if (maxm == 0) return; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) magcoef[i][j] *= 1/maxm; cv.repaint(pause); } void measureE() { normalize(); double n = random.nextDouble(); int i = 0, j = 0; int picki = -1; int pickj = -1; for (i = 0; i < modeCountTh; i++) for (j = 0; j < modeCountR; j++) { double m = magcoef[i][j]*magcoef[i][j]; n -= m; if (n < 0) { picki = i; pickj = j; i = j = 10000; break; } } if (picki == -1) return; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) if (elevels[i][j] != elevels[picki][pickj]) magcoef[i][j] = 0; if (alwaysNormItem.getState()) normalize(); else maximize(); } final int lspacing = 3; void calcLSpectrum() { int lzcount = modeCountTh*lspacing; if (lzspectrum == null) lzspectrum = new double[lzcount]; int i, j; for (i = 0; i != lzcount; i++) lzspectrum[i] = 0; int lc = (lzcount/2); for (i = 0; i != modeCountTh; i++) { int m = ((i % 2) == 0) ? (i/2*lspacing+lc) : (lc-lspacing*(i+1)/2); for (j = 0; j != modeCountR; j++) lzspectrum[m] += magcoef[i][j]*magcoef[i][j]; } } void measureL() { normalize(); calcLSpectrum(); double n = random.nextDouble(); int i = 0; int picki = -1; int lzcount = modeCountTh*lspacing; for (i = 0; i != lzcount; i++) { double m = lzspectrum[i]; n -= m; if (n < 0) { picki = i; i = lzcount; break; } } if (picki == -1) return; int lc = (lzcount/2); int j; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) { int m = ((i % 2) == 0) ? (i/2*lspacing+lc) : (lc-lspacing*(i+1)/2); if (m != picki) magcoef[i][j] = 0; } if (alwaysNormItem.getState()) normalize(); else maximize(); } void doBlank() { int x, y; for (x = 0; x != modeCountTh; x++) for (y = 0; y != modeCountR; y++) magcoef[x][y] = 0; } int getPanelHeight() { return winSize.height / 3; } 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 updateQuantumCirc(Graphics realg) { Graphics g = dbimage.getGraphics(); if (winSize == null || winSize.width == 0 || dbimage == null) return; boolean allQuiet = true; if (!stoppedCheck.getState() && !dragging) { int val = speedBar.getValue(); double tadd = java.lang.Math.exp(val/20.)*(.1/5); long sysTime = System.currentTimeMillis(); if (lastTime == 0) lastTime = sysTime; tadd *= (sysTime-lastTime)*(1/170.); t += tadd; 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, j; for (i = 1; i != viewCount; i++) { g.setColor(i == selectedPaneHandle ? Color.yellow : Color.gray); g.drawLine(0, viewList[i].paneY, winSize.width, viewList[i].paneY); } int x, y; if (dragStop) t = 0; double norm = 0; double normmult = 0, normmult2 = 0; if (!editingFunc) { // update phases for (i = 0; i != modeCountTh; i++) { for (j = 0; j != modeCountR; j++) { if (magcoef[i][j] < epsilon && magcoef[i][j] > -epsilon) { magcoef[i][j] = phasecoef[i][j] = phasecoefadj[i][j] = 0; continue; } allQuiet = false; phasecoef[i][j] = (-elevels[i][j]*t+phasecoefadj[i][j]) % (2*pi); phasecoefcos[i][j] = java.lang.Math.cos(phasecoef[i][j]); phasecoefsin[i][j] = java.lang.Math.sin(phasecoef[i][j]); norm += magcoef[i][j]*magcoef[i][j]; } } normmult2 = 1/norm; if (norm == 0) normmult2 = 0; normmult = java.lang.Math.sqrt(normmult2); genFunc(normmult, true); } brightmult = java.lang.Math.exp(brightnessBar.getValue()/200.-5); if (norm == 0) normmult = normmult2 = 0; int half = sampleCountTh/2; xpoints = new int[4]; ypoints = new int[4]; if (viewPotential != null) { int floory = viewPotential.y + viewPotential.height - 5; double ymult = 200; if (floorValues == null) floorValues = new int[floory+1]; for (i = 0; i <= floory; i++) floorValues[i] = 0; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) { double dy = elevels[i][j]; double m = magcoef[i][j]*magcoef[i][j]; int mc = (int) ((256-32)*m)+1; y = floory - (int) (ymult * dy); if (y >= 0 && y <= floory) floorValues[y] += mc; } for (i = 0; i <= floory; i++) { if (floorValues[i] == 0) continue; int mc = floorValues[i]+32; if (mc > 255) mc = 255; g.setColor(grayLevels[mc]); g.drawLine(0, i, winSize.width, i); } g.setColor(Color.white); g.drawLine(viewXMap.x, 0, viewXMap.x, floory); int x0 = viewXMap.x+viewXMap.width; g.drawLine(x0, 0, x0, floory); g.drawLine(viewXMap.x, floory, x0, floory); // calculate expectation value of E if (norm != 0 && (expectCheckItem.getState() || uncertaintyCheckItem.getState())) { double expecte = 0; double expecte2 = 0; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) { double prob = magcoef[i][j]*magcoef[i][j]*normmult2; expecte += prob*elevels[i][j]; expecte2 += prob*elevels[i][j]*elevels[i][j]; } double uncert = java.lang.Math.sqrt(expecte2-expecte*expecte); if (uncertaintyCheckItem.getState()) { if (!(uncert >= 0)) uncert = 0; g.setColor(Color.blue); y = floory - (int) (ymult * (expecte+uncert)); g.drawLine(0, y, winSize.width, y); y = floory - (int) (ymult * (expecte-uncert)); if (expecte-uncert >= 0) g.drawLine(0, y, winSize.width, y); } if (expectCheckItem.getState()) { y = floory - (int) (ymult * expecte); g.setColor(Color.red); g.drawLine(0, y, winSize.width, y); } } if (selectedCoefX != -1 && !dragging) { g.setColor(Color.yellow); y = floory - (int) (ymult * elevels[selectedCoefX][selectedCoefY]); g.drawLine(0, y, winSize.width, y); } } if (viewX != null) drawRadial(g, viewXMap, func, funci); if (viewP != null) { genFunc(normmult, false); drawRadial(g, viewPMap, pfunc, pfunci); } if (viewL != null) { int lzcount = modeCountTh*lspacing; calcLSpectrum(); for (i = 0; i != lzcount; i++) lzspectrum[i] = java.lang.Math.sqrt(lzspectrum[i]); drawFunction(g, viewL, lzspectrum, null, lzcount, 0); } if (viewStatesMap != null) { // draw frequency grid int termWidth = getTermWidth(); int stateSize = termWidth; int ss2 = termWidth/2; for (i = 0; i < modeCountTh && i < maxDispPhasorsTh; i++) for (j = 0; j < modeCountR && j < maxDispPhasorsR; j++) { x = viewStatesMap.x + i*termWidth + ss2; y = viewStatesMap.y + j*termWidth + ss2; boolean yel = (selectedCoefX != -1 && elevels[selectedCoefX][selectedCoefY] == elevels[i][j]); g.setColor(yel ? Color.yellow : (magcoef[i][j] == 0) ? gray2 : Color.white); g.drawOval(x-ss2, y-ss2, stateSize, stateSize); int xa = (int) (magcoef[i][j]*phasecoefcos[i][j]*ss2); int ya = (int) (-magcoef[i][j]*phasecoefsin[i][j]*ss2); g.drawLine(x, y, x+xa, y+ya); g.drawLine(x+xa-1, y+ya, x+xa+1, y+ya); g.drawLine(x+xa, y+ya-1, x+xa, y+ya+1); } g.setColor(Color.white); } if (selectedCoefX != -1) { g.setColor(Color.yellow); int m = (selectedCoefX+1)/2; if ((selectedCoefX & 1) != 0) m = -m; if (viewStatesMap != null && viewX != null) centerString(g, "nr = " + selectedCoefY + ", m = " + m, viewX.y+viewX.height-10); if (viewL != null) { int lzcount = modeCountTh*lspacing; // XXX int mx = m * lspacing + lzcount/2; x = viewL.width*mx/(lzcount-1); g.drawLine(x, viewL.y, x, viewL.y+viewL.height); } } realg.drawImage(dbimage, 0, 0, this); if (dragStop) allQuiet = true; if (!stoppedCheck.getState() && !allQuiet) cv.repaint(pause); } void drawRadial(Graphics g, View view, double fr[][], double fi[][]) { int rcol = 0x00010000; int gcol = 0x00000100; int cx = view.width/2; int cy = view.height/2; int cr = view.width/2; int x, y; double mx = 0; double expectx = 0, expectx2 = 0; double expecty = 0, expecty2 = 0; double tot = 0; for (y = 0; y <= sampleCountR; y++) { for (x = 0; x != sampleCountTh; x++) { double ar = fr[x][y]; double ai = fi[x][y]; double fv = (ar*ar+ai*ai); double xv = y*angle1CosTab[x]; double yv = y*angle1SinTab[x]; expectx += fv*y*xv; expecty += fv*y*yv; expectx2 += fv*y*xv*xv; expecty2 += fv*y*yv*yv; tot += fv*y; if (magPhaseCheckItem.getState()) fv = java.lang.Math.sqrt(fv); if (fv > mx) mx = fv; } } expectx /= tot; expecty /= tot; expectx2 /= tot; expecty2 /= tot; double mult = 255*brightmult/mx; double rscale = -cr/(double) sampleCountR; for (y = 0; y != sampleCountR; y++) { double r1 = rscale*y; double r2 = rscale*(y+1); xpoints[0] = (int) (cx+r1); ypoints[0] = cy; xpoints[3] = (int) (cx+r2); ypoints[3] = cy; for (x = 0; x != sampleCountTh; x++) { double ar = fr[x][y]; double ai = fi[x][y]; double fv = (ar*ar+ai*ai); if (magPhaseCheckItem.getState()) fv = java.lang.Math.sqrt(fv); fv *= mult; PhaseColor c = getPhaseColor(ar, ai); if (fv > 255) fv = 255; int clr = (int) (c.r * fv); int clg = (int) (c.g * fv); int clb = (int) (c.b * fv); int col = (255<<24) | (clr<<16) | (clg<<8) | clb; g.setColor(new Color(col)); xpoints[1] = (int) (cx+r1*angle2CosTab[x]); ypoints[1] = (int) (cy-r1*angle2SinTab[x]); xpoints[2] = (int) (cx+r2*angle2CosTab[x]); ypoints[2] = (int) (cy-r2*angle2SinTab[x]); fillTriangle(view, xpoints[0], ypoints[0], xpoints[1], ypoints[1], xpoints[2], ypoints[2], col); fillTriangle(view, xpoints[0], ypoints[0], xpoints[2], ypoints[2], xpoints[3], ypoints[3], col); xpoints[0] = xpoints[1]; ypoints[0] = ypoints[1]; xpoints[3] = xpoints[2]; ypoints[3] = ypoints[2]; } } if (view.imageSource != null) view.imageSource.newPixels(); g.drawImage(view.memimage, view.x, view.y, null); cx += view.x; cy += view.y; if (expectCheckItem.getState()) { x = (int) (cx+expectx*rscale); y = (int) (cy-expecty*rscale); g.setColor(Color.red); g.drawLine(x, view.y, x, view.y+view.height); g.drawLine(view.x, y, view.x+view.width, y); } if (uncertaintyCheckItem.getState()) { double uncertx = java.lang.Math.sqrt(expectx2-expectx*expectx); double uncerty = java.lang.Math.sqrt(expecty2-expecty*expecty); int xx1 = (int) (cx+(expectx+uncertx)*rscale); int xx2 = (int) (cx+(expectx-uncertx)*rscale); int yy1 = (int) (cy-(expecty-uncerty)*rscale); int yy2 = (int) (cy-(expecty+uncerty)*rscale); g.setColor(Color.blue); g.drawRect(xx1, yy1, xx2-xx1, yy2-yy1); } g.setColor(Color.white); g.drawOval(view.x, view.y, view.width, view.height); } void fillTriangle(View view, int x1, int y1, int x2, int y2, int x3, int y3, int col) { if (x1 > x2) { if (x2 > x3) { // x1 > x2 > x3 int ay = interp(x1, y1, x3, y3, x2); fillTriangle1(view, x3, y3, x2, y2, ay, col); fillTriangle1(view, x1, y1, x2, y2, ay, col); } else if (x1 > x3) { // x1 > x3 > x2 int ay = interp(x1, y1, x2, y2, x3); fillTriangle1(view, x2, y2, x3, y3, ay, col); fillTriangle1(view, x1, y1, x3, y3, ay, col); } else { // x3 > x1 > x2 int ay = interp(x3, y3, x2, y2, x1); fillTriangle1(view, x2, y2, x1, y1, ay, col); fillTriangle1(view, x3, y3, x1, y1, ay, col); } } else { if (x1 > x3) { // x2 > x1 > x3 int ay = interp(x2, y2, x3, y3, x1); fillTriangle1(view, x3, y3, x1, y1, ay, col); fillTriangle1(view, x2, y2, x1, y1, ay, col); } else if (x2 > x3) { // x2 > x3 > x1 int ay = interp(x2, y2, x1, y1, x3); fillTriangle1(view, x1, y1, x3, y3, ay, col); fillTriangle1(view, x2, y2, x3, y3, ay, col); } else { // x3 > x2 > x1 int ay = interp(x3, y3, x1, y1, x2); fillTriangle1(view, x1, y1, x2, y2, ay, col); fillTriangle1(view, x3, y3, x2, y2, ay, col); } } } int interp(int x1, int y1, int x2, int y2, int x) { if (x1 == x2) return y1; if (x < x1 && x < x2 || x > x1 && x > x2) System.out.print("interp out of bounds\n"); return (int) (y1+((double) x-x1)*(y2-y1)/(x2-x1)); } void fillTriangle1(View v, int x1, int y1, int x2, int y2, int y3, int col) { // x2 == x3 int dir = (x1 > x2) ? -1 : 1; int x = x1; if (x < 0) { x = 0; if (x2 < 0) return; } if (x >= v.width) { x = v.width-1; if (x2 >= v.width) return; } if (y2 > y3) { int q = y2; y2 = y3; y3 = q; } // y2 < y3 while (x != x2+dir) { // XXX this could be speeded up int ya = interp(x1, y1, x2, y2, x); int yb = interp(x1, y1, x2, y3, x); if (ya < 0) ya = 0; if (yb >= v.height) yb = v.height-1; int p1 = x+ya*v.width; int p2 = x+yb*v.width; for (; p1 <= p2; p1 += v.width) v.pixels[p1] = col; x += dir; if (x < 0 || x >= v.width) return; } } 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 = java.lang.Math.sqrt(maxsq); double uncert = java.lang.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 (view.scale > 1e8) view.scale = 1e8; g.setColor(Color.gray); int mid_x = winSize.width * (count/2) / (count-1); g.drawLine(mid_x, view.y, mid_x, view.y+view.height); int mid_y = view.lower_y; double mult = view.ymult2*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) { 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); } } } Color computeColor(int x, int y, double c) { double h = func[x][y]; if (!colorCheck.getState()) { h = 0; } if (c < 0) c = 0; if (c > 1) c = 1; c = .5 + c * .5; double redness = (h < 0) ? -h : 0; double grnness = (h > 0) ? h : 0; if (redness > 1) redness = 1; if (grnness > 1) grnness = 1; if (grnness < 0) grnness = 0; if (redness < 0) redness = 0; double grayness = (1-(redness+grnness))*c; double gray = .6; return new Color((int) ((c*redness+gray*grayness)*255), (int) ((c*grnness+gray*grayness)*255), (int) ((gray*grayness)*255)); } void genFunc(double normmult, boolean do_x) { int i, j, th, r; int wc = sampleCountTh*2; int wm = wc - 1; double states[][][] = (do_x) ? xStates : pStates; double outr[][] = (do_x) ? func : pfunc; double outi[][] = (do_x) ? funci : pfunci; // step through each value of r and use inverse fft to calculate // values for all theta for (r = 0; r <= sampleCountR; r++) { for (i = 0; i != wc; i++) xformbuf[i] = 0; // calculate contribution from modes with m=0 double d0r = 0; double d0i = 0; for (j = 0; j != modeCountR; j++) { d0r += states[0][j][r]*magcoef[0][j]*phasecoefcos[0][j]; d0i += states[0][j][r]*magcoef[0][j]*phasecoefsin[0][j]; } xformbuf[0] = d0r; xformbuf[1] = d0i; // calculate contributions from modes with m>0 for (i = 1; i < modeCountTh; i += 2) { double d1r = 0, d2r = 0, d1i = 0, d2i = 0; int ii = (i+1)/2; for (j = 0; j != modeCountR; j++) { d1r += states[ii][j][r]*magcoef[i][j]* phasecoefcos[i][j]; d1i += states[ii][j][r]*magcoef[i][j]* phasecoefsin[i][j]; d2r += states[ii][j][r]*magcoef[i+1][j]* phasecoefcos[i+1][j]; d2i += states[ii][j][r]*magcoef[i+1][j]* phasecoefsin[i+1][j]; } if (!do_x) { double adj = pi/2 * ii; double acos = java.lang.Math.cos(adj); double asin = java.lang.Math.sin(adj); double q1 = d1r; double q2 = d1i; d1r = q1 * acos + q2 * asin; d1i = -q1 * asin + q2 * acos; q1 = d2r; q2 = d2i; d2r = q1 * acos + q2 * asin; d2i = -q1 * asin + q2 * acos; } xformbuf[ii*2] = d2r; xformbuf[ii*2+1] = d2i; xformbuf[wm & (wc-ii*2)] = d1r; xformbuf[wm & (wc-ii*2+1)] = d1i; } // take fft fftTh.transform(xformbuf); for (i = 0; i != sampleCountTh; i++) { outr[i][r] = xformbuf[i*2] *normmult; outi[i][r] = xformbuf[i*2+1]*normmult; } outr[sampleCountTh][r] = outr[0][r]; outi[sampleCountTh][r] = outi[0][r]; } } PhaseColor getPhaseColor(double x, double y) { int sector = 0; double val = 0; if (probCheckItem.getState()) return whitePhaseColor; if (x == 0 && y == 0) return phaseColors[0][0]; if (y >= 0) { if (x >= 0) { if (x >= y) { sector = 0; val = y/x; } else { sector = 1; val = 1-x/y; } } else { if (-x <= y) { sector = 2; val = -x/y; } else { sector = 3; val = 1+y/x; } } } else { if (x <= 0) { if (y >= x) { sector = 4; val = y/x; } else { sector = 5; val = 1-x/y; } } else { if (-y >= x) { sector = 6; val = -x/y; } else { sector = 7; val = 1+y/x; } } } return phaseColors[sector][(int) (val*phaseColorCount)]; } int getTermWidth() { int termWidth1 = viewStatesMap.width / min(modeCountTh, maxDispPhasorsTh); int termWidth2 = viewStatesMap.height / min(modeCountR, maxDispPhasorsR); return (termWidth1 < termWidth2) ? termWidth1 : termWidth2; } 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_STATES: editMag(x, y); break; case SEL_POTENTIAL: findStateByEnergy(y); enterSelectedState(); break; case SEL_X: editX(x, y); break; case SEL_L: editL(x, y); break; } } void editHandle(int y) { int dy = y-viewList[selectedPaneHandle].paneY; 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.paneY += dy; cv.repaint(pause); setSubViews(); } void editMag(int x, int y) { if (selectedCoefX == -1) return; int stateSize = getTermWidth(); // XXX int ss2 = stateSize/2; int x0 = stateSize*selectedCoefX+ss2 + viewStatesMap.x; int y0 = stateSize*selectedCoefY+ss2 + viewStatesMap.y; x -= x0; y -= y0; double mag = java.lang.Math.sqrt(x*x+y*y)/ss2; double ang = java.lang.Math.atan2(-y, x); double ang0 = (-elevels[selectedCoefX][selectedCoefY]*t) % (2*pi); if (mag > 10) mag = 0; if (mag > 1) mag = 1; magcoef[selectedCoefX][selectedCoefY] = mag; phasecoefadj[selectedCoefX][selectedCoefY] = (ang-ang0) % (2*pi); if (phasecoefadj[selectedCoefX][selectedCoefY] > pi) phasecoefadj[selectedCoefX][selectedCoefY] -= 2*pi; if (alwaysNormItem.getState()) normalize(); cv.repaint(pause); } void editMagClick() { if (selectedCoefX == -1) return; if (magDragStart < .5) magcoef[selectedCoefX][selectedCoefY] = 1; else magcoef[selectedCoefX][selectedCoefY] = 0; phasecoefadj[selectedCoefX][selectedCoefY] = 0; cv.repaint(pause); } void editX(int x, int y) { switch (mouseChooser.getSelectedIndex()) { case MOUSE_GAUSS: editXGauss(x, y); return; case MOUSE_GAUSSP: editXGaussP(x, y); return; case MOUSE_ROTATE: editRotate(x, y); return; } } void editL(int x, int y) { int xi = x * modeCountTh / winSize.width; int m = xi - modeCountTh/2; int r, th; for (r = 0; r <= sampleCountR; r++) for (th = 0; th <= sampleCountTh; th++) { if (r == 0 && m != 0) func[th][0] = funci[th][0] = 0; else { double thr = th*2*pi/sampleCountTh; func [th][r] = java.lang.Math.cos(thr*m); funci[th][r] = java.lang.Math.sin(thr*m); } } transform(); cv.repaint(pause); } double lastGaussWx = -8, lastGaussWy = -8; void editXGauss(int x, int y) { int i, j; int gx = x-dragX + 8; int gy = y-dragY + 8; double wx = 1/(abs(gx)+.0001); double wy = 1/(abs(gy)+.0001); wx = -wx*wx*2000; wy = -wy*wy*2000; lastGaussWx = wx; lastGaussWy = wy; for (x = 0; x != sampleCountR; x++) { for (y = 0; y != sampleCountTh; y++) { double th = y*2*pi/sampleCountTh; double xx = -java.lang.Math.cos(th)*x/sampleCountR - selectedGridX; double yy = -java.lang.Math.sin(th)*x/sampleCountR - selectedGridY; double rfunc = java.lang.Math.exp(wx*xx*xx + wy*yy*yy); func[y][x] = rfunc; funci[y][x] = 0; } } transform(); cv.repaint(pause); } void editXGaussP(int x, int y) { int i, j; double wx = lastGaussWx; double wy = lastGaussWy; double momentumX = (x-dragX) * .1; double momentumY = -(y-dragY) * .1; for (x = 0; x != sampleCountR; x++) { for (y = 0; y != sampleCountTh; y++) { double th = y*2*pi/sampleCountTh; double xx = -java.lang.Math.cos(th)*x/sampleCountR - selectedGridX; double yy = -java.lang.Math.sin(th)*x/sampleCountR - selectedGridY; double cx = java.lang.Math.cos(momentumX*xx); double cy = java.lang.Math.cos(momentumY*yy); double sx = java.lang.Math.sin(momentumX*xx); double sy = java.lang.Math.sin(momentumY*yy); double rfunc = java.lang.Math.exp(wx*xx*xx + wy*yy*yy); func[y][x] = rfunc*(cx*cy - sx*sy); funci[y][x] = rfunc*(cx*sy + cy*sx); } } transform(); cv.repaint(pause); } void editRotate(int x, int y) { int cx = viewXMap.x + viewXMap.width/2; int cy = viewXMap.y + viewXMap.height/2; double angle1 = java.lang.Math.atan2(-(dragY-cy), dragX-cx); double angle2 = java.lang.Math.atan2(-(y-cy), x-cx); double ad = angle2-angle1; int i, j; for (i = 1; i < modeCountTh; i++) for (j = 0; j < modeCountR; j++) { int m = (i+1)/2; if ((i % 2) == 0) m = -m; phasecoefadj[i][j] += ad*m; } dragX = x; dragY = y; cv.repaint(pause); } void transform() { t = 0; int i, j; // zero out arrays. phasecoefcos and phasecoefsin are // the real and imaginary parts of the state coefficients. for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) phasecoefcos[i][j] = phasecoefsin[i][j] = 0; int r, th; // integrate the function func[][] with each mode times r (since the // modes are only orthogonal with a weighting function of r) and also // integrate each mode with itself times r to get the norm. for (r = 0; r <= sampleCountR; r++) { // fft each set of samples at constant r for (th = 0; th != sampleCountTh*2; th++) xformbuf[th] = 0; for (th = 0; th != sampleCountTh; th++) { xformbuf[th*2] = func[th][r]*r; xformbuf[th*2+1] = funci[th][r]*r; } fftTh.transform(xformbuf); // perform integration step for each m=0 mode for (j = 0; j != modeCountR; j++) { phasecoefcos[0][j] += xStates[0][j][r]*xformbuf[0]; phasecoefsin[0][j] += xStates[0][j][r]*xformbuf[1]; } // perform integration step with each m>0 mode int wc = sampleCountTh*2; int wm = wc - 1; for (i = 1; i < modeCountTh; i += 2) { for (j = 0; j != modeCountR; j++) { int ii = i+1; int m = ii/2; phasecoefcos[i][j] += xStates[m][j][r]* xformbuf[ii]; phasecoefsin[i][j] += xStates[m][j][r]* xformbuf[ii+1]; phasecoefcos[i+1][j] += xStates[m][j][r]* xformbuf[wm & -ii]; phasecoefsin[i+1][j] += xStates[m][j][r]* xformbuf[wm & (-ii+1)]; } } } // finish up by dividing out the norms and moving the results // to magcoef and phasecoefadj for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) { double a = phasecoefcos[i][j]; double b = phasecoefsin[i][j]; if (a < epsilon && a > -epsilon) a = 0; if (b < epsilon && b > -epsilon) b = 0; magcoef[i][j] = java.lang.Math.sqrt(a*a+b*b); phasecoefadj[i][j] = java.lang.Math.atan2(b, a); } if (alwaysNormItem.getState()) normalize(); else if (alwaysMaxItem.getState()) maximize(); } int sign(int x) { return (x < 0) ? -1 : (x == 0) ? 0 : 1; } int abs(int x) { return x < 0 ? -x : x; } 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(); if (e.getSource() == blankButton) doBlank(); if (e.getSource() == normalizeButton) normalize(); if (e.getSource() == maximizeButton) maximize(); if (e.getSource() == measureEItem) measureE(); if (e.getSource() == measureLItem) measureL(); } public void adjustmentValueChanged(AdjustmentEvent e) { System.out.print(((Scrollbar) e.getSource()).getValue() + "\n"); if (e.getSource() == resBar) { if (resBar.getValue() != modeCountR) setResolution(); } if (e.getSource() == pZoomBar) calcPStates(); if (e.getSource() == phasorBar) { maxDispPhasorsR = phasorBar.getValue(); maxDispPhasorsTh = maxDispPhasorsR*2+1; } cv.repaint(pause); } public boolean handleEvent(Event ev) { if (ev.id == Event.WINDOW_DESTROY) { applet.destroyFrame(); return true; } return super.handleEvent(ev); } void setResolution() { int oldCountTh = modeCountTh; int oldCountR = modeCountR; // calculate number of samples in R and theta directions. // number of theta samples must be power of 2 (for fft) modeCountR = sampleCountR = resBar.getValue(); sampleCountR *= 4; int sth = resBar.getValue() * 2; sampleCountTh = 1; while (sampleCountTh < sth) sampleCountTh *= 2; modeCountTh = sampleCountTh+1; modeCountM = sampleCountTh/2 + 1; sampleCountTh *= 2; fftTh = new FFT(sampleCountTh); double oldmagcoef[][] = magcoef; magcoef = new double[modeCountTh][modeCountR]; phasecoef = new double[modeCountTh][modeCountR]; phasecoefcos = new double[modeCountTh][modeCountR]; phasecoefsin = new double[modeCountTh][modeCountR]; phasecoefadj = new double[modeCountTh][modeCountR]; xformbuf = new double[sampleCountTh*2]; func = new double[sampleCountTh+1][sampleCountR+1]; funci = new double[sampleCountTh+1][sampleCountR+1]; pfunc = new double[sampleCountTh+1][sampleCountR+1]; pfunci = new double[sampleCountTh+1][sampleCountR+1]; lzspectrum = null; System.out.print("grid: " + sampleCountTh + " " + sampleCountR + " " + sampleCountTh * sampleCountR + "\n"); scaleHeight = 6; step = pi/sampleCountTh; viewDistance = 50; int m, n; elevels = new double[modeCountTh][modeCountR]; double angstep = step*2; // m = angular modes // n = radial modes System.out.print("calc omegas...\n"); for (m = 0; m != modeCountTh; m++) for (n = 0; n != modeCountR; n++) { int realm = (m+1)/2; elevels[m][n] = zeroj(realm, n+1)/sampleCountR; } System.out.print("calc omegas...done\n"); double jj[] = new double[modeCountM+1]; int x, y; // x = th, y = r xStates = new double[modeCountM][modeCountR][sampleCountR+1]; System.out.print("calc modes...\n"); for (m = 0; m != modeCountM; m++) { for (n = 0; n != modeCountR; n++) { double max = 0; double nm = 0; for (y = 0; y <= sampleCountR; y++) { // work around bess() bug at x=0 if (y == 0) jj[m+1] = (m == 0) ? 1 : 0; else bess(m, y*elevels[m*2][n], jj); double q = xStates[m][n][y] = jj[m+1]; if (q > max) max = q; if (q < -max) max = -q; nm += q*q*y; } nm = java.lang.Math.sqrt(nm); for (y = 0; y <= sampleCountR; y++) xStates[m][n][y] /= nm; } } double mult = .01/(elevels[0][0]*elevels[0][0]); int i, j; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) elevels[i][j] *= elevels[i][j]*mult; System.out.print("calc modes...done\n"); if (oldmagcoef != null) { for (i = 0; i != oldCountTh && i != modeCountTh; i++) for (j = 0; j != oldCountR && j != modeCountR; j++) magcoef[i][j] = oldmagcoef[i][j]; } pZoomBarValue = -1; calcPStates(); angle1SinTab = new double[sampleCountTh+1]; angle1CosTab = new double[sampleCountTh+1]; angle2SinTab = new double[sampleCountTh+1]; angle2CosTab = new double[sampleCountTh+1]; for (i = 0; i <= sampleCountTh; i++) { double th1 = 2*pi*i/sampleCountTh; double th2 = 2*pi*(i+1)/sampleCountTh + .001; angle1SinTab[i] = java.lang.Math.sin(th1); angle1CosTab[i] = java.lang.Math.cos(th1); angle2SinTab[i] = java.lang.Math.sin(th2); angle2CosTab[i] = java.lang.Math.cos(th2); } } void calcPStates() { if (pZoomBar.getValue() == pZoomBarValue) return; pZoomBarValue = pZoomBar.getValue(); double pmult = pZoomBar.getValue() / (5.*sampleCountR); double jj[] = new double[modeCountM+1]; double jz[] = new double[modeCountM+1]; int i, j, x, y, realm; System.out.print("calc pstates\n"); pStates = new double[modeCountM][modeCountR][sampleCountR+1]; for (realm = 0; realm != modeCountM; realm++) { int bessm = (realm == 0) ? 1 : realm; for (j = 0; j != modeCountR; j++) { double z0 = zeroj(realm, j+1); bess(bessm, z0, jz); jz[0] = -jz[2]; for (x = 0; x != sampleCountR; x++) { // work around bess() bug at x=0 double x0 = pmult*x; if (x == 0) { if (realm == 0) { jj[1] = 1; jj[0] = 0; } else { jj[realm+1] = 0; jj[realm] = (realm == 1) ? 1 : 0; } } else { // calculate bessel functions of order 0 // through bessm and store in jj[1..bessm+1]. bess(bessm, x0, jj); // We store J(-1, x) in jj[0]. It's just -J(1, x) jj[0] = -jj[2]; } pStates[realm][j][x] = (z0*jz[realm]*jj[realm+1])/(x0*x0-z0*z0); } } } System.out.print("calc pstates, done\n"); } // this routine not tested for m_order > 64 or n_zero > 34 !! double zeroj( int m_order, int n_zero) { // Zeros of the Bessel function J(x) // Inputs // m_order Order of the Bessel function // n_zero Index of the zero (first, second, etc.) // Output // z The "n_zero"th zero of the Bessel function if (m_order >= 48 && n_zero == 1) { switch (m_order) { case 48: return 55.0283; case 49: return 56.0729; case 50: return 57.1169; case 51: return 58.1603; case 52: return 59.2032; case 53: return 60.2456; case 54: return 61.2875; case 55: return 62.3288; case 56: return 63.3697; case 57: return 64.4102; case 58: return 65.4501; case 59: return 66.4897; case 60: return 67.5288; case 61: return 68.5675; case 62: return 69.6058; case 63: return 70.6437; case 64: return 71.6812; } } if (m_order >= 62 && n_zero == 2) { switch (m_order) { case 62: return 75.6376; case 63: return 76.7021; case 64: return 77.7659; } } //* Use asymtotic formula for initial guess double beta = (n_zero + 0.5*m_order - 0.25)*(3.141592654); double mu = 4*m_order*m_order; double beta8 = 8*beta; double beta82 = beta8*beta8; double beta84 = beta82*beta82; double z = beta - (mu-1)/beta8 - 4*(mu-1)*(7*mu-31)/(3*beta82*beta8); z -= 32*(mu-1)*(83*mu*mu-982*mu+3779)/(15*beta84*beta8); z -= 64*(mu-1)*(6949*mu*mu*mu-153855*mu*mu+1585743*mu-6277237)/ (105*beta84*beta82*beta8); //* Use Newton's method to locate the root double jj[] = new double[m_order+3]; int i; double deriv; for( i=1; i<=5; i++ ) { bess( m_order+1, z, jj ); // Remember j(1) is J_0(z) // Use the recursion relation to evaluate derivative deriv = -jj[m_order+2] + m_order/z * jj[m_order+1]; z -= jj[m_order+1]/deriv; // Newton's root finding } return(z); } void bess( int m_max, double x, double jj[] ) { // Bessel function // Inputs // m_max Largest desired order // x = Value at which Bessel function J(x) is evaluated // Output // jj = Vector of J(x) for order m = 0, 1, ..., m_max //* Perform downward recursion from initial guess int maxmx = (m_max > x) ? m_max : ((int)x); // Max(m,x) // Recursion is downward from m_top (which is even) int m_top = 2*((int)( (maxmx+15)/2 + 1 )); double j[] = new double[m_top+2]; j[m_top+1] = 0.0; j[m_top] = 1.0; double tinyNumber = 1e-16; int m; for( m=m_top-2; m>=0; m--) // Downward recursion j[m+1] = 2*(m+1)/(x+tinyNumber)*j[m+2] - j[m+3]; //* Normalize using identity and return requested values double norm = j[1]; // NOTE: Be careful, m=0,1,... but for( m=2; m<=m_top; m+=2 ) // vector goes j(1),j(2),... norm += 2*j[m+1]; for( m=0; m<=m_max; m++ ) // Send back only the values for jj[m+1] = j[m+1]/norm; // m=0,...,m_max and discard values } // for m=m_max+1,...,m_top void findGridPoint2D(View v, int mx, int my) { int cx = v.x + v.width/2; int cy = v.y + v.height/2; int cr = v.width/2; selectedGridX = (mx-cx)/(double) cr; selectedGridY = -(my-cy)/(double) cr; double r = java.lang.Math.sqrt(selectedGridX*selectedGridX + selectedGridY*selectedGridY); if (r > 1) { selectedGridX /= r; selectedGridY /= r; } } public void mouseDragged(MouseEvent e) { dragging = true; edit(e); } public void mouseMoved(MouseEvent e) { if (dragging) return; int x = e.getX(); int y = e.getY(); dragX = x; dragY = y; int panelHeight = getPanelHeight(); int oldCoefX = selectedCoefX; int oldCoefY = selectedCoefY; selectedCoefX = -1; selectedCoefY = -1; selectedPaneHandle = -1; selection = 0; int i; for (i = 1; i != viewCount; i++) { int dy = y-viewList[i].paneY; if (dy >= -3 && dy <= 3) { selectedPaneHandle = i; selection = SEL_HANDLE; } } if (viewXMap != null && viewXMap.inside(x, y)) selection = SEL_X; else if (viewPotential != null && viewPotential.contains(x, y)) { selection = SEL_POTENTIAL; findStateByEnergy(y); } else if (viewStatesMap != null && viewStatesMap.inside(x, y)) { int termWidth = getTermWidth(); selectedCoefX = (x-viewStatesMap.x)/termWidth; selectedCoefY = (y-viewStatesMap.y)/termWidth; if (selectedCoefX >= modeCountTh || selectedCoefX >= maxDispPhasorsTh) selectedCoefX = selectedCoefY = -1; if (selectedCoefY >= modeCountR || selectedCoefY >= maxDispPhasorsR) selectedCoefX = selectedCoefY = -1; if (selectedCoefX < 0 || selectedCoefY < 0) selectedCoefX = selectedCoefY = -1; if (selectedCoefX != -1 && selectedCoefY != -1) selection = SEL_STATES; } else if (viewL != null && viewL.contains(x, y)) selection = SEL_L; if (selectedCoefX != oldCoefX || selectedCoefY != oldCoefY) cv.repaint(pause); } void findStateByEnergy(int y) { int i, j; int floory = viewPotential.y + viewPotential.height - 5; double ymult = 200; double dist = 100; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) { int yy = floory - (int) (ymult * elevels[i][j]); double d = java.lang.Math.abs(y-yy); if (d < dist) { dist = d; selectedCoefX = i; selectedCoefY = j; } } } public void mouseClicked(MouseEvent e) { if (selection == SEL_STATES) editMagClick(); if (e.getClickCount() == 2 && selectedCoefX != -1) enterSelectedState(); } void enterSelectedState() { int i, j; for (i = 0; i != modeCountTh; i++) for (j = 0; j != modeCountR; j++) if (selectedCoefX != i || selectedCoefY != j) magcoef[i][j] = 0; magcoef[selectedCoefX][selectedCoefY] = 1; cv.repaint(pause); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { if (!dragging) { if (selectedCoefX != -1) { selectedCoefX = selectedCoefY = -1; cv.repaint(pause); } if (selectedPaneHandle != -1) { selectedPaneHandle = -1; cv.repaint(pause); } } } public void mousePressed(MouseEvent e) { if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0) return; mouseMoved(e); if (selection == SEL_X) findGridPoint2D(viewXMap, e.getX(), e.getY()); dragStartX = e.getX(); dragStartY = e.getY(); if (selectedCoefX != -1) magDragStart = magcoef[selectedCoefX][selectedCoefY]; dragging = true; edit(e); } public void mouseReleased(MouseEvent e) { if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0) return; dragging = editingFunc = dragStop = false; dragSet = dragClear = false; mouseMoved(e); cv.repaint(pause); } public void itemStateChanged(ItemEvent e) { if (e.getItemSelectable() == stoppedCheck) { cv.repaint(pause); return; } if (e.getItemSelectable() == xCheckItem || e.getItemSelectable() == pCheckItem || e.getItemSelectable() == lCheckItem || e.getItemSelectable() == eCheckItem || e.getItemSelectable() == statesCheckItem) { handleResize(); cv.repaint(pause); } if (e.getItemSelectable() == alwaysNormItem && alwaysNormItem.getState()) { normalize(); alwaysMaxItem.setState(false); cv.repaint(pause); } if (e.getItemSelectable() == alwaysMaxItem && alwaysMaxItem.getState()) { maximize(); alwaysNormItem.setState(false); cv.repaint(pause); } int i; for (i = 0; i != waveFunctionMenu.countItems(); i++) if (e.getItemSelectable() == waveFunctionMenu.getItem(i)) { int j; ((CheckboxMenuItem) waveFunctionMenu.getItem(i)) .setState(true); for (j = 0; j != waveFunctionMenu.countItems(); j++) if (i != j) ((CheckboxMenuItem) waveFunctionMenu.getItem(j)) .setState(false); } } class FFT { double wtab[]; 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 wtab = new double[size]; int i; for (i = 0; i != size; i += 2) { double th = pi*i/size; wtab[i ] = Math.cos(th); wtab[i+1] = Math.sin(th); } } void transform(double data[]) { int i; int j = 0; int size2 = size*2; // bit-reversal for (i = 0; i != size2; i += 2) { if (i > j) { double 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) int bit = size; while ((bit & j) != 0) { j &= ~bit; bit >>= 1; } j |= bit; } // amount to skip through w table int tabskip = size2; int skip1; for (skip1 = 4; skip1 <= size2; skip1 <<= 1) { // skip2 = length of subarrays we are combining // skip1 = length of subarray after combination int skip2 = skip1 >> 1; tabskip >>= 1; // for each subarray for (i = 0; i < size2; i += skip1) { int ix = 0; // for each pair of complex numbers (one in each subarray) for (j = i; j != i+skip2; j += 2, ix += tabskip) { double wr = wtab[ix]; double wi = wtab[ix+1]; double d1r = data[j]; double d1i = data[j+1]; int j2 = j+skip2; double d2r = data[j2]; double d2i = data[j2+1]; double d2wr = d2r*wr - d2i*wi; double d2wi = d2r*wi + d2i*wr; data[j] = d1r+d2wr; data[j+1] = d1i+d2wi; data[j2 ] = d1r-d2wr; data[j2+1] = d1i-d2wi; }; } } } } class PhaseColor { public double r, g, b; PhaseColor(double rr, double gg, double bb) { r = rr; g = gg; b = bb; } Color getColor() { return new Color((int) (r*255), (int) (g*255), (int) (b*255)); } // XXX } class View extends Rectangle { View() { } View(View v) { super(v); } double ymult, ymult2, scale; int mid_y, lower_y; int paneY; MemoryImageSource imageSource; Image memimage; int pixels[]; } };