View Javadoc

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