Home | History | Annotate | Download | only in sampling
      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 import 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 fvr. 2011) $
     48  * @since 1.2
     49  */
     50 
     51 public 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 }
    162