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; 019 020 import java.util.ArrayList; 021 import java.util.Collection; 022 import java.util.Collections; 023 024 import org.apache.commons.math.MaxEvaluationsExceededException; 025 import org.apache.commons.math.ode.events.CombinedEventsManager; 026 import org.apache.commons.math.ode.events.EventHandler; 027 import org.apache.commons.math.ode.events.EventState; 028 import org.apache.commons.math.ode.sampling.StepHandler; 029 030 /** 031 * Base class managing common boilerplate for all integrators. 032 * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $ 033 * @since 2.0 034 */ 035 public abstract class AbstractIntegrator implements FirstOrderIntegrator { 036 037 038 /** Name of the method. */ 039 private final String name; 040 041 /** Maximal number of evaluations allowed. */ 042 private int maxEvaluations; 043 044 /** Number of evaluations already performed. */ 045 private int evaluations; 046 047 /** Differential equations to integrate. */ 048 private transient FirstOrderDifferentialEquations equations; 049 050 /** Step handler. */ 051 protected Collection<StepHandler> stepHandlers; 052 053 /** Current step start time. */ 054 protected double stepStart; 055 056 /** Current stepsize. */ 057 protected double stepSize; 058 059 /** Events handlers manager. */ 060 protected CombinedEventsManager eventsHandlersManager; 061 062 /** Build an instance. 063 * @param name name of the method 064 */ 065 public AbstractIntegrator(final String name) { 066 this.name = name; 067 stepHandlers = new ArrayList<StepHandler>(); 068 stepStart = Double.NaN; 069 stepSize = Double.NaN; 070 eventsHandlersManager = new CombinedEventsManager(); 071 setMaxEvaluations(-1); 072 resetEvaluations(); 073 } 074 075 /** Build an instance with a null name. 076 */ 077 protected AbstractIntegrator() { 078 this(null); 079 } 080 081 /** {@inheritDoc} */ 082 public String getName() { 083 return name; 084 } 085 086 /** {@inheritDoc} */ 087 public void addStepHandler(final StepHandler handler) { 088 stepHandlers.add(handler); 089 } 090 091 /** {@inheritDoc} */ 092 public Collection<StepHandler> getStepHandlers() { 093 return Collections.unmodifiableCollection(stepHandlers); 094 } 095 096 /** {@inheritDoc} */ 097 public void clearStepHandlers() { 098 stepHandlers.clear(); 099 } 100 101 /** {@inheritDoc} */ 102 public void addEventHandler(final EventHandler function, 103 final double maxCheckInterval, 104 final double convergence, 105 final int maxIterationCount) { 106 eventsHandlersManager.addEventHandler(function, maxCheckInterval, 107 convergence, maxIterationCount); 108 } 109 110 /** {@inheritDoc} */ 111 public Collection<EventHandler> getEventHandlers() { 112 return eventsHandlersManager.getEventsHandlers(); 113 } 114 115 /** {@inheritDoc} */ 116 public void clearEventHandlers() { 117 eventsHandlersManager.clearEventsHandlers(); 118 } 119 120 /** Check if one of the step handlers requires dense output. 121 * @return true if one of the step handlers requires dense output 122 */ 123 protected boolean requiresDenseOutput() { 124 for (StepHandler handler : stepHandlers) { 125 if (handler.requiresDenseOutput()) { 126 return true; 127 } 128 } 129 return false; 130 } 131 132 /** {@inheritDoc} */ 133 public double getCurrentStepStart() { 134 return stepStart; 135 } 136 137 /** {@inheritDoc} */ 138 public double getCurrentSignedStepsize() { 139 return stepSize; 140 } 141 142 /** {@inheritDoc} */ 143 public void setMaxEvaluations(int maxEvaluations) { 144 this.maxEvaluations = (maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations; 145 } 146 147 /** {@inheritDoc} */ 148 public int getMaxEvaluations() { 149 return maxEvaluations; 150 } 151 152 /** {@inheritDoc} */ 153 public int getEvaluations() { 154 return evaluations; 155 } 156 157 /** Reset the number of evaluations to zero. 158 */ 159 protected void resetEvaluations() { 160 evaluations = 0; 161 } 162 163 /** Set the differential equations. 164 * @param equations differential equations to integrate 165 * @see #computeDerivatives(double, double[], double[]) 166 */ 167 protected void setEquations(final FirstOrderDifferentialEquations equations) { 168 this.equations = equations; 169 } 170 171 /** Compute the derivatives and check the number of evaluations. 172 * @param t current value of the independent <I>time</I> variable 173 * @param y array containing the current value of the state vector 174 * @param yDot placeholder array where to put the time derivative of the state vector 175 * @throws DerivativeException this exception is propagated to the caller if the 176 * underlying user function triggers one 177 */ 178 public void computeDerivatives(final double t, final double[] y, final double[] yDot) 179 throws DerivativeException { 180 if (++evaluations > maxEvaluations) { 181 throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations)); 182 } 183 equations.computeDerivatives(t, y, yDot); 184 } 185 186 /** Perform some sanity checks on the integration parameters. 187 * @param equations differential equations set 188 * @param t0 start time 189 * @param y0 state vector at t0 190 * @param t target time for the integration 191 * @param y placeholder where to put the state vector 192 * @exception IntegratorException if some inconsistency is detected 193 */ 194 protected void sanityChecks(final FirstOrderDifferentialEquations equations, 195 final double t0, final double[] y0, 196 final double t, final double[] y) 197 throws IntegratorException { 198 199 if (equations.getDimension() != y0.length) { 200 throw new IntegratorException( 201 "dimensions mismatch: ODE problem has dimension {0}," + 202 " initial state vector has dimension {1}", 203 equations.getDimension(), y0.length); 204 } 205 206 if (equations.getDimension() != y.length) { 207 throw new IntegratorException( 208 "dimensions mismatch: ODE problem has dimension {0}," + 209 " final state vector has dimension {1}", 210 equations.getDimension(), y.length); 211 } 212 213 if (Math.abs(t - t0) <= 1.0e-12 * Math.max(Math.abs(t0), Math.abs(t))) { 214 throw new IntegratorException( 215 "too small integration interval: length = {0}", 216 Math.abs(t - t0)); 217 } 218 219 } 220 221 /** Add an event handler for end time checking. 222 * <p>This method can be used to simplify handling of integration end time. 223 * It leverages the nominal stop condition with the exceptional stop 224 * conditions.</p> 225 * @param startTime integration start time 226 * @param endTime desired end time 227 * @param manager manager containing the user-defined handlers 228 * @return a new manager containing all the user-defined handlers plus a 229 * dedicated manager triggering a stop event at entTime 230 */ 231 protected CombinedEventsManager addEndTimeChecker(final double startTime, 232 final double endTime, 233 final CombinedEventsManager manager) { 234 CombinedEventsManager newManager = new CombinedEventsManager(); 235 for (final EventState state : manager.getEventsStates()) { 236 newManager.addEventHandler(state.getEventHandler(), 237 state.getMaxCheckInterval(), 238 state.getConvergence(), 239 state.getMaxIterationCount()); 240 } 241 newManager.addEventHandler(new EndTimeChecker(endTime), 242 Double.POSITIVE_INFINITY, 243 Math.ulp(Math.max(Math.abs(startTime), Math.abs(endTime))), 244 100); 245 return newManager; 246 } 247 248 /** Specialized event handler to stop integration. */ 249 private static class EndTimeChecker implements EventHandler { 250 251 /** Desired end time. */ 252 private final double endTime; 253 254 /** Build an instance. 255 * @param endTime desired time 256 */ 257 public EndTimeChecker(final double endTime) { 258 this.endTime = endTime; 259 } 260 261 /** {@inheritDoc} */ 262 public int eventOccurred(double t, double[] y, boolean increasing) { 263 return STOP; 264 } 265 266 /** {@inheritDoc} */ 267 public double g(double t, double[] y) { 268 return t - endTime; 269 } 270 271 /** {@inheritDoc} */ 272 public void resetState(double t, double[] y) { 273 } 274 275 } 276 277 }