/*
// double well BifurcationPlot.java /* applet to construct bifurcation diagram for motion of particle in double-well potential */ import java.awt.*; import java.awt.event.*; import java.lang.*; import java.applet.Applet; public class DWBifurcationPlot extends Applet implements ActionListener { DoubleWell dw1; VariableSet tvars; plotCanvas b; // canvas that draws bifurcation diagram plotCanvas pp; //canvas for phase plot calcThread calculate1; // suspendable thread for calculation loop. double fmin, fmax, xmin, xmax; //bounding values of the bifurcation map double pmax; //estimate of maximum momentum. int transienttime = 100; // number of periods discarded // before plotting int width = 630, height = 440; // width and height of drawing canvas Button startButton, stopButton, resetButton, switchPlot; // buttons to control flow TextField forceTF; // text fields for user input of force, TextField transienttimeTF; // number of drive periods to discard, TextField fminTF, fmaxTF; // range of force plotted on canvas TextField xminTF, xmaxTF; // range of x plotted on canvas boolean frozen = false; // true if user has stopped the motion public void init () { dw1 = new DoubleWell(); // instantiate dynamical system object //width = getWidth() - 20; height=getHeight() - 80; // set plot size // set initial values of fmin, fmax, xmin, xmax: fmin = 0.65; fmax = 0.69; xmin = -.7 ; xmax = -.3 ; dw1.setforce(fmin + .01*(fmax-fmin)); b = new plotCanvas(createImage(width, height), fmin, fmax, xmin, xmax ); b.setBackground( Color.white ); // set white background b.setHLabel("force"); b.setVLabel("x"); b.drawbox(); dw1.setdt(0.20); // set time step dw1.setomega(2.*Math.PI/5.); // set drive frequency b.ghostGraphics.drawString("Double well dynamics: bifurcation diagram and phase plot", 100, 70); b.ghostGraphics.drawString("Equations of motion: "+dw1.getmass()+" dx/dt = p; ", 100, 110); b.ghostGraphics.drawString("dp/dt = d/dx (4 x^3 - 2 ("+(dw1.getA()*dw1.getA())+") x) - " +dw1.getdamping()+ " p/"+ dw1.getmass()+ " + " + dw1.getforce()+ " cos(" + (dw1.getomega()/Math.PI) + "pi t)", 100, 140); b.ghostGraphics.drawString("Bifurcation plot makes a dot every driving cycle after waiting", 100, 170); b.ghostGraphics.drawString("the number of cycles indicated below.", 100, 200); b.ghostGraphics.drawString(" Fill in blanks, then hit 'new plot'; to shift force"+ "amplitude fill in new force and hit RETURN", 100, 230); b.ghostGraphics.drawString("To add more dots, hit RETURN (with the force blank highlighted)", 100, 260); b.ghostGraphics.drawString("To see phase plot, click the 'phase' button", 100, 290); b.ghostGraphics.drawString("force = .7258 is especially interesting", 100, 320); // make canvas for phase plot pmax = 1.3*Math.sqrt(xmax*xmax + xmin*xmin) * dw1.getomega()* dw1.getmass(); pp = new plotCanvas(createImage(width, height), xmin, xmax, -pmax, pmax); pp.setHLabel("x"); pp.setVLabel("p"); pp.drawbox(); // put the user interface components on the applet Panel p = new Panel(); startButton = new Button("new plot"); startButton.addActionListener( this ); stopButton = new Button("Stop"); stopButton.addActionListener( this ); switchPlot = new Button("phase"); switchPlot.addActionListener(this); resetButton = new Button("reset"); resetButton.addActionListener( this ); p.add( startButton ); p.add( stopButton ); p.add( switchPlot ); p.add( resetButton ); Panel p2 = new Panel(); Label transienttimeprompt = new Label("number of periods before plotting:"); transienttimeTF = new TextField (Integer.toString(transienttime), 5); transienttimeTF.addActionListener( this ); p2.add( transienttimeprompt ); p2.add( transienttimeTF ); Panel p3 = new Panel(); p3.setLayout(new FlowLayout()); Label fprompt = new Label ("force, hit RETURN:"); forceTF = new TextField (6); forceTF.setText(Double.toString(dw1.getforce())); forceTF.addActionListener( this ); p3.add( fprompt ); p3.add( forceTF ); Panel p4 = new Panel(); Label fminprompt = new Label("fmin:"); fminTF = new TextField (5 ); fminTF.setText(Double.toString(fmin)); Label fmaxprompt = new Label("fmax:"); fmaxTF = new TextField (5 ); fmaxTF.setText(Double.toString(fmax)); p4.add( fminprompt ); p4.add( fminTF ); p4.add( fmaxprompt ); p4.add( fmaxTF ); Panel p5 = new Panel(); Label xminprompt = new Label("xmin:"); xminTF = new TextField (5 ); xminTF.setText(Double.toString(xmin)); Label xmaxprompt = new Label("xmax:"); xmaxTF = new TextField (5); xmaxTF.setText(Double.toString(xmax)); p5.add( xminprompt ); p5.add( xminTF ); p5.add( xmaxprompt ); p5.add( xmaxTF ); add(b); add(p2); add(p3); add(p4); add(p5); add(p); } // end of init public class calcThread extends Thread { // thread to do the calculations and make the canvas image. VariableSet vars, nextvars; boolean die=false; calcThread() { //constructor sets up initial values and dw1 parameters setPriority(Thread.MIN_PRIORITY); die=false; } public void run() { int n_var = 2, kount; // double xvec[] = new double[n_var]; // xvec[0]=position, xvec[1]=velocity double time; showStatus("starting calcThread. frozen = " + frozen); b.ghostGraphics.setColor(Color.white); b.ghostGraphics.drawRect(0,0,width,1); pp.ghostGraphics.setColor(Color.yellow); for (kount=1; kount<200*25 && !die ; kount++) { //calculation loop vars = dw1.getvars(); // get DoubleWell variables nextvars = vars; // Get new position nextvars = dw1.nextvars(); time = nextvars.gettime(); b.ghostGraphics.drawRect(kount/10,0,0,1); b.repaint(); dw1.setvars(nextvars); pp.addLine(vars.getx()[0], vars.getx()[1], nextvars.getx()[0], nextvars.getx()[1]); pp.repaint(); vars = nextvars; // discard first transienttime periods at new parameter values, and // use fact that period is exactly 5 time units: if( (time > 5*transienttime-.001) && ( Math.abs( (time/5.)-Math.round(time/5.) ) < 0.01) ) { b.ghostGraphics.setColor(Color.blue); pp.ghostGraphics.setColor(Color.blue); b.addPoint(dw1.getforce(), vars.getx()[0]); // put point (f,x) on canvas b.repaint(); // showStatus("plotting..."); } //end of if // try{sleep(5);} catch(InterruptedException e) {showStatus("interrupted sleep"); } while(frozen && !die) {try {sleep(100); } catch(InterruptedException e) {showStatus("interrupted sleep");} } } //end of calculation loop pp.repaint(); showStatus("calcThread ends"); System.out.println("time, force, x: "+ vars.gettime() + ", "+ '\t'+ dw1.getforce()+", "+ '\t' + vars.getx()[0]); } // end of run } //end of calcThread public void actionPerformed(ActionEvent evt) // handle user instructions { System.out.println(evt.paramString()); if(evt.getSource() == switchPlot) { if(switchPlot.getLabel() == "phase") { remove(b); add(pp, 0); validate(); switchPlot.setLabel("bifurc."); return; } else {remove(pp); add(b, 0); validate(); switchPlot.setLabel("phase"); return;} } if(calculate1 != null) {calculate1.die = true; try {calculate1.join();} catch(InterruptedException e) {showStatus("dieing interrupted\007");} //System.out.print(" threads= "+calculate1.activeCount() ); } // kill the thread. if (evt.getSource() == stopButton) { frozen = true;} //suspend else if (evt.getSource() == resetButton) { // clear plotting canvas fmin = 0.65; fmax = 0.69; xmin = -.7 ; xmax = -.3 ; transienttime=100; dw1.setforce(fmin + .01*(fmax-fmin)); fminTF.setText(Double.toString(fmin)); fmaxTF.setText(Double.toString(fmax)); xminTF.setText(Double.toString(xmin)); xmaxTF.setText(Double.toString(xmax)); forceTF.setText(Double.toString(dw1.getforce())); transienttimeTF.setText(Integer.toString(transienttime)); b = new plotCanvas(createImage(width, height), fmin, fmax, xmin, xmax ); b.setBackground( Color.white ); // set white background b.setHLabel("force"); b.setVLabel("x"); b.drawbox(); pmax = 1.3*Math.sqrt(xmax*xmax + xmin*xmin) * dw1.getomega()* dw1.getmass(); pp = new plotCanvas(createImage(width, height), xmin, xmax, -pmax, pmax); pp.setHLabel("x"); pp.setVLabel("p"); pp.drawbox(); remove(0); add(b,0); switchPlot.setLabel("phase"); validate(); dw1.setvars( dw1.resetvars ); // reset variables frozen=true; } else if(evt.getSource() == startButton) { //remake plotCanvas with new parameters System.out.println( "getting new parameters..." ); String s = fminTF.getText(); // read string for fmin fmin = new Double(s).doubleValue() ; s = fmaxTF.getText(); // read string for fmax fmax = new Double(s).doubleValue() ; s = xminTF.getText(); // read string for xmin xmin = new Double(s).doubleValue() ; s = xmaxTF.getText(); // read string for xmax xmax = new Double(s).doubleValue() ; frozen=false; b = new plotCanvas(createImage(width, height), fmin, fmax, xmin, xmax ); b.setBackground( Color.white ); // set white background b.setHLabel("force"); b.setVLabel("x"); b.drawbox(); pmax = 1.3*Math.sqrt(xmax*xmax + xmin*xmin) * dw1.getomega()* dw1.getmass(); pp = new plotCanvas(createImage(width, height), xmin, xmax, -pmax, pmax); pp.setHLabel("x"); pp.setVLabel("p"); pp.drawbox(); remove(0); add(b,0); switchPlot.setLabel("phase"); validate(); } else frozen=false; // end of if else // any event requires restarting new calculation String s = forceTF.getText(); // read string for force dw1.setforce(new Double(s).doubleValue() ); // convert to double s = transienttimeTF.getText(); // read string for transienttime transienttime = new Integer(s).intValue(); // convert to double showStatus("setting up new calculation thread"); b.repaint(); calculate1 = new calcThread(); dw1.settime(0.); calculate1.start(); } // end of action method class plotCanvas extends Canvas { // canvas for plotting data points. //set xmin, xmax, ymin, ymax to control range of plot. // Draw on my ghostGraphics object or call addPoint(double x, double y) to add a point. Graphics ghostGraphics; Image ghostImage; double xwidth, yheight; // ranges of x and y on graph double xmin, xmax, ymin, ymax; //bounding values of the graphed variables int imin, iwidth, jmax, jheight; // pixel values String HLabel = "x", VLabel = "y"; // constructor for plotCanvas: plotCanvas(Image image, double xmin, double xmax, double ymin, double ymax) { super(); // first call Canvas constructor setSize(image.getWidth(null), image.getHeight(null)); setBackground( Color.white ); this.xmin=xmin; this.xmax=xmax; this.ymin=ymin; this.ymax=ymax; ghostImage = image; ghostGraphics = image.getGraphics(); xwidth = xmax-xmin; // horizontal width yheight = ymax-ymin; //vertical height // set imin, iwidth, jmin, jheight based on size of the canvas: imin = 3*(getSize().width/20); iwidth = getSize().width - (3*imin/2); jmax = getSize().height - 2*(getSize().height/20); jheight = getSize().height - 3*(getSize().height/20); drawbox(ghostGraphics); // draw the box, numbers, and labels } // end of plotCanvas constructor int xtoi(double x) { // converts x to screen coord i return Math.round( (float) (imin + iwidth*(x-xmin)/xwidth) ); } int ytoj(double y) { // converts x to screen coord j return Math.round( (float) (jmax - jheight*(y-ymin)/yheight) ); } public void setHLabel(String HLabel) {this.HLabel = HLabel;} public void setVLabel(String VLabel) {this.VLabel = VLabel;} public void drawbox() {drawbox(ghostGraphics);} public void drawbox(Graphics g) { // draw box, numbers, and labels for graph g.setColor(Color.white); g.fillRect(0,0,width,height); g.setColor(Color.black); g.drawRect(imin, jmax-jheight, iwidth, jheight); g.drawString(Double.toString(xmin), imin-10, jmax+15); g.drawString(Double.toString(xmax), imin+iwidth-10, jmax+15); g.drawString(HLabel, imin+iwidth/2-20, jmax+15); g.drawString(Double.toString(ymin), imin-30, jmax+5); g.drawString(Double.toString(ymax), imin-30, jmax-jheight+5); g.drawString(VLabel, imin-30, jmax-jheight/2+10); } //end of drawbox public void addPoint(double x, double y) { ghostGraphics.drawRect(xtoi(x), ytoj( y ), 0, 0); } public void addLine(double x1, double y1, double x2, double y2) { ghostGraphics.drawLine(xtoi(x1), ytoj(y1), xtoi(x2), ytoj(y2)); } public void update(Graphics g) {paint(g);} public void paint( Graphics g ) { g.drawImage(ghostImage, 0, 0, null); //display the buffer image } } // end of Canvas } // end of applet