/*---------------------------- Ingeneue source code ?Copyright 2000 by George von Dassow, Eli Meir, Edwin Munro, and Garrett Odell. Permission is granted for use by private individuals and by individuals and groups at all non-profit institutions, as long as those using the software or examining the code do not intend to make a profit from its use, and subject to all other conditions given on the website www.ingenenue.org. www.ingeneue.org contact@ingeneue.org ----------------------------*/ package main; import integrators.Integrator; import integrators.IntegratorList; import java.io.FileOutputStream; import stoppers.SimpleStop; public class ModelRunner extends Object implements Runnable { public Thread runThread = null; public Integrator integrator=null; public SimpleStop stopper; private int totalSteps=0; // QUESTION: does this have any use anymore? private int numIntSteps=0; public boolean running = false; private float redrawInterval = 1f, nextSnap = 0.0f; private FileOutputStream outfile = null; private float errTol = 0.0001f; private static boolean runningSomething = false; private static int runNumber = 0; static final int CASHKARP = 0, FIXEDPOINT = 1, OTHER = 2; private int runmode = 0; private float FPStabilizer = 0.3f; // Allows one to tell the model runner to put up an inspector panel private boolean showInspector = false; // and this allows me to get useful stuff private Model model = null; public ModelRunner(Model model, SimpleStop stopper) { super(); stopper.init(model); this.stopper = stopper; this.model = model; try { Class c = Class.forName("integrators." + IntegratorList.getIntegratorClass(0) + "Integrator"); integrator = (Integrator)c.newInstance(); integrator.init(model); } catch(Exception e) { System.out.println("Couldn't make default integrator"); } } public void setStopper(SimpleStop stopper) { this.stopper = stopper; } public SimpleStop getStopper() { return stopper; } /** These next functions wrap the running of a model inside a thread. You can either use these threaded functions, or you can directly run a model by calling doStartRun() and doRun().
Call startRun() to start running a model in a new thread. startRun() calls run(). The parent function should then wait until running gets set to false, at which point the model is done running. */ public void startRun() { doStartRun(); runThread = new Thread(this); runThread.setPriority(Thread.NORM_PRIORITY-1); runThread.start(); } /** No other class should call run() directly. Instead, call startRun(). */ public void run() { try { doRun(); } catch(Exception e) { System.out.println(e.toString()); e.printStackTrace(); } runThread = null; } /** Call stopRun() to stop a model that's currently running. It should work for both threaded and non-threaded models, I think. */ public void stopRun() { if(runThread != null) runThread.stop(); runThread = null; running = false; runningSomething = false; } /** Returns true if the model is currently running */ public boolean isRunning() { return running; } /** Call doStartRun() to initialize a model for running it. If you want to run the model inside a thread, call startRun() instead. */ public void doStartRun() { if(runningSomething) { System.out.println("\r\rCalled startRun in ModelRunner while another runner is running\r\r\r\r\r\r\r"); } doReset(); runningSomething = true; running = true; } public void doReset() { if(runThread != null) stopRun(); // Kill it if its running for(int i = 0; i < model.numCells; i++) { model.cells[i].init(); // This sets the initial values of all nodes in each cell } // In many cases, we will want to initialize the model to values differnt from those contained // in the input file. Globals.time = 0; if(model.out != null) { for(int i = 0; i < model.numCells; i++) { model.cells[i].save(model.out); } model.out.println(); } model.updateOutput(Model.NEW_RUN); nextSnap = 0.0f; totalSteps = 0; numIntSteps = 0; if(integrator != null) integrator.reset(); stopper.reset(); } /** This has the code which actually runs a model. You need to call doStartRun() first before calling doRun(). If you want to run the model inside a thread, call startRun() instead, and the run() method will call this function.*/ public void doRun() throws Exception { running = true; // doTimestep() throws an exception when numbers go bad while(running && !stopper.stop(Globals.time)) { if(runThread != null) runThread.yield(); doTimestep(); } //System.out.println("integrator took " + numIntSteps + " steps"); model.updateOutput(Model.END_OF_RUN); running = false; runningSomething = false; } public void doStep() throws Exception { running = true; try { do { if(runThread != null) runThread.yield(); doTimestep(); } while(!stopper.stop(Globals.time) && nextSnap != 0.0f); } catch(Exception e) { } running = false; runningSomething = false; } private void doTimestep() throws Exception { ++numIntSteps; float stepTaken = integrator.IntegrateOneStep(); Globals.time += stepTaken; nextSnap += stepTaken; totalSteps++; if(nextSnap > redrawInterval) { model.updateOutput(Model.UPDATE_CELLS); if(model.out != null) { model.out.print(Globals.time); for(int i = 0; i < model.numCells; i++) { model.cells[i].save(model.out); } model.out.println(); } nextSnap = 0.0f; totalSteps = 0; // Check for NaN - I do it in here so it only happens occassionally, // although it doesn't logically belong in the drawing code checkForNaN(); } } /* I had a problem with an NaN that I didn't catch for a long time, so now for safety I call this function every now and then. */ /** Checks through all nodes of all cells in the model to see whether any of them have out of range numbers (NaN). Currently called every time the screen display is updated while running a model, and at the end of each uberiterator run. */ public void checkForNaN() throws Exception { for(int cell = 0; cell < model.numCells; cell++) { for(int n = 0; n < model.cells[cell].nodes.length; n++) { float val = model.cells[cell].getValue(n); if( (!(val >= 0 || val <= 0)) || Float.isNaN(val) || Float.isInfinite(val)) throw new Exception ("There was an out of bounds number (" + val + ") in this run"); } } } public void setRunMode(String rm) { if(integrator != null && integrator.isType(rm)) { integrator.reset(); } else { try { Class c = Class.forName("integrators." + rm + "Integrator"); integrator = (Integrator)c.newInstance(); integrator.init(model); } catch (Exception e) { System.out.println("ModelRunner: problem making integrator '" + rm + "'; using CashKarp instead"); try { Class c = Class.forName("integrators." + IntegratorList.getIntegratorClass(0) + "Integrator"); integrator = (Integrator)c.newInstance(); integrator.init(model); } catch(Exception e2) { System.out.println("ERROR: Couldn't make default integrator"); } } } } public Model getModel() { return model; } public Cell [] getCells() { return model.cells; } public int getNumCells() { return model.cells.length; } public int getNumNodes() { return model.cells[1].nodes.length; } }