📄 graggbulirschstoerintegrator.java
字号:
/* * 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.math.ode;/** * This class implements a Gragg-Bulirsch-Stoer integrator for * Ordinary Differential Equations. * * <p>The Gragg-Bulirsch-Stoer algorithm is one of the most efficient * ones currently available for smooth problems. It uses Richardson * extrapolation to estimate what would be the solution if the step * size could be decreased down to zero.</p> * * <p> * This method changes both the step size and the order during * integration, in order to minimize computation cost. It is * particularly well suited when a very high precision is needed. The * limit where this method becomes more efficient than high-order * embedded Runge-Kutta methods like {@link DormandPrince853Integrator * Dormand-Prince 8(5,3)} depends on the problem. Results given in the * Hairer, Norsett and Wanner book show for example that this limit * occurs for accuracy around 1e-6 when integrating Saltzam-Lorenz * equations (the authors note this problem is <i>extremely sensitive * to the errors in the first integration steps</i>), and around 1e-11 * for a two dimensional celestial mechanics problems with seven * bodies (pleiades problem, involving quasi-collisions for which * <i>automatic step size control is essential</i>). * </p> * * <p> * This implementation is basically a reimplementation in Java of the * <a * href="http://www.unige.ch/math/folks/hairer/prog/nonstiff/odex.f">odex</a> * fortran code by E. Hairer and G. Wanner. The redistribution policy * for this code is available <a * href="http://www.unige.ch/~hairer/prog/licence.txt">here</a>, for * convenience, it is reproduced below.</p> * </p> * * <table border="0" width="80%" cellpadding="10" align="center" bgcolor="#E0E0E0"> * <tr><td>Copyright (c) 2004, Ernst Hairer</td></tr> * * <tr><td>Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * <ul> * <li>Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer.</li> * <li>Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution.</li> * </ul></td></tr> * * <tr><td><strong>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</strong></td></tr> * </table> * * @author E. Hairer and G. Wanner (fortran version) * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $ * @since 1.2 */public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator { /** Integrator method name. */ private static final String methodName = "Gragg-Bulirsch-Stoer"; /** Simple constructor. * Build a Gragg-Bulirsch-Stoer integrator with the given step * bounds. All tuning parameters are set to their default * values. The default step handler does nothing. * @param minStep minimal step (must be positive even for backward * integration), the last step can be smaller than this * @param maxStep maximal step (must be positive even for backward * integration) * @param scalAbsoluteTolerance allowed absolute error * @param scalRelativeTolerance allowed relative error */ public GraggBulirschStoerIntegrator(double minStep, double maxStep, double scalAbsoluteTolerance, double scalRelativeTolerance) { super(minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance); denseOutput = (handler.requiresDenseOutput() || (! switchesHandler.isEmpty())); setStabilityCheck(true, -1, -1, -1); setStepsizeControl(-1, -1, -1, -1); setOrderControl(-1, -1, -1); setInterpolationControl(true, -1); } /** Simple constructor. * Build a Gragg-Bulirsch-Stoer integrator with the given step * bounds. All tuning parameters are set to their default * values. The default step handler does nothing. * @param minStep minimal step (must be positive even for backward * integration), the last step can be smaller than this * @param maxStep maximal step (must be positive even for backward * integration) * @param vecAbsoluteTolerance allowed absolute error * @param vecRelativeTolerance allowed relative error */ public GraggBulirschStoerIntegrator(double minStep, double maxStep, double[] vecAbsoluteTolerance, double[] vecRelativeTolerance) { super(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance); denseOutput = (handler.requiresDenseOutput() || (! switchesHandler.isEmpty())); setStabilityCheck(true, -1, -1, -1); setStepsizeControl(-1, -1, -1, -1); setOrderControl(-1, -1, -1); setInterpolationControl(true, -1); } /** Set the stability check controls. * <p>The stability check is performed on the first few iterations of * the extrapolation scheme. If this test fails, the step is rejected * and the stepsize is reduced.</p> * <p>By default, the test is performed, at most during two * iterations at each step, and at most once for each of these * iterations. The default stepsize reduction factor is 0.5.</p> * @param performTest if true, stability check will be performed, if false, the check will be skipped * @param maxIter maximal number of iterations for which checks are * performed (the number of iterations is reset to default if negative * or null) * @param maxChecks maximal number of checks for each iteration * (the number of checks is reset to default if negative or null) * @param stabilityReduction stepsize reduction factor in case of * failure (the factor is reset to default if lower than 0.0001 or * greater than 0.9999) */ public void setStabilityCheck(boolean performTest, int maxIter, int maxChecks, double stabilityReduction) { this.performTest = performTest; this.maxIter = (maxIter <= 0) ? 2 : maxIter; this.maxChecks = (maxChecks <= 0) ? 1 : maxChecks; if ((stabilityReduction < 0.0001) || (stabilityReduction > 0.9999)) { this.stabilityReduction = 0.5; } else { this.stabilityReduction = stabilityReduction; } } /** Set the step size control factors. * <p>The new step size hNew is computed from the old one h by: * <pre> * hNew = h * stepControl2 / (err/stepControl1)^(1/(2k+1)) * </pre> * where err is the scaled error and k the iteration number of the * extrapolation scheme (counting from 0). The default values are * 0.65 for stepControl1 and 0.94 for stepControl2.</p> * <p>The step size is subject to the restriction: * <pre> * stepControl3^(1/(2k+1))/stepControl4 <= hNew/h <= 1/stepControl3^(1/(2k+1)) * </pre> * The default values are 0.02 for stepControl3 and 4.0 for * stepControl4.</p> * @param stepControl1 first stepsize control factor (the factor is * reset to default if lower than 0.0001 or greater than 0.9999) * @param stepControl2 second stepsize control factor (the factor * is reset to default if lower than 0.0001 or greater than 0.9999) * @param stepControl3 third stepsize control factor (the factor is * reset to default if lower than 0.0001 or greater than 0.9999) * @param stepControl4 fourth stepsize control factor (the factor * is reset to default if lower than 1.0001 or greater than 999.9) */ public void setStepsizeControl(double stepControl1, double stepControl2, double stepControl3, double stepControl4) { if ((stepControl1 < 0.0001) || (stepControl1 > 0.9999)) { this.stepControl1 = 0.65; } else { this.stepControl1 = stepControl1; } if ((stepControl2 < 0.0001) || (stepControl2 > 0.9999)) { this.stepControl2 = 0.94; } else { this.stepControl2 = stepControl2; } if ((stepControl3 < 0.0001) || (stepControl3 > 0.9999)) { this.stepControl3 = 0.02; } else { this.stepControl3 = stepControl3; } if ((stepControl4 < 1.0001) || (stepControl4 > 999.9)) { this.stepControl4 = 4.0; } else { this.stepControl4 = stepControl4; } } /** Set the order control parameters. * <p>The Gragg-Bulirsch-Stoer method changes both the step size and * the order during integration, in order to minimize computation * cost. Each extrapolation step increases the order by 2, so the * maximal order that will be used is always even, it is twice the * maximal number of columns in the extrapolation table.</p> * <pre> * order is decreased if w(k-1) <= w(k) * orderControl1 * order is increased if w(k) <= w(k-1) * orderControl2 * </pre> * <p>where w is the table of work per unit step for each order * (number of function calls divided by the step length), and k is * the current order.</p> * <p>The default maximal order after construction is 18 (i.e. the * maximal number of columns is 9). The default values are 0.8 for * orderControl1 and 0.9 for orderControl2.</p> * @param maxOrder maximal order in the extrapolation table (the * maximal order is reset to default if order <= 6 or odd) * @param orderControl1 first order control factor (the factor is * reset to default if lower than 0.0001 or greater than 0.9999) * @param orderControl2 second order control factor (the factor * is reset to default if lower than 0.0001 or greater than 0.9999) */ public void setOrderControl(int maxOrder, double orderControl1, double orderControl2) { if ((maxOrder <= 6) || (maxOrder % 2 != 0)) { this.maxOrder = 18; } if ((orderControl1 < 0.0001) || (orderControl1 > 0.9999)) { this.orderControl1 = 0.8; } else { this.orderControl1 = orderControl1; } if ((orderControl2 < 0.0001) || (orderControl2 > 0.9999)) { this.orderControl2 = 0.9; } else { this.orderControl2 = orderControl2; } // reinitialize the arrays initializeArrays(); } /** Set the step handler for this integrator. * The handler will be called by the integrator for each accepted * step. * @param handler handler for the accepted steps */ public void setStepHandler (StepHandler handler) { super.setStepHandler(handler); denseOutput = (handler.requiresDenseOutput() || (! switchesHandler.isEmpty())); // reinitialize the arrays initializeArrays(); } /** Add a switching function to the integrator. * @param function switching function * @param maxCheckInterval maximal time interval between switching * function checks (this interval prevents missing sign changes in * case the integration steps becomes very large) * @param convergence convergence threshold in the event time search * @param maxIterationCount upper limit of the iteration count in * the event time search */ public void addSwitchingFunction(SwitchingFunction function, double maxCheckInterval, double convergence, int maxIterationCount) { super.addSwitchingFunction(function, maxCheckInterval, convergence, maxIterationCount); denseOutput = (handler.requiresDenseOutput() || (! switchesHandler.isEmpty())); // reinitialize the arrays initializeArrays(); } /** Initialize the integrator internal arrays. */ private void initializeArrays() { int size = maxOrder / 2; if ((sequence == null) || (sequence.length != size)) { // all arrays should be reallocated with the right size sequence = new int[size]; costPerStep = new int[size]; coeff = new double[size][]; costPerTimeUnit = new double[size]; optimalStep = new double[size]; } if (denseOutput) { // step size sequence: 2, 6, 10, 14, ... for (int k = 0; k < size; ++k) { sequence[k] = 4 * k + 2; } } else { // step size sequence: 2, 4, 6, 8, ... for (int k = 0; k < size; ++k) { sequence[k] = 2 * (k + 1); } } // initialize the order selection cost array // (number of function calls for each column of the extrapolation table) costPerStep[0] = sequence[0] + 1; for (int k = 1; k < size; ++k) { costPerStep[k] = costPerStep[k-1] + sequence[k]; } // initialize the extrapolation tables
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -