1 /*
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
18 package org.apache.commons.math.ode;
19
20 /**
21 * This class wraps an object implementing {@link FixedStepHandler}
22 * into a {@link StepHandler}.
23
24 * <p>This wrapper allows to use fixed step handlers with general
25 * integrators which cannot guaranty their integration steps will
26 * remain constant and therefore only accept general step
27 * handlers.</p>
28 *
29 * <p>The stepsize used is selected at construction time. The {@link
30 * FixedStepHandler#handleStep handleStep} method of the underlying
31 * {@link FixedStepHandler} object is called at the beginning time of
32 * the integration t0 and also at times t0+h, t0+2h, ... If the
33 * integration range is an integer multiple of the stepsize, then the
34 * last point handled will be the endpoint of the integration tend, if
35 * not, the last point will belong to the interval [tend - h ;
36 * tend].</p>
37 *
38 * <p>There is no constraint on the integrator, it can use any
39 * timestep it needs (time steps longer or shorter than the fixed time
40 * step and non-integer ratios are all allowed).</p>
41 *
42 * @see StepHandler
43 * @see FixedStepHandler
44 * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $
45 * @since 1.2
46 */
47
48 public class StepNormalizer
49 implements StepHandler {
50
51 /** Simple constructor.
52 * @param h fixed time step (sign is not used)
53 * @param handler fixed time step handler to wrap
54 */
55 public StepNormalizer(double h, FixedStepHandler handler) {
56 this.h = Math.abs(h);
57 this.handler = handler;
58 reset();
59 }
60
61 /** Determines whether this handler needs dense output.
62 * This handler needs dense output in order to provide data at
63 * regularly spaced steps regardless of the steps the integrator
64 * uses, so this method always returns true.
65 * @return always true
66 */
67 public boolean requiresDenseOutput() {
68 return true;
69 }
70
71 /** Reset the step handler.
72 * Initialize the internal data as required before the first step is
73 * handled.
74 */
75 public void reset() {
76 lastTime = Double.NaN;
77 lastState = null;
78 forward = true;
79 }
80
81 /**
82 * Handle the last accepted step
83 * @param interpolator interpolator for the last accepted step. For
84 * efficiency purposes, the various integrators reuse the same
85 * object on each call, so if the instance wants to keep it across
86 * all calls (for example to provide at the end of the integration a
87 * continuous model valid throughout the integration range), it
88 * should build a local copy using the clone method and store this
89 * copy.
90 * @param isLast true if the step is the last one
91 * @throws DerivativeException this exception is propagated to the
92 * caller if the underlying user function triggers one
93 */
94 public void handleStep(StepInterpolator interpolator, boolean isLast)
95 throws DerivativeException {
96
97 double nextTime;
98
99 if (lastState == null) {
100
101 lastTime = interpolator.getPreviousTime();
102 interpolator.setInterpolatedTime(lastTime);
103
104 double[] state = interpolator.getInterpolatedState();
105 lastState = (double[]) state.clone();
106
107 // take the integration direction into account
108 forward = (interpolator.getCurrentTime() >= lastTime);
109 if (! forward) {
110 h = -h;
111 }
112
113 }
114
115 nextTime = lastTime + h;
116 boolean nextInStep = forward ^ (nextTime > interpolator.getCurrentTime());
117 while (nextInStep) {
118
119 // output the stored previous step
120 handler.handleStep(lastTime, lastState, false);
121
122 // store the next step
123 lastTime = nextTime;
124 interpolator.setInterpolatedTime(lastTime);
125 System.arraycopy(interpolator.getInterpolatedState(), 0,
126 lastState, 0, lastState.length);
127
128 nextTime += h;
129 nextInStep = forward ^ (nextTime > interpolator.getCurrentTime());
130
131 }
132
133 if (isLast) {
134 // there will be no more steps,
135 // the stored one should be flagged as being the last
136 handler.handleStep(lastTime, lastState, true);
137 }
138
139 }
140
141 /** Fixed time step. */
142 private double h;
143
144 /** Underlying step handler. */
145 private FixedStepHandler handler;
146
147 /** Last step time. */
148 private double lastTime;
149
150 /** Last State vector. */
151 private double[] lastState;
152
153 /** Integration direction indicator. */
154 private boolean forward;
155
156 }