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 org.apache.commons.math.ode.DerivativeException;
021 import org.apache.commons.math.ode.ODEIntegrator;
022 import org.apache.commons.math.ode.sampling.StepHandler;
023 import org.apache.commons.math.ode.sampling.StepInterpolator;
024
025 /**
026 * This class is used to handle steps for the test problems
027 * integrated during the junit tests for the ODE integrators.
028 */
029 public class TestProblemHandler
030 implements StepHandler {
031
032 /** Associated problem. */
033 private TestProblemAbstract problem;
034
035 /** Maximal errors encountered during the integration. */
036 private double maxValueError;
037 private double maxTimeError;
038
039 /** Error at the end of the integration. */
040 private double lastError;
041
042 /** Time at the end of integration. */
043 private double lastTime;
044
045 /** ODE solver used. */
046 private ODEIntegrator integrator;
047
048 /** Expected start for step. */
049 private double expectedStepStart;
050
051 /**
052 * Simple constructor.
053 * @param problem problem for which steps should be handled
054 * @param integrator ODE solver used
055 */
056 public TestProblemHandler(TestProblemAbstract problem, ODEIntegrator integrator) {
057 this.problem = problem;
058 this.integrator = integrator;
059 reset();
060 }
061
062 public boolean requiresDenseOutput() {
063 return true;
064 }
065
066 public void reset() {
067 maxValueError = 0;
068 maxTimeError = 0;
069 lastError = 0;
070 expectedStepStart = Double.NaN;
071 }
072
073 public void handleStep(StepInterpolator interpolator,
074 boolean isLast)
075 throws DerivativeException {
076
077 double start = integrator.getCurrentStepStart();
078 if (Math.abs((start - problem.getInitialTime()) / integrator.getCurrentSignedStepsize()) > 0.001) {
079 // multistep integrators do not handle the first steps themselves
080 // so we have to make sure the integrator we look at has really started its work
081 if (!Double.isNaN(expectedStepStart)) {
082 maxTimeError = Math.max(maxTimeError, Math.abs(start - expectedStepStart));
083 }
084 expectedStepStart = start + integrator.getCurrentSignedStepsize();
085 }
086
087 double pT = interpolator.getPreviousTime();
088 double cT = interpolator.getCurrentTime();
089 double[] errorScale = problem.getErrorScale();
090
091 // store the error at the last step
092 if (isLast) {
093 double[] interpolatedY = interpolator.getInterpolatedState();
094 double[] theoreticalY = problem.computeTheoreticalState(cT);
095 for (int i = 0; i < interpolatedY.length; ++i) {
096 double error = Math.abs(interpolatedY[i] - theoreticalY[i]);
097 lastError = Math.max(error, lastError);
098 }
099 lastTime = cT;
100 }
101
102 // walk through the step
103 for (int k = 0; k <= 20; ++k) {
104
105 double time = pT + (k * (cT - pT)) / 20;
106 interpolator.setInterpolatedTime(time);
107 double[] interpolatedY = interpolator.getInterpolatedState();
108 double[] theoreticalY = problem.computeTheoreticalState(interpolator.getInterpolatedTime());
109
110 // update the errors
111 for (int i = 0; i < interpolatedY.length; ++i) {
112 double error = errorScale[i] * Math.abs(interpolatedY[i] - theoreticalY[i]);
113 maxValueError = Math.max(error, maxValueError);
114 }
115 }
116 }
117
118 /**
119 * Get the maximal value error encountered during integration.
120 * @return maximal value error
121 */
122 public double getMaximalValueError() {
123 return maxValueError;
124 }
125
126 /**
127 * Get the maximal time error encountered during integration.
128 * @return maximal time error
129 */
130 public double getMaximalTimeError() {
131 return maxTimeError;
132 }
133
134 /**
135 * Get the error at the end of the integration.
136 * @return error at the end of the integration
137 */
138 public double getLastError() {
139 return lastError;
140 }
141
142 /**
143 * Get the time at the end of the integration.
144 * @return time at the end of the integration.
145 */
146 public double getLastTime() {
147 return lastTime;
148 }
149
150 }