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