/* * DynamicalVariable.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.evomodel.epidemiology; import java.util.ArrayList; import java.util.List; import java.util.Collections; /** * @author Trevor Bedford */ public class DynamicalVariable { private String name = "variable"; private List<Double> times = new ArrayList<Double>(); private List<Double> values = new ArrayList<Double>(); private double currentTime = 0.0; private double currentValue = 0.0; private List<Double> storedTimes = new ArrayList<Double>(); private List<Double> storedValues = new ArrayList<Double>(); private double storedTime = 0.0; private double storedValue = 0.0; // initialize variable public DynamicalVariable(String n, double t0, double v0) { name = n; currentTime = t0; currentValue = v0; add(currentTime, currentValue); } // add a time / value pair public void add(double t, double v) { Double tD = new Double(t); Double vD = new Double(v); times.add(tD); values.add(vD); } public void pushCurrentState() { add(currentTime,currentValue); } public void modCurrentTime(double dt) { currentTime += dt; } public void modCurrentValue(double dv) { currentValue += dv; } // reset arrays public void reset(double t0, double v0) { currentTime = t0; currentValue = v0; times.clear(); values.clear(); add(currentTime, currentValue); } // copy values to stored state public void store() { storedTimes.clear(); for (Double t : times) { Double tD = new Double(t.doubleValue()); storedTimes.add(tD); } storedValues.clear(); for (Double v : values) { Double vD = new Double(v.doubleValue()); storedValues.add(vD); } storedTime = currentTime; storedValue = currentValue; } // copy values from stored state public void restore() { times.clear(); for (Double t : storedTimes) { Double tD = new Double(t.doubleValue()); times.add(tD); } values.clear(); for (Double v : storedValues) { Double vD = new Double(v.doubleValue()); values.add(vD); } currentTime = storedTime; currentValue = storedValue; } public int size() { return times.size(); } public String getName() { return name; } public double getTimeAtIndex(int i) { return times.get(i).doubleValue(); } public double getValueAtIndex(int i) { return values.get(i).doubleValue(); } // pull value closest to given point in time // uses linear interpolation when the exact time point isn't present public double getValue(double t) { double rval = 0.0; Double tD = new Double(t); int index = Collections.binarySearch(times, tD); // found exact match if (index >= 0) { Double vD = values.get(index); rval = vD.doubleValue(); } // need to interpolate between two adjacent values else { int a = Math.abs(index) - 2; int b = Math.abs(index) - 1; double t0 = getTimeAtIndex(a); double v0 = getValueAtIndex(a); double t1 = getTimeAtIndex(b); double v1 = getValueAtIndex(b); rval = v0 + (t-t0) * ( (v1-v0) / (t1-t0) ); } return rval; } // return integral between two points in time // approximation via trapezoidal rule public double getIntegral(double start, double finish) { // first index after start and last index before finish int a = 0; int b = 0; double sum = 0.0; // if not exact match, need first index after than start int index = Collections.binarySearch(times, new Double(start)); if (index >= 0) a = index; else a = Math.abs(index) - 1; // if not exact match, need last index before than finish index = Collections.binarySearch(times, new Double(finish)); if (index >= 0) b = index; else b = Math.abs(index) - 2; // from start to a sum += 0.5 * (getTimeAtIndex(a) - start) * (getValueAtIndex(a) + getValue(start)); // between a and b for (index = a; index < b; index++) { sum += 0.5 * (getTimeAtIndex(index+1) - getTimeAtIndex(index)) * (getValueAtIndex(index+1) + getValueAtIndex(index)); } // b to finish sum += 0.5 * (finish - getTimeAtIndex(b)) * (getValue(finish) + getValueAtIndex(b)); return sum; } public double getAverage(double start, double finish) { return 0.5*(getValue(start) + getValue(finish)); } public void print() { System.out.println(name); for (int i=0; i<size(); i++) { System.out.println(times.get(i) + "\t" + values.get(i)); } } }