/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.math4.ode; import org.apache.commons.math4.RealFieldElement; import org.apache.commons.math4.exception.MaxCountExceededException; import org.apache.commons.math4.ode.sampling.FieldStepHandler; import org.apache.commons.math4.ode.sampling.FieldStepInterpolator; import org.apache.commons.math4.util.MathUtils; /** * This class is used to handle steps for the test problems * integrated during the junit tests for the ODE integrators. * @param <T> the type of the field elements */ public class TestFieldProblemHandler<T extends RealFieldElement<T>> implements FieldStepHandler<T> { /** Associated problem. */ private TestFieldProblemAbstract<T> problem; /** Maximal errors encountered during the integration. */ private T maxValueError; private T maxTimeError; /** Error at the end of the integration. */ private T lastError; /** Time at the end of integration. */ private T lastTime; /** ODE solver used. */ private FirstOrderFieldIntegrator<T> integrator; /** Expected start for step. */ private T expectedStepStart; /** * Simple constructor. * @param problem problem for which steps should be handled * @param integrator ODE solver used */ public TestFieldProblemHandler(TestFieldProblemAbstract<T> problem, FirstOrderFieldIntegrator<T> integrator) { this.problem = problem; this.integrator = integrator; maxValueError = problem.getField().getZero(); maxTimeError = problem.getField().getZero(); lastError = problem.getField().getZero(); expectedStepStart = null; } @Override public void init(FieldODEStateAndDerivative<T> state0, T t) { maxValueError = problem.getField().getZero(); maxTimeError = problem.getField().getZero(); lastError = problem.getField().getZero(); expectedStepStart = null; } @Override public void handleStep(FieldStepInterpolator<T> interpolator, boolean isLast) throws MaxCountExceededException { T start = integrator.getCurrentStepStart().getTime(); if (start.subtract(problem.getInitialState().getTime()).divide(integrator.getCurrentSignedStepsize()).abs().getReal() > 0.001) { // multistep integrators do not handle the first steps themselves // so we have to make sure the integrator we look at has really started its work if (expectedStepStart != null) { // the step should either start at the end of the integrator step // or at an event if the step is split into several substeps T stepError = MathUtils.max(maxTimeError, start.subtract(expectedStepStart).abs()); for (T eventTime : problem.getTheoreticalEventsTimes()) { stepError = MathUtils.min(stepError, start.subtract(eventTime).abs()); } maxTimeError = MathUtils.max(maxTimeError, stepError); } expectedStepStart = start.add(integrator.getCurrentSignedStepsize()); } T pT = interpolator.getPreviousState().getTime(); T cT = interpolator.getCurrentState().getTime(); T[] errorScale = problem.getErrorScale(); // store the error at the last step if (isLast) { T[] interpolatedY = interpolator.getInterpolatedState(cT).getState(); T[] theoreticalY = problem.computeTheoreticalState(cT); for (int i = 0; i < interpolatedY.length; ++i) { T error = interpolatedY[i].subtract(theoreticalY[i]).abs(); lastError = MathUtils.max(error, lastError); } lastTime = cT; } // walk through the step for (int k = 0; k <= 20; ++k) { T time = pT.add(cT.subtract(pT).multiply(k).divide(20)); T[] interpolatedY = interpolator.getInterpolatedState(time).getState(); T[] theoreticalY = problem.computeTheoreticalState(time); // update the errors for (int i = 0; i < interpolatedY.length; ++i) { T error = errorScale[i].multiply(interpolatedY[i].subtract(theoreticalY[i]).abs()); maxValueError = MathUtils.max(error, maxValueError); } } } /** * Get the maximal value error encountered during integration. * @return maximal value error */ public T getMaximalValueError() { return maxValueError; } /** * Get the maximal time error encountered during integration. * @return maximal time error */ public T getMaximalTimeError() { return maxTimeError; } /** * Get the error at the end of the integration. * @return error at the end of the integration */ public T getLastError() { return lastError; } /** * Get the time at the end of the integration. * @return time at the end of the integration. */ public T getLastTime() { return lastTime; } }