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    }