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;
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 }