Phil Steitz a écrit :
Luc,

I am about to commit the code.  Actually was working on that when I
saw this.  Once I have the code in, submit the patch against the code
in svn.

Here is the patch. I hope it is not too large to be submitted through this list. If anybody is upset with this, please accept my apologies.

The commit message I suggest is the following one:

fixed a problem when switching functions triggered derivatives discontinuities

Luc
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/geometry/Rotation.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/geometry/Rotation.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/geometry/Rotation.java	(working copy)
@@ -99,22 +99,6 @@
   }
 
   /** Build a rotation from the quaternion coordinates.
-   * @param q0 scalar part of the quaternion
-   * @param q1 first coordinate of the vectorial part of the quaternion
-   * @param q2 second coordinate of the vectorial part of the quaternion
-   * @param q3 third coordinate of the vectorial part of the quaternion
-   * @deprecated since Mantissa 6.3, this method as been deprecated as it
-   * does not properly handles non-normalized quaternions, it should be
-   * replaced by [EMAIL PROTECTED] #Rotation(double, double, double, double, boolean)}
-   */
-  public Rotation(double q0, double q1, double q2, double q3) {
-    this.q0 = q0;
-    this.q1 = q1;
-    this.q2 = q2;
-    this.q3 = q3;
-  }
-
-  /** Build a rotation from the quaternion coordinates.
    * <p>A rotation can be built from a <em>normalized</em> quaternion,
    * i.e. a quaternion for which q<sub>0</sub><sup>2</sup> +
    * q<sub>1</sub><sup>2</sup> + q<sub>2</sub><sup>2</sup> +
@@ -120,9 +104,6 @@
    * q<sub>1</sub><sup>2</sup> + q<sub>2</sub><sup>2</sup> +
    * q<sub>3</sub><sup>2</sup> = 1. If the quaternion is not normalized,
    * the constructor can normalize it in a preprocessing step.</p>
-   * <p>This method replaces the [EMAIL PROTECTED] #Rotation(double, double,
-   * double, double) constructor using only 4 doubles} which was deprecated
-   * as of version 6.3 of Mantissa.</p>
    * @param q0 scalar part of the quaternion
    * @param q1 first coordinate of the vectorial part of the quaternion
    * @param q2 second coordinate of the vectorial part of the quaternion
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/MessagesResources_fr.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/MessagesResources_fr.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/MessagesResources_fr.java	(working copy)
@@ -91,7 +91,7 @@
     { "dimensions mismatch: ODE problem has dimension {0},"
     + " state vector has dimension {1}",
       "incompatibilit\u00e9 de dimensions entre le probl\u00e8me ODE ({0}),"
-    + " et le vecteur d'\u00e9tat ({1})" },
+    + " et le vecteur d''\u00e9tat ({1})" },
     { "too small integration interval: length = {0}",
       "intervalle d''int\u00e9gration trop petit : {0}" },
 
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/GraggBulirschStoerIntegrator.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/GraggBulirschStoerIntegrator.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/GraggBulirschStoerIntegrator.java	(working copy)
@@ -880,7 +880,11 @@
         interpolator.storeTime(currentT);
         handler.handleStep(interpolator, lastStep);
 
-        switchesHandler.reset(currentT, y);
+        if (switchesHandler.reset(currentT, y) && ! lastStep) {
+          // some switching function has triggered changes that
+          // invalidate the derivatives, we need to recompute them
+          firstStepAlreadyComputed = false;
+        }
 
         int optimalIter;
         if (k == 1) {
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/RungeKuttaFehlbergIntegrator.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/RungeKuttaFehlbergIntegrator.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/RungeKuttaFehlbergIntegrator.java	(working copy)
@@ -311,7 +311,11 @@
         System.arraycopy(yDotK[stages - 1], 0, yDotK[0], 0, y0.length);
       }
 
-      switchesHandler.reset(currentT, y);
+      if (switchesHandler.reset(currentT, y) && ! lastStep) {
+        // some switching function has triggered changes that
+        // invalidate the derivatives, we need to recompute them
+        equations.computeDerivatives(currentT, y, yDotK[0]);
+      }
 
       if (! lastStep) {
         // stepsize control for next step
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/RungeKuttaIntegrator.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/RungeKuttaIntegrator.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/RungeKuttaIntegrator.java	(working copy)
@@ -234,7 +234,11 @@
         System.arraycopy(yDotK[stages - 1], 0, yDotK[0], 0, y0.length);
       }
 
-      switchesHandler.reset(currentT, y);
+      if (switchesHandler.reset(currentT, y) && ! lastStep) {
+        // some switching function has triggered changes that
+        // invalidate the derivatives, we need to recompute them
+        equations.computeDerivatives(currentT, y, yDotK[0]);
+      }
 
       if (needUpdate) {
         // a switching function has changed the step
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchingFunction.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchingFunction.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchingFunction.java	(working copy)
@@ -22,18 +22,20 @@
  * <p>A switching function allows to handle discrete events in
  * integration problems. These events occur for example when the
  * integration process should be stopped as some value is reached
- * (G-stop facility), or when the derivatives has
- * discontinuities. These events are traditionally defined as
- * occurring when a <code>g</code> function sign changes.</p>
+ * (G-stop facility), or when the derivatives have
+ * discontinuities, or simply when the user wants to monitor some
+ * states boundaries crossings. These events are traditionally defined
+ * as occurring when a <code>g</code> function sign changes, hence
+ * the name <em>switching functions</em>.</p>
  *
  * <p>Since events are only problem-dependent and are triggered by the
  * independant <i>time</i> variable and the state vector, they can
- * occur at virtually any time. The integrators will take care to
- * avoid sign changes inside the steps, they will reduce the step size
- * when such an event is detected in order to put this event exactly
- * at the end of the current step. This guarantees that step
- * interpolation (which always has a one step scope) is relevant even
- * in presence of discontinuities. This is independent from the
+ * occur at virtually any time, unknown in advance. The integrators will
+ * take care to avoid sign changes inside the steps, they will reduce
+ * the step size when such an event is detected in order to put this
+ * event exactly at the end of the current step. This guarantees that
+ * step interpolation (which always has a one step scope) is relevant
+ * even in presence of discontinuities. This is independent from the
  * stepsize control provided by integrators that monitor the local
  * error (this feature is available on all integrators, including
  * fixed step ones).</p>
@@ -52,14 +54,23 @@
    */
   public static final int STOP = 0;
 
-  /** Reset indicator.
+  /** Reset state indicator.
    * <p>This value should be used as the return value of the [EMAIL PROTECTED]
    * #eventOccurred eventOccurred} method when the integration should
    * go on after the event ending the current step, with a new state
-   * vector (which will be retrieved through the [EMAIL PROTECTED] #resetState
+   * vector (which will be retrieved thanks to the [EMAIL PROTECTED] #resetState
    * resetState} method).</p>
    */
-  public static final int RESET = 1;
+  public static final int RESET_STATE = 1;
+
+  /** Reset derivatives indicator.
+   * <p>This value should be used as the return value of the [EMAIL PROTECTED]
+   * #eventOccurred eventOccurred} method when the integration should
+   * go on after the event ending the current step, with a new derivatives
+   * vector (which will be retrieved thanks to the [EMAIL PROTECTED]
+   * FirstOrderDifferentialEquations#computeDerivatives} method).</p>
+   */
+  public static final int RESET_DERIVATIVES = 2;
 
   /** Continue indicator.
    * <p>This value should be used as the return value of the [EMAIL PROTECTED]
@@ -66,7 +77,7 @@
    * #eventOccurred eventOccurred} method when the integration should go
    * on after the event ending the current step.</p>
    */
-  public static final int CONTINUE = 2;
+  public static final int CONTINUE = 3;
 
   /** Compute the value of the switching function.
 
@@ -73,8 +84,8 @@
    * <p>Discrete events are generated when the sign of this function
    * changes, the integrator will take care to change the stepsize in
    * such a way these events occur exactly at step boundaries. This
-   * function must be continuous, as the integrator will need to find
-   * its roots to locate the events.</p>
+   * function must be continuous (at least in its roots neighborhood),
+   * as the integrator will need to find its roots to locate the events.</p>
 
    * @param t current value of the independant <i>time</i> variable
    * @param y array containing the current value of the state vector
@@ -88,16 +99,27 @@
    * ending exactly on a sign change of the function, just before the
    * step handler itself is called. It allows the user to update his
    * internal data to acknowledge the fact the event has been handled
-   * (for example setting a flag to switch the derivatives computation
-   * in case of discontinuity), and it allows to direct the integrator
-   * to either stop or continue integration, possibly with a reset
-   * state.</p>
+   * (for example setting a flag in the [EMAIL PROTECTED]
+   * FirstOrderDifferentialEquations differential equations} to switch
+   * the derivatives computation in case of discontinuity), or to
+   * direct the integrator to either stop or continue integration,
+   * possibly with a reset state or derivatives.</p>
 
-   * <p>If [EMAIL PROTECTED] #STOP} is returned, the step handler will be called
-   * with the <code>isLast</code> flag of the [EMAIL PROTECTED]
-   * StepHandler#handleStep handleStep} method set to true. If [EMAIL PROTECTED]
-   * #RESET} is returned, the [EMAIL PROTECTED] #resetState resetState} method
-   * will be called once the step handler has finished its task.</p>
+   * <ul>
+   *   <li>if [EMAIL PROTECTED] #STOP} is returned, the step handler will be called
+   *   with the <code>isLast</code> flag of the [EMAIL PROTECTED]
+   *   StepHandler#handleStep handleStep} method set to true and the
+   *   integration will be stopped,</li>
+   *   <li>if [EMAIL PROTECTED] #RESET_STATE} is returned, the [EMAIL PROTECTED] #resetState
+   *   resetState} method will be called once the step handler has
+   *   finished its task, and the integrator will also recompute the
+   *   derivatives,</li>
+   *   <li>if [EMAIL PROTECTED] #RESET_DERIVATIVES} is returned, the integrator
+   *   will recompute the derivatives,
+   *   <li>if [EMAIL PROTECTED] #CONTINUE} is returned, no specific action will
+   *   be taken (apart from having called this method) and integration
+   *   will continue.</li>
+   * </ul>
 
    * @param t current value of the independant <i>time</i> variable
    * @param y array containing the current value of the state vector
@@ -102,8 +124,8 @@
    * @param t current value of the independant <i>time</i> variable
    * @param y array containing the current value of the state vector
    * @return indication of what the integrator should do next, this
-   * value must be one of [EMAIL PROTECTED] #STOP}, [EMAIL PROTECTED] #RESET} or [EMAIL PROTECTED]
-   * #CONTINUE}
+   * value must be one of [EMAIL PROTECTED] #STOP}, [EMAIL PROTECTED] #RESET_STATE},
+   * [EMAIL PROTECTED] #RESET_DERIVATIVES} or [EMAIL PROTECTED] #CONTINUE}
    */
   public int eventOccurred(double t, double[] y);
   
@@ -111,11 +133,11 @@
 
    * <p>This method is called after the step handler has returned and
    * before the next step is started, but only when [EMAIL PROTECTED]
-   * #eventOccurred} has itself returned the [EMAIL PROTECTED] #RESET}
+   * #eventOccurred} has itself returned the [EMAIL PROTECTED] #RESET_STATE}
    * indicator. It allows the user to reset the state vector for the
    * next step, without perturbing the step handler of the finishing
    * step. If the [EMAIL PROTECTED] #eventOccurred} never returns the [EMAIL PROTECTED]
-   * #RESET} indicator, this function will never be called, and it is
+   * #RESET_STATE} indicator, this function will never be called, and it is
    * safe to leave its body empty.</p>
 
    * @param t current value of the independant <i>time</i> variable
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchingFunctionsHandler.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchingFunctionsHandler.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchingFunctionsHandler.java	(working copy)
@@ -166,11 +166,16 @@
    * beginning of the next step
    * @param y array were to put the desired state vector at the beginning
    * of the next step
+   * @return true if the integrator should reset the derivatives too
    */
-  public void reset(double t, double[] y) {
+  public boolean reset(double t, double[] y) {
+    boolean resetDerivatives = false;
     for (Iterator iter = functions.iterator(); iter.hasNext();) {
-      ((SwitchState) iter.next()).reset(t, y);
+      if (((SwitchState) iter.next()).reset(t, y)) {
+        resetDerivatives = true;
+      }
     }
+    return resetDerivatives;
   }
 
   /** Switching functions. */
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchState.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchState.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/src/org/spaceroots/mantissa/ode/SwitchState.java	(working copy)
@@ -239,15 +239,23 @@
    * beginning of the next step
    * @param y array were to put the desired state vector at the beginning
    * of the next step
+   * @return true if the integrator should reset the derivatives too
    */
-  public void reset(double t, double[] y) {
-    if (pendingEvent) {
-      if (nextAction == SwitchingFunction.RESET) {
-        function.resetState(t, y);
-      }
-      pendingEvent      = false;
-      pendingEventTime  = Double.NaN;
+  public boolean reset(double t, double[] y) {
+
+    if (! pendingEvent) {
+      return false;
+    }
+
+    if (nextAction == SwitchingFunction.RESET_STATE) {
+      function.resetState(t, y);
     }
+    pendingEvent      = false;
+    pendingEventTime  = Double.NaN;
+
+    return (nextAction == SwitchingFunction.RESET_STATE)
+        || (nextAction == SwitchingFunction.RESET_DERIVATIVES);
+
   }
 
   /** Get the value of the g function at the specified time.
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/DormandPrince853IntegratorTest.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/DormandPrince853IntegratorTest.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/DormandPrince853IntegratorTest.java	(working copy)
@@ -305,6 +305,17 @@
 
   }
 
+  public void testUnstableDerivative()
+  throws DerivativeException, IntegratorException {
+    final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0);
+    FirstOrderIntegrator integ =
+      new DormandPrince853Integrator(0.1, 10, 1.0e-12, 0.0);
+    integ.addSwitchingFunction(stepProblem, 1.0, 1.0e-12);
+    double[] y = { Double.NaN };
+    integ.integrate(stepProblem, 0.0, new double[] { 0.0 }, 10.0, y);
+    assertEquals(8.0, y[0], 1.0e-12);
+  }
+
   public static Test suite() {
     return new TestSuite(DormandPrince853IntegratorTest.class);
   }
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/GillIntegratorTest.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/GillIntegratorTest.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/GillIntegratorTest.java	(working copy)
@@ -196,6 +196,16 @@
                     pb.getFinalTime(), new double[pb.getDimension()]);
   }
 
+  public void testUnstableDerivative()
+  throws DerivativeException, IntegratorException {
+    final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0);
+    FirstOrderIntegrator integ = new GillIntegrator(0.3);
+    integ.addSwitchingFunction(stepProblem, 1.0, 1.0e-12);
+    double[] y = { Double.NaN };
+    integ.integrate(stepProblem, 0.0, new double[] { 0.0 }, 10.0, y);
+    assertEquals(8.0, y[0], 1.0e-12);
+  }
+
   public static Test suite() {
     return new TestSuite(GillIntegratorTest.class);
   }
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/GraggBulirschStoerIntegratorTest.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/GraggBulirschStoerIntegratorTest.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/GraggBulirschStoerIntegratorTest.java	(working copy)
@@ -256,6 +256,17 @@
                     pb.getFinalTime(), new double[pb.getDimension()]);
   }
 
+  public void testUnstableDerivative()
+    throws DerivativeException, IntegratorException {
+    final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0);
+    FirstOrderIntegrator integ =
+      new GraggBulirschStoerIntegrator(0.1, 10, 1.0e-12, 0.0);
+    integ.addSwitchingFunction(stepProblem, 1.0, 1.0e-12);
+    double[] y = { Double.NaN };
+    integ.integrate(stepProblem, 0.0, new double[] { 0.0 }, 10.0, y);
+    assertEquals(8.0, y[0], 1.0e-12);
+  }
+
   public static Test suite() {
     return new TestSuite(GraggBulirschStoerIntegratorTest.class);
   }
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/StepProblem.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/StepProblem.java	(revision 0)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/StepProblem.java	(revision 0)
@@ -0,0 +1,42 @@
+package org.spaceroots.mantissa.ode;
+
+
+public class StepProblem
+  implements FirstOrderDifferentialEquations, SwitchingFunction {
+
+  public StepProblem(double rateBefore, double rateAfter,
+                     double switchTime) {
+    this.rateAfter  = rateAfter;
+    this.switchTime = switchTime;
+    setRate(rateBefore);
+  }
+
+  public void computeDerivatives(double t, double[] y, double[] yDot) {
+    yDot[0] = rate;
+  }
+
+  public int getDimension() {
+    return 1;
+  }
+
+  public void setRate(double rate) {
+    this.rate = rate;
+  }
+
+  public int eventOccurred(double t, double[] y) {
+    setRate(rateAfter);
+    return RESET_DERIVATIVES;
+  }
+
+  public double g(double t, double[] y) {
+    return t - switchTime;
+  }
+
+  public void resetState(double t, double[] y) {
+  }
+
+  private double rate;
+  private double rateAfter;
+  private double switchTime;
+
+}
Index: /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/TestProblem4.java
===================================================================
--- /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/TestProblem4.java	(revision 476939)
+++ /home/luc/sources/jakarta/commons-math/src/mantissa/tests-src/org/spaceroots/mantissa/ode/TestProblem4.java	(working copy)
@@ -104,7 +104,7 @@
     public int eventOccurred(double t, double[] y) {
       // this sign change is needed because the state will be reset soon
       sign = -sign;
-      return SwitchingFunction.RESET;
+      return SwitchingFunction.RESET_STATE;
     }
   
     public void resetState(double t, double[] y) {

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to