class Environment { String shortname = "", name = "", commentary = ""; Ecosystem eco; int Ncells = 1; Statevar time; Statevar[] vars = new Statevar[0]; Flux[] fluxes = new Flux[0]; FreeParam[] params = new FreeParam[0]; Archive archive; Toolbar viewsToolbar = null, controller = null; SliderList paramSliders = null; HashMap views = new HashMap(); View currentView = null; // these don't belong here anymore float[] displayRect; boolean showArrows = true, showDetails = false; boolean showArrowsButton = false, showDetailsButton = false; boolean awakened = false; float internalTimestep = 0.01; boolean implicit = true; // method for derivatives in takeStep boolean clipAtMaxMin = false; // constrain variables to their max and min at each step, at the expense of tracer conservation boolean exitOnNan = true; Environment() {} Environment(Ecosystem eco) { linkToEcosystem(eco); } // initialization ------------------------------------------------------------------- void linkToEcosystem(Ecosystem eco) { this.eco = eco; eco.allocate(Ncells); vars = (Statevar[])concat(vars, eco.vars); fluxes = (Flux[])concat(fluxes, eco.fluxes); params = (FreeParam[]) concat(params, eco.params); time = addVar("time","t","d",1); eco.time = time; } Statevar addVar(String name, String shortname, String units, int N) { Statevar V = new Statevar(name,shortname,units,N); vars = (Statevar[])append(vars,V); return V; } Flux addFlux(String name, String shortname, Statevar from, Statevar to, int N) { Flux F = new Flux(name,shortname,from,to,N); fluxes = (Flux[])append(fluxes,F); return F; } FreeParam addParam(String name, String shortname, String units, float initial, float min, float max) { FreeParam P = new FreeParam(name, shortname, units, initial, min, max); params = (FreeParam[])append(params,P); return P; } void wakeup() { // initializations that happen at the last possible moment before the model starts visibly running // tonicella 0.6 calls setUnits(time) for all fluxes here awakened = true; resetParams(); // note: needs to happen before rewind() rewind(); if (archive != null) archive.basename = shortname; // user probably set the shortname after constructing the Environment object } void rewind() { for (int i=0; i 0 && (F.from != null && F.from.current[i] != 0 && F.from.min==0))) { // implicit, from "from" to "to" // note: only does the implicit calculation if the statevar's .min field is set to make it positive definite float adj = 1.0 / (1.0 + F.current[i] * dt / F.from.current[i]); // adjustment to conserve total tracer if (F.to != null) F.to.current[i] += F.current[i] * dt * adj; F.from.current[i] *= adj; } else if (implicit && (F.current[i] <= 0 && (F.to != null && F.to.current[i] != 0 && F.to.min==0))) { // implicit, reversing sign and from "to" to "from" // note: only does the implicit calculation if the statevar's .min field is set to make it positive definite float adj = 1.0 / (1.0 - F.current[i] * dt / F.to.current[i]); if (F.from != null) F.from.current[i] -= F.current[i] * dt * adj; F.to.current[i] *= adj; } else { // simple, explicit version if (F.to != null) F.to.current[i] += F.current[i] * dt; if (F.from != null) F.from.current[i] -= F.current[i] * dt; } if (clipAtMaxMin) { if (F.to != null) F.to.current[i] = constrain(F.to.current[i], F.to.min, F.to.max); if (F.from != null) F.from.current[i] = constrain(F.from.current[i], F.from.min, F.from.max); } } } calcFluxes(); } State takeStep(State S, float dt) { // this version takes a step from one arbitrary state to another, using "current" as scratch space // (would use this, along with getCurrentState() and setCurrentState(), to Runge-Kutta, for example) setCurrentState(S); takeStep(dt); return getCurrentState(); } String integrate(float dt) { String errorMsg = ""; // this is where to put a fancy timestepping routine int Nsteps = floor(dt / internalTimestep); float leftover = dt - internalTimestep * Nsteps; for (int n=0; n 1e-6 * dt) { takeStep(leftover); } if (archive != null) archive.offer(getCurrentState()); return errorMsg; } // interaction with gui and views ------------------------------------------------------------------ void toggleArrows() {showArrows = !showArrows;} void toggleDetails() {showDetails = !showDetails;} void addView(View view) { views.put(view.shortname, view); if (currentView==null) currentView = view; } // archiving ------------------------------------------------------------------------- void startArchive(float dt) { if (online) return; archive = new Archive(shortname, dt, this); } void saveArchive() { if (archive==null) return; archive.toFile(); } // utility --------------------------------------------------------------------------- Statevar getVar(String S) { for (int i=0; i