blob: dc5ca189c2593f0c42dd6c1dc0e46edb2def745c [file] [log] [blame]
Raymonddee08492015-04-02 10:43:13 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.commons.math.ode.jacobians;
19
20import java.io.IOException;
21import java.io.ObjectInput;
22import java.io.ObjectOutput;
23import java.lang.reflect.Array;
24import java.util.ArrayList;
25import java.util.Collection;
26
27import org.apache.commons.math.MathRuntimeException;
28import org.apache.commons.math.MaxEvaluationsExceededException;
29import org.apache.commons.math.ode.DerivativeException;
30import org.apache.commons.math.exception.util.LocalizedFormats;
31import org.apache.commons.math.ode.ExtendedFirstOrderDifferentialEquations;
32import org.apache.commons.math.ode.FirstOrderIntegrator;
33import org.apache.commons.math.ode.IntegratorException;
34import org.apache.commons.math.ode.events.EventException;
35import org.apache.commons.math.ode.events.EventHandler;
36import org.apache.commons.math.ode.sampling.StepHandler;
37import org.apache.commons.math.ode.sampling.StepInterpolator;
38
39/** This class enhances a first order integrator for differential equations to
40 * compute also partial derivatives of the solution with respect to initial state
41 * and parameters.
42 * <p>In order to compute both the state and its derivatives, the ODE problem
43 * is extended with jacobians of the raw ODE and the variational equations are
44 * added to form a new compound problem of higher dimension. If the original ODE
45 * problem has dimension n and there are p parameters, the compound problem will
46 * have dimension n &times; (1 + n + p).</p>
47 * @see ParameterizedODE
48 * @see ODEWithJacobians
49 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $
50 * @since 2.1
51 * @deprecated as of 2.2 the complete package is deprecated, it will be replaced
52 * in 3.0 by a completely rewritten implementation
53 */
54@Deprecated
55public class FirstOrderIntegratorWithJacobians {
56
57 /** Underlying integrator for compound problem. */
58 private final FirstOrderIntegrator integrator;
59
60 /** Raw equations to integrate. */
61 private final ODEWithJacobians ode;
62
63 /** Maximal number of evaluations allowed. */
64 private int maxEvaluations;
65
66 /** Number of evaluations already performed. */
67 private int evaluations;
68
69 /** Build an enhanced integrator using internal differentiation to compute jacobians.
70 * @param integrator underlying integrator to solve the compound problem
71 * @param ode original problem (f in the equation y' = f(t, y))
72 * @param p parameters array (may be null if {@link
73 * ParameterizedODE#getParametersDimension()
74 * getParametersDimension()} from original problem is zero)
75 * @param hY step sizes to use for computing the jacobian df/dy, must have the
76 * same dimension as the original problem
77 * @param hP step sizes to use for computing the jacobian df/dp, must have the
78 * same dimension as the original problem parameters dimension
79 * @see #FirstOrderIntegratorWithJacobians(FirstOrderIntegrator,
80 * ODEWithJacobians)
81 */
82 public FirstOrderIntegratorWithJacobians(final FirstOrderIntegrator integrator,
83 final ParameterizedODE ode,
84 final double[] p, final double[] hY, final double[] hP) {
85 checkDimension(ode.getDimension(), hY);
86 checkDimension(ode.getParametersDimension(), p);
87 checkDimension(ode.getParametersDimension(), hP);
88 this.integrator = integrator;
89 this.ode = new FiniteDifferencesWrapper(ode, p, hY, hP);
90 setMaxEvaluations(-1);
91 }
92
93 /** Build an enhanced integrator using ODE builtin jacobian computation features.
94 * @param integrator underlying integrator to solve the compound problem
95 * @param ode original problem, which can compute the jacobians by itself
96 * @see #FirstOrderIntegratorWithJacobians(FirstOrderIntegrator,
97 * ParameterizedODE, double[], double[], double[])
98 */
99 public FirstOrderIntegratorWithJacobians(final FirstOrderIntegrator integrator,
100 final ODEWithJacobians ode) {
101 this.integrator = integrator;
102 this.ode = ode;
103 setMaxEvaluations(-1);
104 }
105
106 /** Add a step handler to this integrator.
107 * <p>The handler will be called by the integrator for each accepted
108 * step.</p>
109 * @param handler handler for the accepted steps
110 * @see #getStepHandlers()
111 * @see #clearStepHandlers()
112 */
113 public void addStepHandler(StepHandlerWithJacobians handler) {
114 final int n = ode.getDimension();
115 final int k = ode.getParametersDimension();
116 integrator.addStepHandler(new StepHandlerWrapper(handler, n, k));
117 }
118
119 /** Get all the step handlers that have been added to the integrator.
120 * @return an unmodifiable collection of the added events handlers
121 * @see #addStepHandler(StepHandlerWithJacobians)
122 * @see #clearStepHandlers()
123 */
124 public Collection<StepHandlerWithJacobians> getStepHandlers() {
125 final Collection<StepHandlerWithJacobians> handlers =
126 new ArrayList<StepHandlerWithJacobians>();
127 for (final StepHandler handler : integrator.getStepHandlers()) {
128 if (handler instanceof StepHandlerWrapper) {
129 handlers.add(((StepHandlerWrapper) handler).getHandler());
130 }
131 }
132 return handlers;
133 }
134
135 /** Remove all the step handlers that have been added to the integrator.
136 * @see #addStepHandler(StepHandlerWithJacobians)
137 * @see #getStepHandlers()
138 */
139 public void clearStepHandlers() {
140 integrator.clearStepHandlers();
141 }
142
143 /** Add an event handler to the integrator.
144 * @param handler event handler
145 * @param maxCheckInterval maximal time interval between switching
146 * function checks (this interval prevents missing sign changes in
147 * case the integration steps becomes very large)
148 * @param convergence convergence threshold in the event time search
149 * @param maxIterationCount upper limit of the iteration count in
150 * the event time search
151 * @see #getEventHandlers()
152 * @see #clearEventHandlers()
153 */
154 public void addEventHandler(EventHandlerWithJacobians handler,
155 double maxCheckInterval,
156 double convergence,
157 int maxIterationCount) {
158 final int n = ode.getDimension();
159 final int k = ode.getParametersDimension();
160 integrator.addEventHandler(new EventHandlerWrapper(handler, n, k),
161 maxCheckInterval, convergence, maxIterationCount);
162 }
163
164 /** Get all the event handlers that have been added to the integrator.
165 * @return an unmodifiable collection of the added events handlers
166 * @see #addEventHandler(EventHandlerWithJacobians, double, double, int)
167 * @see #clearEventHandlers()
168 */
169 public Collection<EventHandlerWithJacobians> getEventHandlers() {
170 final Collection<EventHandlerWithJacobians> handlers =
171 new ArrayList<EventHandlerWithJacobians>();
172 for (final EventHandler handler : integrator.getEventHandlers()) {
173 if (handler instanceof EventHandlerWrapper) {
174 handlers.add(((EventHandlerWrapper) handler).getHandler());
175 }
176 }
177 return handlers;
178 }
179
180 /** Remove all the event handlers that have been added to the integrator.
181 * @see #addEventHandler(EventHandlerWithJacobians, double, double, int)
182 * @see #getEventHandlers()
183 */
184 public void clearEventHandlers() {
185 integrator.clearEventHandlers();
186 }
187
188 /** Integrate the differential equations and the variational equations up to the given time.
189 * <p>This method solves an Initial Value Problem (IVP) and also computes the derivatives
190 * of the solution with respect to initial state and parameters. This can be used as
191 * a basis to solve Boundary Value Problems (BVP).</p>
192 * <p>Since this method stores some internal state variables made
193 * available in its public interface during integration ({@link
194 * #getCurrentSignedStepsize()}), it is <em>not</em> thread-safe.</p>
195 * @param t0 initial time
196 * @param y0 initial value of the state vector at t0
197 * @param dY0dP initial value of the state vector derivative with respect to the
198 * parameters at t0
199 * @param t target time for the integration
200 * (can be set to a value smaller than <code>t0</code> for backward integration)
201 * @param y placeholder where to put the state vector at each successful
202 * step (and hence at the end of integration), can be the same object as y0
203 * @param dYdY0 placeholder where to put the state vector derivative with respect
204 * to the initial state (dy[i]/dy0[j] is in element array dYdY0[i][j]) at each successful
205 * step (and hence at the end of integration)
206 * @param dYdP placeholder where to put the state vector derivative with respect
207 * to the parameters (dy[i]/dp[j] is in element array dYdP[i][j]) at each successful
208 * step (and hence at the end of integration)
209 * @return stop time, will be the same as target time if integration reached its
210 * target, but may be different if some event handler stops it at some point.
211 * @throws IntegratorException if the integrator cannot perform integration
212 * @throws DerivativeException this exception is propagated to the caller if
213 * the underlying user function triggers one
214 */
215 public double integrate(final double t0, final double[] y0, final double[][] dY0dP,
216 final double t, final double[] y,
217 final double[][] dYdY0, final double[][] dYdP)
218 throws DerivativeException, IntegratorException {
219
220 final int n = ode.getDimension();
221 final int k = ode.getParametersDimension();
222 checkDimension(n, y0);
223 checkDimension(n, y);
224 checkDimension(n, dYdY0);
225 checkDimension(n, dYdY0[0]);
226 if (k != 0) {
227 checkDimension(n, dY0dP);
228 checkDimension(k, dY0dP[0]);
229 checkDimension(n, dYdP);
230 checkDimension(k, dYdP[0]);
231 }
232
233 // set up initial state, including partial derivatives
234 // the compound state z contains the raw state y and its derivatives
235 // with respect to initial state y0 and to parameters p
236 // y[i] is stored in z[i]
237 // dy[i]/dy0[j] is stored in z[n + i * n + j]
238 // dy[i]/dp[j] is stored in z[n * (n + 1) + i * k + j]
239 final double[] z = new double[n * (1 + n + k)];
240 System.arraycopy(y0, 0, z, 0, n);
241 for (int i = 0; i < n; ++i) {
242
243 // set diagonal element of dy/dy0 to 1.0 at t = t0
244 z[i * (1 + n) + n] = 1.0;
245
246 // set initial derivatives with respect to parameters
247 System.arraycopy(dY0dP[i], 0, z, n * (n + 1) + i * k, k);
248
249 }
250
251 // integrate the compound state variational equations
252 evaluations = 0;
253 final double stopTime = integrator.integrate(new MappingWrapper(), t0, z, t, z);
254
255 // dispatch the final compound state into the state and partial derivatives arrays
256 dispatchCompoundState(z, y, dYdY0, dYdP);
257
258 return stopTime;
259
260 }
261
262 /** Dispatch a compound state array into state and jacobians arrays.
263 * @param z compound state
264 * @param y raw state array to fill
265 * @param dydy0 jacobian array to fill
266 * @param dydp jacobian array to fill
267 */
268 private static void dispatchCompoundState(final double[] z, final double[] y,
269 final double[][] dydy0, final double[][] dydp) {
270
271 final int n = y.length;
272 final int k = dydp[0].length;
273
274 // state
275 System.arraycopy(z, 0, y, 0, n);
276
277 // jacobian with respect to initial state
278 for (int i = 0; i < n; ++i) {
279 System.arraycopy(z, n * (i + 1), dydy0[i], 0, n);
280 }
281
282 // jacobian with respect to parameters
283 for (int i = 0; i < n; ++i) {
284 System.arraycopy(z, n * (n + 1) + i * k, dydp[i], 0, k);
285 }
286
287 }
288
289 /** Get the current value of the step start time t<sub>i</sub>.
290 * <p>This method can be called during integration (typically by
291 * the object implementing the {@link org.apache.commons.math.ode.FirstOrderDifferentialEquations
292 * differential equations} problem) if the value of the current step that
293 * is attempted is needed.</p>
294 * <p>The result is undefined if the method is called outside of
295 * calls to <code>integrate</code>.</p>
296 * @return current value of the step start time t<sub>i</sub>
297 */
298 public double getCurrentStepStart() {
299 return integrator.getCurrentStepStart();
300 }
301
302 /** Get the current signed value of the integration stepsize.
303 * <p>This method can be called during integration (typically by
304 * the object implementing the {@link org.apache.commons.math.ode.FirstOrderDifferentialEquations
305 * differential equations} problem) if the signed value of the current stepsize
306 * that is tried is needed.</p>
307 * <p>The result is undefined if the method is called outside of
308 * calls to <code>integrate</code>.</p>
309 * @return current signed value of the stepsize
310 */
311 public double getCurrentSignedStepsize() {
312 return integrator.getCurrentSignedStepsize();
313 }
314
315 /** Set the maximal number of differential equations function evaluations.
316 * <p>The purpose of this method is to avoid infinite loops which can occur
317 * for example when stringent error constraints are set or when lots of
318 * discrete events are triggered, thus leading to many rejected steps.</p>
319 * @param maxEvaluations maximal number of function evaluations (negative
320 * values are silently converted to maximal integer value, thus representing
321 * almost unlimited evaluations)
322 */
323 public void setMaxEvaluations(int maxEvaluations) {
324 this.maxEvaluations = (maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations;
325 }
326
327 /** Get the maximal number of functions evaluations.
328 * @return maximal number of functions evaluations
329 */
330 public int getMaxEvaluations() {
331 return maxEvaluations;
332 }
333
334 /** Get the number of evaluations of the differential equations function.
335 * <p>
336 * The number of evaluations corresponds to the last call to the
337 * <code>integrate</code> method. It is 0 if the method has not been called yet.
338 * </p>
339 * @return number of evaluations of the differential equations function
340 */
341 public int getEvaluations() {
342 return evaluations;
343 }
344
345 /** Check array dimensions.
346 * @param expected expected dimension
347 * @param array (may be null if expected is 0)
348 * @throws IllegalArgumentException if the array dimension does not match the expected one
349 */
350 private void checkDimension(final int expected, final Object array)
351 throws IllegalArgumentException {
352 int arrayDimension = (array == null) ? 0 : Array.getLength(array);
353 if (arrayDimension != expected) {
354 throw MathRuntimeException.createIllegalArgumentException(
355 LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, arrayDimension, expected);
356 }
357 }
358
359 /** Wrapper class used to map state and jacobians into compound state. */
360 private class MappingWrapper implements ExtendedFirstOrderDifferentialEquations {
361
362 /** Current state. */
363 private final double[] y;
364
365 /** Time derivative of the current state. */
366 private final double[] yDot;
367
368 /** Derivatives of yDot with respect to state. */
369 private final double[][] dFdY;
370
371 /** Derivatives of yDot with respect to parameters. */
372 private final double[][] dFdP;
373
374 /** Simple constructor.
375 */
376 public MappingWrapper() {
377
378 final int n = ode.getDimension();
379 final int k = ode.getParametersDimension();
380 y = new double[n];
381 yDot = new double[n];
382 dFdY = new double[n][n];
383 dFdP = new double[n][k];
384
385 }
386
387 /** {@inheritDoc} */
388 public int getDimension() {
389 final int n = y.length;
390 final int k = dFdP[0].length;
391 return n * (1 + n + k);
392 }
393
394 /** {@inheritDoc} */
395 public int getMainSetDimension() {
396 return ode.getDimension();
397 }
398
399 /** {@inheritDoc} */
400 public void computeDerivatives(final double t, final double[] z, final double[] zDot)
401 throws DerivativeException {
402
403 final int n = y.length;
404 final int k = dFdP[0].length;
405
406 // compute raw ODE and its jacobians: dy/dt, d[dy/dt]/dy0 and d[dy/dt]/dp
407 System.arraycopy(z, 0, y, 0, n);
408 if (++evaluations > maxEvaluations) {
409 throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
410 }
411 ode.computeDerivatives(t, y, yDot);
412 ode.computeJacobians(t, y, yDot, dFdY, dFdP);
413
414 // state part of the compound equations
415 System.arraycopy(yDot, 0, zDot, 0, n);
416
417 // variational equations: from d[dy/dt]/dy0 to d[dy/dy0]/dt
418 for (int i = 0; i < n; ++i) {
419 final double[] dFdYi = dFdY[i];
420 for (int j = 0; j < n; ++j) {
421 double s = 0;
422 final int startIndex = n + j;
423 int zIndex = startIndex;
424 for (int l = 0; l < n; ++l) {
425 s += dFdYi[l] * z[zIndex];
426 zIndex += n;
427 }
428 zDot[startIndex + i * n] = s;
429 }
430 }
431
432 // variational equations: from d[dy/dt]/dy0 and d[dy/dt]/dp to d[dy/dp]/dt
433 for (int i = 0; i < n; ++i) {
434 final double[] dFdYi = dFdY[i];
435 final double[] dFdPi = dFdP[i];
436 for (int j = 0; j < k; ++j) {
437 double s = dFdPi[j];
438 final int startIndex = n * (n + 1) + j;
439 int zIndex = startIndex;
440 for (int l = 0; l < n; ++l) {
441 s += dFdYi[l] * z[zIndex];
442 zIndex += k;
443 }
444 zDot[startIndex + i * k] = s;
445 }
446 }
447
448 }
449
450 }
451
452 /** Wrapper class to compute jacobians by finite differences for ODE which do not compute them themselves. */
453 private class FiniteDifferencesWrapper implements ODEWithJacobians {
454
455 /** Raw ODE without jacobians computation. */
456 private final ParameterizedODE ode;
457
458 /** Parameters array (may be null if parameters dimension from original problem is zero) */
459 private final double[] p;
460
461 /** Step sizes to use for computing the jacobian df/dy. */
462 private final double[] hY;
463
464 /** Step sizes to use for computing the jacobian df/dp. */
465 private final double[] hP;
466
467 /** Temporary array for state derivatives used to compute jacobians. */
468 private final double[] tmpDot;
469
470 /** Simple constructor.
471 * @param ode original ODE problem, without jacobians computations
472 * @param p parameters array (may be null if parameters dimension from original problem is zero)
473 * @param hY step sizes to use for computing the jacobian df/dy
474 * @param hP step sizes to use for computing the jacobian df/dp
475 */
476 public FiniteDifferencesWrapper(final ParameterizedODE ode,
477 final double[] p, final double[] hY, final double[] hP) {
478 this.ode = ode;
479 this.p = p.clone();
480 this.hY = hY.clone();
481 this.hP = hP.clone();
482 tmpDot = new double[ode.getDimension()];
483 }
484
485 /** {@inheritDoc} */
486 public int getDimension() {
487 return ode.getDimension();
488 }
489
490 /** {@inheritDoc} */
491 public void computeDerivatives(double t, double[] y, double[] yDot) throws DerivativeException {
492 // this call to computeDerivatives has already been counted,
493 // we must not increment the counter again
494 ode.computeDerivatives(t, y, yDot);
495 }
496
497 /** {@inheritDoc} */
498 public int getParametersDimension() {
499 return ode.getParametersDimension();
500 }
501
502 /** {@inheritDoc} */
503 public void computeJacobians(double t, double[] y, double[] yDot,
504 double[][] dFdY, double[][] dFdP)
505 throws DerivativeException {
506
507 final int n = hY.length;
508 final int k = hP.length;
509
510 evaluations += n + k;
511 if (evaluations > maxEvaluations) {
512 throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
513 }
514
515 // compute df/dy where f is the ODE and y is the state array
516 for (int j = 0; j < n; ++j) {
517 final double savedYj = y[j];
518 y[j] += hY[j];
519 ode.computeDerivatives(t, y, tmpDot);
520 for (int i = 0; i < n; ++i) {
521 dFdY[i][j] = (tmpDot[i] - yDot[i]) / hY[j];
522 }
523 y[j] = savedYj;
524 }
525
526 // compute df/dp where f is the ODE and p is the parameters array
527 for (int j = 0; j < k; ++j) {
528 ode.setParameter(j, p[j] + hP[j]);
529 ode.computeDerivatives(t, y, tmpDot);
530 for (int i = 0; i < n; ++i) {
531 dFdP[i][j] = (tmpDot[i] - yDot[i]) / hP[j];
532 }
533 ode.setParameter(j, p[j]);
534 }
535
536 }
537
538 }
539
540 /** Wrapper for step handlers. */
541 private static class StepHandlerWrapper implements StepHandler {
542
543 /** Underlying step handler with jacobians. */
544 private final StepHandlerWithJacobians handler;
545
546 /** Dimension of the original ODE. */
547 private final int n;
548
549 /** Number of parameters. */
550 private final int k;
551
552 /** Simple constructor.
553 * @param handler underlying step handler with jacobians
554 * @param n dimension of the original ODE
555 * @param k number of parameters
556 */
557 public StepHandlerWrapper(final StepHandlerWithJacobians handler,
558 final int n, final int k) {
559 this.handler = handler;
560 this.n = n;
561 this.k = k;
562 }
563
564 /** Get the underlying step handler with jacobians.
565 * @return underlying step handler with jacobians
566 */
567 public StepHandlerWithJacobians getHandler() {
568 return handler;
569 }
570
571 /** {@inheritDoc} */
572 public void handleStep(StepInterpolator interpolator, boolean isLast)
573 throws DerivativeException {
574 handler.handleStep(new StepInterpolatorWrapper(interpolator, n, k), isLast);
575 }
576
577 /** {@inheritDoc} */
578 public boolean requiresDenseOutput() {
579 return handler.requiresDenseOutput();
580 }
581
582 /** {@inheritDoc} */
583 public void reset() {
584 handler.reset();
585 }
586
587 }
588
589 /** Wrapper for step interpolators. */
590 private static class StepInterpolatorWrapper
591 implements StepInterpolatorWithJacobians {
592
593 /** Wrapped interpolator. */
594 private StepInterpolator interpolator;
595
596 /** State array. */
597 private double[] y;
598
599 /** Jacobian with respect to initial state dy/dy0. */
600 private double[][] dydy0;
601
602 /** Jacobian with respect to parameters dy/dp. */
603 private double[][] dydp;
604
605 /** Time derivative of the state array. */
606 private double[] yDot;
607
608 /** Time derivative of the sacobian with respect to initial state dy/dy0. */
609 private double[][] dydy0Dot;
610
611 /** Time derivative of the jacobian with respect to parameters dy/dp. */
612 private double[][] dydpDot;
613
614 /** Simple constructor.
615 * <p>This constructor is used only for externalization. It does nothing.</p>
616 */
617 @SuppressWarnings("unused")
618 public StepInterpolatorWrapper() {
619 }
620
621 /** Simple constructor.
622 * @param interpolator wrapped interpolator
623 * @param n dimension of the original ODE
624 * @param k number of parameters
625 */
626 public StepInterpolatorWrapper(final StepInterpolator interpolator,
627 final int n, final int k) {
628 this.interpolator = interpolator;
629 y = new double[n];
630 dydy0 = new double[n][n];
631 dydp = new double[n][k];
632 yDot = new double[n];
633 dydy0Dot = new double[n][n];
634 dydpDot = new double[n][k];
635 }
636
637 /** {@inheritDoc} */
638 public void setInterpolatedTime(double time) {
639 interpolator.setInterpolatedTime(time);
640 }
641
642 /** {@inheritDoc} */
643 public boolean isForward() {
644 return interpolator.isForward();
645 }
646
647 /** {@inheritDoc} */
648 public double getPreviousTime() {
649 return interpolator.getPreviousTime();
650 }
651
652 /** {@inheritDoc} */
653 public double getInterpolatedTime() {
654 return interpolator.getInterpolatedTime();
655 }
656
657 /** {@inheritDoc} */
658 public double[] getInterpolatedY() throws DerivativeException {
659 double[] extendedState = interpolator.getInterpolatedState();
660 System.arraycopy(extendedState, 0, y, 0, y.length);
661 return y;
662 }
663
664 /** {@inheritDoc} */
665 public double[][] getInterpolatedDyDy0() throws DerivativeException {
666 double[] extendedState = interpolator.getInterpolatedState();
667 final int n = y.length;
668 int start = n;
669 for (int i = 0; i < n; ++i) {
670 System.arraycopy(extendedState, start, dydy0[i], 0, n);
671 start += n;
672 }
673 return dydy0;
674 }
675
676 /** {@inheritDoc} */
677 public double[][] getInterpolatedDyDp() throws DerivativeException {
678 double[] extendedState = interpolator.getInterpolatedState();
679 final int n = y.length;
680 final int k = dydp[0].length;
681 int start = n * (n + 1);
682 for (int i = 0; i < n; ++i) {
683 System.arraycopy(extendedState, start, dydp[i], 0, k);
684 start += k;
685 }
686 return dydp;
687 }
688
689 /** {@inheritDoc} */
690 public double[] getInterpolatedYDot() throws DerivativeException {
691 double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
692 System.arraycopy(extendedDerivatives, 0, yDot, 0, yDot.length);
693 return yDot;
694 }
695
696 /** {@inheritDoc} */
697 public double[][] getInterpolatedDyDy0Dot() throws DerivativeException {
698 double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
699 final int n = y.length;
700 int start = n;
701 for (int i = 0; i < n; ++i) {
702 System.arraycopy(extendedDerivatives, start, dydy0Dot[i], 0, n);
703 start += n;
704 }
705 return dydy0Dot;
706 }
707
708 /** {@inheritDoc} */
709 public double[][] getInterpolatedDyDpDot() throws DerivativeException {
710 double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
711 final int n = y.length;
712 final int k = dydpDot[0].length;
713 int start = n * (n + 1);
714 for (int i = 0; i < n; ++i) {
715 System.arraycopy(extendedDerivatives, start, dydpDot[i], 0, k);
716 start += k;
717 }
718 return dydpDot;
719 }
720
721 /** {@inheritDoc} */
722 public double getCurrentTime() {
723 return interpolator.getCurrentTime();
724 }
725
726 /** {@inheritDoc} */
727 public StepInterpolatorWithJacobians copy() throws DerivativeException {
728 final int n = y.length;
729 final int k = dydp[0].length;
730 StepInterpolatorWrapper copied =
731 new StepInterpolatorWrapper(interpolator.copy(), n, k);
732 copyArray(y, copied.y);
733 copyArray(dydy0, copied.dydy0);
734 copyArray(dydp, copied.dydp);
735 copyArray(yDot, copied.yDot);
736 copyArray(dydy0Dot, copied.dydy0Dot);
737 copyArray(dydpDot, copied.dydpDot);
738 return copied;
739 }
740
741 /** {@inheritDoc} */
742 public void writeExternal(ObjectOutput out) throws IOException {
743 out.writeObject(interpolator);
744 out.writeInt(y.length);
745 out.writeInt(dydp[0].length);
746 writeArray(out, y);
747 writeArray(out, dydy0);
748 writeArray(out, dydp);
749 writeArray(out, yDot);
750 writeArray(out, dydy0Dot);
751 writeArray(out, dydpDot);
752 }
753
754 /** {@inheritDoc} */
755 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
756 interpolator = (StepInterpolator) in.readObject();
757 final int n = in.readInt();
758 final int k = in.readInt();
759 y = new double[n];
760 dydy0 = new double[n][n];
761 dydp = new double[n][k];
762 yDot = new double[n];
763 dydy0Dot = new double[n][n];
764 dydpDot = new double[n][k];
765 readArray(in, y);
766 readArray(in, dydy0);
767 readArray(in, dydp);
768 readArray(in, yDot);
769 readArray(in, dydy0Dot);
770 readArray(in, dydpDot);
771 }
772
773 /** Copy an array.
774 * @param src source array
775 * @param dest destination array
776 */
777 private static void copyArray(final double[] src, final double[] dest) {
778 System.arraycopy(src, 0, dest, 0, src.length);
779 }
780
781 /** Copy an array.
782 * @param src source array
783 * @param dest destination array
784 */
785 private static void copyArray(final double[][] src, final double[][] dest) {
786 for (int i = 0; i < src.length; ++i) {
787 copyArray(src[i], dest[i]);
788 }
789 }
790
791 /** Write an array.
792 * @param out output stream
793 * @param array array to write
794 * @exception IOException if array cannot be read
795 */
796 private static void writeArray(final ObjectOutput out, final double[] array)
797 throws IOException {
798 for (int i = 0; i < array.length; ++i) {
799 out.writeDouble(array[i]);
800 }
801 }
802
803 /** Write an array.
804 * @param out output stream
805 * @param array array to write
806 * @exception IOException if array cannot be read
807 */
808 private static void writeArray(final ObjectOutput out, final double[][] array)
809 throws IOException {
810 for (int i = 0; i < array.length; ++i) {
811 writeArray(out, array[i]);
812 }
813 }
814
815 /** Read an array.
816 * @param in input stream
817 * @param array array to read
818 * @exception IOException if array cannot be read
819 */
820 private static void readArray(final ObjectInput in, final double[] array)
821 throws IOException {
822 for (int i = 0; i < array.length; ++i) {
823 array[i] = in.readDouble();
824 }
825 }
826
827 /** Read an array.
828 * @param in input stream
829 * @param array array to read
830 * @exception IOException if array cannot be read
831 */
832 private static void readArray(final ObjectInput in, final double[][] array)
833 throws IOException {
834 for (int i = 0; i < array.length; ++i) {
835 readArray(in, array[i]);
836 }
837 }
838
839 }
840
841 /** Wrapper for event handlers. */
842 private static class EventHandlerWrapper implements EventHandler {
843
844 /** Underlying event handler with jacobians. */
845 private final EventHandlerWithJacobians handler;
846
847 /** State array. */
848 private double[] y;
849
850 /** Jacobian with respect to initial state dy/dy0. */
851 private double[][] dydy0;
852
853 /** Jacobian with respect to parameters dy/dp. */
854 private double[][] dydp;
855
856 /** Simple constructor.
857 * @param handler underlying event handler with jacobians
858 * @param n dimension of the original ODE
859 * @param k number of parameters
860 */
861 public EventHandlerWrapper(final EventHandlerWithJacobians handler,
862 final int n, final int k) {
863 this.handler = handler;
864 y = new double[n];
865 dydy0 = new double[n][n];
866 dydp = new double[n][k];
867 }
868
869 /** Get the underlying event handler with jacobians.
870 * @return underlying event handler with jacobians
871 */
872 public EventHandlerWithJacobians getHandler() {
873 return handler;
874 }
875
876 /** {@inheritDoc} */
877 public int eventOccurred(double t, double[] z, boolean increasing)
878 throws EventException {
879 dispatchCompoundState(z, y, dydy0, dydp);
880 return handler.eventOccurred(t, y, dydy0, dydp, increasing);
881 }
882
883 /** {@inheritDoc} */
884 public double g(double t, double[] z)
885 throws EventException {
886 dispatchCompoundState(z, y, dydy0, dydp);
887 return handler.g(t, y, dydy0, dydp);
888 }
889
890 /** {@inheritDoc} */
891 public void resetState(double t, double[] z)
892 throws EventException {
893 dispatchCompoundState(z, y, dydy0, dydp);
894 handler.resetState(t, y, dydy0, dydp);
895 }
896
897 }
898
899}