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