View Javadoc

1   /*
2    * @(#)CachingNumericalIntegrator.java May 2, 2004
3    * 
4    * Copyright (c) 2003, 2004 Delft University of Technology Jaffalaan 5, 2628 BX
5    * Delft, the Netherlands All rights reserved.
6    * 
7    * This software is proprietary information of Delft University of Technology
8    * The code is published under the General Public License
9    */
10  
11  package nl.tudelft.simulation.jstats.ode.integrators;
12  
13  import nl.tudelft.simulation.jstats.ode.DifferentialEquationInterface;
14  
15  /***
16   * The CachingNumericalIntegrator is the basis for an integrator that needs
17   * access to previously calculated values of y', e.g. y'_(k-1), y'_(k-2), etc.
18   * <br>
19   * (c) copyright 2003-2004 <a href="http://www.simulation.tudelft.nl">Delft
20   * University of Technology </a>, the Netherlands. <br>
21   * See for project information <a href="http://www.simulation.tudelft.nl">
22   * www.simulation.tudelft.nl </a> <br>
23   * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
24   * License (GPL) </a>, no warranty <br>
25   * 
26   * @version May 2, 2004 <br>
27   * @author <a
28   *         href="http://www.tbm.tudelft.nl/webstaf/alexandv/index.htm">Alexander
29   *         Verbraeck </a>
30   */
31  public abstract class CachingNumericalIntegrator extends NumericalIntegrator
32  {
33  	/*** the number of cachePlaces to store, e.g for k-1, k-2 set it to 2 */
34  	private int cachePlaces = 0;
35  
36  	/*** the cache for y(k-1), y(k-2), etc. */
37  	private double[][] cacheY;
38  
39  	/*** the cache for y'(k-1), y'(k-2), etc. */
40  	private double[][] cacheDY;
41  
42  	/*** the number of cache places filled = the last cache place used */
43  	private int lastCachePlace = -1;
44  
45  	/*** the primer integrator */
46  	protected NumericalIntegrator startingIntegrator = null;
47  
48  	/*** the substeps to use when starting the integrator */
49  	protected int startingSubSteps = 10;
50  
51  	/***
52  	 * constructs a new CachingNumericalIntegrator with a fixed number of cache
53  	 * places.
54  	 * 
55  	 * @param timeStep the timeStep
56  	 * @param equation the differentialEquation
57  	 * @param cachePlaces the number of cache places to store
58  	 * @param integrationMethod the primer integrator to use
59  	 * @param startingSubSteps the number of substeps per timestep during
60  	 *        starting of the integrator
61  	 */
62  	public CachingNumericalIntegrator(final double timeStep,
63  			final DifferentialEquationInterface equation,
64  			final int cachePlaces, final short integrationMethod,
65  			final int startingSubSteps)
66  	{
67  		super(timeStep, equation);
68  		this.cachePlaces = cachePlaces;
69  		this.cacheY = new double[cachePlaces][];
70  		this.cacheDY = new double[cachePlaces][];
71  		this.startingIntegrator = NumericalIntegrator.resolve(
72  				integrationMethod, timeStep / (1.0d * startingSubSteps),
73  				equation);
74  		this.startingSubSteps = startingSubSteps;
75  	}
76  
77  	/***
78  	 * @see nl.tudelft.simulation.jstats.ode.integrators.NumericalIntegrator#setTimeStep(double)
79  	 */
80  	public void setTimeStep(final double timeStep)
81  	{
82  		super.setTimeStep(timeStep);
83  		this.lastCachePlace = -1;
84  	}
85  
86  	/***
87  	 * @see nl.tudelft.simulation.jstats.ode.integrators.NumericalIntegrator#next(double,
88  	 *      double[])
89  	 */
90  	public double[] next(final double x, final double[] y)
91  	{
92  		double[] ynext = null;
93  		// look whether we have to prime, or can calculate
94  		if (this.lastCachePlace < this.cachePlaces)
95  		{
96  			// calculate next y-value using the primer, which can have a
97  			// much smaller timestep
98  			ynext = (double[]) y.clone();
99  			double xstep = x;
100 			for (int i = 0; i < this.startingSubSteps; i++)
101 			{
102 				ynext = this.startingIntegrator.next(xstep, ynext);
103 				xstep += this.timeStep / (1.0d * this.startingSubSteps);
104 			}
105 		} else
106 		{
107 			// calculate next y-value using the intended method
108 			ynext = next(x);
109 		}
110 		this.lastCachePlace++;
111 		this.cacheY[this.lastCachePlace % this.cachePlaces] = ynext;
112 		this.cacheDY[this.lastCachePlace % this.cachePlaces] = this.equation
113 				.dy(x + this.timeStep, ynext);
114 		return ynext;
115 	}
116 
117 	/***
118 	 * get a cached Y-value,
119 	 * 
120 	 * @param numberDown the number of the previous value we want
121 	 * @return the corresponding Y-value
122 	 */
123 	public double[] getY(final int numberDown)
124 	{
125 		if (this.lastCachePlace < this.cachePlaces)
126 		{
127 			throw new RuntimeException(
128 					"Tried to retrieve y-value that was not yet primed");
129 		}
130 		if (numberDown >= this.cachePlaces)
131 		{
132 			throw new RuntimeException(
133 					"Tried to retrieve y-value beyond cache limits");
134 		}
135 		return (double[]) this.cacheY[(this.lastCachePlace - numberDown)
136 				% this.cachePlaces].clone();
137 	}
138 
139 	/***
140 	 * get a cached dY-value,
141 	 * 
142 	 * @param numberDown the number of the previous value we want
143 	 * @return the corresponding dY-value
144 	 */
145 	public double[] getDY(final int numberDown)
146 	{
147 		if (this.lastCachePlace < this.cachePlaces)
148 		{
149 			throw new RuntimeException(
150 					"Tried to retrieve dy-value that was not yet primed");
151 		}
152 		if (numberDown >= this.cachePlaces)
153 		{
154 			throw new RuntimeException(
155 					"Tried to retrieve dy-value beyond cache limits");
156 		}
157 		return (double[]) this.cacheDY[(this.lastCachePlace - numberDown)
158 				% this.cachePlaces].clone();
159 	}
160 
161 	/***
162 	 * The integrators that extend the CachingNumericalIntegrator calculate the
163 	 * value of y(x+timeStep) just based on the x-value. They retrieve y(x),
164 	 * y(x-timeStep), etc. or y(k), y(k-1) all from the cache.
165 	 * 
166 	 * @param x the x-value to use in the calculation
167 	 * @return the value of y(x+timeStep)
168 	 */
169 	public abstract double[] next(final double x);
170 }