001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.math.ode.sampling; 019 020 import org.apache.commons.math.ode.DerivativeException; 021 import org.apache.commons.math.util.FastMath; 022 023 /** 024 * This class wraps an object implementing {@link FixedStepHandler} 025 * into a {@link StepHandler}. 026 027 * <p>This wrapper allows to use fixed step handlers with general 028 * integrators which cannot guaranty their integration steps will 029 * remain constant and therefore only accept general step 030 * handlers.</p> 031 * 032 * <p>The stepsize used is selected at construction time. The {@link 033 * FixedStepHandler#handleStep handleStep} method of the underlying 034 * {@link FixedStepHandler} object is called at the beginning time of 035 * the integration t0 and also at times t0+h, t0+2h, ... If the 036 * integration range is an integer multiple of the stepsize, then the 037 * last point handled will be the endpoint of the integration tend, if 038 * not, the last point will belong to the interval [tend - h ; 039 * tend].</p> 040 * 041 * <p>There is no constraint on the integrator, it can use any 042 * timestep it needs (time steps longer or shorter than the fixed time 043 * step and non-integer ratios are all allowed).</p> 044 * 045 * @see StepHandler 046 * @see FixedStepHandler 047 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $ 048 * @since 1.2 049 */ 050 051 public class StepNormalizer implements StepHandler { 052 053 /** Fixed time step. */ 054 private double h; 055 056 /** Underlying step handler. */ 057 private final FixedStepHandler handler; 058 059 /** Last step time. */ 060 private double lastTime; 061 062 /** Last State vector. */ 063 private double[] lastState; 064 065 /** Last Derivatives vector. */ 066 private double[] lastDerivatives; 067 068 /** Integration direction indicator. */ 069 private boolean forward; 070 071 /** Simple constructor. 072 * @param h fixed time step (sign is not used) 073 * @param handler fixed time step handler to wrap 074 */ 075 public StepNormalizer(final double h, final FixedStepHandler handler) { 076 this.h = FastMath.abs(h); 077 this.handler = handler; 078 reset(); 079 } 080 081 /** Determines whether this handler needs dense output. 082 * This handler needs dense output in order to provide data at 083 * regularly spaced steps regardless of the steps the integrator 084 * uses, so this method always returns true. 085 * @return always true 086 */ 087 public boolean requiresDenseOutput() { 088 return true; 089 } 090 091 /** Reset the step handler. 092 * Initialize the internal data as required before the first step is 093 * handled. 094 */ 095 public void reset() { 096 lastTime = Double.NaN; 097 lastState = null; 098 lastDerivatives = null; 099 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 }