From 3601eb92eec39706d25e02bdb5a4b5f30d840a1a Mon Sep 17 00:00:00 2001
From: Luc Maisonobe <luc@orekit.org>
Date: Mon, 10 Jan 2011 08:11:44 +0000
Subject: [PATCH] completely revamped partial derivatives computation in
 numerical propagation added a way to perform numerical propagation in either
 cartesian parameters or equinoctial parameters

---
 .gitignore                                    |   4 +
 checkstyle.xml                                |  20 +-
 findbugs-exclude-filter.xml                   |  31 +-
 pom.xml                                       |  28 +-
 src/design/OrekitForces.png                   | Bin 0 -> 8678 bytes
 src/design/OrekitVariableThrust.png           | Bin 0 -> 11477 bytes
 src/design/attitude-class-diagram.png         | Bin 0 -> 33375 bytes
 src/design/bodies-class-diagram.png           | Bin 0 -> 12819 bytes
 src/design/cartesian-class-diagram.png        | Bin 0 -> 16939 bytes
 src/design/data-class-diagram.png             | Bin 0 -> 13104 bytes
 src/design/frames-class-diagram.png           | Bin 0 -> 25254 bytes
 src/design/orbits-class-diagram.png           | Bin 0 -> 23939 bytes
 src/design/orekit-packages.png                | Bin 0 -> 29050 bytes
 .../partial-derivatives-class-diagram.png     | Bin 0 -> 21022 bytes
 src/design/propagation-class-diagram.png      | Bin 0 -> 44744 bytes
 src/design/sequence_diagram_propagation.png   | Bin 0 -> 11621 bytes
 src/design/time-class-diagram.png             | Bin 0 -> 25568 bytes
 src/design/tle-class-diagram.png              | Bin 0 -> 7119 bytes
 .../java/org/orekit/attitudes/LofOffset.java  |   6 +-
 .../orekit/bodies/AbstractCelestialBody.java  |  14 +-
 .../java/org/orekit/bodies/CelestialBody.java |   5 +
 .../orekit/bodies/JPLEphemeridesLoader.java   |  18 +-
 .../org/orekit/bodies/OneAxisEllipsoid.java   |   2 +-
 .../org/orekit/errors/OrekitMessages.java     |  10 +-
 .../forces/AbstractParameterizable.java       |  89 +++
 .../forces/BoxAndSolarArraySpacecraft.java    |   7 +
 .../java/org/orekit/forces/ForceModel.java    |   4 +-
 .../forces/ForceModelWithJacobians.java       |  47 --
 .../org/orekit/forces/Parameterizable.java    |  14 +-
 .../orekit/forces/SphericalSpacecraft.java    |  39 +-
 .../org/orekit/forces/drag/DragForce.java     |  27 +-
 .../gravity/CunninghamAttractionModel.java    |  20 +-
 .../gravity/DrozinerAttractionModel.java      |  20 +-
 .../forces/gravity/NewtonianAttraction.java   | 127 +++++
 .../forces/gravity/ThirdBodyAttraction.java   |  28 +-
 .../gravity/potential/SHMFormatReader.java    |   3 +-
 .../maneuvers/ConstantThrustManeuver.java     |  35 +-
 src/main/java/org/orekit/forces/package.html  |   5 +-
 .../forces/radiation/RadiationSensitive.java  |   9 +
 .../radiation/SolarRadiationPressure.java     | 126 +++--
 src/main/java/org/orekit/frames/Frame.java    |   2 +-
 .../java/org/orekit/frames/FramesFactory.java |   2 +-
 .../org/orekit/frames/SpacecraftFrame.java    |   2 +-
 .../java/org/orekit/frames/TIRF2000Frame.java |   2 +-
 .../java/org/orekit/frames/VEISFrame.java     |   2 +-
 .../org/orekit/orbits/CartesianOrbit.java     | 233 +++++++-
 .../java/org/orekit/orbits/CircularOrbit.java | 108 +++-
 .../org/orekit/orbits/EquinoctialOrbit.java   |  89 ++-
 .../org/orekit/orbits/KeplerianOrbit.java     | 322 +++++++++--
 src/main/java/org/orekit/orbits/Orbit.java    |  75 +--
 .../orekit/propagation/SpacecraftState.java   |   4 +-
 .../events/AdaptedEventDetector.java          |  51 +-
 .../orekit/propagation/events/EventState.java |   6 +-
 .../events/GroundMaskElevationDetector.java   |  16 +-
 .../AccelerationJacobiansProvider.java        |  51 ++
 .../numerical/AdditionalEquations.java        |  71 +++
 .../AdditionalStateAndEquations.java          |  82 +++
 .../propagation/numerical/Jacobianizer.java   | 282 ++++++++++
 .../propagation/numerical/ModeHandler.java    |  11 +-
 .../numerical/NumericalPropagator.java        | 374 +++++++++---
 .../NumericalPropagatorWithJacobians.java     | 530 ------------------
 .../numerical/ParameterConfiguration.java     |  77 +++
 .../PartialDerivativesEquations.java          | 454 +++++++++++++++
 .../propagation/numerical/StateMapper.java    |  59 ++
 .../numerical/StateMapperCartesian.java       |  87 +++
 .../numerical/StateMapperEquinoctial.java     |  74 +++
 .../numerical/TimeDerivativesEquations.java   | 294 +---------
 .../TimeDerivativesEquationsCartesian.java    | 114 ++++
 .../TimeDerivativesEquationsEquinoctial.java  | 280 +++++++++
 ...TimeDerivativesEquationsWithJacobians.java |  90 ---
 .../java/org/orekit/propagation/package.html  |   4 -
 .../precomputed/IntegratedEphemeris.java      |  52 +-
 .../sampling/AdaptedStepHandler.java          |  64 ++-
 .../sampling/BasicStepInterpolator.java       |   9 +
 .../sampling/OrekitStepInterpolator.java      |  10 +
 .../localization/OrekitMessages_de.properties |  24 +
 .../localization/OrekitMessages_en.properties |  24 +
 .../localization/OrekitMessages_es.properties |  24 +
 .../localization/OrekitMessages_fr.properties |  24 +
 .../localization/OrekitMessages_gl.properties |  24 +
 .../localization/OrekitMessages_it.properties |  24 +
 .../localization/OrekitMessages_no.properties |  24 +
 src/site/xdoc/changes.xml                     |  27 +
 .../attitudes/LofOffsetPointingTest.java      |   2 +-
 .../org/orekit/attitudes/LofOffsetTest.java   |   2 +-
 .../org/orekit/errors/OrekitMessagesTest.java |   2 +-
 .../java/org/orekit/frames/FrameTest.java     |   4 +-
 .../TODFrameAlternateConfigurationTest.java   |   4 +-
 .../java/org/orekit/frames/TODFrameTest.java  |   2 +-
 .../orbits/CartesianParametersTest.java       |  76 +++
 .../orbits/KeplerianParametersTest.java       |  67 ++-
 .../propagation/SpacecraftStateTest.java      |   5 +-
 .../EcksteinHechlerPropagatorTest.java        |   2 +-
 .../propagation/events/DetectorTest.java      |   2 +
 .../numerical/NumericalPropagatorTest.java    |  96 +++-
 .../NumericalPropagatorWithJacobiansTest.java | 347 ------------
 .../IntegratedEphemerisTest.java              |   3 +-
 .../org/orekit/time/AbsoluteDateTest.java     |   2 +-
 98 files changed, 3772 insertions(+), 1760 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 src/design/OrekitForces.png
 create mode 100644 src/design/OrekitVariableThrust.png
 create mode 100644 src/design/attitude-class-diagram.png
 create mode 100644 src/design/bodies-class-diagram.png
 create mode 100644 src/design/cartesian-class-diagram.png
 create mode 100644 src/design/data-class-diagram.png
 create mode 100644 src/design/frames-class-diagram.png
 create mode 100644 src/design/orbits-class-diagram.png
 create mode 100644 src/design/orekit-packages.png
 create mode 100644 src/design/partial-derivatives-class-diagram.png
 create mode 100644 src/design/propagation-class-diagram.png
 create mode 100644 src/design/sequence_diagram_propagation.png
 create mode 100644 src/design/time-class-diagram.png
 create mode 100644 src/design/tle-class-diagram.png
 create mode 100644 src/main/java/org/orekit/forces/AbstractParameterizable.java
 delete mode 100644 src/main/java/org/orekit/forces/ForceModelWithJacobians.java
 create mode 100644 src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/AccelerationJacobiansProvider.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/AdditionalEquations.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/AdditionalStateAndEquations.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/Jacobianizer.java
 delete mode 100644 src/main/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobians.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/ParameterConfiguration.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/PartialDerivativesEquations.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/StateMapper.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/StateMapperCartesian.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/StateMapperEquinoctial.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsCartesian.java
 create mode 100644 src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsEquinoctial.java
 delete mode 100644 src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsWithJacobians.java
 delete mode 100644 src/test/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobiansTest.java
 rename src/test/java/org/orekit/propagation/{numerical => precomputed}/IntegratedEphemerisTest.java (97%)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..1b74f44447
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.classpath
+.project
+bin
+
diff --git a/checkstyle.xml b/checkstyle.xml
index 3903d294b9..2e039e229e 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -11,16 +11,15 @@
         <module name="FallThrough"/>
         <module name="FinalLocalVariable"/>
         <module name="FinalParameters"/>
-        <module name="GenericIllegalRegexp">
-            <property name="format" value="\s$"/>
-            <property name="message" value="spurious spaces at end of line"/>
+        <module name="Regexp">
+            <property name="format" value="[ \t]+$"/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message" value="Trailing whitespace"/>
         </module>
-        <module name="GenericIllegalRegexp">
+        <module name="Regexp">
             <property name="format" value="System\.out\.println"/>
-            <property name="message" value="forbidden print to standard output"/>
-        </module>
-        <module name="RegexpHeader">
-          <property name="headerFile" value="license-header.txt" />
+            <property name="illegalPattern" value="true"/>
+            <property name="ignoreComments" value="true"/>
         </module>
         <module name="HiddenField">
             <property name="ignoreConstructorParameter" value="true"/>
@@ -55,7 +54,6 @@
         </module>
         <module name="RedundantModifier"/>
         <module name="StringLiteralEquality"/>
-        <module name="TabCharacter"/>
         <module name="TodoComment"/>
         <module name="UnnecessaryParentheses"/>
         <module name="UnusedImports"/>
@@ -74,6 +72,10 @@
         </module>
         <module name="FileContentsHolder"/>
     </module>
+    <module name="RegexpHeader">
+      <property name="headerFile" value="license-header.txt" />
+    </module>
+    <module name="FileTabCharacter"/>
     <module name="NewlineAtEndOfFile"/>
     <module name="SuppressionCommentFilter">
         <property name="offCommentFormat" value="CHECKSTYLE\: stop JavadocVariable check"/>
diff --git a/findbugs-exclude-filter.xml b/findbugs-exclude-filter.xml
index 249f7a91c6..7ae26a4e0b 100644
--- a/findbugs-exclude-filter.xml
+++ b/findbugs-exclude-filter.xml
@@ -63,11 +63,40 @@
     <Bug pattern="DLS_DEAD_LOCAL_STORE" />
   </Match>
 
-  <!-- The following equality test is intentional and needed for semantic purposes -->
+  <!-- The following equality tests are intentional and needed for semantic purposes -->
   <Match>
     <Class name="org.orekit.time.TimeComponents" />
     <Method name="equals" params="java.lang.Object" returns="boolean" />
     <Bug pattern="FE_FLOATING_POINT_EQUALITY" />
   </Match>
+  <Match>
+    <Class name="org.orekit.orbits.KeplerianOrbit"/>
+    <Method name ="eMeSinE" params="double" returns="double" />
+    <Bug pattern="FE_FLOATING_POINT_EQUALITY" />
+  </Match>
+
+  <!-- The following internal representation exposure are intentional,
+       They are used to pass data back and forth between classes
+    -->
+  <Match>
+    <Class name="org.orekit.propagation.numerical.AdditionalStateAndEquations"/>
+    <Method name ="getAdditionalState" params="" returns="double[]" />
+    <Bug pattern="EI_EXPOSE_REP" />
+  </Match>
+  <Match>
+    <Class name="org.orekit.propagation.numerical.AdditionalStateAndEquations"/>
+    <Method name ="getAdditionalStateDot" params="" returns="double[]" />
+    <Bug pattern="EI_EXPOSE_REP" />
+  </Match>
+  <Match>
+    <Class name="org.orekit.propagation.numerical.TimeDerivativesEquationsCartesian"/>
+    <Method name ="initDerivatives" params="double[],org.orekit.orbits.Orbit" returns="void" />
+    <Bug pattern="EI_EXPOSE_REP2" />
+  </Match>
+  <Match>
+    <Class name="org.orekit.propagation.numerical.TimeDerivativesEquationsEquinoctial"/>
+    <Method name ="initDerivatives" params="double[],org.orekit.orbits.Orbit" returns="void" />
+    <Bug pattern="EI_EXPOSE_REP2" />
+  </Match>
 
 </FindBugsFilter>
diff --git a/pom.xml b/pom.xml
index 82b34be574..48600ae829 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,7 +133,7 @@
   	<dependency>
   		<groupId>junit</groupId>
   		<artifactId>junit</artifactId>
-  		<version>4.4</version>
+  		<version>4.8.1</version>
   		<type>jar</type>
   		<scope>test</scope>
   		<optional>false</optional>
@@ -144,7 +144,7 @@
     <plugins>
       <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
-        <version>2.2-beta-4</version>
+        <version>2.2-beta-5</version>
         <configuration>
           <descriptors>
             <descriptor>src/main/assembly/source-assembly.xml</descriptor>
@@ -155,7 +155,7 @@
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.0.1</version>
+        <version>2.1.0</version>
         <extensions>true</extensions>
         <configuration>
           <instructions>
@@ -181,7 +181,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>2.0.2</version>
+        <version>2.3.1</version>
         <configuration>
           <source>1.5</source>
           <target>1.5</target>
@@ -190,7 +190,7 @@
       </plugin>
       <plugin>
         <artifactId>maven-site-plugin</artifactId>
-        <version>2.0.1</version>
+        <version>2.1.1</version>
         <configuration>
           <inputEncoding>UTF-8</inputEncoding>
           <outputEncoding>UTF-8</outputEncoding>
@@ -199,12 +199,12 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
-        <version>2.3</version>
+        <version>2.4</version>
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
-        <version>2.1</version>
+        <version>2.3.1</version>
         <configuration>
           <threshold>Normal</threshold>
           <effort>Default</effort>
@@ -214,22 +214,22 @@
        <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
-        <version>2.4.3</version>
+        <version>2.5</version>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>2.3</version>
+        <version>2.5</version>
         <configuration>
           <encoding>UTF-8</encoding>
-          <configLocation>checkstyle.xml</configLocation>
+          <configLocation>${basedir}/checkstyle.xml</configLocation>
           <enableRulesSummary>false</enableRulesSummary>
         </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-changes-plugin</artifactId>
-        <version>2.1</version>
+        <version>2.3</version>
         <configuration>
           <xmlPath>${basedir}/src/site/xdoc/changes.xml</xmlPath>
         </configuration>
@@ -244,7 +244,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jxr-plugin</artifactId>
-        <version>2.1</version>
+        <version>2.2</version>
         <configuration>
           <outputEncoding>UTF-8</outputEncoding>
           <linkJavadoc>false</linkJavadoc>
@@ -253,7 +253,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
-        <version>2.6</version>
+        <version>2.7</version>
         <configuration>
           <overview>${basedir}/src/main/java/org/orekit/overview.html</overview>
           <links>
@@ -283,7 +283,7 @@
            <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-source-plugin</artifactId>
-            <version>2.1</version>
+            <version>2.1.2</version>
             <executions>
               <execution>
                 <id>create-source-jar</id>
diff --git a/src/design/OrekitForces.png b/src/design/OrekitForces.png
new file mode 100644
index 0000000000000000000000000000000000000000..c51a7e9b3eb634e7ae520778cd9679bf1e5e19c1
GIT binary patch
literal 8678
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
KkeMc@uKW*ub+Taq

literal 0
HcmV?d00001

diff --git a/src/design/OrekitVariableThrust.png b/src/design/OrekitVariableThrust.png
new file mode 100644
index 0000000000000000000000000000000000000000..f1e5803d61fcbd1986a40f620fbca1a9c935d671
GIT binary patch
literal 11477
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
Nh^hI(yaVTM{vY=P=Z^pY

literal 0
HcmV?d00001

diff --git a/src/design/attitude-class-diagram.png b/src/design/attitude-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..2ae9126259b635ad1fb3a400cff40a7b0dd748a9
GIT binary patch
literal 33375
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
FzW`wub>;v7

literal 0
HcmV?d00001

diff --git a/src/design/bodies-class-diagram.png b/src/design/bodies-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..c866cd3503861bfbaea9222b1888434d044ed5ff
GIT binary patch
literal 12819
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

literal 0
HcmV?d00001

diff --git a/src/design/cartesian-class-diagram.png b/src/design/cartesian-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..e600b0e740fe03b9af4e8105a05767a0c8055f55
GIT binary patch
literal 16939
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
P0g}H3yP0*v;P?Lpn-?_p

literal 0
HcmV?d00001

diff --git a/src/design/data-class-diagram.png b/src/design/data-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..079ccdc9d009f11a2b71190dce1804939a780d40
GIT binary patch
literal 13104
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
MV5(nw?)HO!15`hf6aWAK

literal 0
HcmV?d00001

diff --git a/src/design/frames-class-diagram.png b/src/design/frames-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..f5d2c635e8762623c8a77aef82c4c5f38d24ec9d
GIT binary patch
literal 25254
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

literal 0
HcmV?d00001

diff --git a/src/design/orbits-class-diagram.png b/src/design/orbits-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..93c5f9e0d758d4580ef82397fad7e199703eca8d
GIT binary patch
literal 23939
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

literal 0
HcmV?d00001

diff --git a/src/design/orekit-packages.png b/src/design/orekit-packages.png
new file mode 100644
index 0000000000000000000000000000000000000000..71516cf30b65401b4568941c0ea64e115f5995c1
GIT binary patch
literal 29050
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

literal 0
HcmV?d00001

diff --git a/src/design/partial-derivatives-class-diagram.png b/src/design/partial-derivatives-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc7fd62a147f7118513507e2f961c5207ed61092
GIT binary patch
literal 21022
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

literal 0
HcmV?d00001

diff --git a/src/design/propagation-class-diagram.png b/src/design/propagation-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..aae78d9145869f528c8950cad908dd52e5f7f0c4
GIT binary patch
literal 44744
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
WI>YTxwsXLHkS(6BelF{r5}E*=H-~`$

literal 0
HcmV?d00001

diff --git a/src/design/sequence_diagram_propagation.png b/src/design/sequence_diagram_propagation.png
new file mode 100644
index 0000000000000000000000000000000000000000..e6bf168d5a452b0dbef8b37a4d95d1213495c127
GIT binary patch
literal 11621
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

literal 0
HcmV?d00001

diff --git a/src/design/time-class-diagram.png b/src/design/time-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..cdf7f5226b5b7254ea84c0c0e52659d5cb2bc17e
GIT binary patch
literal 25568
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%0Ab)Pq
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
Q+=$pt8%JxlrB~EH0DFQ06#xJL

literal 0
HcmV?d00001

diff --git a/src/design/tle-class-diagram.png b/src/design/tle-class-diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..5cac94d6654d0472d45015c2f07c40d9bf1e1b21
GIT binary patch
literal 7119
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
X=6vd<ts1~X9q8zxV>T5B&s_Zv99sqd

literal 0
HcmV?d00001

diff --git a/src/main/java/org/orekit/attitudes/LofOffset.java b/src/main/java/org/orekit/attitudes/LofOffset.java
index f7a511a11b..03ca560ea4 100644
--- a/src/main/java/org/orekit/attitudes/LofOffset.java
+++ b/src/main/java/org/orekit/attitudes/LofOffset.java
@@ -75,9 +75,9 @@ public class LofOffset implements AttitudeLaw {
      *   // note the call to revert in the following statement
      *   double[] angles = offsetProper.revert().getAngles(order);
      *
-     *   System.out.println(alpha1 + " == " + angles[0]);  
-     *   System.out.println(alpha2 + " == " + angles[1]);  
-     *   System.out.println(alpha3 + " == " + angles[2]);  
+     *   System.out.println(alpha1 + " == " + angles[0]);
+     *   System.out.println(alpha2 + " == " + angles[1]);
+     *   System.out.println(alpha3 + " == " + angles[2]);
      * </pre>
      * @param order order of rotations to use for (alpha1, alpha2, alpha3) composition
      * @param alpha1 angle of the first elementary rotation
diff --git a/src/main/java/org/orekit/bodies/AbstractCelestialBody.java b/src/main/java/org/orekit/bodies/AbstractCelestialBody.java
index b1f1936617..6b31d11bc3 100644
--- a/src/main/java/org/orekit/bodies/AbstractCelestialBody.java
+++ b/src/main/java/org/orekit/bodies/AbstractCelestialBody.java
@@ -44,6 +44,9 @@ public abstract class AbstractCelestialBody implements CelestialBody {
     /** Serializable UID. */
     private static final long serialVersionUID = 6769512376971866660L;
 
+    /** Name of the body. */
+    private final String name;
+
     /** Attraction coefficient of the body (m<sup>3</sup>/s<sup>2</sup>). */
     private final double gm;
 
@@ -60,15 +63,17 @@ public abstract class AbstractCelestialBody implements CelestialBody {
     private final Frame bodyFrame;
 
     /** Build an instance and the underlying frame.
+     * @param name name of the body
      * @param gm attraction coefficient (in m<sup>3</sup>/s<sup>2</sup>)
      * @param iauPole IAU pole implementation
      * @param definingFrame frame in which celestial body coordinates are defined
      * @param inertialFrameName name to use for inertially oriented body centered frame
      * @param bodyFrameName name to use for body oriented body centered frame
      */
-    protected AbstractCelestialBody(final double gm, final IAUPole iauPole,
-                                    final Frame definingFrame,
+    protected AbstractCelestialBody(final String name, final double gm,
+                                    final IAUPole iauPole, final Frame definingFrame,
                                     final String inertialFrameName, String bodyFrameName) {
+        this.name          = name;
         this.gm            = gm;
         this.iauPole       = iauPole;
         this.definingFrame = definingFrame;
@@ -76,6 +81,11 @@ public abstract class AbstractCelestialBody implements CelestialBody {
         this.bodyFrame     = new BodyOrientedFrame(bodyFrameName);
     }
 
+    /** {@inheritDoc} */
+    public String getName() {
+        return name;
+    }
+
     /** {@inheritDoc} */
     public double getGM() {
         return gm;
diff --git a/src/main/java/org/orekit/bodies/CelestialBody.java b/src/main/java/org/orekit/bodies/CelestialBody.java
index 48cc229c85..a06fade659 100644
--- a/src/main/java/org/orekit/bodies/CelestialBody.java
+++ b/src/main/java/org/orekit/bodies/CelestialBody.java
@@ -57,6 +57,11 @@ public interface CelestialBody extends Serializable, PVCoordinatesProvider {
      */
     Frame getBodyOrientedFrame() throws OrekitException;
 
+    /** Get the name of the body.
+     * @return name of the body
+     */
+    String getName();
+
     /** Get the attraction coefficient of the body.
      * @return attraction coefficient of the body (m<sup>3</sup>/s<sup>2</sup>)
      */
diff --git a/src/main/java/org/orekit/bodies/JPLEphemeridesLoader.java b/src/main/java/org/orekit/bodies/JPLEphemeridesLoader.java
index 6a181ae903..6c48873dd2 100644
--- a/src/main/java/org/orekit/bodies/JPLEphemeridesLoader.java
+++ b/src/main/java/org/orekit/bodies/JPLEphemeridesLoader.java
@@ -207,7 +207,7 @@ public class JPLEphemeridesLoader implements CelestialBodyLoader {
 
         switch (generateType) {
         case SOLAR_SYSTEM_BARYCENTER :
-            return new JPLCelestialBody(supportedNames, gm, IAUPoleFactory.getIAUPole(generateType),
+            return new JPLCelestialBody(supportedNames, name, gm, IAUPoleFactory.getIAUPole(generateType),
                                         CelestialBodyFactory.getEarthMoonBarycenter().getInertiallyOrientedFrame(),
                                         inertialFrameName, bodyFrameName) {
 
@@ -226,7 +226,7 @@ public class JPLEphemeridesLoader implements CelestialBodyLoader {
             };
         case EARTH_MOON :
             final double scale = 1.0 / (1.0 + getLoadedEarthMoonMassRatio());
-            return new JPLCelestialBody(supportedNames, gm, IAUPoleFactory.getIAUPole(generateType),
+            return new JPLCelestialBody(supportedNames, name, gm, IAUPoleFactory.getIAUPole(generateType),
                                         FramesFactory.getEME2000(), inertialFrameName, bodyFrameName) {
 
                 /** Serializable UID. */
@@ -272,6 +272,11 @@ public class JPLEphemeridesLoader implements CelestialBodyLoader {
                     return FramesFactory.getITRF2005();
                 }
 
+                /** {@inheritDoc} */
+                public String getName() {
+                    return name;
+                }
+
                 /** {@inheritDoc} */
                 public double getGM() {
                     return gm;
@@ -279,10 +284,10 @@ public class JPLEphemeridesLoader implements CelestialBodyLoader {
 
             };
         case MOON :
-            return new JPLCelestialBody(supportedNames, gm, IAUPoleFactory.getIAUPole(generateType),
+            return new JPLCelestialBody(supportedNames, name, gm, IAUPoleFactory.getIAUPole(generateType),
                                         FramesFactory.getEME2000(), inertialFrameName, bodyFrameName);
         default :
-            return new JPLCelestialBody(supportedNames, gm, IAUPoleFactory.getIAUPole(generateType),
+            return new JPLCelestialBody(supportedNames, name, gm, IAUPoleFactory.getIAUPole(generateType),
                                         CelestialBodyFactory.getSolarSystemBarycenter().getInertiallyOrientedFrame(),
                                         inertialFrameName, bodyFrameName);
         }
@@ -899,16 +904,17 @@ public class JPLEphemeridesLoader implements CelestialBodyLoader {
 
         /** Private constructor for the singletons.
          * @param supportedNames regular expression for supported files names (may be null)
+         * @param name name of the body
          * @param gm attraction coefficient (in m<sup>3</sup>/s<sup>2</sup>)
          * @param iauPole IAU pole implementation
          * @param definingFrame frame in which ephemeris are defined
          * @param inertialFrameName name to use for inertially oriented body centered frame
          * @param bodyFrameName name to use for body oriented body centered frame
          */
-        private JPLCelestialBody(final String supportedNames, final double gm,
+        private JPLCelestialBody(final String supportedNames, final String name, final double gm,
                                  final IAUPole iauPole, final Frame definingFrame,
                                  final String inertialFrameName, String bodyFrameName) {
-            super(gm, iauPole, definingFrame, inertialFrameName, bodyFrameName);
+            super(name, gm, iauPole, definingFrame, inertialFrameName, bodyFrameName);
             this.model         = null;
             this.definingFrame = definingFrame;
         }
diff --git a/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java b/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java
index 62bdbc4aff..a93266c51f 100644
--- a/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java
+++ b/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java
@@ -77,7 +77,7 @@ public class OneAxisEllipsoid implements BodyShape {
     /** Simple constructor.
      * <p>The following table provides conventional parameters for global Earth models:</p>
      * <table border="1" cellpadding="5">
-     * <tr bgcolor="#ccccff"><font size="+3"><th>model</th><th>a<sub>e</sub> (m)</th><th>f</th></font></tr>
+     * <tr bgcolor="#ccccff"><th>model</th><th>a<sub>e</sub> (m)</th><th>f</th></tr>
      * <tr><td bgcolor="#eeeeff">GRS 80</td><td>6378137.0</td><td>1.0 / 298.257222101</td></tr>
      * <tr><td bgcolor="#eeeeff">WGS84</td><td>6378137.0</td><td>1.0 / 298.257223563</td></tr>
      * </table>
diff --git a/src/main/java/org/orekit/errors/OrekitMessages.java b/src/main/java/org/orekit/errors/OrekitMessages.java
index f72a99bdd2..389193c542 100644
--- a/src/main/java/org/orekit/errors/OrekitMessages.java
+++ b/src/main/java/org/orekit/errors/OrekitMessages.java
@@ -54,7 +54,7 @@ public enum OrekitMessages implements Localizable {
     FRAME_ANCESTOR_OF_BOTH_FRAMES("frame {0} is an ancestor of both frames {1} and {2}"),
     FRAME_ANCESTOR_OF_NEITHER_FRAME("frame {0} is an ancestor of neither frame {1} nor {2}"),
     UNSUPPORTED_LOCAL_ORBITAL_FRAME("unsupported local orbital frame, supported types: {0} and {1}"),
-    NON_QUASI_INERTIAL_FRAME_NOT_SUITABLE_FOR_DEFINING_ORBITS("non quasi-inertial frame \"{0}\" is not suitable for defining orbits"),
+    NON_PSEUDO_INERTIAL_FRAME_NOT_SUITABLE_FOR_DEFINING_ORBITS("non pseudo-inertial frame \"{0}\" is not suitable for defining orbits"),
     DATA_ROOT_DIRECTORY_DOESN_NOT_EXISTS("data root directory {0} does not exist"),
     NOT_A_DIRECTORY("{0} is not a directory"),
     NEITHER_DIRECTORY_NOR_ZIP_OR_JAR("{0} is neither a directory nor a zip/jar archive file"),
@@ -117,6 +117,14 @@ public enum OrekitMessages implements Localizable {
     OUT_OF_RANGE_EPHEMERIDES_DATE("out of range date for ephemerides: {0}, [{1}, {2}]"),
     UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH("unexpected two elevation values: {0} and {1}, for one azimuth: {2}"),
     UNKNOWN_PARAMETER("unknown parameter {0}"),
+    UNSUPPORTED_PARAMETER_1_2("unsupported parameter name {0}: supported names {1}, {2}"),
+    UNKNOWN_ADDITIONAL_EQUATION("unknown additional equation"),
+    PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN("partial derivatives can be propagated only in cartesian parameters type"),
+    STATE_JACOBIAN_NEITHER_6X6_NOR_7X7("state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix"),
+    STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH("state jacobian has {0} rows but parameters jacobian has {1} rows"),
+    INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH("initial jacobian matrix has {0} columns, but {1} parameters have been selected"),
+    ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE("orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}"),
+    HYPERBOLIC_ORBIT_NOT_HANDLED_AS("hyperbolic orbits cannot be handled as {0} instances"),
     CCSDS_DATE_INVALID_PREAMBLE_FIELD("invalid preamble field in CCSDS date: {0}"),
     CCSDS_DATE_INVALID_LENGTH_TIME_FIELD("invalid time field length in CCSDS date: {0}, expected {1}"),
     CCSDS_DATE_MISSING_AGENCY_EPOCH("missing agency epoch in CCSDS date"),
diff --git a/src/main/java/org/orekit/forces/AbstractParameterizable.java b/src/main/java/org/orekit/forces/AbstractParameterizable.java
new file mode 100644
index 0000000000..159fb4cc7d
--- /dev/null
+++ b/src/main/java/org/orekit/forces/AbstractParameterizable.java
@@ -0,0 +1,89 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.forces;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.orekit.errors.OrekitException;
+import org.orekit.errors.OrekitMessages;
+
+/** Simple abstract class providing boilerplate parameters list.
+ *
+ * @author Luc Maisonobe
+ * @version $Revision$ $Date$
+ */
+
+public abstract class AbstractParameterizable implements Parameterizable {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 3408804493769459294L;
+
+   /** List of the parameters names. */
+    private final Collection<String> parametersNames;
+
+    /** Simple constructor.
+     * @param names names of the supported parameters
+     */
+    protected AbstractParameterizable(final String ... names) {
+        parametersNames = new ArrayList<String>();
+        for (final String name : names) {
+            parametersNames.add(name);
+        }
+    }
+
+    /** Simple constructor.
+     * @param names names of the supported parameters
+     */
+    protected AbstractParameterizable(final Collection<String> names) {
+        parametersNames = new ArrayList<String>();
+        parametersNames.addAll(names);
+    }
+
+    /** {@inheritDoc} */
+    public Collection<String> getParametersNames() {
+        return parametersNames;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSupported(final String name) {
+        for (final String supportedName : parametersNames) {
+            if (supportedName.equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Check if a parameter is supported and throw an IllegalArgumentException if not.
+     * @param name name of the parameter to check
+     * @exception IllegalArgumentException if the parameter is not supported
+     * @see #isSupported(String)
+     */
+    public void complainIfNotSupported(final String name) throws IllegalArgumentException {
+        if (!isSupported(name)) {
+            throw OrekitException.createIllegalArgumentException(OrekitMessages.UNKNOWN_PARAMETER, name);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public abstract double getParameter(String name) throws IllegalArgumentException;
+
+    /** {@inheritDoc} */
+    public abstract void setParameter(String name, double value) throws IllegalArgumentException;
+
+}
diff --git a/src/main/java/org/orekit/forces/BoxAndSolarArraySpacecraft.java b/src/main/java/org/orekit/forces/BoxAndSolarArraySpacecraft.java
index 55d4a950da..2841c70c1b 100644
--- a/src/main/java/org/orekit/forces/BoxAndSolarArraySpacecraft.java
+++ b/src/main/java/org/orekit/forces/BoxAndSolarArraySpacecraft.java
@@ -490,4 +490,11 @@ public class BoxAndSolarArraySpacecraft implements RadiationSensitive, DragSensi
         return dragCoeff;
     }
 
+    /** {@inheritDoc} */
+    public void addDAccDParam(final Vector3D acceleration, final String paramName, final double[] dAccdParam)
+        throws OrekitException {
+        // TODO: not supported yet
+        throw OrekitException.createInternalError(null);
+    }
+
 }
diff --git a/src/main/java/org/orekit/forces/ForceModel.java b/src/main/java/org/orekit/forces/ForceModel.java
index f972e2ef4f..e3d95fb975 100644
--- a/src/main/java/org/orekit/forces/ForceModel.java
+++ b/src/main/java/org/orekit/forces/ForceModel.java
@@ -16,8 +16,6 @@
  */
 package org.orekit.forces;
 
-import java.io.Serializable;
-
 import org.orekit.errors.OrekitException;
 import org.orekit.propagation.SpacecraftState;
 import org.orekit.propagation.events.EventDetector;
@@ -53,7 +51,7 @@ import org.orekit.propagation.numerical.TimeDerivativesEquations;
  * @author V&eacute;ronique Pommier-Maurussane
  * @version $Revision$ $Date$
  */
-public interface ForceModel extends Serializable {
+public interface ForceModel extends Parameterizable {
 
     /** Compute the contribution of the force model to the perturbing
      * acceleration.
diff --git a/src/main/java/org/orekit/forces/ForceModelWithJacobians.java b/src/main/java/org/orekit/forces/ForceModelWithJacobians.java
deleted file mode 100644
index 6a581ffd51..0000000000
--- a/src/main/java/org/orekit/forces/ForceModelWithJacobians.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright 2002-2010 CS Communication & Systèmes
- * Licensed to CS Communication & Systèmes (CS) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS 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.orekit.forces;
-
-import org.orekit.errors.OrekitException;
-import org.orekit.propagation.SpacecraftState;
-import org.orekit.propagation.numerical.TimeDerivativesEquationsWithJacobians;
-
-/** This interface represents a parameterized force modifying spacecraft motion.
- *
- * <p> Objects implementing this interface are intended to be added, before the propagation is started,
- * to a {@link org.orekit.propagation.numerical.NumericalPropagatorWithJacobians numerical propagator}
- * in order to compute partial derivatives of orbital parameters with respect to the
- * {@link org.orekit.propagation.numerical.NumericalPropagatorWithJacobians#selectParameters(String[]) selected}
- * force model parameters.</p>
- *
- * @see ForceModel
- *
- * @author Pascal Parraud
- * @version $Revision$ $Date$
- */
-public interface ForceModelWithJacobians extends Parameterizable, ForceModel {
-
-    /** Compute the contribution of the force model to the perturbing
-     * acceleration and to the jacobians.
-     * @param s current state information: date, kinematics, attitude
-     * @param adder object where the contribution should be added
-     * @exception OrekitException if some specific error occurs
-     */
-    void addContributionWithJacobians(SpacecraftState s, TimeDerivativesEquationsWithJacobians adder)
-        throws OrekitException;
-
-}
diff --git a/src/main/java/org/orekit/forces/Parameterizable.java b/src/main/java/org/orekit/forces/Parameterizable.java
index 7fec1641c9..35eccb5463 100644
--- a/src/main/java/org/orekit/forces/Parameterizable.java
+++ b/src/main/java/org/orekit/forces/Parameterizable.java
@@ -16,6 +16,7 @@
  */
 package org.orekit.forces;
 
+import java.io.Serializable;
 import java.util.Collection;
 
 /** This interface enables to process partial derivatives
@@ -25,13 +26,24 @@ import java.util.Collection;
  * @version $Revision$ $Date$
  */
 
-public interface Parameterizable {
+public interface Parameterizable extends Serializable {
 
     /** Get the names of the supported parameters for partial derivatives processing.
      * @return parameters names
+     * @see #isSupported(String)
      */
     Collection<String> getParametersNames();
 
+    /** Check if a parameter is supported.
+     * <p>
+     * Supported parameters are the ones that are listed in {@link #getParametersNames()}
+     * </p>
+     * @param name parameter name to check
+     * @return true if the parameter is supported
+     * @see #getParametersNames()
+     */
+    boolean isSupported(String name);
+
     /** Get parameter value from its name.
      * @param name parameter name
      * @return parameter value
diff --git a/src/main/java/org/orekit/forces/SphericalSpacecraft.java b/src/main/java/org/orekit/forces/SphericalSpacecraft.java
index 0429606e6f..d7c41853bf 100644
--- a/src/main/java/org/orekit/forces/SphericalSpacecraft.java
+++ b/src/main/java/org/orekit/forces/SphericalSpacecraft.java
@@ -17,8 +17,11 @@
 package org.orekit.forces;
 
 import org.apache.commons.math.geometry.Vector3D;
+import org.orekit.errors.OrekitException;
+import org.orekit.errors.OrekitMessages;
 import org.orekit.forces.drag.DragSensitive;
 import org.orekit.forces.radiation.RadiationSensitive;
+import org.orekit.forces.radiation.SolarRadiationPressure;
 import org.orekit.propagation.SpacecraftState;
 
 /** This class represents the features of a simplified spacecraft.
@@ -129,7 +132,41 @@ public class SphericalSpacecraft implements RadiationSensitive, DragSensitive {
 
     /** Set kP value. */
     private void setKP() {
-        kP = crossSection * (1 + 4 * (1.0 - absorptionCoeff) * (1.0 - specularReflectionCoeff) / 9);
+        kP = crossSection * (1 + 4 * (1.0 - absorptionCoeff) * (1.0 - specularReflectionCoeff) / 9.0);
+    }
+
+    /** Computes kP derivative with respect to absorption coefficient.
+     * @return kP derivative with respect to absorption coefficient*/
+    private double computeDKPDCa() {
+        return -4 * crossSection * (1.0 - specularReflectionCoeff) / 9;
+    }
+
+    /** Computes kP derivative with respect to reflection coefficient.
+     * @return kP derivative with respect to reflection coefficient*/
+    private double computeDKPDCr() {
+        return -4 * crossSection * (1.0 - absorptionCoeff) / 9;
+    }
+
+    /** {@inheritDoc} */
+    public void addDAccDParam(final Vector3D acceleration, final String paramName, final double[] dAccdParam)
+        throws OrekitException {
+
+        final double coefficient;
+        if (paramName.equals(SolarRadiationPressure.ABSORPTION_COEFFICIENT)) {
+            coefficient = computeDKPDCa() / kP;
+        } else if (paramName.equals(SolarRadiationPressure.REFLECTION_COEFFICIENT)) {
+            coefficient = computeDKPDCr() / kP;
+        } else {
+            throw OrekitException.createIllegalArgumentException(OrekitMessages.UNSUPPORTED_PARAMETER_1_2,
+                                                                 paramName,
+                                                                 SolarRadiationPressure.ABSORPTION_COEFFICIENT,
+                                                                 SolarRadiationPressure.REFLECTION_COEFFICIENT);
+        }
+
+        dAccdParam[0] += coefficient * acceleration.getX();
+        dAccdParam[1] += coefficient * acceleration.getY();
+        dAccdParam[2] += coefficient * acceleration.getZ();
+
     }
 
 }
diff --git a/src/main/java/org/orekit/forces/drag/DragForce.java b/src/main/java/org/orekit/forces/drag/DragForce.java
index 16035827e0..c6f9b15b75 100644
--- a/src/main/java/org/orekit/forces/drag/DragForce.java
+++ b/src/main/java/org/orekit/forces/drag/DragForce.java
@@ -22,12 +22,11 @@ import java.util.Collection;
 import org.apache.commons.math.geometry.Vector3D;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
-import org.orekit.forces.ForceModelWithJacobians;
+import org.orekit.forces.Parameterizable;
 import org.orekit.frames.Frame;
 import org.orekit.propagation.SpacecraftState;
 import org.orekit.propagation.events.EventDetector;
 import org.orekit.propagation.numerical.TimeDerivativesEquations;
-import org.orekit.propagation.numerical.TimeDerivativesEquationsWithJacobians;
 import org.orekit.time.AbsoluteDate;
 
 
@@ -47,13 +46,20 @@ import org.orekit.time.AbsoluteDate;
  * @version $Revision:1665 $ $Date:2008-06-11 12:12:59 +0200 (mer., 11 juin 2008) $
  */
 
-public class DragForce implements ForceModelWithJacobians {
+public class DragForce implements Parameterizable {
 
     /** Parameter name for drag coefficient enabling jacobian processing. */
     public static final String DRAG_COEFFICIENT = "DRAG COEFFICIENT";
 
+    /** List of the parameters names. */
+    private static final ArrayList<String> PARAMETERS_NAMES;
+    static {
+        PARAMETERS_NAMES = new ArrayList<String>();
+        PARAMETERS_NAMES.add(DRAG_COEFFICIENT);
+    }
+
     /** Serializable UID. */
-    private static final long serialVersionUID = 2574653656986559955L;
+    private static final long serialVersionUID = 5386256916056674950L;
 
     /** Atmospheric model. */
     private final Atmosphere atmosphere;
@@ -61,9 +67,6 @@ public class DragForce implements ForceModelWithJacobians {
     /** Spacecraft. */
     private final DragSensitive spacecraft;
 
-    /** List of the parameters names. */
-    private final ArrayList<String> parametersNames = new ArrayList<String>();
-
     /** Simple constructor.
      * @param atmosphere atmospheric model
      * @param spacecraft the object physical and geometrical information
@@ -71,7 +74,6 @@ public class DragForce implements ForceModelWithJacobians {
     public DragForce(final Atmosphere atmosphere, final DragSensitive spacecraft) {
         this.atmosphere = atmosphere;
         this.spacecraft = spacecraft;
-        this.parametersNames.add(DRAG_COEFFICIENT);
     }
 
     /** Compute the contribution of the drag to the perturbing acceleration.
@@ -104,14 +106,13 @@ public class DragForce implements ForceModelWithJacobians {
     }
 
     /** {@inheritDoc} */
-    public void addContributionWithJacobians(final SpacecraftState s,
-                                             final TimeDerivativesEquationsWithJacobians adder)
-        throws OrekitException {
+    public Collection<String> getParametersNames() {
+        return PARAMETERS_NAMES;
     }
 
     /** {@inheritDoc} */
-    public Collection<String> getParametersNames() {
-        return parametersNames;
+    public boolean isSupported(final String name) {
+        return name.equals(DRAG_COEFFICIENT);
     }
 
     /** {@inheritDoc} */
diff --git a/src/main/java/org/orekit/forces/gravity/CunninghamAttractionModel.java b/src/main/java/org/orekit/forces/gravity/CunninghamAttractionModel.java
index 75784896b0..c40768939e 100644
--- a/src/main/java/org/orekit/forces/gravity/CunninghamAttractionModel.java
+++ b/src/main/java/org/orekit/forces/gravity/CunninghamAttractionModel.java
@@ -21,6 +21,7 @@ import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
+import org.orekit.forces.AbstractParameterizable;
 import org.orekit.forces.ForceModel;
 import org.orekit.frames.Frame;
 import org.orekit.frames.Transform;
@@ -42,10 +43,10 @@ import org.orekit.propagation.numerical.TimeDerivativesEquations;
  * @version $Revision:1665 $ $Date:2008-06-11 12:12:59 +0200 (mer., 11 juin 2008) $
  */
 
-public class CunninghamAttractionModel implements ForceModel {
+public class CunninghamAttractionModel extends AbstractParameterizable implements ForceModel {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = 2609845747545125479L;
+    private static final long serialVersionUID = 759122284106467933L;
 
     /** Equatorial radius of the Central Body. */
     private final double equatorialRadius;
@@ -81,6 +82,7 @@ public class CunninghamAttractionModel implements ForceModel {
                                      final double equatorialRadius, final double mu,
                                      final double[][] C, final double[][] S)
         throws IllegalArgumentException {
+        super("central attraction coefficient");
 
         this.bodyFrame = centralBodyFrame;
         this.equatorialRadius = equatorialRadius;
@@ -375,4 +377,18 @@ public class CunninghamAttractionModel implements ForceModel {
         return new EventDetector[0];
     }
 
+    /** {@inheritDoc} */
+    public double getParameter(final String name)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        return mu;
+    }
+
+    /** {@inheritDoc} */
+    public void setParameter(final String name, final double value)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        mu = value;
+    }
+
 }
diff --git a/src/main/java/org/orekit/forces/gravity/DrozinerAttractionModel.java b/src/main/java/org/orekit/forces/gravity/DrozinerAttractionModel.java
index 3218ff9986..2469fd4b44 100644
--- a/src/main/java/org/orekit/forces/gravity/DrozinerAttractionModel.java
+++ b/src/main/java/org/orekit/forces/gravity/DrozinerAttractionModel.java
@@ -20,6 +20,7 @@ import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
+import org.orekit.forces.AbstractParameterizable;
 import org.orekit.forces.ForceModel;
 import org.orekit.frames.Frame;
 import org.orekit.frames.Transform;
@@ -39,10 +40,10 @@ import org.orekit.propagation.numerical.TimeDerivativesEquations;
  * @version $Revision:1665 $ $Date:2008-06-11 12:12:59 +0200 (mer., 11 juin 2008) $
  */
 
-public class DrozinerAttractionModel implements ForceModel {
+public class DrozinerAttractionModel extends AbstractParameterizable implements ForceModel {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = 9117000158528461356L;
+    private static final long serialVersionUID = -6897768625006106349L;
 
     /** Reference equatorial radius of the potential. */
     private final double equatorialRadius;
@@ -79,6 +80,7 @@ public class DrozinerAttractionModel implements ForceModel {
                                    final double[][] C, final double[][] S)
         throws IllegalArgumentException {
 
+        super("central attraction coefficient");
         this.centralBodyFrame = centralBodyFrame;
         this.equatorialRadius = equatorialRadius;
         this.mu = mu;
@@ -274,4 +276,18 @@ public class DrozinerAttractionModel implements ForceModel {
         return new EventDetector[0];
     }
 
+    /** {@inheritDoc} */
+    public double getParameter(final String name)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        return mu;
+    }
+
+    /** {@inheritDoc} */
+    public void setParameter(final String name, final double value)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        mu = value;
+    }
+
 }
diff --git a/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java b/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java
new file mode 100644
index 0000000000..1bddd9aa07
--- /dev/null
+++ b/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java
@@ -0,0 +1,127 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.forces.gravity;
+
+import org.apache.commons.math.geometry.Vector3D;
+import org.apache.commons.math.util.FastMath;
+import org.orekit.errors.OrekitException;
+import org.orekit.forces.AbstractParameterizable;
+import org.orekit.forces.ForceModel;
+import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.events.EventDetector;
+import org.orekit.propagation.numerical.AccelerationJacobiansProvider;
+import org.orekit.propagation.numerical.TimeDerivativesEquations;
+
+/** Force model for Newtonian central body attraction.
+ * @author Luc Maisonobe
+ * @version $Revision$ $Date$
+ */
+public class NewtonianAttraction extends AbstractParameterizable implements AccelerationJacobiansProvider, ForceModel {
+
+    /** Name of the single parameter of this model: the central attraction coefficient. */
+    public static final String CENTRAL_ATTRACTION_COEFFICIENT = "central attraction coefficient";
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = -7754312556095545327L;
+
+    /** Central attraction coefficient (m^3/s^2). */
+    private double mu;
+
+   /** Simple constructor.
+     * @param mu central attraction coefficient (m^3/s^2)
+     */
+    public NewtonianAttraction(final double mu) {
+        super(CENTRAL_ATTRACTION_COEFFICIENT);
+        this.mu = mu;
+    }
+
+    /** {@inheritDoc} */
+    public void addDAccDState(final SpacecraftState s,
+                              final double[][] dAccdPos, final double[][] dAccdVel, final double[] dAccdM)
+        throws OrekitException {
+
+        final Vector3D position     = s.getPVCoordinates().getPosition();
+        final double r2             = position.getNormSq();
+        final Vector3D acceleration = new Vector3D(-mu / (r2 * FastMath.sqrt(r2)), position);
+
+        final double x2 = position.getX() * position.getX();
+        final double y2 = position.getY() * position.getY();
+        final double z2 = position.getZ() * position.getZ();
+        final double xy = position.getX() * position.getY();
+        final double yz = position.getY() * position.getZ();
+        final double zx = position.getZ() * position.getX();
+        final double prefix = -Vector3D.dotProduct(acceleration, position) / (r2 * r2);
+
+        // the only non-null contribution for this force is on dAcc/dPos
+        dAccdPos[0][0] += prefix * (2 * x2 - y2 - z2);
+        dAccdPos[0][1] += prefix * 3 * xy;
+        dAccdPos[0][2] += prefix * 3 * zx;
+        dAccdPos[1][0] += prefix * 3 * xy;
+        dAccdPos[1][1] += prefix * (2 * y2 - z2 - x2);
+        dAccdPos[1][2] += prefix * 3 * yz;
+        dAccdPos[2][0] += prefix * 3 * zx;
+        dAccdPos[2][1] += prefix * 3 * yz;
+        dAccdPos[2][2] += prefix * (2 * z2 - x2 - y2);
+
+    }
+
+    /** {@inheritDoc} */
+    public void addDAccDParam(final SpacecraftState s, final String paramName, final double[] dAccdParam)
+        throws OrekitException {
+        complainIfNotSupported(paramName);
+        final Vector3D position = s.getPVCoordinates().getPosition();
+        final double r2         = position.getNormSq();
+        final double factor     = -1.0 / (r2 * FastMath.sqrt(r2));
+        dAccdParam[0] += factor * position.getX();
+        dAccdParam[1] += factor * position.getY();
+        dAccdParam[2] += factor * position.getZ();
+    }
+
+    /** Get the central attraction coefficient &mu;.
+     * @return mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
+     */
+    public double getMu() {
+        return mu;
+    }
+
+    /** {@inheritDoc} */
+    public double getParameter(final String name)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        return mu;
+    }
+
+    /** {@inheritDoc} */
+    public void setParameter(final String name, final double value)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        this.mu = value;
+    }
+
+    /** {@inheritDoc} */
+    public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder)
+        throws OrekitException {
+        adder.addKeplerContribution(mu);
+    }
+
+    /** {@inheritDoc} */
+    public EventDetector[] getEventsDetectors() {
+        return new EventDetector[0];
+    }
+
+}
+
diff --git a/src/main/java/org/orekit/forces/gravity/ThirdBodyAttraction.java b/src/main/java/org/orekit/forces/gravity/ThirdBodyAttraction.java
index 7b806383b6..b99b3d4f9c 100644
--- a/src/main/java/org/orekit/forces/gravity/ThirdBodyAttraction.java
+++ b/src/main/java/org/orekit/forces/gravity/ThirdBodyAttraction.java
@@ -20,6 +20,7 @@ import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
 import org.orekit.bodies.CelestialBody;
 import org.orekit.errors.OrekitException;
+import org.orekit.forces.AbstractParameterizable;
 import org.orekit.forces.ForceModel;
 import org.orekit.propagation.SpacecraftState;
 import org.orekit.propagation.events.EventDetector;
@@ -32,21 +33,26 @@ import org.orekit.propagation.numerical.TimeDerivativesEquations;
  * @author V&eacute;ronique Pommier-Maurussane
  * @version $Revision:1665 $ $Date:2008-06-11 12:12:59 +0200 (mer., 11 juin 2008) $
  */
-public class ThirdBodyAttraction implements ForceModel {
+public class ThirdBodyAttraction extends AbstractParameterizable implements ForceModel {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = 9017402538195695004L;
+    private static final long serialVersionUID = -1703641239448217284L;
 
     /** The body to consider. */
     private final CelestialBody body;
 
+    /** Local value for body attraction coefficient. */
+    private double gm;
+
     /** Simple constructor.
      * @param body the third body to consider
      * (ex: {@link org.orekit.bodies.CelestialBodyFactory#getSun()} or
      * {@link org.orekit.bodies.CelestialBodyFactory#getMoon()})
      */
     public ThirdBodyAttraction(final CelestialBody body) {
+        super(body.getName() + " attraction coefficient");
         this.body = body;
+        this.gm   = body.getGM();
     }
 
     /** {@inheritDoc} */
@@ -61,8 +67,8 @@ public class ThirdBodyAttraction implements ForceModel {
 
         // compute relative acceleration
         final Vector3D gamma =
-            new Vector3D(body.getGM() * FastMath.pow(r2Sat, -1.5), satToBody,
-                        -body.getGM() * FastMath.pow(r2Central, -1.5), centralToBody);
+            new Vector3D(gm * FastMath.pow(r2Sat, -1.5), satToBody,
+                        -gm * FastMath.pow(r2Central, -1.5), centralToBody);
 
         // add contribution to the ODE second member
         adder.addXYZAcceleration(gamma.getX(), gamma.getY(), gamma.getZ());
@@ -74,4 +80,18 @@ public class ThirdBodyAttraction implements ForceModel {
         return new EventDetector[0];
     }
 
+    /** {@inheritDoc} */
+    public double getParameter(final String name)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        return gm;
+    }
+
+    /** {@inheritDoc} */
+    public void setParameter(final String name, final double value)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        gm = value;
+    }
+
 }
diff --git a/src/main/java/org/orekit/forces/gravity/potential/SHMFormatReader.java b/src/main/java/org/orekit/forces/gravity/potential/SHMFormatReader.java
index 78fc9492f7..7002869b6e 100644
--- a/src/main/java/org/orekit/forces/gravity/potential/SHMFormatReader.java
+++ b/src/main/java/org/orekit/forces/gravity/potential/SHMFormatReader.java
@@ -68,7 +68,8 @@ public class SHMFormatReader extends PotentialCoefficientsReader {
         boolean okSHM    = false;
         boolean okCoeffs = false;
         String line = r.readLine();
-        if ("FIRST ".equals(line.substring(0, 6)) &&
+        if ((line != null) &&
+            "FIRST ".equals(line.substring(0, 6)) &&
             "SHM    ".equals(line.substring(49, 56))) {
             for (line = r.readLine(); line != null; line = r.readLine()) {
                 if (line.length() >= 6) {
diff --git a/src/main/java/org/orekit/forces/maneuvers/ConstantThrustManeuver.java b/src/main/java/org/orekit/forces/maneuvers/ConstantThrustManeuver.java
index ff20bbb216..6b140a081d 100644
--- a/src/main/java/org/orekit/forces/maneuvers/ConstantThrustManeuver.java
+++ b/src/main/java/org/orekit/forces/maneuvers/ConstantThrustManeuver.java
@@ -18,6 +18,7 @@ package org.orekit.forces.maneuvers;
 
 import org.apache.commons.math.geometry.Vector3D;
 import org.orekit.errors.OrekitException;
+import org.orekit.forces.AbstractParameterizable;
 import org.orekit.forces.ForceModel;
 import org.orekit.propagation.SpacecraftState;
 import org.orekit.propagation.events.DateDetector;
@@ -37,11 +38,17 @@ import org.orekit.time.AbsoluteDate;
  * @author Luc Maisonobe
  * @version $Revision:1665 $ $Date:2008-06-11 12:12:59 +0200 (mer., 11 juin 2008) $
  */
-public class ConstantThrustManeuver implements ForceModel {
+public class ConstantThrustManeuver extends AbstractParameterizable implements ForceModel {
 
     /** Reference gravity acceleration constant (m/s<sup>2</sup>). */
     public static final double G0 = 9.80665;
 
+    /** Parameter name for thrust. */
+    private static final String THRUST = "thrust";
+
+    /** Parameter name for flow rate. */
+    private static final String FLOW_RATE = "flow rate";
+
     /** Serializable UID. */
     private static final long serialVersionUID = 5349622732741384211L;
 
@@ -55,10 +62,10 @@ public class ConstantThrustManeuver implements ForceModel {
     private final AbsoluteDate endDate;
 
     /** Engine thrust. */
-    private final double thrust;
+    private double thrust;
 
     /** Engine flow-rate. */
-    private final double flowRate;
+    private double flowRate;
 
     /** Direction of the acceleration in satellite frame. */
     private final Vector3D direction;
@@ -75,6 +82,7 @@ public class ConstantThrustManeuver implements ForceModel {
                                   final double thrust, final double isp,
                                   final Vector3D direction) {
 
+        super(THRUST, FLOW_RATE);
         if (duration >= 0) {
             this.startDate = date;
             this.endDate   = date.shiftedBy(duration);
@@ -115,6 +123,27 @@ public class ConstantThrustManeuver implements ForceModel {
         };
     }
 
+    /** {@inheritDoc} */
+    public double getParameter(final String name)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        if (name.equals(THRUST)) {
+            return thrust;
+        }
+        return flowRate;
+    }
+
+    /** {@inheritDoc} */
+    public void setParameter(final String name, final double value)
+        throws IllegalArgumentException {
+        complainIfNotSupported(name);
+        if (name.equals(THRUST)) {
+            thrust = value;
+        } else {
+            flowRate = value;
+        }
+    }
+
     /** Detector for start of maneuver. */
     private class FiringStartDetector extends DateDetector {
 
diff --git a/src/main/java/org/orekit/forces/package.html b/src/main/java/org/orekit/forces/package.html
index 53c91fd7f2..864d2d8dc6 100644
--- a/src/main/java/org/orekit/forces/package.html
+++ b/src/main/java/org/orekit/forces/package.html
@@ -1,12 +1,11 @@
 <html>
 <body>
 This package provides the interface for force models that will be used by the 
-{@link org.orekit.propagation.numerical.NumericalPropagator} and the
-{@link org.orekit.propagation.numerical.NumericalPropagatorWithJacobians}, as well as
+{@link org.orekit.propagation.numerical.NumericalPropagator}, as well as
  some classical spacecraft models for surface forces (spherical, box and solar array ...).
 
 @author Luc Maisonobe
 @author Pascal Parraud
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/src/main/java/org/orekit/forces/radiation/RadiationSensitive.java b/src/main/java/org/orekit/forces/radiation/RadiationSensitive.java
index ae49115fd2..b111d33eba 100644
--- a/src/main/java/org/orekit/forces/radiation/RadiationSensitive.java
+++ b/src/main/java/org/orekit/forces/radiation/RadiationSensitive.java
@@ -64,4 +64,13 @@ public interface RadiationSensitive extends Serializable {
      */
     double getReflectionCoefficient();
 
+    /** Compute acceleration derivatives with respect to additional parameters.
+     * @param acceleration spacecraft acceleration
+     * @param paramName name of the parameter with respect to which derivatives are required
+     * @param dAccdParam acceleration derivatives with respect to additional parameters
+     * @exception OrekitException if derivatives cannot be computed
+     */
+    void addDAccDParam(Vector3D acceleration,  String paramName, double[] dAccdParam)
+        throws OrekitException;
+
 }
diff --git a/src/main/java/org/orekit/forces/radiation/SolarRadiationPressure.java b/src/main/java/org/orekit/forces/radiation/SolarRadiationPressure.java
index 12ff8a86ab..b89717d77d 100644
--- a/src/main/java/org/orekit/forces/radiation/SolarRadiationPressure.java
+++ b/src/main/java/org/orekit/forces/radiation/SolarRadiationPressure.java
@@ -16,20 +16,18 @@
  */
 package org.orekit.forces.radiation;
 
-import java.util.ArrayList;
-import java.util.Collection;
-
 import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
-import org.orekit.forces.ForceModelWithJacobians;
+import org.orekit.forces.AbstractParameterizable;
+import org.orekit.forces.ForceModel;
 import org.orekit.frames.Frame;
 import org.orekit.propagation.SpacecraftState;
 import org.orekit.propagation.events.AbstractDetector;
 import org.orekit.propagation.events.EventDetector;
+import org.orekit.propagation.numerical.AccelerationJacobiansProvider;
 import org.orekit.propagation.numerical.TimeDerivativesEquations;
-import org.orekit.propagation.numerical.TimeDerivativesEquationsWithJacobians;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.PVCoordinates;
 import org.orekit.utils.PVCoordinatesProvider;
@@ -42,18 +40,18 @@ import org.orekit.utils.PVCoordinatesProvider;
  * @author Pascal Parraud
  * @version $Revision:1665 $ $Date:2008-06-11 12:12:59 +0200 (mer., 11 juin 2008) $
  */
-public class SolarRadiationPressure implements ForceModelWithJacobians {
+public class SolarRadiationPressure extends AbstractParameterizable implements ForceModel, AccelerationJacobiansProvider {
 
-    /** Parameter name for absorption coefficient enabling jacobian processing. */
-    public static final String ABSORPTION_COEFFICIENT = "ABSORPTION COEFFICIENT";
+    /** Parameter name for absorption coefficient. */
+    public static final String ABSORPTION_COEFFICIENT = "absorption coefficient";
 
-    /** Parameter name for specular reflection coefficient enabling jacobian processing. */
-    public static final String REFLECTION_COEFFICIENT = "REFLECTION COEFFICIENT";
+    /** Parameter name for reflection coefficient. */
+    public static final String REFLECTION_COEFFICIENT = "reflection coefficient";
 
     /** Serializable UID. */
-    private static final long serialVersionUID = 8874297900604482921L;
+    private static final long serialVersionUID = -4510170320082379419L;
 
-    /** Sun radius (m). */
+     /** Sun radius (m). */
     private static final double SUN_RADIUS = 6.95e8;
 
     /** Reference flux normalized for a 1m distance (N). */
@@ -68,9 +66,6 @@ public class SolarRadiationPressure implements ForceModelWithJacobians {
     /** Spacecraft. */
     private final RadiationSensitive spacecraft;
 
-    /** List of the parameters names. */
-    private final ArrayList<String> parametersNames = new ArrayList<String>();
-
     /** Simple constructor with default reference values.
      * <p>When this constructor is used, the reference values are:</p>
      * <ul>
@@ -102,30 +97,49 @@ public class SolarRadiationPressure implements ForceModelWithJacobians {
                                   final PVCoordinatesProvider sun,
                                   final double equatorialRadius,
                                   final RadiationSensitive spacecraft) {
+        super(ABSORPTION_COEFFICIENT, REFLECTION_COEFFICIENT);
         this.kRef  = pRef * dRef * dRef;
         this.sun   = sun;
         this.equatorialRadius = equatorialRadius;
         this.spacecraft = spacecraft;
-        this.parametersNames.add(ABSORPTION_COEFFICIENT);
-        this.parametersNames.add(REFLECTION_COEFFICIENT);
     }
 
-    /** {@inheritDoc} */
-    public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder)
-        throws OrekitException {
-
+    /** Compute radiation coefficient.
+     * @param s spacecraft state
+     * @return coefficient for acceleration computation
+     * @exception OrekitException if position cannot be computed
+     */
+    private double computeRawP (final SpacecraftState s) throws OrekitException {
         final AbsoluteDate date     = s.getDate();
         final Frame        frame    = s.getFrame();
         final Vector3D     position = s.getPVCoordinates().getPosition();
 
-        // raw radiation pressure
         final Vector3D satSunVector = getSatSunVector(s);
         final double r2             = satSunVector.getNormSq();
-        final double rawP           = kRef * getLightningRatio(position, frame, date) / r2;
-        final Vector3D flux         = new Vector3D(-rawP / FastMath.sqrt(r2), satSunVector);
+        return kRef * getLightningRatio(position, frame, date) / r2;
+    }
+
+    /** Compute radiation acceleration.
+     * @param s spacecraft state
+     * @return acceleration
+     * @exception OrekitException if position cannot be computed
+     */
+    private Vector3D computeAcceleration(final SpacecraftState s) throws OrekitException {
+
+        final Vector3D satSunVector = getSatSunVector(s);
+        final double r2             = satSunVector.getNormSq();
+
+        final double rawP = computeRawP(s);
+        // raw radiation pressure
+        return spacecraft.radiationPressureAcceleration(s, new Vector3D(-rawP / FastMath.sqrt(r2), satSunVector));
+    }
+
+    /** {@inheritDoc} */
+    public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder)
+        throws OrekitException {
 
         // provide the perturbing acceleration to the derivatives adder
-        adder.addAcceleration(spacecraft.radiationPressureAcceleration(s, flux), frame);
+        adder.addAcceleration(computeAcceleration(s), s.getFrame());
 
     }
 
@@ -185,12 +199,8 @@ public class SolarRadiationPressure implements ForceModelWithJacobians {
                 alpha2 * FastMath.sqrt(alphaEarth * alphaEarth - alpha2 * alpha2);
 
             result = (P1 - P2) / (FastMath.PI * alphaSun * alphaSun);
-
-
         }
-
         return result;
-
     }
 
     /** Compute sat-Sun vector in spacecraft state frame.
@@ -213,37 +223,69 @@ public class SolarRadiationPressure implements ForceModelWithJacobians {
     }
 
     /** {@inheritDoc} */
-    public void addContributionWithJacobians(final SpacecraftState s,
-                                             final TimeDerivativesEquationsWithJacobians adder)
+    public void addDAccDState(final SpacecraftState s,
+                              final double[][] dAccdPos, final double[][] dAccdVel, final double[] dAccdM)
         throws OrekitException {
+
+        final Vector3D satSunVector = getSatSunVector(s);
+        final double r2             = satSunVector.getNormSq();
+        final double rawP           = computeRawP(s);
+        final Vector3D acceleration = spacecraft.radiationPressureAcceleration(s, new Vector3D(-rawP / FastMath.sqrt(r2), satSunVector));
+
+        final double x2 = satSunVector.getX() * satSunVector.getX();
+        final double y2 = satSunVector.getY() * satSunVector.getY();
+        final double z2 = satSunVector.getZ() * satSunVector.getZ();
+        final double xy = satSunVector.getX() * satSunVector.getY();
+        final double yz = satSunVector.getY() * satSunVector.getZ();
+        final double zx = satSunVector.getZ() * satSunVector.getX();
+        final double prefix = Vector3D.dotProduct(acceleration, satSunVector) / (r2 * r2);
+
+        // jacobian with respect to position
+        dAccdPos[0][0] += prefix * (2 * x2 - y2 - z2);
+        dAccdPos[0][1] += prefix * 3 * xy;
+        dAccdPos[0][2] += prefix * 3 * zx;
+        dAccdPos[1][0] += prefix * 3 * xy;
+        dAccdPos[1][1] += prefix * (2 * y2 - z2 - x2);
+        dAccdPos[1][2] += prefix * 3 * yz;
+        dAccdPos[2][0] += prefix * 3 * zx;
+        dAccdPos[2][1] += prefix * 3 * yz;
+        dAccdPos[2][2] += prefix * (2 * z2 - x2 - y2);
+
+        // jacobian with respect to velocity is null
+
+        if (dAccdM != null) {
+            // jacobian with respect to mass
+            dAccdM[0] -= acceleration.getX() / s.getMass();
+            dAccdM[1] -= acceleration.getY() / s.getMass();
+            dAccdM[2] -= acceleration.getZ() / s.getMass();
+        }
+
     }
 
     /** {@inheritDoc} */
-    public Collection<String> getParametersNames() {
-        return parametersNames;
+    public void addDAccDParam(final SpacecraftState s, final String paramName, final double[] dAccdParam)
+        throws OrekitException {
+        spacecraft.addDAccDParam(computeAcceleration(s), paramName, dAccdParam);
     }
 
     /** {@inheritDoc} */
     public double getParameter(final String name)
         throws IllegalArgumentException {
-        if (name.matches(ABSORPTION_COEFFICIENT)) {
+        complainIfNotSupported(name);
+        if (name.equals(ABSORPTION_COEFFICIENT)) {
             return spacecraft.getAbsorptionCoefficient();
-        } else if (name.matches(REFLECTION_COEFFICIENT)) {
-            return spacecraft.getReflectionCoefficient();
-        } else {
-            throw OrekitException.createIllegalArgumentException(OrekitMessages.UNKNOWN_PARAMETER, name);
         }
+        return spacecraft.getReflectionCoefficient();
     }
 
     /** {@inheritDoc} */
     public void setParameter(final String name, final double value)
         throws IllegalArgumentException {
-        if (name.matches(ABSORPTION_COEFFICIENT)) {
+        complainIfNotSupported(name);
+        if (name.equals(ABSORPTION_COEFFICIENT)) {
             spacecraft.setAbsorptionCoefficient(value);
-        } else if (name.matches(REFLECTION_COEFFICIENT)) {
-            spacecraft.setReflectionCoefficient(value);
         } else {
-            throw OrekitException.createIllegalArgumentException(OrekitMessages.UNKNOWN_PARAMETER, name);
+            spacecraft.setReflectionCoefficient(value);
         }
     }
 
diff --git a/src/main/java/org/orekit/frames/Frame.java b/src/main/java/org/orekit/frames/Frame.java
index 67f73be414..1bc68a3e82 100644
--- a/src/main/java/org/orekit/frames/Frame.java
+++ b/src/main/java/org/orekit/frames/Frame.java
@@ -64,7 +64,7 @@ public class Frame implements Serializable {
     private Transform transform;
 
     /** Map of deepest frames commons with other frames. */
-    private final WeakHashMap<Frame, Frame> commons;
+    private final transient WeakHashMap<Frame, Frame> commons;
 
     /** Instance name. */
     private final String name;
diff --git a/src/main/java/org/orekit/frames/FramesFactory.java b/src/main/java/org/orekit/frames/FramesFactory.java
index 01b4aa9e54..5438d21d13 100644
--- a/src/main/java/org/orekit/frames/FramesFactory.java
+++ b/src/main/java/org/orekit/frames/FramesFactory.java
@@ -149,7 +149,7 @@ public class FramesFactory implements Serializable {
     private static final long serialVersionUID = 1720647682459923909L;
 
     /** Predefined frames. */
-    private static Map<Predefined, FactoryManagedFrame> FRAMES =
+    private static transient Map<Predefined, FactoryManagedFrame> FRAMES =
         new WeakHashMap<Predefined, FactoryManagedFrame>();
 
     /** EOP 1980 loaders. */
diff --git a/src/main/java/org/orekit/frames/SpacecraftFrame.java b/src/main/java/org/orekit/frames/SpacecraftFrame.java
index e533a8cf9f..105b226e77 100644
--- a/src/main/java/org/orekit/frames/SpacecraftFrame.java
+++ b/src/main/java/org/orekit/frames/SpacecraftFrame.java
@@ -37,7 +37,7 @@ public class SpacecraftFrame extends Frame implements PVCoordinatesProvider {
     private final Propagator propagator;
 
     /** Cached date to avoid useless computation. */
-    private AbsoluteDate cachedDate;
+    private transient AbsoluteDate cachedDate;
 
     /** Simple constructor.
      * @param propagator orbit/attitude propagator computing spacecraft state evolution
diff --git a/src/main/java/org/orekit/frames/TIRF2000Frame.java b/src/main/java/org/orekit/frames/TIRF2000Frame.java
index 6fb3c8110b..b9d919ba2b 100644
--- a/src/main/java/org/orekit/frames/TIRF2000Frame.java
+++ b/src/main/java/org/orekit/frames/TIRF2000Frame.java
@@ -54,7 +54,7 @@ class TIRF2000Frame extends FactoryManagedFrame {
     private static final double ERA_1B = ERA_1A * 0.00273781191135448;
 
     /** Cached date to avoid useless calculus. */
-    private AbsoluteDate cachedDate;
+    private transient AbsoluteDate cachedDate;
 
     /** Earth Rotation Angle, in radians. */
     private double era;
diff --git a/src/main/java/org/orekit/frames/VEISFrame.java b/src/main/java/org/orekit/frames/VEISFrame.java
index e113db2b4b..143a3bb9ee 100644
--- a/src/main/java/org/orekit/frames/VEISFrame.java
+++ b/src/main/java/org/orekit/frames/VEISFrame.java
@@ -50,7 +50,7 @@ class VEISFrame extends FactoryManagedFrame {
     private static final double VSTD = 7.292115146705209e-5;
 
     /** Cached date to avoid useless calculus. */
-    private AbsoluteDate cachedDate;
+    private transient AbsoluteDate cachedDate;
 
     /** Constructor for the singleton.
      * @param factoryKey key of the frame within the factory
diff --git a/src/main/java/org/orekit/orbits/CartesianOrbit.java b/src/main/java/org/orekit/orbits/CartesianOrbit.java
index af7740ef3e..8db09f7b5d 100644
--- a/src/main/java/org/orekit/orbits/CartesianOrbit.java
+++ b/src/main/java/org/orekit/orbits/CartesianOrbit.java
@@ -16,6 +16,9 @@
  */
 package org.orekit.orbits;
 
+import org.apache.commons.math.geometry.Rotation;
+import org.apache.commons.math.geometry.Vector3D;
+import org.apache.commons.math.util.FastMath;
 import org.orekit.frames.Frame;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.PVCoordinates;
@@ -59,10 +62,10 @@ import org.orekit.utils.PVCoordinates;
 public class CartesianOrbit extends Orbit {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = -6035381767203311530L;
+    private static final long serialVersionUID = -5411308212620896302L;
 
-    /** Underlying equinoctial orbit providing non-cartesian elements. */
-    private final EquinoctialOrbit equinoctial;
+    /** Underlying equinoctial orbit to which high-level methods are delegated. */
+    private transient EquinoctialOrbit equinoctial;
 
     /** Constructor from cartesian parameters.
      * @param pvCoordinates the position and velocity of the satellite.
@@ -77,7 +80,7 @@ public class CartesianOrbit extends Orbit {
                           final AbsoluteDate date, final double mu)
         throws IllegalArgumentException {
         super(pvCoordinates, frame, date, mu);
-        equinoctial = new EquinoctialOrbit(pvCoordinates, frame, date, mu);
+        equinoctial = null;
     }
 
     /** Constructor from any kind of orbital parameters.
@@ -85,34 +88,56 @@ public class CartesianOrbit extends Orbit {
      */
     public CartesianOrbit(final Orbit op) {
         super(op.getPVCoordinates(), op.getFrame(), op.getDate(), op.getMu());
-        equinoctial = (op instanceof EquinoctialOrbit) ? (EquinoctialOrbit) op : new EquinoctialOrbit(op);
+        if (op instanceof EquinoctialOrbit) {
+            equinoctial = (EquinoctialOrbit) op;
+        } else if (op instanceof CartesianOrbit) {
+            equinoctial = ((CartesianOrbit) op).equinoctial;
+        } else {
+            equinoctial = null;
+        }
+    }
+
+    /** Lazy evaluation of equinoctial parameters. */
+    private void initEquinoctial() {
+        if (equinoctial == null) {
+            equinoctial = new EquinoctialOrbit(getPVCoordinates(), getFrame(), getDate(), getMu());
+        }
     }
 
     /** Get the semi-major axis.
      * @return semi-major axis (m)
      */
     public double getA() {
-        return equinoctial.getA();
+        // lazy evaluation of semi-major axis
+        final double r  = getPVCoordinates().getPosition().getNorm();
+        final double V2 = getPVCoordinates().getVelocity().getNormSq();
+        return r / (2 - r * V2 / getMu());
     }
 
     /** Get the eccentricity.
      * @return eccentricity
      */
     public double getE() {
-        return equinoctial.getE();
+        final Vector3D pvP   = getPVCoordinates().getPosition();
+        final Vector3D pvV   = getPVCoordinates().getVelocity();
+        final double rV2OnMu = pvP.getNorm() * pvV.getNormSq() / getMu();
+        final double eSE     = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(getMu() * getA());
+        final double eCE     = rV2OnMu - 1;
+        return FastMath.sqrt(eCE * eCE + eSE * eSE);
     }
 
     /** Get the inclination.
      * @return inclination (rad)
      */
     public double getI() {
-        return equinoctial.getI();
+        return Vector3D.angle(Vector3D.PLUS_K, getPVCoordinates().getMomentum());
     }
 
     /** Get the first component of the eccentricity vector.
      * @return first component of the eccentricity vector
      */
     public double getEquinoctialEx() {
+        initEquinoctial();
         return equinoctial.getEquinoctialEx();
     }
 
@@ -120,6 +145,7 @@ public class CartesianOrbit extends Orbit {
      * @return second component of the eccentricity vector
      */
     public double getEquinoctialEy() {
+        initEquinoctial();
         return equinoctial.getEquinoctialEy();
     }
 
@@ -127,20 +153,31 @@ public class CartesianOrbit extends Orbit {
      * @return first component of the inclination vector.
      */
     public double getHx() {
-        return equinoctial.getHx();
+        final Vector3D w = getPVCoordinates().getMomentum().normalize();
+        // Check for equatorial retrograde orbit
+        if (((w.getX() * w.getX() + w.getY() * w.getY()) == 0) && w.getZ() < 0) {
+            return Double.NaN;
+        }
+        return -w.getY() / (1 + w.getZ());
     }
 
     /** Get the second component of the inclination vector.
      * @return second component of the inclination vector.
      */
     public double getHy() {
-        return equinoctial.getHy();
+        final Vector3D w = getPVCoordinates().getMomentum().normalize();
+        // Check for equatorial retrograde orbit
+        if (((w.getX() * w.getX() + w.getY() * w.getY()) == 0) && w.getZ() < 0) {
+            return Double.NaN;
+        }
+        return  w.getX() / (1 + w.getZ());
     }
 
     /** Get the true latitude argument.
      * @return true latitude argument (rad)
      */
     public double getLv() {
+        initEquinoctial();
         return equinoctial.getLv();
     }
 
@@ -148,6 +185,7 @@ public class CartesianOrbit extends Orbit {
      * @return eccentric latitude argument.(rad)
      */
     public double getLE() {
+        initEquinoctial();
         return equinoctial.getLE();
     }
 
@@ -155,12 +193,185 @@ public class CartesianOrbit extends Orbit {
      * @return mean latitude argument.(rad)
      */
     public double getLM() {
+        initEquinoctial();
         return equinoctial.getLM();
     }
 
+    /** {@inheritDoc} */
+    protected PVCoordinates initPVCoordinates() {
+        // nothing to do here, as the canonical elements are already the cartesian ones
+        return getPVCoordinates();
+    }
+
     /** {@inheritDoc} */
     public CartesianOrbit shiftedBy(final double dt) {
-        return new CartesianOrbit(equinoctial.shiftedBy(dt));
+        final PVCoordinates shiftedPV = (getA() < 0) ? shiftPVHyperbolic(dt) : shiftPVElliptic(dt);
+        return new CartesianOrbit(shiftedPV, getFrame(), getDate().shiftedBy(dt), getMu());
+    }
+
+    /** Compute shifted position and velocity in elliptic case.
+     * @param dt time shift
+     * @return shifted position and velocity
+     */
+    private PVCoordinates shiftPVElliptic(final double dt) {
+
+        // preliminary computation
+        final Vector3D pvP   = getPVCoordinates().getPosition();
+        final Vector3D pvV   = getPVCoordinates().getVelocity();
+        final double r       = pvP.getNorm();
+        final double rV2OnMu = r * pvV.getNormSq() / getMu();
+        final double a       = getA();
+        final double eSE     = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(getMu() * a);
+        final double eCE     = rV2OnMu - 1;
+        final double e2      = eCE * eCE + eSE * eSE;
+
+        // we can use any arbitrary reference 2D frame in the orbital plane
+        // in order to simplify some equations below, we use the current position as the u axis
+        final Vector3D u     = pvP.normalize();
+        final Vector3D v     = Vector3D.crossProduct(getPVCoordinates().getMomentum(), u).normalize();
+
+        // the following equations rely on the specific choice of u explained above,
+        // some coefficients that vanish to 0 in this case have already been removed here
+        final double ex      = (eCE - e2) * a / r;
+        final double ey      = -FastMath.sqrt(1 - e2) * eSE * a / r;
+        final double beta    = 1 / (1 + FastMath.sqrt(1 - e2));
+        final double thetaE0 = FastMath.atan2(ey + eSE * beta * ex, r / a + ex - eSE * beta * ey);
+        final double thetaM0 = thetaE0 - ex * FastMath.sin(thetaE0) + ey * FastMath.cos(thetaE0);
+
+        // compute in-plane shifted eccentric argument
+        final double thetaM1 = thetaM0 + getKeplerianMeanMotion() * dt;
+        final double thetaE1 = meanToEccentric(thetaM1, ex, ey);
+        final double cTE     = FastMath.cos(thetaE1);
+        final double sTE     = FastMath.sin(thetaE1);
+
+        // compute shifted in-plane cartesian coordinates
+        final double exey   = ex * ey;
+        final double exCeyS = ex * cTE + ey * sTE;
+        final double x      = a * ((1 - beta * ey * ey) * cTE + beta * exey * sTE - ex);
+        final double y      = a * ((1 - beta * ex * ex) * sTE + beta * exey * cTE - ey);
+        final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
+        final double xDot   = factor * (-sTE + beta * ey * exCeyS);
+        final double yDot   = factor * ( cTE - beta * ex * exCeyS);
+
+        return new PVCoordinates(new Vector3D(x, u, y, v), new Vector3D(xDot, u, yDot, v));
+
+    }
+
+    /** Compute shifted position and velocity in hyperbolic case.
+     * @param dt time shift
+     * @return shifted position and velocity
+     */
+    private PVCoordinates shiftPVHyperbolic(final double dt) {
+
+        final PVCoordinates pv = getPVCoordinates();
+        final Vector3D pvP   = pv.getPosition();
+        final Vector3D pvV   = pv.getVelocity();
+        final Vector3D pvM   = pv.getMomentum();
+        final double r       = pvP.getNorm();
+        final double rV2OnMu = r * pvV.getNormSq() / getMu();
+        final double a       = getA();
+        final double muA     = getMu() * a;
+        final double e       = FastMath.sqrt(1 - Vector3D.dotProduct(pvM, pvM) / muA);
+        final double sqrt    = FastMath.sqrt((e + 1) / (e - 1));
+
+        // compute mean anomaly
+        final double eSH     = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(-muA);
+        final double eCH     = rV2OnMu - 1;
+        final double H0      = FastMath.log((eCH + eSH) / (eCH - eSH)) / 2;
+        final double M0      = e * FastMath.sinh(H0) - H0;
+
+        // find canonical 2D frame with p pointing to perigee
+        final double v0      = 2 * FastMath.atan(sqrt * FastMath.tanh(H0 / 2));
+        final Vector3D p     = new Rotation(pvM, -v0).applyTo(pvP).normalize();
+        final Vector3D q     = Vector3D.crossProduct(pvM, p).normalize();
+
+        // compute shifted eccentric anomaly
+        final double M1      = M0 + getKeplerianMeanMotion() * dt;
+        final double H1      = meanToHyperbolicEccentric(M1, e);
+
+        // compute shifted in-plane cartesian coordinates
+        final double cH     = FastMath.cosh(H1);
+        final double sH     = FastMath.sinh(H1);
+        final double sE2m1  = FastMath.sqrt((e - 1) * (e + 1));
+
+        // coordinates of position and velocity in the orbital plane
+        final double x      = a * (cH - e);
+        final double y      = -a * sE2m1 * sH;
+        final double factor = FastMath.sqrt(getMu() / -a) / (e * cH - 1);
+        final double xDot   = -factor * sH;
+        final double yDot   =  factor * sE2m1 * cH;
+
+        return new PVCoordinates(new Vector3D(x, p, y, q), new Vector3D(xDot, p, yDot, q));
+
+    }
+
+    /** Computes the eccentric in-plane argument from the mean in-plane argument.
+     * @param thetaM = mean in-plane argument (rad)
+     * @param ex first component of eccentricity vector
+     * @param ey second component of eccentricity vector
+     * @return the eccentric in-plane argument.
+     */
+    private double meanToEccentric(final double thetaM, final double ex, final double ey) {
+        // Generalization of Kepler equation to in-plane parameters
+        // with thetaE = eta + E and
+        //      thetaM = eta + M = thetaE - ex.sin(thetaE) + ey.cos(thetaE)
+        // and eta being counted from an arbitrary reference in the orbital plane
+        double thetaE        = thetaM;
+        double shift         = 0.0;
+        double thetaEMthetaM = 0.0;
+        double cosThetaE     = FastMath.cos(thetaE);
+        double sinThetaE     = FastMath.sin(thetaE);
+        int    iter          = 0;
+        do {
+            final double f2 = ex * sinThetaE - ey * cosThetaE;
+            final double f1 = 1.0 - ex * cosThetaE - ey * sinThetaE;
+            final double f0 = thetaEMthetaM - f2;
+
+            final double f12 = 2.0 * f1;
+            shift = f0 * f12 / (f1 * f12 - f0 * f2);
+
+            thetaEMthetaM -= shift;
+            thetaE         = thetaM + thetaEMthetaM;
+            cosThetaE      = FastMath.cos(thetaE);
+            sinThetaE      = FastMath.sin(thetaE);
+
+        } while ((++iter < 50) && (FastMath.abs(shift) > 1.0e-12));
+
+        return thetaE;
+
+    }
+
+    /** Computes the hyperbolic eccentric anomaly from the mean anomaly.
+     * <p>
+     * The algorithm used here for solving hyperbolic Kepler equation is
+     * a naive initialization and classical Halley method for iterations.
+     * </p>
+     * @param M mean anomaly (rad)
+     * @param e eccentricity
+     * @return the true anomaly
+     */
+    private double meanToHyperbolicEccentric(final double M, final double e) {
+
+        // resolution of hyperbolic Kepler equation for keplerian parameters
+        double H     = -M;
+        double shift = 0.0;
+        double HpM   = 0.0;
+        int    iter  = 0;
+        do {
+            final double f2 = e * FastMath.sinh(H);
+            final double f1 = e * FastMath.cosh(H) - 1;
+            final double f0 = f2 - HpM;
+
+            final double f12 = 2 * f1;
+            shift = f0 * f12 / (f1 * f12 - f0 * f2);
+
+            HpM -= shift;
+            H    = HpM - M;
+
+        } while ((++iter < 50) && (FastMath.abs(shift) > 1.0e-12));
+
+        return H;
+
     }
 
     /**  Returns a string representation of this Orbit object.
diff --git a/src/main/java/org/orekit/orbits/CircularOrbit.java b/src/main/java/org/orekit/orbits/CircularOrbit.java
index 8901690b7f..ce021871e6 100644
--- a/src/main/java/org/orekit/orbits/CircularOrbit.java
+++ b/src/main/java/org/orekit/orbits/CircularOrbit.java
@@ -78,7 +78,7 @@ public class CircularOrbit
     public static final int TRUE_LONGITUDE_ARGUMENT = 2;
 
     /** Serializable UID. */
-    private static final long serialVersionUID = -5031200932453701026L;
+    private static final long serialVersionUID = 5042463409964008691L;
 
     /** Semi-major axis (m). */
     private final double a;
@@ -133,10 +133,10 @@ public class CircularOrbit
 
         switch (type) {
         case MEAN_LONGITUDE_ARGUMENT :
-            this.alphaV = computeAlphaM(alpha);
+            this.alphaV = eccentricToTrue(meanToEccentric(alpha));
             break;
         case ECCENTRIC_LONGITUDE_ARGUMENT :
-            this.alphaV = computeAlphaE(alpha);
+            this.alphaV = eccentricToTrue(alpha);
             break;
         case TRUE_LONGITUDE_ARGUMENT :
             this.alphaV = alpha;
@@ -171,6 +171,12 @@ public class CircularOrbit
         final double r  = pvP.getNorm();
         final double V2 = pvV.getNormSq();
         final double rV2OnMu = r * V2 / mu;
+
+        if (rV2OnMu > 2) {
+            throw OrekitException.createIllegalArgumentException(
+                  OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS, getClass().getName());
+        }
+
         a = r / (2 - rV2OnMu);
 
         // compute inclination
@@ -188,10 +194,11 @@ public class CircularOrbit
         final double sinRaan = FastMath.sin(raan);
         final double cosI    = FastMath.cos(i);
         final double sinI    = FastMath.sin(i);
-        final Vector3D rVec  = new Vector3D(cosRaan, FastMath.sin(raan), 0);
-        final Vector3D sVec  = new Vector3D(-cosI * sinRaan, cosI * cosRaan, sinI);
-        final double x2      = Vector3D.dotProduct(pvP, rVec) / a;
-        final double y2      = Vector3D.dotProduct(pvP, sVec) / a;
+        final double xP      = pvP.getX();
+        final double yP      = pvP.getY();
+        final double zP      = pvP.getZ();
+        final double x2      = (xP * cosRaan + yP * sinRaan) / a;
+        final double y2      = ((yP * cosRaan - xP * sinRaan) * cosI + zP * sinI) / a;
 
         // compute eccentricity vector
         final double eSE    = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a);
@@ -206,7 +213,7 @@ public class CircularOrbit
 
         // compute longitude argument
         final double beta = 1 / (1 + FastMath.sqrt(1 - ex * ex - ey * ey));
-        alphaV = computeAlphaE(FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey));
+        alphaV = eccentricToTrue(FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey));
     }
 
     /** Constructor from any kind of orbital parameters.
@@ -293,11 +300,11 @@ public class CircularOrbit
                                       (epsilon + 1 + ex * cosAlphaV + ey * sinAlphaV));
     }
 
-    /** Computes the eccentric longitude argument.
+    /** Computes the true longitude argument from the eccentric longitude argument.
      * @param alphaE = E + &omega; eccentric longitude argument (rad)
      * @return the true longitude argument.
      */
-    private double computeAlphaE(final double alphaE) {
+    private double eccentricToTrue(final double alphaE) {
         final double epsilon   = FastMath.sqrt(1 - ex * ex - ey * ey);
         final double cosAlphaE = FastMath.cos(alphaE);
         final double sinAlphaE = FastMath.sin(alphaE);
@@ -313,23 +320,23 @@ public class CircularOrbit
         return alphaE - ex * FastMath.sin(alphaE) + ey * FastMath.cos(alphaE);
     }
 
-    /** Computes the mean longitude argument.
+    /** Computes the eccentric longitude argument from the mean longitude argument.
      * @param alphaM = M + &omega;  mean longitude argument (rad)
-     * @return the true longitude argument.
+     * @return the eccentric longitude argument.
      */
-    private double computeAlphaM(final double alphaM) {
-        // Generalization of Kepler equation to equinoctial parameters
+    private double meanToEccentric(final double alphaM) {
+        // Generalization of Kepler equation to circular parameters
         // with alphaE = PA + E and
         //      alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE)
-        double alphaE = alphaM;
-        double shift = 0.0;
+        double alphaE        = alphaM;
+        double shift         = 0.0;
         double alphaEMalphaM = 0.0;
-        double cosLE = FastMath.cos(alphaE);
-        double sinLE = FastMath.sin(alphaE);
-        int iter = 0;
+        double cosAlphaE     = FastMath.cos(alphaE);
+        double sinAlphaE     = FastMath.sin(alphaE);
+        int    iter          = 0;
         do {
-            final double f2 = ex * sinLE - ey * cosLE;
-            final double f1 = 1.0 - ex * cosLE - ey * sinLE;
+            final double f2 = ex * sinAlphaE - ey * cosAlphaE;
+            final double f1 = 1.0 - ex * cosAlphaE - ey * sinAlphaE;
             final double f0 = alphaEMalphaM - f2;
 
             final double f12 = 2.0 * f1;
@@ -337,12 +344,12 @@ public class CircularOrbit
 
             alphaEMalphaM -= shift;
             alphaE         = alphaM + alphaEMalphaM;
-            cosLE          = FastMath.cos(alphaE);
-            sinLE          = FastMath.sin(alphaE);
+            cosAlphaE      = FastMath.cos(alphaE);
+            sinAlphaE      = FastMath.sin(alphaE);
 
         } while ((++iter < 50) && (FastMath.abs(shift) > 1.0e-12));
 
-        return computeAlphaE(alphaE); // which set the alphaV parameter
+        return alphaE;
 
     }
 
@@ -388,6 +395,59 @@ public class CircularOrbit
         return getAlphaM() + raan;
     }
 
+    /** {@inheritDoc} */
+    protected PVCoordinates initPVCoordinates() {
+
+        // get equinoctial parameters
+        final double equEx = getEquinoctialEx();
+        final double equEy = getEquinoctialEy();
+        final double hx = getHx();
+        final double hy = getHy();
+        final double lE = getLE();
+
+        // inclination-related intermediate parameters
+        final double hx2   = hx * hx;
+        final double hy2   = hy * hy;
+        final double factH = 1. / (1 + hx2 + hy2);
+
+        // reference axes defining the orbital plane
+        final double ux = (1 + hx2 - hy2) * factH;
+        final double uy =  2 * hx * hy * factH;
+        final double uz = -2 * hy * factH;
+
+        final double vx = uy;
+        final double vy = (1 - hx2 + hy2) * factH;
+        final double vz =  2 * hx * factH;
+
+        // eccentricity-related intermediate parameters
+        final double exey = equEx * equEy;
+        final double ex2  = equEx * equEx;
+        final double ey2  = equEy * equEy;
+        final double e2   = ex2 + ey2;
+        final double eta  = 1 + FastMath.sqrt(1 - e2);
+        final double beta = 1. / eta;
+
+        // eccentric latitude argument
+        final double cLe    = FastMath.cos(lE);
+        final double sLe    = FastMath.sin(lE);
+        final double exCeyS = equEx * cLe + equEy * sLe;
+
+        // coordinates of position and velocity in the orbital plane
+        final double x      = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - equEx);
+        final double y      = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - equEy);
+
+        final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
+        final double xdot   = factor * (-sLe + beta * equEy * exCeyS);
+        final double ydot   = factor * ( cLe - beta * equEx * exCeyS);
+
+        final Vector3D position =
+            new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
+        final Vector3D velocity =
+            new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);
+        return new PVCoordinates(position, velocity);
+
+    }
+
     /** {@inheritDoc} */
     public CircularOrbit shiftedBy(final double dt) {
         return new CircularOrbit(a, ex, ey, i, raan,
diff --git a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java
index ded75577dc..b2d96c4e20 100644
--- a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java
+++ b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java
@@ -76,7 +76,7 @@ public class EquinoctialOrbit extends Orbit {
     public static final int TRUE_LATITUDE_ARGUMENT = 2;
 
     /** Serializable UID. */
-    private static final long serialVersionUID = -1779638201767656602L;
+    private static final long serialVersionUID = -2000712440570076839L;
 
     /** Semi-major axis (m). */
     private final double a;
@@ -131,10 +131,10 @@ public class EquinoctialOrbit extends Orbit {
 
         switch (type) {
         case MEAN_LATITUDE_ARGUMENT :
-            this.lv = computeLM(l);
+            this.lv = eccentricToTrue(meanToEccentric(l));
             break;
         case ECCENTRIC_LATITUDE_ARGUMENT :
-            this.lv = computeLE(l);
+            this.lv = eccentricToTrue(l);
             break;
         case TRUE_LATITUDE_ARGUMENT :
             this.lv = l;
@@ -169,7 +169,11 @@ public class EquinoctialOrbit extends Orbit {
         final double r = pvP.getNorm();
         final double V2 = pvV.getNormSq();
         final double rV2OnMu = r * V2 / mu;
-        a = r / (2 - rV2OnMu);
+
+        if (rV2OnMu > 2) {
+            throw OrekitException.createIllegalArgumentException(
+                  OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS, getClass().getName());
+        }
 
         // compute inclination vector
         final Vector3D w = pvCoordinates.getMomentum().normalize();
@@ -178,19 +182,23 @@ public class EquinoctialOrbit extends Orbit {
         hy =  d * w.getX();
 
         // compute true latitude argument
-        final Vector3D p = pvP;
-        final double cLv = (p.getX() - d * p.getZ() * w.getX()) / r;
-        final double sLv = (p.getY() - d * p.getZ() * w.getY()) / r;
+        final double cLv = (pvP.getX() - d * pvP.getZ() * w.getX()) / r;
+        final double sLv = (pvP.getY() - d * pvP.getZ() * w.getY()) / r;
         lv = FastMath.atan2(sLv, cLv);
 
+
+        // compute semi-major axis
+        a = r / (2 - rV2OnMu);
+
         // compute eccentricity vector
-        final double eSE = Vector3D.dotProduct(p, pvV) / FastMath.sqrt(mu * a);
+        final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a);
         final double eCE = rV2OnMu - 1;
         final double e2  = eCE * eCE + eSE * eSE;
         final double f   = eCE - e2;
         final double g   = FastMath.sqrt(1 - e2) * eSE;
         ex = a * (f * cLv + g * sLv) / r;
         ey = a * (f * sLv - g * cLv) / r;
+
     }
 
     /** Constructor from any kind of orbital parameters.
@@ -260,16 +268,16 @@ public class EquinoctialOrbit extends Orbit {
         return lv + 2 * FastMath.atan(num / den);
     }
 
-    /** Computes the eccentric latitude argument.
+    /** Computes the true latitude argument from the eccentric latitude argument.
      * @param lE = E + &omega; + &Omega; eccentric latitude argument (rad)
      * @return the true latitude argument
      */
-    private double computeLE(final double lE) {
+    private double eccentricToTrue(final double lE) {
         final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey);
         final double cosLE   = FastMath.cos(lE);
         final double sinLE   = FastMath.sin(lE);
-        final double num = ex * sinLE - ey * cosLE;
-        final double den = epsilon + 1 - ex * cosLE - ey * sinLE;
+        final double num     = ex * sinLE - ey * cosLE;
+        final double den     = epsilon + 1 - ex * cosLE - ey * sinLE;
         return lE + 2 * FastMath.atan(num / den);
     }
 
@@ -281,11 +289,11 @@ public class EquinoctialOrbit extends Orbit {
         return lE - ex * FastMath.sin(lE) + ey * FastMath.cos(lE);
     }
 
-    /** Computes the mean latitude argument.
+    /** Computes the eccentric latitude argument from the mean latitude argument.
      * @param lM = M + &omega; + &Omega; mean latitude argument (rad)
-     * @return the true latitude argument
+     * @return the eccentric latitude argument
      */
-    private double computeLM(final double lM) {
+    private double meanToEccentric(final double lM) {
         // Generalization of Kepler equation to equinoctial parameters
         // with lE = PA + RAAN + E and
         //      lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE)
@@ -310,7 +318,7 @@ public class EquinoctialOrbit extends Orbit {
 
         } while ((++iter < 50) && (FastMath.abs(shift) > 1.0e-12));
 
-        return computeLE(lE); // which set the lv parameter
+        return lE;
 
     }
 
@@ -328,6 +336,55 @@ public class EquinoctialOrbit extends Orbit {
         return 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy));
     }
 
+    /** {@inheritDoc} */
+    protected PVCoordinates initPVCoordinates() {
+
+        // get equinoctial parameters
+        final double lE = getLE();
+
+        // inclination-related intermediate parameters
+        final double hx2   = hx * hx;
+        final double hy2   = hy * hy;
+        final double factH = 1. / (1 + hx2 + hy2);
+
+        // reference axes defining the orbital plane
+        final double ux = (1 + hx2 - hy2) * factH;
+        final double uy =  2 * hx * hy * factH;
+        final double uz = -2 * hy * factH;
+
+        final double vx = uy;
+        final double vy = (1 - hx2 + hy2) * factH;
+        final double vz =  2 * hx * factH;
+
+        // eccentricity-related intermediate parameters
+        final double exey = ex * ey;
+        final double ex2  = ex * ex;
+        final double ey2  = ey * ey;
+        final double e2   = ex2 + ey2;
+        final double eta  = 1 + FastMath.sqrt(1 - e2);
+        final double beta = 1. / eta;
+
+        // eccentric latitude argument
+        final double cLe    = FastMath.cos(lE);
+        final double sLe    = FastMath.sin(lE);
+        final double exCeyS = ex * cLe + ey * sLe;
+
+        // coordinates of position and velocity in the orbital plane
+        final double x      = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - ex);
+        final double y      = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - ey);
+
+        final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
+        final double xdot   = factor * (-sLe + beta * ey * exCeyS);
+        final double ydot   = factor * ( cLe - beta * ex * exCeyS);
+
+        final Vector3D position =
+            new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
+        final Vector3D velocity =
+            new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);
+        return new PVCoordinates(position, velocity);
+
+    }
+
     /** {@inheritDoc} */
     public EquinoctialOrbit shiftedBy(final double dt) {
         return new EquinoctialOrbit(a, ex, ey, hx, hy,
diff --git a/src/main/java/org/orekit/orbits/KeplerianOrbit.java b/src/main/java/org/orekit/orbits/KeplerianOrbit.java
index ddbecdab78..5ea68d580b 100644
--- a/src/main/java/org/orekit/orbits/KeplerianOrbit.java
+++ b/src/main/java/org/orekit/orbits/KeplerianOrbit.java
@@ -18,6 +18,7 @@ package org.orekit.orbits;
 
 import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
+import org.apache.commons.math.util.MathUtils;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
 import org.orekit.frames.Frame;
@@ -42,6 +43,10 @@ import org.orekit.utils.PVCoordinates;
  * Right Ascension of the Ascending Node and v stands for the true anomaly.
  * </p>
  * <p>
+ * This class supports hyperbolic orbits, using the convention that semi major
+ * axis is negative for such orbits (and of course eccentricity is greater than 1).
+ * </p>
+ * <p>
  * When orbit is either equatorial or circular, some keplerian elements
  * (more precisely &omega; and &Omega;) become ambiguous so this class should not
  * be used for such orbits. For this reason, {@link EquinoctialOrbit equinoctial
@@ -78,7 +83,21 @@ public class KeplerianOrbit extends Orbit {
     public static final double E_CIRC = 1.e-10;
 
     /** Serializable UID. */
-    private static final long serialVersionUID = -8628129146897296527L;
+    private static final long serialVersionUID = 2077785958734298873L;
+
+    /** First coefficient to compute Kepler equation solver starter. */
+    private static final double A;
+
+    /** Second coefficient to compute Kepler equation solver starter. */
+    private static final double B;
+
+    static {
+        final double k1 = 3 * FastMath.PI + 2;
+        final double k2 = FastMath.PI - 1;
+        final double k3 = 6 * FastMath.PI - 1;
+        A  = 3 * k2 * k2 / k1;
+        B  = k3 * k3 / (6 * k1);
+    }
 
     /** Semi-major axis (m). */
     private final double a;
@@ -99,7 +118,7 @@ public class KeplerianOrbit extends Orbit {
     private final double v;
 
     /** Creates a new instance.
-     * @param a  semi-major axis (m)
+     * @param a  semi-major axis (m), negative for hyperbolic orbits
      * @param e eccentricity
      * @param i inclination (rad)
      * @param pa perigee argument (&omega;, rad)
@@ -125,6 +144,11 @@ public class KeplerianOrbit extends Orbit {
                           final Frame frame, final AbsoluteDate date, final double mu)
         throws IllegalArgumentException {
         super(frame, date, mu);
+
+        if (a * (1 - e) < 0) {
+            throw OrekitException.createIllegalArgumentException(OrekitMessages.ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE, a, e);
+        }
+
         this.a    =    a;
         this.e    =    e;
         this.i    =    i;
@@ -133,10 +157,14 @@ public class KeplerianOrbit extends Orbit {
 
         switch (type) {
         case MEAN_ANOMALY :
-            this.v = computeMeanAnomaly(anomaly);
+            this.v = (a < 0) ?
+                     hyperbolicEccentricToTrue(meanToHyperbolicEccentric(anomaly)) :
+                     ellipticEccentricToTrue(meanToEllipticEccentric(anomaly));
             break;
         case ECCENTRIC_ANOMALY :
-            this.v = computeEccentricAnomaly(anomaly);
+            this.v = (a < 0) ?
+                     hyperbolicEccentricToTrue(anomaly) :
+                     ellipticEccentricToTrue(anomaly);
             break;
         case TRUE_ANOMALY :
             this.v = anomaly;
@@ -164,20 +192,6 @@ public class KeplerianOrbit extends Orbit {
         throws IllegalArgumentException {
         super(pvCoordinates, frame, date, mu);
 
-        // compute semi-major axis
-        final Vector3D pvP = pvCoordinates.getPosition();
-        final Vector3D pvV = pvCoordinates.getVelocity();
-        final double r = pvP.getNorm();
-        final double V2 = pvV.getNormSq();
-        final double rV2OnMu = r * V2 / mu;
-        a = r / (2 - rV2OnMu);
-
-        // compute eccentricity
-        final double muA = mu * a;
-        final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(muA);
-        final double eCE = rV2OnMu - 1;
-        e = FastMath.sqrt(eSE * eSE + eCE * eCE);
-
         // compute inclination
         final Vector3D momentum = pvCoordinates.getMomentum();
         final double m2 = Vector3D.dotProduct(momentum, momentum);
@@ -189,36 +203,50 @@ public class KeplerianOrbit extends Orbit {
         // the following comparison with 0 IS REALLY numerically justified and stable
         raan = (n2 == 0) ? 0 : FastMath.atan2(node.getY(), node.getX());
 
+        // preliminary computations for parameters depending on orbit shape (elliptic or hyperbolic)
+        final Vector3D pvP     = pvCoordinates.getPosition();
+        final Vector3D pvV     = pvCoordinates.getVelocity();
+        final double   r       = pvP.getNorm();
+        final double   V2      = pvV.getNormSq();
+        final double   rV2OnMu = r * V2 / mu;
+
+        // compute semi-major axis (will be negative for hyperbolic orbits)
+        a = r / (2 - rV2OnMu);
+
+        // compute eccentricity (will be larger than 1 for hyperbolic orbits)
+        final double muA = mu * a;
+        e = FastMath.sqrt(1 - m2 / muA);
+
         // compute true anomaly
-        if (e < E_CIRC) {
-            v = 0;
+        if (a > 0) {
+            if (e < E_CIRC) {
+                // circular orbit
+                v = 0;
+            } else {
+                // elliptic orbit
+                final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(muA);
+                final double eCE = rV2OnMu - 1;
+                v = ellipticEccentricToTrue(FastMath.atan2(eSE, eCE));
+            }
         } else {
-            final double E = FastMath.atan2(eSE, eCE);
-            final double k = 1 / (1 + FastMath.sqrt(m2 / muA));
-            v = E + 2 * FastMath.atan(k * eSE / (1 - k * eCE));
+            // hyperbolic orbit
+            final double eSH = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(-muA);
+            final double eCH = rV2OnMu - 1;
+            v = hyperbolicEccentricToTrue(FastMath.log((eCH + eSH) / (eCH - eSH)) / 2);
         }
 
         // compute perigee argument
-        final double cosRaan = FastMath.cos(raan);
-        final double sinRaan = FastMath.sin(raan);
-        final double px = cosRaan * pvP.getX() +
-                          sinRaan * pvP.getY();
-        final double py = FastMath.cos(i) * (cosRaan * pvP.getY() - sinRaan * pvP.getX()) +
-                          FastMath.sin(i) * pvP.getZ();
+        final double px = Vector3D.dotProduct(pvP, node);
+        final double py = Vector3D.dotProduct(pvP, Vector3D.crossProduct(momentum, node)) / FastMath.sqrt(m2);
         pa = FastMath.atan2(py, px) - v;
+
     }
 
     /** Constructor from any kind of orbital parameters.
      * @param op orbital parameters to copy
      */
     public KeplerianOrbit(final Orbit op) {
-        super(op.getFrame(), op.getDate(), op.getMu());
-        a    = op.getA();
-        e    = op.getE();
-        i    = op.getI();
-        raan = FastMath.atan2(op.getHy(), op.getHx());
-        pa   = FastMath.atan2(op.getEquinoctialEy(), op.getEquinoctialEx()) - raan;
-        v    = op.getLv() - (pa + raan);
+        this(op.getPVCoordinates(), op.getFrame(), op.getDate(), op.getMu());
     }
 
     /** Get the semi-major axis.
@@ -267,52 +295,165 @@ public class KeplerianOrbit extends Orbit {
      * @return eccentric anomaly (rad)
      */
     public double getEccentricAnomaly() {
+        if (a < 0) {
+            // hyperbolic case
+            final double t = FastMath.sqrt((e - 1) / (e + 1)) * FastMath.tan(v / 2);
+            return FastMath.log((1 + t) / (1 - t));
+        }
+
+        // elliptic case
         final double beta = e / (1 + FastMath.sqrt((1 - e) * (1 + e)));
         return v - 2 * FastMath.atan(beta * FastMath.sin(v) / (1 + beta * FastMath.cos(v)));
+
     }
 
-    /** Computes the eccentric anomaly.
+    /** Computes the true anomaly from the elliptic eccentric anomaly.
      * @param E eccentric anomaly (rad)
      * @return v the true anomaly
      */
-    private double computeEccentricAnomaly (final double E) {
+    private double ellipticEccentricToTrue(final double E) {
         final double beta = e / (1 + FastMath.sqrt((1 - e) * (1 + e)));
         return E + 2 * FastMath.atan(beta * FastMath.sin(E) / (1 - beta * FastMath.cos(E)));
     }
 
+    /** Computes the true anomaly from the hyperbolic eccentric anomaly.
+     * @param H hyperbolic eccentric anomaly (rad)
+     * @return v the true anomaly
+     */
+    private double hyperbolicEccentricToTrue(final double H) {
+        return 2 * FastMath.atan(FastMath.sqrt((e + 1) / (e - 1)) * FastMath.tanh(H / 2));
+    }
+
     /** Get the mean anomaly.
      * @return mean anomaly (rad)
      */
     public double getMeanAnomaly() {
+
+        if (a < 0) {
+            // hyperbolic case
+            final double H = getEccentricAnomaly();
+            return e * FastMath.sinh(H) - H;
+        }
+
+        // elliptic case
         final double E = getEccentricAnomaly();
         return E - e * FastMath.sin(E);
+
     }
 
-    /** Computes the mean anomaly.
+    /** Computes the elliptic eccentric anomaly from the mean anomaly.
+     * <p>
+     * The algorithm used here for solving Kepler equation has been published
+     * in: "Procedures for  solving Kepler's Equation", A. W. Odell and
+     * R. H. Gooding, Celestial Mechanics 38 (1986) 307-334
+     * </p>
      * @param M mean anomaly (rad)
      * @return v the true anomaly
      */
-    private double computeMeanAnomaly (final double M) {
+    private double meanToEllipticEccentric(final double M) {
+
+        // reduce M to [-PI PI) interval
+        final double reducedM = MathUtils.normalizeAngle(M, 0.0);
+
+        // compute start value according to A. W. Odell and R. H. Gooding S12 starter
+        double E;
+        if (FastMath.abs(reducedM) < 1.0 / 6.0) {
+            E = reducedM + e * (FastMath.cbrt(6 * reducedM) - reducedM);
+        } else {
+            if (reducedM < 0) {
+                final double w = FastMath.PI + reducedM;
+                E = reducedM + e * (A * w / (B - w) - FastMath.PI - reducedM);
+            } else {
+                final double w = FastMath.PI - reducedM;
+                E = reducedM + e * (FastMath.PI - A * w / (B - w) - reducedM);
+            }
+        }
+
+        final double e1 = 1 - e;
+        final boolean noCancellationRisk = (e1 + E * E / 6) >= 0.1;
+
+        // perform two iterations, each consisting of one Halley step and one Newton-Raphson step
+        for (int j = 0; j < 2; ++j) {
+            double f;
+            double fd;
+            final double fdd  = e * FastMath.sin(E);
+            final double fddd = e * FastMath.cos(E);
+            if (noCancellationRisk) {
+                f  = (E - fdd) - reducedM;
+                fd = 1 - fddd;
+            } else {
+                f  = eMeSinE(E) - reducedM;
+                final double s = FastMath.sin(0.5 * E);
+                fd = e1 + 2 * e * s * s;
+            }
+            final double dee = f * fd / (0.5 * f * fdd - fd * fd);
+
+            // update eccentric anomaly, using expressions that limit underflow problems
+            final double w = fd + 0.5 * dee * (fdd + dee * fddd / 3);
+            fd += dee * (fdd + 0.5 * dee * fddd);
+            E  -= (f - dee * (fd - w)) / fd;
+
+        }
 
-        // resolution of Kepler equation for keplerian parameters
-        double E = M;
+        // expand the result back to original range
+        E += M - reducedM;
+
+        return E;
+
+    }
+
+    /** Accurate computation of E - e sin(E).
+     * <p>
+     * This method is used when E is close to 0 and e close to 1,
+     * i.e. near the perigee of almost parabolic orbits
+     * </p>
+     * @param E eccentric anomaly
+     * @return E - e sin(E)
+     */
+    private double eMeSinE(final double E) {
+        double x = (1 - e) * FastMath.sin(E);
+        final double mE2 = -E * E;
+        double term = E;
+        double d    = 0;
+        // the inequality test below IS intentional and should NOT be replaced by a check with a small tolerance
+        for (double x0 = Double.NaN; x != x0;) {
+            d += 2;
+            term *= mE2 / (d * (d + 1));
+            x0 = x;
+            x = x - term;
+        }
+        return x;
+    }
+
+    /** Computes the hyperbolic eccentric anomaly from the mean anomaly.
+     * <p>
+     * The algorithm used here for solving hyperbolic Kepler equation is
+     * a naive initialization and classical Halley method for iterations.
+     * </p>
+     * @param M mean anomaly (rad)
+     * @return v the true anomaly
+     */
+    private double meanToHyperbolicEccentric(final double M) {
+
+        // resolution of hyperbolic Kepler equation for keplerian parameters
+        double H     = -M;
         double shift = 0.0;
-        double EmM   = 0.0;
-        int iter = 0;
+        double HpM   = 0.0;
+        int    iter  = 0;
         do {
-            final double f2 = e * FastMath.sin(E);
-            final double f1 = 1.0 - e * FastMath.cos(E);
-            final double f0 = EmM - f2;
+            final double f2 = e * FastMath.sinh(H);
+            final double f1 = e * FastMath.cosh(H) - 1;
+            final double f0 = f2 - HpM;
 
             final double f12 = 2 * f1;
             shift = f0 * f12 / (f1 * f12 - f0 * f2);
 
-            EmM -= shift;
-            E    = M + EmM;
+            HpM -= shift;
+            H    = HpM - M;
 
         } while ((++iter < 50) && (FastMath.abs(shift) > 1.0e-12));
 
-        return computeEccentricAnomaly(E);
+        return H;
 
     }
 
@@ -334,6 +475,10 @@ public class KeplerianOrbit extends Orbit {
      * @return first component of the inclination vector.
      */
     public double getHx() {
+        // Check for equatorial retrograde orbit
+        if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
+            return Double.NaN;
+        }
         return  FastMath.cos(raan) * FastMath.tan(i / 2);
     }
 
@@ -341,6 +486,10 @@ public class KeplerianOrbit extends Orbit {
      * @return second component of the inclination vector.
      */
     public double getHy() {
+        // Check for equatorial retrograde orbit
+        if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
+            return Double.NaN;
+        }
         return  FastMath.sin(raan) * FastMath.tan(i / 2);
     }
 
@@ -365,6 +514,79 @@ public class KeplerianOrbit extends Orbit {
         return pa + raan + getMeanAnomaly();
     }
 
+    /** {@inheritDoc} */
+    protected PVCoordinates initPVCoordinates() {
+
+        // preliminary variables
+        final double cosRaan = FastMath.cos(raan);
+        final double sinRaan = FastMath.sin(raan);
+        final double cosPa   = FastMath.cos(pa);
+        final double sinPa   = FastMath.sin(pa);
+        final double cosI    = FastMath.cos(i);
+        final double sinI    = FastMath.sin(i);
+
+        final double crcp    = cosRaan * cosPa;
+        final double crsp    = cosRaan * sinPa;
+        final double srcp    = sinRaan * cosPa;
+        final double srsp    = sinRaan * sinPa;
+
+        // reference axes defining the orbital plane
+        final Vector3D p = new Vector3D( crcp - cosI * srsp,  srcp + cosI * crsp, sinI * sinPa);
+        final Vector3D q = new Vector3D(-crsp - cosI * srcp, -srsp + cosI * crcp, sinI * cosPa);
+
+        return (a > 0) ? initPVCoordinatesElliptical(p, q) : initPVCoordinatesHyperbolic(p, q);
+
+    }
+
+    /** Initialize the position/velocity coordinates, elliptic case.
+     * @param p unit vector in the orbital plane pointing towards perigee
+     * @param q unit vector in the orbital plane in quadrature with q
+     * @return computed position/velocity coordinates
+     */
+    private PVCoordinates initPVCoordinatesElliptical(final Vector3D p, final Vector3D q) {
+
+        // elliptic eccentric anomaly
+        final double uME2   = (1 - e) * (1 + e);
+        final double s1Me2  = FastMath.sqrt(uME2);
+        final double E      = getEccentricAnomaly();
+        final double cosE   = FastMath.cos(E);
+        final double sinE   = FastMath.sin(E);
+
+        // coordinates of position and velocity in the orbital plane
+        final double x      = a * (cosE - e);
+        final double y      = a * sinE * s1Me2;
+        final double factor = FastMath.sqrt(getMu() / a) / (1 - e * cosE);
+        final double xDot   = -sinE * factor;
+        final double yDot   =  cosE * s1Me2 * factor;
+
+        return new PVCoordinates(new Vector3D(x, p, y, q), new Vector3D(xDot, p, yDot, q));
+
+    }
+
+    /** Initialize the position/velocity coordinates, hyperbolic case.
+     * @param p unit vector in the orbital plane pointing towards perigee
+     * @param q unit vector in the orbital plane in quadrature with q
+     * @return computed position/velocity coordinates
+     */
+    private PVCoordinates initPVCoordinatesHyperbolic(final Vector3D p, final Vector3D q) {
+
+        // hyperbolic eccentric anomaly
+        final double h      = getEccentricAnomaly();
+        final double cH     = FastMath.cosh(h);
+        final double sH     = FastMath.sinh(h);
+        final double sE2m1  = FastMath.sqrt((e - 1) * (e + 1));
+
+        // coordinates of position and velocity in the orbital plane
+        final double x      = a * (cH - e);
+        final double y      = -a * sE2m1 * sH;
+        final double factor = FastMath.sqrt(getMu() / -a) / (e * cH - 1);
+        final double xDot   = -factor * sH;
+        final double yDot   =  factor * sE2m1 * cH;
+
+        return new PVCoordinates(new Vector3D(x, p, y, q), new Vector3D(xDot, p, yDot, q));
+
+    }
+
     /** {@inheritDoc} */
     public KeplerianOrbit shiftedBy(final double dt) {
         return new KeplerianOrbit(a, e, i, pa, raan,
diff --git a/src/main/java/org/orekit/orbits/Orbit.java b/src/main/java/org/orekit/orbits/Orbit.java
index 8583335706..d20563b70a 100644
--- a/src/main/java/org/orekit/orbits/Orbit.java
+++ b/src/main/java/org/orekit/orbits/Orbit.java
@@ -18,9 +18,7 @@ package org.orekit.orbits;
 
 import java.io.Serializable;
 
-import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
-import org.apache.commons.math.util.MathUtils;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
 import org.orekit.frames.Frame;
@@ -63,7 +61,7 @@ import org.orekit.utils.PVCoordinates;
 public abstract class Orbit implements TimeStamped, Serializable {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = -5391613859481554640L;
+    private static final long serialVersionUID = 438733454597999578L;
 
     /** Frame in which are defined the orbital parameters. */
     private final Frame frame;
@@ -136,6 +134,7 @@ public abstract class Orbit implements TimeStamped, Serializable {
     }
 
     /** Get the semi-major axis.
+     * <p>Note that the semi-major axis is considered negative for hyperbolic orbits.</p>
      * @return semi-major axis (m)
      */
     public abstract double getA();
@@ -197,11 +196,11 @@ public abstract class Orbit implements TimeStamped, Serializable {
     /** Get the keplerian period.
      * <p>The keplerian period is computed directly from semi major axis
      * and central acceleration constant.</p>
-     * @return keplerian period in seconds
+     * @return keplerian period in seconds, or positive infinity for hyperbolic orbits
      */
     public double getKeplerianPeriod() {
         final double a = getA();
-        return MathUtils.TWO_PI * a * FastMath.sqrt(a / mu);
+        return (a < 0) ? Double.POSITIVE_INFINITY : 2.0 * FastMath.PI * a * FastMath.sqrt(a / mu);
     }
 
     /** Get the keplerian mean motion.
@@ -210,8 +209,8 @@ public abstract class Orbit implements TimeStamped, Serializable {
      * @return keplerian mean motion in radians per second
      */
     public double getKeplerianMeanMotion() {
-        final double a = getA();
-        return FastMath.sqrt(mu / a) / a;
+        final double absA = FastMath.abs(getA());
+        return FastMath.sqrt(mu / absA) / absA;
     }
 
     /** Get the date of orbital parameters.
@@ -221,7 +220,7 @@ public abstract class Orbit implements TimeStamped, Serializable {
         return date;
     }
 
-    /** Get the {@link PVCoordinates}.
+    /** Get the {@link PVCoordinates} in a specified frame.
      * @param outputFrame frame in which the position/velocity coordinates shall be computed
      * @return pvCoordinates in the specified output frame
      * @exception OrekitException if transformation between frames cannot be computed
@@ -230,7 +229,7 @@ public abstract class Orbit implements TimeStamped, Serializable {
     public PVCoordinates getPVCoordinates(final Frame outputFrame)
         throws OrekitException {
         if (pvCoordinates == null) {
-            initPVCoordinates();
+            pvCoordinates = initPVCoordinates();
         }
 
         // If output frame requested is the same as definition frame,
@@ -250,65 +249,15 @@ public abstract class Orbit implements TimeStamped, Serializable {
      */
     public PVCoordinates getPVCoordinates() {
         if (pvCoordinates == null) {
-            initPVCoordinates();
+            pvCoordinates = initPVCoordinates();
         }
         return pvCoordinates;
     }
 
-    /** Initialize the position/velocity coordinates.
+    /** Compute the position/velocity coordinates from the canonical parameters.
+     * @return computed position/velocity coordinates
      */
-    private void initPVCoordinates() {
-
-        // get equinoctial parameters
-        final double a  = getA();
-        final double ex = getEquinoctialEx();
-        final double ey = getEquinoctialEy();
-        final double hx = getHx();
-        final double hy = getHy();
-        final double lE = getLE();
-
-        // inclination-related intermediate parameters
-        final double hx2   = hx * hx;
-        final double hy2   = hy * hy;
-        final double factH = 1. / (1 + hx2 + hy2);
-
-        // reference axes defining the orbital plane
-        final double ux = (1 + hx2 - hy2) * factH;
-        final double uy =  2 * hx * hy * factH;
-        final double uz = -2 * hy * factH;
-
-        final double vx = uy;
-        final double vy = (1 - hx2 + hy2) * factH;
-        final double vz =  2 * hx * factH;
-
-        // eccentricity-related intermediate parameters
-        final double exey = ex * ey;
-        final double ex2  = ex * ex;
-        final double ey2  = ey * ey;
-        final double e2   = ex2 + ey2;
-        final double eta  = 1 + FastMath.sqrt(1 - e2);
-        final double beta = 1. / eta;
-
-        // eccentric latitude argument
-        final double cLe    = FastMath.cos(lE);
-        final double sLe    = FastMath.sin(lE);
-        final double exCeyS = ex * cLe + ey * sLe;
-
-        // coordinates of position and velocity in the orbital plane
-        final double x      = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - ex);
-        final double y      = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - ey);
-
-        final double factor = FastMath.sqrt(mu / a) / (1 - exCeyS);
-        final double xdot   = factor * (-sLe + beta * ey * exCeyS);
-        final double ydot   = factor * ( cLe - beta * ex * exCeyS);
-
-        final Vector3D position =
-            new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
-        final Vector3D velocity =
-            new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);
-        pvCoordinates = new PVCoordinates(position, velocity);
-
-    }
+    protected abstract PVCoordinates initPVCoordinates();
 
     /** Get a time-shifted orbit.
      * <p>
diff --git a/src/main/java/org/orekit/propagation/SpacecraftState.java b/src/main/java/org/orekit/propagation/SpacecraftState.java
index 29b1d823f8..3af432e63c 100644
--- a/src/main/java/org/orekit/propagation/SpacecraftState.java
+++ b/src/main/java/org/orekit/propagation/SpacecraftState.java
@@ -160,9 +160,9 @@ public class SpacecraftState implements TimeStamped, Serializable {
      * that these results may be different for other orbits.
      * </p>
      * <table border="1" cellpadding="5">
-     * <tr bgcolor="#ccccff"><font size="+3"><th>interpolation time (s)</th>
+     * <tr bgcolor="#ccccff"><th>interpolation time (s)</th>
      * <th>position error (m)</th><th>velocity error (m/s)</th>
-     * <th>attitude error (&deg;)</th></font></tr>
+     * <th>attitude error (&deg;)</th></tr>
      * <tr><td bgcolor="#eeeeff"> 60</td><td>  20</td><td>1</td><td>0.001</td></tr>
      * <tr><td bgcolor="#eeeeff">120</td><td> 100</td><td>2</td><td>0.002</td></tr>
      * <tr><td bgcolor="#eeeeff">300</td><td> 600</td><td>4</td><td>0.005</td></tr>
diff --git a/src/main/java/org/orekit/propagation/events/AdaptedEventDetector.java b/src/main/java/org/orekit/propagation/events/AdaptedEventDetector.java
index da28c71409..79454eaf82 100644
--- a/src/main/java/org/orekit/propagation/events/AdaptedEventDetector.java
+++ b/src/main/java/org/orekit/propagation/events/AdaptedEventDetector.java
@@ -18,11 +18,10 @@ package org.orekit.propagation.events;
 
 import org.apache.commons.math.ode.events.EventException;
 import org.apache.commons.math.ode.events.EventHandler;
-import org.orekit.attitudes.AttitudeLaw;
 import org.orekit.errors.OrekitException;
 import org.orekit.frames.Frame;
-import org.orekit.orbits.EquinoctialOrbit;
 import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.numerical.StateMapper;
 import org.orekit.time.AbsoluteDate;
 
 /** Adapt an {@link org.orekit.propagation.events.EventDetector}
@@ -35,6 +34,9 @@ public class AdaptedEventDetector implements EventHandler {
     /** Serializable UID. */
     private static final long serialVersionUID = -2156830611432730429L;
 
+    /** Mapper between spacecraft state and simple array. */
+    private StateMapper mapper;
+
     /** Underlying event detector. */
     private final EventDetector detector;
 
@@ -47,31 +49,29 @@ public class AdaptedEventDetector implements EventHandler {
     /** integrationFrame frame in which integration is performed. */
     private final Frame integrationFrame;
 
-    /** attitudeLaw spacecraft attitude law. */
-    private final AttitudeLaw attitudeLaw;
-
     /** Build a wrapped event detector.
      * @param detector event detector to wrap
+     * @param mapper mapper between spacecraft state and simple array
      * @param referenceDate reference date from which t is counted
      * @param mu central body attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
      * @param integrationFrame frame in which integration is performed
-     * @param attitudeLaw spacecraft attitude law
      */
-    public AdaptedEventDetector(final EventDetector detector,
+    public AdaptedEventDetector(final EventDetector detector, final StateMapper mapper,
                                 final AbsoluteDate referenceDate, final double mu,
-                                final Frame integrationFrame, final AttitudeLaw attitudeLaw) {
+                                final Frame integrationFrame) {
         this.detector         = detector;
+        this.mapper           = mapper;
         this.referenceDate    = referenceDate;
         this.mu               = mu;
         this.integrationFrame = integrationFrame;
-        this.attitudeLaw      = attitudeLaw;
     }
 
     /** {@inheritDoc} */
     public double g(final double t, final double[] y)
         throws EventException {
         try {
-            return detector.g(mapState(t, y));
+            final AbsoluteDate currentDate = referenceDate.shiftedBy(t);
+            return detector.g(mapper.mapArrayToState(y, currentDate, mu, integrationFrame));
         } catch (OrekitException oe) {
             throw new EventException(oe);
         }
@@ -81,7 +81,10 @@ public class AdaptedEventDetector implements EventHandler {
     public int eventOccurred(final double t, final double[] y, final boolean increasing)
         throws EventException {
         try {
-            final int whatNext = detector.eventOccurred(mapState(t, y), increasing);
+            final AbsoluteDate currentDate = referenceDate.shiftedBy(t);
+            final int whatNext = detector.eventOccurred(mapper.mapArrayToState(y, currentDate, mu,
+                                                                               integrationFrame),
+                                                        increasing);
             switch (whatNext) {
             case EventDetector.STOP :
                 return STOP;
@@ -101,7 +104,9 @@ public class AdaptedEventDetector implements EventHandler {
     public void resetState(final double t, final double[] y)
         throws EventException {
         try {
-            final SpacecraftState newState = detector.resetState(mapState(t, y));
+            final AbsoluteDate currentDate = referenceDate.shiftedBy(t);
+            final SpacecraftState newState = detector.resetState(mapper.mapArrayToState(y, currentDate, mu,
+                                                                                        integrationFrame));
             y[0] = newState.getA();
             y[1] = newState.getEquinoctialEx();
             y[2] = newState.getEquinoctialEy();
@@ -114,26 +119,4 @@ public class AdaptedEventDetector implements EventHandler {
         }
     }
 
-    /** Convert state array to space dynamics objects
-     * ({@link org.orekit.time.AbsoluteDate AbsoluteDate} and
-     * ({@link org.orekit.orbits.Orbit OrbitalParameters}).
-     * @param t integration time (s)
-     * @param y state as a flat array
-     * @return state corresponding to the flat array as a space dynamics object
-     * @exception OrekitException if attitude law cannot provide state
-     */
-    private SpacecraftState mapState(final double t, final double [] y)
-        throws OrekitException {
-
-        // update space dynamics view
-        final AbsoluteDate currentDate = referenceDate.shiftedBy(t);
-        final EquinoctialOrbit currentOrbit =
-            new EquinoctialOrbit(y[0], y[1], y[2], y[3], y[4], y[5],
-                                 EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                 integrationFrame, currentDate, mu);
-
-        return new SpacecraftState(currentOrbit, attitudeLaw.getAttitude(currentOrbit), y[6]);
-
-    }
-
 }
diff --git a/src/main/java/org/orekit/propagation/events/EventState.java b/src/main/java/org/orekit/propagation/events/EventState.java
index cd2b41a522..7bea078535 100644
--- a/src/main/java/org/orekit/propagation/events/EventState.java
+++ b/src/main/java/org/orekit/propagation/events/EventState.java
@@ -148,7 +148,9 @@ class EventState implements Serializable {
             for (int i = 0; i < n; ++i) {
 
                 // evaluate detector value at the end of the substep
-                final AbsoluteDate tb = (i == n - 1) ? t1 : start.shiftedBy((i + 1) * h);
+                // TODO this may lead to infinite loops
+                // final AbsoluteDate tb = (i == n - 1) ? t1 : start.shiftedBy((i + 1) * h);
+                final AbsoluteDate tb = start.shiftedBy((i + 1) * h);
                 interpolator.setInterpolatedDate(tb);
                 final double gb = detector.g(interpolator.getInterpolatedState());
 
@@ -195,7 +197,7 @@ class EventState implements Serializable {
                         }
                     }
 
-                    final double dtRoot = (dtA <= dtB) ? solver.solve(f, dtA, dtB) : solver.solve(f, dtB, dtA);
+                    final double dtRoot = (dtA <= dtB) ? solver.solve(1000, f, dtA, dtB) : solver.solve(1000, f, dtB, dtA);
                     final AbsoluteDate root = t0.shiftedBy(dtRoot);
 
                     if ((previousEventTime != null) &&
diff --git a/src/main/java/org/orekit/propagation/events/GroundMaskElevationDetector.java b/src/main/java/org/orekit/propagation/events/GroundMaskElevationDetector.java
index 744325ea6e..e41a5b8bec 100644
--- a/src/main/java/org/orekit/propagation/events/GroundMaskElevationDetector.java
+++ b/src/main/java/org/orekit/propagation/events/GroundMaskElevationDetector.java
@@ -38,14 +38,14 @@ import org.orekit.propagation.SpacecraftState;
  *  azimuth values, second row with elevation values, as in the following snippet:
  *  <pre>
  *    double [][] mask = {
- *                        {FastMathMath.toRadians(0),   FastMath.toRadians(10)},
- *                        {FastMathMath.toRadians(45),  FastMath.toRadians(8)},
- *                        {FastMathMath.toRadians(90),  FastMath.toRadians(6)},
- *                        {FastMathMath.toRadians(135), FastMath.toRadians(4)},
- *                        {FastMathMath.toRadians(180), FastMath.toRadians(5)},
- *                        {FastMathMath.toRadians(225), FastMath.toRadians(6)},
- *                        {FastMathMath.toRadians(270), FastMath.toRadians(8)},
- *                        {FastMathMath.toRadians(315), FastMath.toRadians(9)}
+ *                        {FastMathFastMath.toRadians(0),   FastMath.toRadians(10)},
+ *                        {FastMathFastMath.toRadians(45),  FastMath.toRadians(8)},
+ *                        {FastMathFastMath.toRadians(90),  FastMath.toRadians(6)},
+ *                        {FastMathFastMath.toRadians(135), FastMath.toRadians(4)},
+ *                        {FastMathFastMath.toRadians(180), FastMath.toRadians(5)},
+ *                        {FastMathFastMath.toRadians(225), FastMath.toRadians(6)},
+ *                        {FastMathFastMath.toRadians(270), FastMath.toRadians(8)},
+ *                        {FastMathFastMath.toRadians(315), FastMath.toRadians(9)}
  *                       };
  *  </pre>
  * </p>
diff --git a/src/main/java/org/orekit/propagation/numerical/AccelerationJacobiansProvider.java b/src/main/java/org/orekit/propagation/numerical/AccelerationJacobiansProvider.java
new file mode 100644
index 0000000000..bdcf843564
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/AccelerationJacobiansProvider.java
@@ -0,0 +1,51 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import org.orekit.errors.OrekitException;
+import org.orekit.forces.Parameterizable;
+import org.orekit.propagation.SpacecraftState;
+
+/**
+ * Interface for computing acceleration jacobians, for the sake of {@link PartialDerivativesEquations
+ * partial derivatives equations}.
+ * @author Luc Maisonobe
+ * @version $Revision$ $Date$
+ */
+public interface AccelerationJacobiansProvider extends Parameterizable {
+
+    /** Compute acceleration derivatives with respect to state parameters.
+     * @param s spacecraft state
+     * @param dAccdPos acceleration derivatives with respect to position
+     * @param dAccdVel acceleration derivatives with respect to velocity
+     * @param dAccdM acceleration derivatives with respect to mass (may be null when
+     * the caller does not need the derivatives with respect to mass)
+     * @exception OrekitException if derivatives cannot be computed
+     */
+    void addDAccDState(SpacecraftState s, double[][] dAccdPos, double[][] dAccdVel, double[] dAccdM)
+        throws OrekitException;
+
+    /** Compute acceleration derivatives with respect to additional parameters.
+     * @param s spacecraft state
+     * @param paramName name of the parameter with respect to which derivatives are required
+     * @param dAccdParam acceleration derivatives with respect to specified parameters
+     * @exception OrekitException if derivatives cannot be computed
+     */
+    void addDAccDParam(SpacecraftState s, String paramName, double[] dAccdParam)
+        throws OrekitException;
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/AdditionalEquations.java b/src/main/java/org/orekit/propagation/numerical/AdditionalEquations.java
new file mode 100644
index 0000000000..99fbfe064a
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/AdditionalEquations.java
@@ -0,0 +1,71 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.io.Serializable;
+
+import org.orekit.errors.OrekitException;
+import org.orekit.propagation.SpacecraftState;
+
+
+/** This interface allows users to add their own differential equations to a numerical propagator.
+ *
+ * <p>
+ * In some cases users may need to integrate some problem-specific equations along with
+ * classical spacecraft equations of motions. One example is optimal control in low
+ * thrust where adjoint parameters linked to the minimized hamiltonian must be integrated.
+ * Another example is formation flying or rendez-vous which use the Clohessy-Whiltshire
+ * equations for the relative motion.
+ * </p>
+ * <p>
+ * This interface allows users to add such equations to a {@link NumericalPropagator numerical
+ * propagator}. Users provide the equations as an implementation of this interface and register
+ * it to the propagator thanks to its {@link
+ * NumericalPropagator#addAdditionalEquations(AdditionalEquations)} method. Several such objects
+ * can be registered with each numerical propagator, but it is recommended to gather in the same
+ * object the sets of parameters which equations can interact on each others states.
+ * </p>
+ * <p>
+ * The additional parameters are gathered in a simple p array. The additional equations compute
+ * the pDot array, which is the time-derivative of the p array. Since the additional parameters
+ * p may also have an influence on the equations of motion themselves (for example an equation
+ * linked to a complex thrust model may induce an acceleration and a mass change), the same
+ * {@link TimeDerivativesEquations time derivatives equations adder} already shared by all force
+ * models to add their contributions is also provided to the additional equations implementation
+ * object. This means these equations can be used as an additional force model if needed. If the
+ * additional parameters have no influence at all on the spacecraft state, this adder can
+ * simply be ignored.
+ * </p>
+ * @see NumericalPropagator
+ * @author Luc Maisonobe
+ * @version $Revision$ $Date$
+ */
+public interface AdditionalEquations extends Serializable {
+
+    /** Compute the derivatives related to the additional parameters.
+     * @param s current state information: date, kinematics, attitude
+     * @param adder object where the contribution of the additional parameters
+     * p to the orbit evolution (accelerations, mass time-derivative) should be added
+     * @param p current value of the additional parameters
+     * @param pDot placeholder where the derivatives of the additional parameters
+     * should be put
+     * @exception OrekitException if some specific error occurs
+     */
+    void computeDerivatives(SpacecraftState s, TimeDerivativesEquations adder,
+                            double[] p, double[] pDot) throws OrekitException;
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/AdditionalStateAndEquations.java b/src/main/java/org/orekit/propagation/numerical/AdditionalStateAndEquations.java
new file mode 100644
index 0000000000..e9ebcf578b
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/AdditionalStateAndEquations.java
@@ -0,0 +1,82 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+
+/** This class is a container for additional state parameters and their associated evolution equation.
+*
+* <p>
+* This object is a container allowing the propagator to keep constant consistency between additional
+* states and the corresponding equations. It allows to set additional state values, get current
+* additional state value and by reference on the associated additional equations.
+* </p>
+* @see NumericalPropagator
+* @see AdditionalEquations
+* @author Luc Maisonobe
+* @version $Revision: 3409 $ $Date: 2010-06-10 15:42:04 +0200 (jeu., 10 juin 2010) $
+*/
+public class AdditionalStateAndEquations {
+
+    /** Additional equations. */
+    private AdditionalEquations addEquations;
+
+    /** Current additional state. */
+    private double[] addState;
+
+    /** Current additional state derivatives. */
+    private double[] addStateDot;
+
+    /** Create a new instance of AdditionalStateAndEquations, based on additional equations definition.
+     * @param addEqu additional equations.
+     */
+    public AdditionalStateAndEquations(final AdditionalEquations addEqu) {
+        this.addEquations = addEqu;
+    }
+
+    /** Get a reference to the current value of the additional state.
+     * <p>The array returned is a true reference to the state array, so it may be used
+     * to store data into it.</>
+     * @return a reference current value of the addditional state.
+     */
+    public double[] getAdditionalState() {
+        return addState;
+    }
+
+    /** Get a reference to the current value of the additional state derivatives.
+     * <p>The array returned is a true reference to the state array, so it may be used
+     * to store data into it.</>
+     * @return a reference current value of the addditional state derivatives.
+     */
+    public double[] getAdditionalStateDot() {
+        return addStateDot;
+    }
+
+    /** Gets the instance of additional equations.
+     * @return current value of the additional equations.
+     */
+    public AdditionalEquations getAdditionalEquations() {
+        return addEquations;
+    }
+
+    /** Sets a value to additional state.
+     * @param state additional state value.
+     */
+    public void setAdditionalState(final double[] state) {
+        this.addState = state.clone();
+        this.addStateDot = new double[state.length];
+    }
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/Jacobianizer.java b/src/main/java/org/orekit/propagation/numerical/Jacobianizer.java
new file mode 100644
index 0000000000..0706c580b6
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/Jacobianizer.java
@@ -0,0 +1,282 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.math.geometry.Vector3D;
+import org.apache.commons.math.util.FastMath;
+import org.apache.commons.math.util.MathUtils;
+import org.orekit.errors.OrekitException;
+import org.orekit.forces.ForceModel;
+import org.orekit.frames.Frame;
+import org.orekit.frames.Transform;
+import org.orekit.orbits.CartesianOrbit;
+import org.orekit.orbits.Orbit;
+import org.orekit.propagation.SpacecraftState;
+import org.orekit.utils.PVCoordinates;
+
+/** Class enabling basic {@link ForceModel} instances
+ *  to be used when processing spacecraft state partial derivatives.
+ * @author V&eacute;ronique Pommier-Maurussane
+ * @version $Revision$ $Date$
+ */
+class Jacobianizer implements AccelerationJacobiansProvider {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = -352915943197943037L;
+
+    /** Wrapped force model instance. */
+    private final ForceModel forceModel;
+
+    /** Step used for finite difference computation with respect to spacecraft position. */
+    private double hPos;
+
+    /** Step used for finite difference computation with respect to spacecraft velocity. */
+    private double hVel;
+
+    /** Step used for finite difference computation with respect to spacecraft mass. */
+    private double hMass;
+
+    /** Step used for finite difference computation with respect to parameters value. */
+    private final Map<String, Double> hParam;
+
+    /** Dedicated adder used to retrieve nominal acceleration. */
+    private final AccelerationRetriever nominal;
+
+    /** Dedicated adder used to retrieve shifted acceleration. */
+    private final AccelerationRetriever shifted;
+
+    /** Simple constructor.
+     * @param forceModel force model instance to wrap
+     * @param paramsAndSteps collection of parameters and their associated steps
+     * @param hPos step used for finite difference computation with respect to spacecraft position (m)
+     * @param hVel step used for finite difference computation with respect to spacecraft velocity (m/s)
+     * @param hMass step used for finite difference computation with respect to spacecraft mass (kg)
+     */
+    public Jacobianizer(final ForceModel forceModel, final Collection<ParameterConfiguration> paramsAndSteps,
+                        final double hPos, final double hVel, final double hMass) {
+
+        this.forceModel = forceModel;
+        this.hParam     = new HashMap<String, Double>();
+        this.hPos       = hPos;
+        this.hVel       = hVel;
+        this.hMass      = hMass;
+        this.nominal    = new AccelerationRetriever();
+        this.shifted    = new AccelerationRetriever();
+
+        // set up parameters for jacobian computation
+        for (final ParameterConfiguration param : paramsAndSteps) {
+            final String name = param.getParameterName();
+            if (forceModel.isSupported(name)) {
+                double step = param.getHP();
+                if (Double.isNaN(step)) {
+                    step = forceModel.getParameter(name) * FastMath.sqrt(MathUtils.EPSILON);
+                }
+                hParam.put(name, step);
+            }
+        }
+
+    }
+
+    /** Compute acceleration.
+     * @param retriever acceleration retriever to use for storing acceleration
+     * @param s original state
+     * @param p shifted position
+     * @param v shifted velocity
+     * @param m shifted mass
+     * @exception OrekitException if the underlying force models cannot compute the acceleration
+     */
+    private void computeShiftedAcceleration(final AccelerationRetriever retriever, final SpacecraftState s,
+                                            final Vector3D p, final Vector3D v, final double m)
+        throws OrekitException {
+        final Orbit shiftedORbit = new CartesianOrbit(new PVCoordinates(p, v), s.getFrame(), s.getDate(), s.getMu());
+        retriever.initDerivatives(null, shiftedORbit);
+        forceModel.addContribution(new SpacecraftState(shiftedORbit, s.getAttitude(), m), retriever);
+    }
+
+    /** {@inheritDoc} */
+    public void addDAccDState(final SpacecraftState s,
+                              final double[][] dAccdPos, final double[][] dAccdVel, final double[] dAccdM)
+        throws OrekitException {
+
+        // compute df/dy where f is the ODE and y is the state array
+
+        final Vector3D p0 = s.getPVCoordinates().getPosition();
+        final Vector3D v0 = s.getPVCoordinates().getVelocity();
+        final double m0 = s.getMass();
+        computeShiftedAcceleration(nominal, s, p0, v0, m0);
+
+        // jacobian with respect to position
+        computeShiftedAcceleration(shifted, s, new Vector3D(p0.getX() + hPos, p0.getY(), p0.getZ()), v0, m0);
+        dAccdPos[0][0] += (shifted.getX() - nominal.getX()) / hPos;
+        dAccdPos[1][0] += (shifted.getY() - nominal.getY()) / hPos;
+        dAccdPos[2][0] += (shifted.getZ() - nominal.getZ()) / hPos;
+
+        computeShiftedAcceleration(shifted, s, new Vector3D(p0.getX(), p0.getY() + hPos, p0.getZ()), v0, m0);
+        dAccdPos[0][1] += (shifted.getX() - nominal.getX()) / hPos;
+        dAccdPos[1][1] += (shifted.getY() - nominal.getY()) / hPos;
+        dAccdPos[2][1] += (shifted.getZ() - nominal.getZ()) / hPos;
+
+        computeShiftedAcceleration(shifted, s, new Vector3D(p0.getX(), p0.getY(), p0.getZ() + hPos), v0, m0);
+        dAccdPos[0][2] += (shifted.getX() - nominal.getX()) / hPos;
+        dAccdPos[1][2] += (shifted.getY() - nominal.getY()) / hPos;
+        dAccdPos[2][2] += (shifted.getZ() - nominal.getZ()) / hPos;
+
+        // jacobian with respect to velocity
+        computeShiftedAcceleration(shifted, s, p0, new Vector3D(v0.getX() + hVel, v0.getY(), v0.getZ()), m0);
+        dAccdVel[0][0] += (shifted.getX() - nominal.getX()) / hPos;
+        dAccdVel[1][0] += (shifted.getY() - nominal.getY()) / hPos;
+        dAccdVel[2][0] += (shifted.getZ() - nominal.getZ()) / hPos;
+
+        computeShiftedAcceleration(shifted, s, p0, new Vector3D(v0.getX(), v0.getY() + hVel, v0.getZ()), m0);
+        dAccdVel[0][1] += (shifted.getX() - nominal.getX()) / hPos;
+        dAccdVel[1][1] += (shifted.getY() - nominal.getY()) / hPos;
+        dAccdVel[2][1] += (shifted.getZ() - nominal.getZ()) / hPos;
+
+        computeShiftedAcceleration(shifted, s, p0, new Vector3D(v0.getX(), v0.getY(), v0.getZ() + hVel), m0);
+        dAccdVel[0][2] += (shifted.getX() - nominal.getX()) / hPos;
+        dAccdVel[1][2] += (shifted.getY() - nominal.getY()) / hPos;
+        dAccdVel[2][2] += (shifted.getZ() - nominal.getZ()) / hPos;
+
+        if (dAccdM != null) {
+            // jacobian with respect to mass
+            computeShiftedAcceleration(shifted, s, p0, v0, m0 + hMass);
+            dAccdM[0] += (shifted.getX() - nominal.getX()) / hMass;
+            dAccdM[1] += (shifted.getY() - nominal.getY()) / hMass;
+            dAccdM[2] += (shifted.getZ() - nominal.getZ()) / hMass;
+        }
+
+
+    }
+
+    /** {@inheritDoc} */
+    public void addDAccDParam(final SpacecraftState s, final String paramName,
+                              final double[] dAccdParam) throws OrekitException {
+        final double hP = hParam.get(paramName);
+        nominal.initDerivatives(null, s.getOrbit());
+        forceModel.addContribution(s, nominal);
+
+        final double paramValue = forceModel.getParameter(paramName);
+        forceModel.setParameter(paramName,  paramValue + hP);
+        shifted.initDerivatives(null, s.getOrbit());
+        forceModel.addContribution(s, shifted);
+        forceModel.setParameter(paramName,  paramValue);
+
+        dAccdParam[0] += (shifted.getX() - nominal.getX()) / hP;
+        dAccdParam[1] += (shifted.getY() - nominal.getY()) / hP;
+        dAccdParam[2] += (shifted.getZ() - nominal.getZ()) / hP;
+    }
+
+    /** {@inheritDoc} */
+    public double getParameter(final String name) throws IllegalArgumentException {
+        return forceModel.getParameter(name);
+    }
+
+    /** {@inheritDoc} */
+    public Collection<String> getParametersNames() {
+        return forceModel.getParametersNames();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSupported(final String name) {
+        return forceModel.isSupported(name);
+    }
+
+    /** {@inheritDoc} */
+    public void setParameter(final String name, final double value) throws IllegalArgumentException {
+        forceModel.setParameter(name, value);
+    }
+
+    /** Internal class for retrieving accelerations. */
+    private static class AccelerationRetriever extends TimeDerivativesEquations {
+
+        /** Serializable UID. */
+        private static final long serialVersionUID = -2794923839784176080L;
+
+        /** Stored acceleration. */
+        private final double[] acceleration;
+
+        /** Current orbit. */
+        private Orbit orbit;
+
+        /** Simple constructor.
+         */
+        protected AccelerationRetriever() {
+            acceleration = new double[3];
+            this.orbit   = null;
+        }
+
+        /** Get X component of acceleration.
+         * @return X component of acceleration
+         */
+        public double getX() {
+            return acceleration[0];
+        }
+
+        /** Get Y component of acceleration.
+         * @return Y component of acceleration
+         */
+        public double getY() {
+            return acceleration[1];
+        }
+
+        /** Get Z component of acceleration.
+         * @return Z component of acceleration
+         */
+        public double getZ() {
+            return acceleration[2];
+        }
+
+        /** {@inheritDoc} */
+        void initDerivatives(final double[] yDot, final Orbit currentOrbit) {
+            acceleration[0] = 0;
+            acceleration[1] = 0;
+            acceleration[2] = 0;
+            this.orbit = currentOrbit;
+        }
+
+        /** {@inheritDoc} */
+        public void addKeplerContribution(final double mu) {
+            final Vector3D position = orbit.getPVCoordinates().getPosition();
+            final double r2         = position.getNormSq();
+            final double coeff      = -mu / (r2 * FastMath.sqrt(r2));
+            acceleration[0] += coeff * position.getX();
+            acceleration[1] += coeff * position.getY();
+            acceleration[2] += coeff * position.getZ();
+        }
+
+        /** {@inheritDoc} */
+        public void addXYZAcceleration(final double x, final double y, final double z) {
+            acceleration[0] += x;
+            acceleration[1] += y;
+            acceleration[2] += z;
+        }
+
+        /** {@inheritDoc} */
+        public void addAcceleration(final Vector3D gamma, final Frame frame)
+            throws OrekitException {
+            final Transform t = frame.getTransformTo(orbit.getFrame(), orbit.getDate());
+            final Vector3D gammInRefFrame = t.transformVector(gamma);
+            addXYZAcceleration(gammInRefFrame.getX(), gammInRefFrame.getY(), gammInRefFrame.getZ());
+        }
+
+    }
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/ModeHandler.java b/src/main/java/org/orekit/propagation/numerical/ModeHandler.java
index 9b055437bc..9b2e8f8844 100644
--- a/src/main/java/org/orekit/propagation/numerical/ModeHandler.java
+++ b/src/main/java/org/orekit/propagation/numerical/ModeHandler.java
@@ -1,4 +1,4 @@
-/* Copyright 2002-2010 CS Communication & Systèmes
+/* Copyright 2010 Centre National d'Études Spatiales
  * Licensed to CS Communication & Systèmes (CS) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,7 +16,8 @@
  */
 package org.orekit.propagation.numerical;
 
-import org.orekit.attitudes.AttitudeLaw;
+import java.util.List;
+
 import org.orekit.frames.Frame;
 import org.orekit.time.AbsoluteDate;
 
@@ -27,11 +28,13 @@ import org.orekit.time.AbsoluteDate;
 public interface ModeHandler {
 
     /** Initialize the mode handler.
+     * @param  mapper mapper between spacecraft state and simple array
+     * @param addStateAndEqu list of additional state and equations
      * @param reference reference date
      * @param frame reference frame
      * @param mu central body attraction coefficient
-     * @param attitudeLaw attitude law
      */
-    void initialize(AbsoluteDate reference, Frame frame, double mu, AttitudeLaw attitudeLaw);
+    void initialize(StateMapper mapper, List <AdditionalStateAndEquations> addStateAndEqu,
+                    AbsoluteDate reference, Frame frame, double mu);
 
 }
diff --git a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java
index 687185fcee..ac2d5e6851 100644
--- a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java
+++ b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java
@@ -16,7 +16,9 @@
  */
 package org.orekit.propagation.numerical;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -26,16 +28,18 @@ import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
 import org.apache.commons.math.ode.FirstOrderIntegrator;
 import org.apache.commons.math.ode.IntegratorException;
 import org.apache.commons.math.ode.events.EventHandler;
-import org.apache.commons.math.ode.sampling.DummyStepHandler;
-import org.orekit.attitudes.Attitude;
+import org.apache.commons.math.ode.nonstiff.AdaptiveStepsizeIntegrator;
 import org.orekit.attitudes.AttitudeLaw;
 import org.orekit.attitudes.InertialLaw;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
 import org.orekit.errors.PropagationException;
 import org.orekit.forces.ForceModel;
+import org.orekit.forces.gravity.NewtonianAttraction;
 import org.orekit.frames.Frame;
+import org.orekit.orbits.CartesianOrbit;
 import org.orekit.orbits.EquinoctialOrbit;
+import org.orekit.orbits.Orbit;
 import org.orekit.propagation.BoundedPropagator;
 import org.orekit.propagation.Propagator;
 import org.orekit.propagation.SpacecraftState;
@@ -125,49 +129,75 @@ import org.orekit.utils.PVCoordinates;
  */
 public class NumericalPropagator implements Propagator {
 
+    /** Parameters types that can be used for propagation. */
+    public enum PropagationParametersType {
+
+        /** Type for propagation in cartesian parameters. */
+        CARTESIAN,
+
+        /** Type for propagation in equinoctial parameters. */
+        EQUINOCTIAL
+
+    }
+
     /** Serializable UID. */
     private static final long serialVersionUID = -2385169798425713766L;
 
+    /** Absolute vectorial error field name. */
+    private static final String ABSOLUTE_TOLERANCE = "vecAbsoluteTolerance";
+
+    /** Relative vectorial error field name. */
+    private static final String RELATIVE_TOLERANCE = "vecRelativeTolerance";
+
     // CHECKSTYLE: stop VisibilityModifierCheck
 
     /** Attitude law. */
-    protected AttitudeLaw attitudeLaw;
+    private AttitudeLaw attitudeLaw;
 
-    /** Central body gravitational constant. */
-    protected double mu;
+    /** Central body attraction. */
+    private NewtonianAttraction newtonianAttraction;
 
-    /** Force models used during the extrapolation of the Orbit. */
-    protected final List<ForceModel> forceModels;
+    /** Force models used during the extrapolation of the Orbit, without jacobians. */
+    private final List<ForceModel> forceModels;
 
     /** Event detectors not related to force models. */
-    protected final List<EventDetector> detectors;
+    private final List<EventDetector> detectors;
 
     /** State vector. */
-    protected final double[] stateVector;
+    private double[] stateVector;
 
     /** Start date. */
-    protected AbsoluteDate startDate;
+    private AbsoluteDate startDate;
 
     /** Initial state to propagate. */
-    protected SpacecraftState initialState;
+    private SpacecraftState initialState;
 
     /** Current state to propagate. */
-    protected SpacecraftState currentState;
+    private SpacecraftState currentState;
 
     /** Integrator selected by the user for the orbital extrapolation process. */
-    protected transient FirstOrderIntegrator integrator;
+    private transient FirstOrderIntegrator integrator;
 
     /** Counter for differential equations calls. */
-    protected int calls;
+    private int calls;
 
     /** Gauss equations handler. */
-    protected TimeDerivativesEquations adder;
+    private TimeDerivativesEquations adder;
+
+    /** Mapper between spacecraft state and simple array. */
+    private StateMapper mapper;
 
     /** Propagator mode handler. */
-    protected ModeHandler modeHandler;
+    private ModeHandler modeHandler;
 
     /** Current mode. */
-    protected int mode;
+    private int mode;
+
+    /** Propagation parameters type. */
+    private PropagationParametersType type;
+
+    /** Additional equations. */
+    private List<AdditionalStateAndEquations> addStateAndEqu;
 
     // CHECKSTYLE: resume VisibilityModifierCheck
 
@@ -176,20 +206,21 @@ public class NumericalPropagator implements Propagator {
      * unspecified default law and there are no perturbing forces at all.
      * This means that if {@link #addForceModel addForceModel} is not
      * called after creation, the integrated orbit will follow a keplerian
-     * evolution only.
+     * evolution only. The default parameter type for propagation is {@link
+     * PropagationParametersType#EQUINOCTIAL}.
      * @param integrator numerical integrator to use for propagation.
      */
     public NumericalPropagator(final FirstOrderIntegrator integrator) {
-        this.mu           = Double.NaN;
-        this.forceModels  = new ArrayList<ForceModel>();
-        this.detectors    = new ArrayList<EventDetector>();
-        this.startDate    = new AbsoluteDate();
-        this.currentState = null;
-        this.adder        = null;
-        this.attitudeLaw  = InertialLaw.EME2000_ALIGNED;
-        this.stateVector  = new double[7];
+        this.forceModels    = new ArrayList<ForceModel>();
+        this.detectors      = new ArrayList<EventDetector>();
+        this.startDate      = new AbsoluteDate();
+        this.currentState   = null;
+        this.adder          = null;
+        this.addStateAndEqu = new ArrayList<AdditionalStateAndEquations>();
+        this.attitudeLaw    = InertialLaw.EME2000_ALIGNED;
         setIntegrator(integrator);
         setSlaveMode();
+        setPropagationParametersType(PropagationParametersType.EQUINOCTIAL);
     }
 
     /** Set the integrator.
@@ -200,20 +231,20 @@ public class NumericalPropagator implements Propagator {
     }
 
     /** Set the central attraction coefficient &mu;.
-     * @param mu central attraction coefficient (m^3/s^2)
+     * @param mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
      * @see #getMu()
      * @see #addForceModel(ForceModel)
      */
     public void setMu(final double mu) {
-        this.mu = mu;
+        newtonianAttraction = new NewtonianAttraction(mu);
     }
 
     /** Get the central attraction coefficient &mu;.
-     * @return mu central attraction coefficient (m^3/s^2)
+     * @return mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
      * @see #setMu(double)
      */
     public double getMu() {
-        return mu;
+        return (newtonianAttraction == null) ? Double.NaN : newtonianAttraction.getMu();
     }
 
     /** Set the attitude law.
@@ -239,10 +270,6 @@ public class NumericalPropagator implements Propagator {
     }
 
     /** Add a force model to the global perturbation model.
-     * <p>If the force models is associated to discrete events, these
-     * events will be handled automatically, they must <strong>not</strong>
-     * be added using the {@link #addEventDetector(EventDetector) addEventDetector}
-     * method.</p>
      * <p>If this method is not called at all, the integrated orbit will follow
      * a keplerian evolution only.</p>
      * @param model perturbing {@link ForceModel} to add
@@ -263,6 +290,24 @@ public class NumericalPropagator implements Propagator {
         forceModels.clear();
     }
 
+    /** Get perturbing force models list.
+     * @return list of perturbing force models
+     * @see #addForceModel(ForceModel)
+     * @see #getNewtonianAttractionForceModel()
+     */
+    public List<ForceModel> getForceModels() {
+        return forceModels;
+    }
+
+    /** Get the Newtonian attraction from the central body force model.
+     * @return Newtonian attraction force model
+     * @see #setMu(double)
+     * @see #getForceModels()
+     */
+    public NewtonianAttraction getNewtonianAttractionForceModel() {
+        return newtonianAttraction;
+    }
+
     /** {@inheritDoc} */
     public int getMode() {
         return mode;
@@ -277,7 +322,6 @@ public class NumericalPropagator implements Propagator {
      */
     public void setSlaveMode() {
         integrator.clearStepHandlers();
-        integrator.addStepHandler(DummyStepHandler.getInstance());
         modeHandler = null;
         mode = SLAVE_MODE;
     }
@@ -287,7 +331,7 @@ public class NumericalPropagator implements Propagator {
      * of the underlying integrator set up in the {@link
      * #NumericalPropagator(FirstOrderIntegrator) constructor} or the {@link
      * #setIntegrator(FirstOrderIntegrator) setIntegrator} method. So if a specific
-     * step handler is needed, it should be added after this method has been callled.</p>
+     * step handler is needed, it should be added after this method has been called.</p>
      */
     public void setMasterMode(final double h, final OrekitFixedStepHandler handler) {
         setMasterMode(new OrekitStepNormalizer(h, handler));
@@ -318,11 +362,25 @@ public class NumericalPropagator implements Propagator {
     public void setEphemerisMode() {
         integrator.clearStepHandlers();
         final IntegratedEphemeris ephemeris = new IntegratedEphemeris();
-        integrator.addStepHandler(ephemeris);
         modeHandler = ephemeris;
+        integrator.addStepHandler(ephemeris);
         mode = EPHEMERIS_GENERATION_MODE;
     }
 
+    /** Set propagation parameter type.
+     * @param propagationType parameters type to use for propagation
+     */
+    public void setPropagationParametersType(final PropagationParametersType propagationType) {
+        this.type = propagationType;
+    }
+
+    /** Get propagation parameter type.
+     * @return parameters type used for propagation
+     */
+    public PropagationParametersType getPropagationParametersType() {
+        return type;
+    }
+
     /** {@inheritDoc} */
     public BoundedPropagator getGeneratedEphemeris()
         throws IllegalStateException {
@@ -347,12 +405,59 @@ public class NumericalPropagator implements Propagator {
 
     /** {@inheritDoc} */
     public void resetInitialState(final SpacecraftState state) {
-        if (Double.isNaN(mu)) {
-            mu = state.getMu();
+        if (newtonianAttraction == null) {
+            setMu(state.getMu());
         }
         this.initialState = state;
     }
 
+    /** Select additional state and equations pair in the list.
+     * @param  addEqu Additional equations used as a reference for selection
+     * @return additional state and equations pair
+     * @throws OrekitException if additional equation is unknown */
+    private AdditionalStateAndEquations selectStateAndEquations(final AdditionalEquations addEqu)
+        throws OrekitException {
+        for (AdditionalStateAndEquations stateAndEqu : addStateAndEqu) {
+            if (stateAndEqu.getAdditionalEquations() == addEqu) {
+                return stateAndEqu;
+            }
+        }
+        throw new OrekitException(OrekitMessages.UNKNOWN_ADDITIONAL_EQUATION);
+    }
+
+    /** Add a set of user-specified equations to be integrated along with the orbit propagation.
+     * @param addEqu additional equations
+     * @see #setInitialAdditionalState(double[], AdditionalEquations)
+     * @see #getCurrentAdditionalState(AdditionalEquations)
+     */
+    public void addAdditionalEquations(final AdditionalEquations addEqu) {
+        addStateAndEqu.add(new AdditionalStateAndEquations(addEqu));
+    }
+
+    /** Set initial additional state.
+     * @param addState additional state
+     * @param addEqu additional equations used as a reference for selection
+     * @throws OrekitException if additional equation is unknown
+     * @see #addAdditionalEquations(AdditionalEquations)
+     * @see #getCurrentAdditionalState(AdditionalEquations)
+     */
+    public void setInitialAdditionalState(final double[] addState, final AdditionalEquations addEqu)
+        throws OrekitException {
+        selectStateAndEquations(addEqu).setAdditionalState(addState);
+    }
+
+    /** Get current additional state.
+     * @param addEqu additional equations used as a reference for selection
+     * @return current additional state
+     * @throws OrekitException if additional equation is unknown
+     * @see #addAdditionalEquations(AdditionalEquations)
+     * @see #setInitialAdditionalState(double[], AdditionalEquations)
+     */
+    public double[] getCurrentAdditionalState(final AdditionalEquations addEqu)
+        throws OrekitException  {
+        return selectStateAndEquations(addEqu).getAdditionalState();
+    }
+
     /** {@inheritDoc} */
     public SpacecraftState propagate(final AbsoluteDate finalDate)
         throws PropagationException {
@@ -371,18 +476,36 @@ public class NumericalPropagator implements Propagator {
 
             // space dynamics view
             startDate  = initialState.getDate();
+
+            // set propagation parameters type
+            Orbit initialOrbit = null;
+            switch (type) {
+            case CARTESIAN :
+                initialOrbit = new CartesianOrbit(initialState.getOrbit());
+                adder = new TimeDerivativesEquationsCartesian((CartesianOrbit) initialOrbit);
+                mapper = new StateMapperCartesian();
+                break;
+            case EQUINOCTIAL :
+                initialOrbit = new EquinoctialOrbit(initialState.getOrbit());
+                adder = new TimeDerivativesEquationsEquinoctial((EquinoctialOrbit) initialOrbit);
+                mapper = new StateMapperEquinoctial();
+                break;
+            default :
+                throw OrekitException.createInternalError(null);
+            }
+            mapper.setAttitudeLaw(attitudeLaw);
+
+            // initialize mode handler
             if (modeHandler != null) {
-                modeHandler.initialize(startDate, initialState.getFrame(), mu, attitudeLaw);
+                modeHandler.initialize(mapper, addStateAndEqu, startDate, initialState.getFrame(), getMu());
             }
 
-            final EquinoctialOrbit initialOrbit =
-                new EquinoctialOrbit(initialState.getOrbit());
+            // creating state vector
+            this.stateVector  = new double[computeDimension()];
 
             currentState =
                 new SpacecraftState(initialOrbit, initialState.getAttitude(), initialState.getMass());
 
-            adder = new TimeDerivativesEquations(initialOrbit);
-
             if (initialState.getMass() <= 0.0) {
                 throw new IllegalArgumentException("Mass is null or negative");
             }
@@ -392,13 +515,14 @@ public class NumericalPropagator implements Propagator {
             final double t1 = finalDate.durationFrom(startDate);
 
             // Map state to array
-            stateVector[0] = initialOrbit.getA();
-            stateVector[1] = initialOrbit.getEquinoctialEx();
-            stateVector[2] = initialOrbit.getEquinoctialEy();
-            stateVector[3] = initialOrbit.getHx();
-            stateVector[4] = initialOrbit.getHy();
-            stateVector[5] = initialOrbit.getLv();
-            stateVector[6] = initialState.getMass();
+            mapper.mapStateToArray(initialState, stateVector);
+            int index = 7;
+            for (final AdditionalStateAndEquations stateAndEqu : addStateAndEqu) {
+                final double[] addState = stateAndEqu.getAdditionalState();
+                System.arraycopy(addState, 0, stateVector, index, addState.length);
+                // Incrementing index
+                index += addState.length;
+            }
 
             integrator.clearEventHandlers();
 
@@ -418,17 +542,28 @@ public class NumericalPropagator implements Propagator {
             }
 
             // mathematical integration
+            if (!addStateAndEqu.isEmpty()) {
+                expandToleranceArray();
+            }
             final double stopTime = integrator.integrate(new DifferentialEquations(), t0, stateVector, t1, stateVector);
+            if (!addStateAndEqu.isEmpty()) {
+                resetToleranceArray();
+            }
 
             // back to space dynamics view
             final AbsoluteDate date = startDate.shiftedBy(stopTime);
 
-            final EquinoctialOrbit orbit =
-                new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2], stateVector[3],
-                                     stateVector[4], stateVector[5], EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                     initialOrbit.getFrame(), date, mu);
+            // get final additional state
+            index = 7;
+            for (final AdditionalStateAndEquations stateAndEqu : addStateAndEqu) {
+                final double[] addState = stateAndEqu.getAdditionalState();
+                System.arraycopy(stateVector, index, addState, 0, addState.length);
+                // Incrementing index
+                index += addState.length;
+            }
 
-            resetInitialState(new SpacecraftState(orbit, attitudeLaw.getAttitude(orbit), stateVector[6]));
+            // get final state
+            initialState = mapper.mapArrayToState(stateVector, date, getMu(), initialState.getFrame());
             return initialState;
 
         } catch (OrekitException oe) {
@@ -458,6 +593,56 @@ public class NumericalPropagator implements Propagator {
         }
     }
 
+    /** Expand integrator tolerance array to fit compound state vector.
+     */
+    private void expandToleranceArray() {
+        if (integrator instanceof AdaptiveStepsizeIntegrator) {
+            final int n = computeDimension();
+            resizeArray(integrator, ABSOLUTE_TOLERANCE, n, Double.POSITIVE_INFINITY);
+            resizeArray(integrator, RELATIVE_TOLERANCE, n, 0.0);
+        }
+    }
+
+    /** Reset integrator tolerance array to original size.
+     */
+    private void resetToleranceArray() {
+        if (integrator instanceof AdaptiveStepsizeIntegrator) {
+            final int n = stateVector.length;
+            resizeArray(integrator, ABSOLUTE_TOLERANCE, n, Double.POSITIVE_INFINITY);
+            resizeArray(integrator, RELATIVE_TOLERANCE, n, 0.0);
+        }
+    }
+
+    /** Resize object internal array.
+     * @param instance instance concerned
+     * @param fieldName field name
+     * @param newSize new array size
+     * @param filler value to use to fill uninitialized elements of the new array
+     */
+    private void resizeArray(final Object instance, final String fieldName,
+                             final int newSize, final double filler) {
+        try {
+            final Field arrayField = AdaptiveStepsizeIntegrator.class.getDeclaredField(fieldName);
+            arrayField.setAccessible(true);
+            final double[] originalArray = (double[]) arrayField.get(instance);
+            final int originalSize = originalArray.length;
+            final double[] resizedArray = new double[newSize];
+            if (newSize > originalSize) {
+                // expand array
+                System.arraycopy(originalArray, 0, resizedArray, 0, originalSize);
+                Arrays.fill(resizedArray, originalSize, newSize, filler);
+            } else {
+                // shrink array
+                System.arraycopy(originalArray, 0, resizedArray, 0, newSize);
+            }
+            arrayField.set(instance, resizedArray);
+        } catch (NoSuchFieldException nsfe) {
+            throw OrekitException.createInternalError(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw OrekitException.createInternalError(iae);
+        }
+    }
+
     /** {@inheritDoc} */
     public PVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame)
         throws OrekitException {
@@ -478,14 +663,32 @@ public class NumericalPropagator implements Propagator {
      */
     protected void setUpEventDetector(final EventDetector osf) {
         final EventHandler handler =
-            new AdaptedEventDetector(osf, startDate, mu,
-                                     initialState.getFrame(), attitudeLaw);
+            new AdaptedEventDetector(osf, mapper, startDate, getMu(), initialState.getFrame());
         integrator.addEventHandler(handler,
                                    osf.getMaxCheckInterval(),
                                    osf.getThreshold(),
                                    osf.getMaxIterationCount());
     }
 
+    /** Get state vector dimension without additional parameters.
+     * @return state vector dimension without additional parameters.
+     */
+    public int getBasicDimension() {
+        return 7;
+
+    }
+    /** Compute complete state vector dimension.
+     * @return state vector dimension
+     */
+    private int computeDimension() {
+        int sum = getBasicDimension();
+        for (final AdditionalStateAndEquations stateAndEqu : addStateAndEqu) {
+            sum += stateAndEqu.getAdditionalState().length;
+        }
+        return sum;
+
+    }
+
     /** Internal class for differential equations representation. */
     private class DifferentialEquations implements FirstOrderDifferentialEquations {
 
@@ -499,7 +702,7 @@ public class NumericalPropagator implements Propagator {
 
         /** {@inheritDoc} */
         public int getDimension() {
-            return 7;
+            return computeDimension();
         }
 
         /** {@inheritDoc} */
@@ -508,14 +711,15 @@ public class NumericalPropagator implements Propagator {
 
             try {
                 // update space dynamics view
-                currentState = mapState(t, y, startDate, currentState.getFrame());
+                currentState = mapper.mapArrayToState(y, startDate.shiftedBy(t), currentState.getMu(), currentState.getFrame());
+
 
                 if (currentState.getMass() <= 0.0) {
                     throw new PropagationException(OrekitMessages.SPACECRAFT_MASS_BECOMES_NEGATIVE,
                                                    currentState.getMass());
                 }
                 // initialize derivatives
-                adder.initDerivatives(yDot, (EquinoctialOrbit) currentState.getOrbit());
+                adder.initDerivatives(yDot, currentState.getOrbit());
 
                 // compute the contributions of all perturbing forces
                 for (final ForceModel forceModel : forceModels) {
@@ -523,7 +727,26 @@ public class NumericalPropagator implements Propagator {
                 }
 
                 // finalize derivatives by adding the Kepler contribution
-                adder.addKeplerContribution();
+                newtonianAttraction.addContribution(currentState, adder);
+
+                // Add contribution for additional state
+                int index = 7;
+                for (final AdditionalStateAndEquations stateAndEqu : addStateAndEqu) {
+                    final double[] p    = stateAndEqu.getAdditionalState();
+                    final double[] pDot = stateAndEqu.getAdditionalStateDot();
+
+                    // update current additional state
+                    System.arraycopy(y, index, p, 0, p.length);
+
+                    // compute additional derivatives
+                    stateAndEqu.getAdditionalEquations().computeDerivatives(currentState, adder, p, pDot);
+
+                    // update each additional state contribution in global array
+                    System.arraycopy(pDot, 0, yDot, index, p.length);
+
+                    // incrementing index
+                    index += p.length;
+                }
 
                 // increment calls counter
                 ++calls;
@@ -534,31 +757,8 @@ public class NumericalPropagator implements Propagator {
 
         }
 
-        /** Convert state array to space dynamics objects (AbsoluteDate and OrbitalParameters).
-         * @param t integration time (s)
-         * @param y state as a flat array
-         * @param referenceDate reference date from which t is counted
-         * @param frame frame in which integration is performed
-         * @return state corresponding to the flat array as a space dynamics object
-         * @exception OrekitException if the attitude state cannot be determined
-         * by the attitude law
-         */
-        private SpacecraftState mapState(final double t, final double [] y,
-                                         final AbsoluteDate referenceDate, final Frame frame)
-            throws OrekitException {
-
-            // convert raw mathematical data to space dynamics objects
-            final AbsoluteDate date = referenceDate.shiftedBy(t);
-            final EquinoctialOrbit orbit =
-                new EquinoctialOrbit(y[0], y[1], y[2], y[3], y[4], y[5],
-                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                     frame, date, mu);
-            final Attitude attitude = attitudeLaw.getAttitude(orbit);
-
-            return new SpacecraftState(orbit, attitude, y[6]);
-
-        }
-
     }
 
 }
+
+
diff --git a/src/main/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobians.java b/src/main/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobians.java
deleted file mode 100644
index e77f34d784..0000000000
--- a/src/main/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobians.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/* Copyright 2002-2010 CS Communication & Systèmes
- * Licensed to CS Communication & Systèmes (CS) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS 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.orekit.propagation.numerical;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.math.exception.MathUserException;
-import org.apache.commons.math.ode.FirstOrderIntegrator;
-import org.apache.commons.math.ode.IntegratorException;
-import org.apache.commons.math.ode.jacobians.FirstOrderIntegratorWithJacobians;
-import org.apache.commons.math.ode.jacobians.ODEWithJacobians;
-import org.apache.commons.math.ode.jacobians.ParameterizedODE;
-import org.apache.commons.math.ode.nonstiff.AdaptiveStepsizeIntegrator;
-import org.apache.commons.math.util.FastMath;
-import org.apache.commons.math.util.MathUtils;
-import org.orekit.attitudes.Attitude;
-import org.orekit.errors.OrekitException;
-import org.orekit.errors.OrekitMessages;
-import org.orekit.errors.PropagationException;
-import org.orekit.forces.ForceModel;
-import org.orekit.forces.ForceModelWithJacobians;
-import org.orekit.forces.Parameterizable;
-import org.orekit.frames.Frame;
-import org.orekit.orbits.EquinoctialOrbit;
-import org.orekit.propagation.SpacecraftState;
-import org.orekit.propagation.events.EventDetector;
-import org.orekit.time.AbsoluteDate;
-
-
-/** This class propagates {@link org.orekit.orbits.Orbit orbits} using
- *  numerical integration and enables jacobians computation for orbit parameters
- *  and partial derivatives computation with respect to some force models parameters.
- * <p>
- * As of 5.0, this class is still considered experimental, so use it with care,
- * the API could change in the future.
- * </p>
- * <p>
- * The underlying numerical integrator configuration can be exactly the same
- * as these for a simple {@link NumericalPropagator numerical integration}.
- * </p>
- * <p>
- * The Jacobian for the six {@link EquinoctialOrbit equinoctial orbit parameters}
- * (a, e<sub>x</sub>, e<sub>y</sub>, h<sub>x</sub>, h<sub>y</sub>, l<sub>v</sub>)
- * and the mass is computed as a 7x7 array such as:
- *   <pre>
- *     dFdY[i][j] = dyi/dyj
- *     with: y0 = a, y1 = ex, y2 = ey, y3 = hx, y4 = hy, y5 = lv, y6 = mass
- *   </pre>
- * </p>
- * <p>
- * Partial derivatives can also be computed for the 7 elements state vector with
- * respect to n {@link #selectParameters selected parameters} from
- * {@link ForceModelWithJacobians force models}. They are computed as a 7xn array:
- *   <pre>
- *     dFdP[i][j] = dyi/dpj
- *   </pre>
- * </p>
- *
- * @see NumericalPropagator
- * @see ForceModelWithJacobians
- *
- * @author Pascal Parraud
- * @version $Revision$ $Date$
- */
-public class NumericalPropagatorWithJacobians extends NumericalPropagator {
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = 4139595812211569107L;
-
-    /** Force models used when extrapolating the Orbit. */
-    private final List<ForceModelWithJacobians> forceModelsWJ;
-
-    /** State vector derivative with respect to the parameter. */
-    private double[][] DY0DP = null;
-
-    /** Gauss equations handler. */
-    private TimeDerivativesEquationsWithJacobians adder;
-
-    /** Selected parameters for jacobian computation. */
-    private String[] selectedParameters = new String[0];
-
-    /** Selected parameters with force model associated for jacobian computation. */
-    private List<ParameterPair> paramPairs = new ArrayList<ParameterPair>();
-
-    /** Create a new instance of NumericalPropagatorWithJacobians.
-     * After creation, the instance is empty, i.e. the attitude law is set to an
-     * unspecified default law and there are no perturbing forces at all.
-     * This means that if {@link #addForceModel addForceModel} is not
-     * called after creation, the integrated orbit will follow a keplerian
-     * evolution only.
-     * @param integrator numerical integrator to use for propagation.
-     */
-    public NumericalPropagatorWithJacobians(final FirstOrderIntegrator integrator) {
-        super(integrator);
-        this.forceModelsWJ = new ArrayList<ForceModelWithJacobians>();
-    }
-
-    /** Add a force model to the global perturbation model.
-     * @param model perturbing force model to add
-     * @see #removeForceModels()
-     * @see #removeForceModels()
-     */
-    public void addForceModel(final ForceModel model) {
-        forceModels.add(model);
-        if (!(model instanceof ForceModelWithJacobians)) {
-            forceModelsWJ.add(new ForceModelWrapper(model));
-        } else {
-            forceModelsWJ.add((ForceModelWithJacobians) model);
-        }
-    }
-
-    /** Remove all perturbing force models from the global perturbation model.
-     * <p>Once all perturbing forces have been removed (and as long as no new force
-     * model is added), the integrated orbit will follow a keplerian evolution
-     * only.</p>
-     * @see #addForceModel(ForceModel)
-     */
-    public void removeForceModels() {
-        forceModels.clear();
-        forceModelsWJ.clear();
-    }
-
-    /** Select the parameters to consider for jacobian processing.
-     * <p>Parameters names have to be consistent with some
-     * {@link ForceModelWithJacobians} added elsewhere.</p>
-     * @param parameters parameters to consider for jacobian processing
-     * @see #addForceModel(ForceModel)
-     * @see ForceModelWithJacobians
-     * @see Parameterizable
-     */
-    public void selectParameters(final String[] parameters) {
-        selectedParameters = parameters.clone();
-        DY0DP = new double[7][selectedParameters.length];
-        for (final double[] row : DY0DP) {
-            Arrays.fill(row, 0.0);
-        }
-    }
-
-    /** Get the parameters selected for jacobian processing.
-     * @return parameters considered for jacobian processing
-     * @see #selectParameters(String[])
-     */
-    public String[] getParameterNames() {
-        return selectedParameters.clone();
-    }
-
-    /** Propagate towards a target date and compute partial derivatives.
-     * <p>Propagation is the same as the
-     * {@link NumericalPropagator#propagate(AbsoluteDate) basic one}.</p>
-     * <p>Jacobian for orbit parameters is given as a 7x7 array.</p>
-     * <p>Partial derivatives will be computed as a 7xn array
-     * when n parameters have been {@link #selectParameters(String[]) selected}
-     * (n may be 0).</p>
-     * <p>Those parameters are related to some {@link ForceModelWithJacobians force models}
-     * which must have been added elsewhere.</p>
-     * @param finalDate target date towards which orbit state should be propagated
-     * @param dFdY equinoctial orbit parameters + mass jacobian (7x7 array)
-     * @param dFdP partial derivatives with respect to selected parameters (7xn)
-     * @return propagated state
-     * @exception PropagationException if state cannot be propagated
-     */
-    public SpacecraftState propagate(final AbsoluteDate finalDate,
-                                     final double[][] dFdY, final double[][] dFdP)
-        throws PropagationException {
-        try {
-
-            if (initialState == null) {
-                throw new PropagationException(OrekitMessages.INITIAL_STATE_NOT_SPECIFIED_FOR_ORBIT_PROPAGATION);
-            }
-            if (initialState.getMass() <= 0.0) {
-                throw new PropagationException(OrekitMessages.NOT_POSITIVE_SPACECRAFT_MASS, initialState.getMass());
-            }
-            if (initialState.getDate().equals(finalDate)) {
-                // don't extrapolate
-                return initialState;
-            }
-            if (integrator == null) {
-                throw new PropagationException(OrekitMessages.ODE_INTEGRATOR_NOT_SET_FOR_ORBIT_PROPAGATION);
-            }
-
-            // space dynamics view
-            startDate = initialState.getDate();
-            if (modeHandler != null) {
-                modeHandler.initialize(startDate, initialState.getFrame(), mu, attitudeLaw);
-            }
-
-            final EquinoctialOrbit initialOrbit =
-                new EquinoctialOrbit(initialState.getOrbit());
-
-            currentState =
-                new SpacecraftState(initialOrbit, initialState.getAttitude(), initialState.getMass());
-
-            adder = new TimeDerivativesEquationsWithJacobians(initialOrbit);
-
-            integrator.clearEventHandlers();
-
-            // set up events related to force models
-            for (final ForceModelWithJacobians forceModel : forceModelsWJ) {
-                final EventDetector[] modelDetectors = forceModel.getEventsDetectors();
-                if (modelDetectors != null) {
-                    for (final EventDetector detector : modelDetectors) {
-                        setUpEventDetector(detector);
-                    }
-                }
-            }
-
-            // set up events added by user
-            for (final EventDetector detector : detectors) {
-                setUpEventDetector(detector);
-            }
-
-            // mathematical view
-            final double t0 = 0;
-            final double t1 = finalDate.durationFrom(startDate);
-
-            // Map state to array
-            stateVector[0] = initialOrbit.getA();
-            stateVector[1] = initialOrbit.getEquinoctialEx();
-            stateVector[2] = initialOrbit.getEquinoctialEy();
-            stateVector[3] = initialOrbit.getHx();
-            stateVector[4] = initialOrbit.getHy();
-            stateVector[5] = initialOrbit.getLv();
-            stateVector[6] = initialState.getMass();
-
-            // set up parameters for jacobian computation
-            int noParam = 0;
-            final int      nbParam = selectedParameters.length;
-            final double[] paramWJ = new double[nbParam];
-            final double[] hP      = new double[nbParam];
-
-            for (final String parameter : selectedParameters) {
-                boolean found = false;
-                for (final ForceModelWithJacobians fmwj : forceModelsWJ) {
-                    for (String parFMWJ : fmwj.getParametersNames()) {
-                        if (parFMWJ.matches(parameter)) {
-                            found = true;
-                            paramWJ[noParam] = fmwj.getParameter(parFMWJ);
-                            hP[noParam] = paramWJ[noParam] * FastMath.sqrt(MathUtils.EPSILON);
-                            paramPairs.add(new ParameterPair(parameter, fmwj));
-                            noParam++;
-                        }
-                    }
-                }
-                if (!found) {
-                    throw new PropagationException(OrekitMessages.UNKNOWN_PARAMETER, parameter);
-                }
-            }
-
-            // if selectParameters was not invoked and then no parameter selected
-            if (DY0DP == null) {
-                DY0DP = new double[7][nbParam];
-                for (final double[] row : DY0DP) {
-                    Arrays.fill(row, 0.0);
-                }
-            }
-
-            // get hY from integrator tolerance array
-            final double[] hY = getHy(integrator);
-
-            final FirstOrderIntegratorWithJacobians integratorWJ =
-                    new FirstOrderIntegratorWithJacobians(integrator,
-                                                          new DifferentialEquations(),
-                                                          paramWJ, hY, hP);
-
-            // mathematical integration
-            final double stopTime = integratorWJ.integrate(t0, stateVector, DY0DP,
-                                                           t1, stateVector, dFdY, DY0DP);
-            // fill in jacobian
-            for (int i = 0; i < DY0DP.length; i++) {
-                System.arraycopy(DY0DP[i], 0, dFdP[i], 0, DY0DP[i].length);
-            }
-
-            // back to space dynamics view
-            final AbsoluteDate date = startDate.shiftedBy(stopTime);
-
-            final EquinoctialOrbit orbit =
-                new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2], stateVector[3],
-                                     stateVector[4], stateVector[5], EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                     initialOrbit.getFrame(), date, mu);
-
-            resetInitialState(new SpacecraftState(orbit, attitudeLaw.getAttitude(orbit), stateVector[6]));
-
-            return initialState;
-
-        } catch (OrekitException oe) {
-            throw new PropagationException(oe);
-        } catch (MathUserException mue) {
-
-            // recover a possible embedded PropagationException
-            for (Throwable t = mue; t != null; t = t.getCause()) {
-                if (t instanceof PropagationException) {
-                    throw (PropagationException) t;
-                }
-            }
-
-            throw new PropagationException(mue, mue.getGeneralPattern(), mue.getArguments());
-
-        } catch (IntegratorException ie) {
-
-            // recover a possible embedded PropagationException
-            for (Throwable t = ie; t != null; t = t.getCause()) {
-                if (t instanceof PropagationException) {
-                    throw (PropagationException) t;
-                }
-            }
-
-            throw new PropagationException(ie, ie.getGeneralPattern(), ie.getArguments());
-
-        }
-    }
-
-    /** Get hY from integrator absolute tolerance array.
-     * @param integrator integrator
-     * @return step sizes array for df/dy computing
-     */
-    private double[] getHy(final FirstOrderIntegrator integrator) {
-        double[] hY = new double[0];
-        if (integrator instanceof AdaptiveStepsizeIntegrator) {
-            try {
-                final Field arrayField = AdaptiveStepsizeIntegrator.class.getDeclaredField("vecAbsoluteTolerance");
-                arrayField.setAccessible(true);
-                hY = (double[]) arrayField.get(integrator);
-                for (int i = 0; i < hY.length; i++) {
-                    hY[i] *= 10.;
-                }
-            } catch (NoSuchFieldException nsfe) {
-                throw OrekitException.createInternalError(nsfe);
-            } catch (IllegalAccessException iae) {
-                throw OrekitException.createInternalError(iae);
-            }
-        }
-        return hY;
-    }
-
-    /** Internal class for differential equations representation. */
-    private class DifferentialEquations implements ParameterizedODE, ODEWithJacobians {
-
-        /** Build a new instance. */
-        protected DifferentialEquations() {
-            calls = 0;
-        }
-
-        /** {@inheritDoc} */
-        public int getDimension() {
-            return 7;
-        }
-
-        /** {@inheritDoc} */
-        public void computeDerivatives(final double t, final double[] y, final double[] yDot)
-            throws MathUserException {
-
-            try {
-                // update space dynamics view
-                currentState = mapState(t, y, startDate, currentState.getFrame());
-
-                // compute cartesian coordinates
-                if (currentState.getMass() <= 0.0) {
-                    throw new PropagationException(OrekitMessages.SPACECRAFT_MASS_BECOMES_NEGATIVE,
-                                                   currentState.getMass());
-                }
-
-                // initialize derivatives
-                adder.initDerivatives(yDot, (EquinoctialOrbit) currentState.getOrbit());
-
-                // compute the contributions of all perturbing forces
-                for (final ForceModel forceModel : forceModels) {
-                    forceModel.addContribution(currentState, adder);
-                }
-
-                // finalize derivatives by adding the Kepler contribution
-                adder.addKeplerContribution();
-
-                // increment calls counter
-                ++calls;
-
-            } catch (OrekitException oe) {
-                throw new MathUserException(oe, oe.getSpecifier(), oe.getParts());
-            }
-
-        }
-
-        /** {@inheritDoc} */
-        public void computeJacobians(final double t, final double[] y, final double[] yDot,
-                                     final double[][] dFdY, final double[][] dFdP) {
-        }
-
-        /** {@inheritDoc} */
-        public int getParametersDimension() {
-            return selectedParameters.length;
-        }
-
-        /** {@inheritDoc} */
-        public void setParameter(final int index, final double value) {
-            final ParameterPair pp = paramPairs.get(index);
-            pp.getParamHandler().setParameter(pp.getParamName(), value);
-        }
-
-        /** Convert state array to space dynamics objects (AbsoluteDate and OrbitalParameters).
-         * @param t integration time (s)
-         * @param y state as a flat array
-         * @param referenceDate reference date from which t is counted
-         * @param frame frame in which integration is performed
-         * @return state corresponding to the flat array as a space dynamics object
-         * @exception OrekitException if the attitude state cannot be determined
-         * by the attitude law
-         */
-        private SpacecraftState mapState(final double t, final double [] y,
-                                         final AbsoluteDate referenceDate, final Frame frame)
-            throws OrekitException {
-
-            // convert raw mathematical data to space dynamics objects
-            final AbsoluteDate date = referenceDate.shiftedBy(t);
-            final EquinoctialOrbit orbit =
-                new EquinoctialOrbit(y[0], y[1], y[2], y[3], y[4], y[5],
-                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                     frame, date, mu);
-            final Attitude attitude = attitudeLaw.getAttitude(orbit);
-
-            return new SpacecraftState(orbit, attitude, y[6]);
-
-        }
-
-    }
-
-    /** Internal class used to pair a parameter name with its handler. */
-    private static class ParameterPair {
-
-        /** Parameter name. */
-        private final String paramName;
-
-        /** Parameter handler. */
-        private final Parameterizable paramHandler;
-
-        /** Simple constructor.
-         * @param paramName parameter name
-         * @param paramHandler force model handling the parameter
-         */
-        public ParameterPair(final String paramName, final Parameterizable paramHandler) {
-            this.paramName = paramName;
-            this.paramHandler = paramHandler;
-        }
-
-        /** Get parameter name.
-         * @return parameter name
-         */
-        public String getParamName() {
-            return paramName;
-        }
-
-        /** Get parameter handler.
-         * @return force model handling the parameter
-         */
-        public Parameterizable getParamHandler() {
-            return paramHandler;
-        }
-
-    }
-
-    /** Internal class enabling basic force model
-     *  to be used when processing parameters jacobian.
-     */
-    private static class ForceModelWrapper implements ForceModelWithJacobians {
-
-        /** Serializable UID. */
-        private static final long serialVersionUID = 3625153851142193056L;
-
-        /** Wrapped basic force model. */
-        private final ForceModel basic;
-
-        /** Simple constructor.
-         * @param basic force model to wrap
-         */
-        public ForceModelWrapper(final ForceModel basic) {
-            this.basic = basic;
-        }
-
-        /** {@inheritDoc} */
-        public void addContribution(final SpacecraftState s,
-                                    final TimeDerivativesEquations adder)
-            throws OrekitException {
-            basic.addContribution(s, adder);
-        }
-
-        /** {@inheritDoc} */
-        public EventDetector[] getEventsDetectors() {
-            return basic.getEventsDetectors();
-        }
-
-        /** {@inheritDoc} */
-        public void addContributionWithJacobians(final SpacecraftState s,
-                                                 final TimeDerivativesEquationsWithJacobians adder)
-            throws OrekitException {
-        }
-
-        /** {@inheritDoc} */
-        public double getParameter(final String name) throws IllegalArgumentException {
-            return Double.NaN;
-        }
-
-        /** {@inheritDoc} */
-        public Collection<String> getParametersNames() {
-            return new ArrayList<String>();
-        }
-
-        /** {@inheritDoc} */
-        public void setParameter(final String name, final double value)
-            throws IllegalArgumentException {
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/orekit/propagation/numerical/ParameterConfiguration.java b/src/main/java/org/orekit/propagation/numerical/ParameterConfiguration.java
new file mode 100644
index 0000000000..bd892f1306
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/ParameterConfiguration.java
@@ -0,0 +1,77 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.io.Serializable;
+
+/** Simple container associating a parameter name with a step to compute its jacobian
+ * and the provider thant manages it.
+ * @author V&eacute;ronique Pommier-Maurussane
+ * @version $Revision$ $Date$
+ */
+class ParameterConfiguration implements Serializable {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 2247518849090889379L;
+
+    /** Parameter name. */
+    private String parameterName;
+
+    /** Parameter step for finite difference computation of partial derivative with respect to that parameter. */
+    private double hP;
+
+    /** Provider handling this parameter. */
+    private AccelerationJacobiansProvider provider;
+
+    /** Parameter name and step pair constructor.
+     * @param parameterName parameter name
+     * @param hP parameter step */
+    public ParameterConfiguration(final String parameterName, final double hP) {
+        this.parameterName = parameterName;
+        this.hP = hP;
+        this.provider = null;
+    }
+
+    /** Get parameter name.
+     * @return parameterName parameter name
+     */
+    public String getParameterName() {
+        return parameterName;
+    }
+
+    /** Get parameter step.
+     * @return hP parameter step
+     */
+    public double getHP() {
+        return hP;
+    }
+
+    /** Set the povider handling this parameter.
+     * @param provider provider handling this parameter
+     */
+    public void setProvider(final AccelerationJacobiansProvider provider) {
+        this.provider = provider;
+    }
+
+    /** Get the povider handling this parameter.
+     * @return provider handling this parameter
+     */
+    public AccelerationJacobiansProvider getProvider() {
+        return provider;
+    }
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/PartialDerivativesEquations.java b/src/main/java/org/orekit/propagation/numerical/PartialDerivativesEquations.java
new file mode 100644
index 0000000000..9fd2d9a41d
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/PartialDerivativesEquations.java
@@ -0,0 +1,454 @@
+/* Copyright 2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.math.util.FastMath;
+import org.apache.commons.math.util.MathUtils;
+import org.orekit.errors.OrekitException;
+import org.orekit.errors.OrekitMessages;
+import org.orekit.forces.ForceModel;
+import org.orekit.propagation.SpacecraftState;
+
+/** Set of {@link AdditionalEquations additional equations} computing the partial derivatives
+ * of the state (orbit) with respect to initial state and force models parameters.
+ * <p>
+ * This set of equations can be added to a {@link NumericalPropagator numerical propagator}
+ * in order to compute partial derivatives of the orbit along with the orbit itself. This is
+ * useful for example in orbit determination applications.
+ * </p>
+ * @author V&eacute;ronique Pommier-Maurussane
+ * @version $Revision$ $Date$
+ */
+public class PartialDerivativesEquations implements AdditionalEquations {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 8373349999733456541L;
+
+    /** Selected parameters for jacobian computation. */
+    private NumericalPropagator propagator;
+
+    /** Jacobians providers. */
+    private final List<AccelerationJacobiansProvider> jacobiansProviders;
+
+    /** List of parameters selected for jacobians computation. */
+    private List<ParameterConfiguration> selectedParameters;
+
+    /** State vector dimension without additional parameters
+     * (either 6 or 7 depending on mass derivatives being included or not). */
+    private int stateDim;
+
+    /** Parameters vector dimension. */
+    private int paramDim;
+
+    /** Step used for finite difference computation with respect to spacecraft position. */
+    private double hPos;
+
+    /** Step used for finite difference computation with respect to spacecraft velocity. */
+    private double hVel;
+
+    /** Step used for finite difference computation with respect to spacecraft mass. */
+    private double hM;
+
+    /** Boolean for force models / selected parameters consistency. */
+    private boolean dirty = false;
+
+    /** Jacobian of acceleration with respect to spacecraft position. */
+    private transient double[][] dAccdPos;
+
+    /** Jacobian of acceleration with respect to spacecraft velocity. */
+    private transient double[][] dAccdVel;
+
+    /** Jacobian of acceleration with respect to spacecraft mass. */
+    private transient double[]   dAccdM;
+
+    /** Jacobian of acceleration with respect to one force model parameter (array reused for all parameters). */
+    private transient double[]   dAccdParam;
+
+    /** Simple constructor.
+     * @param propagator the propagator that will handle the orbit propagation
+     */
+    public PartialDerivativesEquations(final NumericalPropagator propagator) {
+        jacobiansProviders = new ArrayList<AccelerationJacobiansProvider>();
+        dirty = true;
+        this.propagator = propagator;
+        selectedParameters = new ArrayList<ParameterConfiguration>();
+        stateDim = -1;
+        paramDim = -1;
+        hPos  = Double.NaN;
+        hVel  = Double.NaN;
+        hM = Double.NaN;
+    }
+
+    /** Get the names of the available parameters in the propagator.
+     * <p>
+     * The names returned depend on the force models set up in the propagator,
+     * including the Newtonian attraction from the central body.
+     * </p>
+     * @return available parameters
+     */
+    public List<String> getAvailableParameters() {
+        final List<String> available = new ArrayList<String>();
+        available.addAll(propagator.getNewtonianAttractionForceModel().getParametersNames());
+        for (final ForceModel model : propagator.getForceModels()) {
+            available.addAll(model.getParametersNames());
+        }
+        return available;
+    }
+
+    /** Select the parameters to consider for jacobian processing.
+     * <p>Parameters names have to be consistent with some
+     * {@link ForceModel} added elsewhere.</p>
+     * @param parameters parameters to consider for jacobian processing
+     * @see NumericalPropagator#addForceModel(ForceModel)
+     * @see #setInitialJacobians(double[][], double[][])
+     * @see ForceModel
+     * @see org.orekit.forces.Parameterizable
+     */
+    public void selectParameters(final String ... parameters) {
+
+        selectedParameters.clear();
+        for (String param : parameters) {
+            selectedParameters.add(new ParameterConfiguration(param, Double.NaN));
+        }
+        dirty = true;
+    }
+
+    /** Select the parameters to consider for jacobian processing.
+     * <p>Parameters names have to be consistent with some
+     * {@link ForceModel} added elsewhere.</p>
+     * @param parameter parameter to consider for jacobian processing
+     * @param hP step to use for computing jacobian column with respect to the specified parameter
+     * @see NumericalPropagator#addForceModel(ForceModel)
+     * @see #setInitialJacobians(double[][], double[][])
+     * @see ForceModel
+     * @see org.orekit.forces.Parameterizable
+     */
+    public void selectParamAndStep(final String parameter, final double hP) {
+        selectedParameters.add(new ParameterConfiguration(parameter, hP));
+        dirty = true;
+    }
+
+    /** Set the steps for finite differences with respect to spacecraft state.
+     * @param hPosition step used for finite difference computation with respect to spacecraft position (m)
+     * @param hVelocity step used for finite difference computation with respect to spacecraft velocity (m/s)
+     * @param hMass step used for finite difference computation with respect to spacecraft mass (kg)
+     */
+    public void setSteps(final double hPosition, final double hVelocity, final double hMass) {
+        this.hPos = hPosition;
+        this.hVel = hVelocity;
+        this.hM   = hMass;
+    }
+
+    /** Set the initial value of the jacobian with respect to state and parameter.
+     * <p>
+     * This method is equivalent to call {@link #setInitialJacobians(double[][], double[][])}
+     * with dYdY0 set to the identity matrix and dYdP set to a zero matrix.
+     * </p>
+     * @param stateDimension state dimension, must be either 6 for orbit only or 7 for orbit and mass
+     * @param paramDimension parameters dimension
+     * @exception OrekitException if the partial equation has not been registered in
+     * the propagator or if matrices dimensions are incorrect
+     * @see #selectedParameters
+     * @see #selectParamAndStep(String, double)
+     */
+    public void setInitialJacobians(final int stateDimension, final int paramDimension)
+        throws OrekitException {
+        final double[][] dYdY0 = new double[stateDimension][stateDimension];
+        final double[][] dYdP  = new double[stateDimension][paramDimension];
+        for (int i = 0; i < stateDimension; ++i) {
+            dYdY0[i][i] = 1.0;
+        }
+        setInitialJacobians(dYdY0, dYdP);
+    }
+
+    /** Set the initial value of the jacobian with respect to state and parameter.
+     * @param dYdY0 initial jacobian w.r to state (may be either 6x6 for orbit only
+     * or 7x7 for orbit and mass)
+     * @param dYdP initial jacobian w.r to parameter (may be null if no parameters are selected)
+     * @exception OrekitException if the partial equation has not been registered in
+     * the propagator or if matrices dimensions are incorrect
+     * @see #selectedParameters
+     * @see #selectParamAndStep(String, double)
+     */
+    public void setInitialJacobians(final double[][] dYdY0, final double[][] dYdP)
+        throws OrekitException {
+
+        // Check dimensions
+        stateDim = dYdY0.length;
+        if ((stateDim < 6) || (stateDim > 7) || (stateDim != dYdY0[0].length)) {
+            throw new OrekitException(OrekitMessages.STATE_JACOBIAN_NEITHER_6X6_NOR_7X7,
+                                      stateDim, dYdY0[0].length);
+        }
+        if ((dYdP != null) && (stateDim != dYdP.length)) {
+            throw new OrekitException(OrekitMessages.STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH,
+                                      stateDim, dYdP.length);
+        }
+
+        paramDim = (dYdP == null) ? 0 : dYdP[0].length;
+
+        // store the matrices in row major order as a single dimension array
+        final double[] p = new double[stateDim * (stateDim + paramDim)];
+        int index = 0;
+        for (final double[] row : dYdY0) {
+            System.arraycopy(row, 0, p, index, stateDim);
+            index += stateDim;
+        }
+
+        if (dYdP != null) {
+            for (final double[] row : dYdP) {
+                System.arraycopy(row, 0, p, index, paramDim);
+                index += paramDim;
+            }
+        }
+
+        // set value in propagator
+        propagator.setInitialAdditionalState(p, this);
+
+    }
+
+    /** Get the initial value of the jacobian with respect to state and parameter.
+     * @param dYdY0 current jacobian w.r to state.
+     * @param dYdP current jacobian w.r to parameter (may be null if no parameters are selected)
+     * @exception OrekitException if the partial equation has not been registered in
+     * the propagator
+     */
+    public void getCurrentJacobians(final double[][] dYdY0, final double[][] dYdP)
+        throws OrekitException {
+
+        // get current state from propagator
+        final double[] p = propagator.getCurrentAdditionalState(this);
+
+        int index = 0;
+        for (int i = 0; i < stateDim; i++) {
+            System.arraycopy(p, index, dYdY0[i], 0, stateDim);
+            index += stateDim;
+        }
+
+        if (paramDim != 0) {
+            for (int i = 0; i < stateDim; i++) {
+                System.arraycopy(p, index, dYdP[i], 0, paramDim);
+                index += paramDim;
+            }
+        }
+
+    }
+
+    /** {@inheritDoc} */
+    public void computeDerivatives(final SpacecraftState s, final TimeDerivativesEquations adder,
+                                   final double[] p, final double[] pDot) throws OrekitException {
+
+        final int dim = 3;
+
+        // Lazy initialization
+        if (dirty) {
+
+            if (propagator.getPropagationParametersType() != NumericalPropagator.PropagationParametersType.CARTESIAN) {
+                throw new OrekitException(OrekitMessages.PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN);
+            }
+
+            // if steps have not been set by user, set default values
+            if (Double.isNaN(hPos)) {
+                final double factor = FastMath.sqrt(MathUtils.EPSILON);
+                hPos  = factor * s.getPVCoordinates().getPosition().getNorm();
+                hVel  = factor * s.getPVCoordinates().getVelocity().getNorm();
+                hM = factor * s.getMass();
+            }
+
+             // set up jacobians providers
+            jacobiansProviders.clear();
+            for (final ForceModel model : propagator.getForceModels()) {
+                if (model instanceof AccelerationJacobiansProvider) {
+
+                    // the force model already provides the jacobians by itself
+                    jacobiansProviders.add((AccelerationJacobiansProvider) model);
+
+                } else {
+
+                    // wrap the force model to compute the jacobians by finite differences
+                    jacobiansProviders.add(new Jacobianizer(model, selectedParameters, hPos, hVel, hM));
+
+                }
+            }
+            jacobiansProviders.add(propagator.getNewtonianAttractionForceModel());
+
+            // check all parameters are handled by at least one jacobian provider
+            for (final ParameterConfiguration param : selectedParameters) {
+                final String name = param.getParameterName();
+                boolean found = false;
+                for (final AccelerationJacobiansProvider provider : jacobiansProviders) {
+                    if (provider.isSupported(name)) {
+                        param.setProvider(provider);
+                        found = true;
+                    }
+                }
+                if (!found) {
+                    throw new OrekitException(OrekitMessages.UNKNOWN_PARAMETER, name);
+                }
+            }
+
+            // check the numbers of parameters and matrix size agree
+            if (selectedParameters.size() != paramDim) {
+                throw new OrekitException(OrekitMessages.INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH,
+                                          paramDim, selectedParameters.size());
+            }
+
+            dAccdParam = new double[dim];
+            dAccdPos   = new double[dim][dim];
+            dAccdVel   = new double[dim][dim];
+            dAccdM     = (stateDim > 6) ? new double[dim] : null;
+
+            dirty = false;
+
+        }
+
+        // compute forces gradients dAccDState
+        for (final double[] row : dAccdPos) {
+            Arrays.fill(row, 0.0);
+        }
+        for (final double[] row : dAccdVel) {
+            Arrays.fill(row, 0.0);
+        }
+        if (dAccdM != null) {
+            Arrays.fill(dAccdM, 0.0);
+        }
+        for (final AccelerationJacobiansProvider jacobProv : jacobiansProviders) {
+            jacobProv.addDAccDState(s, dAccdPos, dAccdVel, dAccdM);
+        }
+
+        // the variational equations of the complete state jacobian matrix have the
+        // following form for 7x7, i.e. when mass partial derivatives are also considered
+        // (when mass is not considered, only the A, B, D and E matrices are used along
+        // with their derivatives):
+
+        // [      ] [      ] [      ]   [                ] [                ] [              ]   [   ] [   ] [   ]
+        // [ Adot ] [ Bdot ] [ Cdot ]   [  dVel/dPos = 0 ] [ dVel/dVel = Id ] [  dVel/dm = 0 ]   [ A ] [ B ] [ C ]
+        // [      ] [      ] [      ]   [                ] [                ] [              ]   [   ] [   ] [   ]
+        // --------+--------+--- ----   ------------------+------------------+----------------   -----+-----+-----
+        // [      ] [      ] [      ]   [                ] [                ] [              ]   [   ] [   ] [   ]
+        // [ Ddot ] [ Edot ] [ Fdot ] = [    dAcc/dPos   ] [    dAcc/dVel   ] [   dAcc/dm    ] * [ D ] [ E ] [ F ]
+        // [      ] [      ] [      ]   [                ] [                ] [              ]   [   ] [   ] [   ]
+        // --------+--------+--- ----   ------------------+------------------+----------------   -----+-----+-----
+        // [ Gdot ] [ Hdot ] [ Idot ]   [ dmDot/dPos = 0 ] [ dmDot/dVel = 0 ] [ dmDot/dm = 0 ]   [ G ] [ H ] [ I ]
+
+        // The A, B, D and E sub-matrices and their derivatives (Adot ...) are 3x3 matrices,
+        // the C and F sub-matrices and their derivatives (Cdot ...) are 3x1 matrices,
+        // the G and H sub-matrices and their derivatives (Gdot ...) are 1x3 matrices,
+        // the I sub-matrix and its derivative (Idot) are 1x1 matrices.
+
+        // The expanded multiplication above can be rewritten to take into account
+        // the fixed values found in the sub-matrices in the left factor. This leads to:
+
+        //     [ Adot ] = [ D ]
+        //     [ Bdot ] = [ E ]
+        //     [ Cdot ] = [ F ]
+        //     [ Ddot ] = [ dAcc/dPos ] * [ A ] + [ dAcc/dVel ] * [ D ] + [ dAcc/dm ] * [ G ]
+        //     [ Edot ] = [ dAcc/dPos ] * [ B ] + [ dAcc/dVel ] * [ E ] + [ dAcc/dm ] * [ H ]
+        //     [ Fdot ] = [ dAcc/dPos ] * [ C ] + [ dAcc/dVel ] * [ F ] + [ dAcc/dm ] * [ I ]
+        //     [ Gdot ] = [ 0 ]
+        //     [ Hdot ] = [ 0 ]
+        //     [ Idot ] = [ 0 ]
+
+        // The following loops compute these expressions taking care of the mapping of the
+        // (A, B, ... I) matrices into the single dimension array p and of the mapping of the
+        // (Adot, Bdot, ... Idot) matrices into the single dimension array pDot.
+
+        // copy D, E and F into Adot, Bdot and Cdot
+        System.arraycopy(p, dim * stateDim, pDot, 0, dim * stateDim);
+
+        // compute Ddot, Edot and Fdot
+        for (int i = 0; i < dim; ++i) {
+            final double[] dAdPi = dAccdPos[i];
+            final double[] dAdVi = dAccdVel[i];
+            for (int j = 0; j < stateDim; ++j) {
+                pDot[(dim + i) * stateDim + j] =
+                    dAdPi[0] * p[j]                + dAdPi[1] * p[j +     stateDim] + dAdPi[2] * p[j + 2 * stateDim] +
+                    dAdVi[0] * p[j + 3 * stateDim] + dAdVi[1] * p[j + 4 * stateDim] + dAdVi[2] * p[j + 5 * stateDim] +
+                    ((dAccdM == null) ? 0.0 : dAccdM[i] * p[j + 6 * stateDim]);
+            }
+        }
+
+        if (dAccdM != null) {
+            // set Gdot, Hdot and Idot to 0
+            Arrays.fill(pDot, 6 * stateDim, 7 * stateDim, 0.0);
+        }
+
+        for (int k = 0; k < paramDim; ++k) {
+
+            // compute the acceleration gradient with respect to current parameter
+            final ParameterConfiguration param = selectedParameters.get(k);
+            final AccelerationJacobiansProvider provider = param.getProvider();
+            Arrays.fill(dAccdParam, 0.0);
+            provider.addDAccDParam(s, param.getParameterName(), dAccdParam);
+
+            // the variational equations of the parameters jacobian matrix are computed
+            // one column at a time, they have the following form:
+            // [      ]   [                ] [                ] [              ]   [   ]   [                  ]
+            // [ Jdot ]   [  dVel/dPos = 0 ] [ dVel/dVel = Id ] [  dVel/dm = 0 ]   [ J ]   [  dVel/dParam = 0 ]
+            // [      ]   [                ] [                ] [              ]   [   ]   [                  ]
+            // --------   ------------------+------------------+----------------   -----   --------------------
+            // [      ]   [                ] [                ] [              ]   [   ]   [                  ]
+            // [ Kdot ] = [    dAcc/dPos   ] [    dAcc/dVel   ] [   dAcc/dm    ] * [ K ] + [    dAcc/dParam   ]
+            // [      ]   [                ] [                ] [              ]   [   ]   [                  ]
+            // --------   ------------------+------------------+----------------   -----   --------------------
+            // [ Ldot ]   [ dmDot/dPos = 0 ] [ dmDot/dVel = 0 ] [ dmDot/dm = 0 ]   [ L ]   [ dmDot/dParam = 0 ]
+
+            // The J and K sub-columns and their derivatives (Jdot ...) are 3 elements columns,
+            // the L sub-colums and its derivative (Ldot) are 1 elements columns.
+
+            // The expanded multiplication and addition above can be rewritten to take into
+            // account the fixed values found in the sub-matrices in the left factor. This leads to:
+
+            //     [ Jdot ] = [ K ]
+            //     [ Kdot ] = [ dAcc/dPos ] * [ J ] + [ dAcc/dVel ] * [ K ] + [ dAcc/dm ] * [ L ] + [ dAcc/dParam ]
+            //     [ Ldot ] = [ 0 ]
+
+            // The following loops compute these expressions taking care of the mapping of the
+            // (J, K, L) columns into the single dimension array p and of the mapping of the
+            // (Jdot, Kdot, Ldot) columns into the single dimension array pDot.
+
+            // copy K into Jdot
+            final int columnTop = stateDim * stateDim + k;
+            pDot[columnTop]                = p[columnTop + 3 * paramDim];
+            pDot[columnTop +     paramDim] = p[columnTop + 4 * paramDim];
+            pDot[columnTop + 2 * paramDim] = p[columnTop + 5 * paramDim];
+
+            // compute Kdot
+            for (int i = 0; i < dim; ++i) {
+                final double[] dAdPi = dAccdPos[i];
+                final double[] dAdVi = dAccdVel[i];
+                pDot[columnTop + (dim + i) * paramDim] =
+                    dAccdParam[i] +
+                    dAdPi[0] * p[columnTop]                + dAdPi[1] * p[columnTop +     paramDim] + dAdPi[2] * p[columnTop + 2 * paramDim] +
+                    dAdVi[0] * p[columnTop + 3 * paramDim] + dAdVi[1] * p[columnTop + 4 * paramDim] + dAdVi[2] * p[columnTop + 5 * paramDim] +
+                    ((dAccdM == null) ? 0.0 : dAccdM[i] * p[columnTop + 6 * paramDim]);
+            }
+
+            if (dAccdM != null) {
+                // set Ldot to 0
+                pDot[columnTop + 6 * paramDim] = 0;
+            }
+
+        }
+
+    }
+
+}
+
diff --git a/src/main/java/org/orekit/propagation/numerical/StateMapper.java b/src/main/java/org/orekit/propagation/numerical/StateMapper.java
new file mode 100644
index 0000000000..9fd512351a
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/StateMapper.java
@@ -0,0 +1,59 @@
+/* Copyright 2002-2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.io.Serializable;
+
+import org.orekit.attitudes.AttitudeLaw;
+import org.orekit.errors.OrekitException;
+import org.orekit.frames.Frame;
+import org.orekit.propagation.SpacecraftState;
+import org.orekit.time.AbsoluteDate;
+
+/** Interface defining mapping between simple state arrays and {@link SpacecraftState} instances.
+ *
+ * @see org.orekit.propagation.SpacecraftState
+ * @see org.orekit.propagation.numerical.NumericalPropagator
+ * @author V&eacute;ronique Pommier-Maurussane
+ * @version $Revision$ $Date$
+ */
+public interface StateMapper extends Serializable {
+
+    /** Set the attitude law.
+     * @param attitudeLaw attitude law
+     */
+    void setAttitudeLaw(final AttitudeLaw attitudeLaw);
+
+    /** Convert spacecraft state to state array.
+    * @param s spacecraft state to map
+    * @param stateVector flat array into which the state vector should be mapped */
+    void mapStateToArray(SpacecraftState s, double[] stateVector);
+
+     /** Convert state array to space dynamics objects (AbsoluteDate and OrbitalParameters).
+     * @param array state as a flat array
+     * @param date integration date
+     * @param mu central attraction coefficient used for propagation (m<sup>3</sup>/s<sup>2</sup>)
+     * @param frame frame in which integration is performed
+     * @return state corresponding to the flat array as a space dynamics object
+     * @exception OrekitException if the attitude state cannot be determined
+     * by the attitude law
+     */
+    SpacecraftState mapArrayToState(final double[] array, final AbsoluteDate date,
+                                    final double mu, final Frame frame)
+        throws OrekitException;
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/StateMapperCartesian.java b/src/main/java/org/orekit/propagation/numerical/StateMapperCartesian.java
new file mode 100644
index 0000000000..b82365d923
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/StateMapperCartesian.java
@@ -0,0 +1,87 @@
+/* Copyright 2002-2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import org.apache.commons.math.geometry.Vector3D;
+import org.orekit.attitudes.AttitudeLaw;
+import org.orekit.errors.OrekitException;
+import org.orekit.frames.Frame;
+import org.orekit.orbits.CartesianOrbit;
+import org.orekit.propagation.SpacecraftState;
+import org.orekit.time.AbsoluteDate;
+import org.orekit.utils.PVCoordinates;
+
+/** Implementation of the {@link StateMapper} interface for state arrays in cartesian coordinates.
+ *
+ * @see org.orekit.propagation.SpacecraftState
+ * @see org.orekit.propagation.numerical.NumericalPropagator
+ * @see TimeDerivativesEquationsCartesian
+ * @author V&eacute;ronique Pommier-Maurussane
+ * @version $Revision$ $Date$
+ */
+public class StateMapperCartesian implements StateMapper {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = -8228988658997240720L;
+
+    /** Attitude law. */
+    private AttitudeLaw attitudeLaw;
+
+    /** Create a new instance.
+     */
+    public StateMapperCartesian() {
+    }
+
+    /** Set the attitude law.
+     * @param attitudeLaw attitude law
+     */
+    public void setAttitudeLaw(final AttitudeLaw attitudeLaw) {
+        this.attitudeLaw = attitudeLaw;
+    }
+
+    /** {@inheritDoc} */
+    public void mapStateToArray(final SpacecraftState s, final double[] stateVector) {
+
+        final PVCoordinates pv = s.getPVCoordinates();
+        final Vector3D      p  = pv.getPosition();
+        final Vector3D      v  = pv.getVelocity();
+
+        stateVector[0] = p.getX();
+        stateVector[1] = p.getY();
+        stateVector[2] = p.getZ();
+        stateVector[3] = v.getX();
+        stateVector[4] = v.getY();
+        stateVector[5] = v.getZ();
+        stateVector[6] = s.getMass();
+
+    }
+
+    /** {@inheritDoc} */
+    public SpacecraftState mapArrayToState(final double[] stateVector, final AbsoluteDate date,
+                                           final double mu, final Frame frame)
+        throws OrekitException {
+
+        final Vector3D       p     = new Vector3D(stateVector[0], stateVector[1], stateVector[2]);
+        final Vector3D       v     = new Vector3D(stateVector[3], stateVector[4], stateVector[5]);
+        final PVCoordinates  pv    = new PVCoordinates(p, v);
+        final CartesianOrbit orbit = new CartesianOrbit(pv, frame, date, mu);
+
+        return new SpacecraftState(orbit, attitudeLaw.getAttitude(orbit), stateVector[6]);
+
+    }
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/StateMapperEquinoctial.java b/src/main/java/org/orekit/propagation/numerical/StateMapperEquinoctial.java
new file mode 100644
index 0000000000..5095e68e08
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/StateMapperEquinoctial.java
@@ -0,0 +1,74 @@
+/* Copyright 2002-2010 Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import org.orekit.attitudes.AttitudeLaw;
+import org.orekit.errors.OrekitException;
+import org.orekit.frames.Frame;
+import org.orekit.orbits.EquinoctialOrbit;
+import org.orekit.propagation.SpacecraftState;
+import org.orekit.time.AbsoluteDate;
+
+/** Implementation of the {@link StateMapper} interface for state arrays in equinoctial parameters.
+*
+* @see org.orekit.propagation.SpacecraftState
+* @see org.orekit.propagation.numerical.NumericalPropagator
+* @see TimeDerivativesEquationsEquinoctial
+* @author V&eacute;ronique Pommier-Maurussane
+* @version $Revision$ $Date$
+*/
+public class StateMapperEquinoctial implements StateMapper {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 2882088208801391437L;
+
+    /** Attitude law. */
+    private AttitudeLaw attitudeLaw;
+
+    /** Set the attitude law.
+     * @param attitudeLaw attitude law
+     */
+    public void setAttitudeLaw(final AttitudeLaw attitudeLaw) {
+        this.attitudeLaw = attitudeLaw;
+    }
+
+    /** {@inheritDoc} */
+    public void mapStateToArray(final SpacecraftState s, final double[] stateVector) {
+
+        stateVector[0] = s.getA();
+        stateVector[1] = s.getEquinoctialEx();
+        stateVector[2] = s.getEquinoctialEy();
+        stateVector[3] = s.getHx();
+        stateVector[4] = s.getHy();
+        stateVector[5] = s.getLv();
+        stateVector[6] = s.getMass();
+
+    }
+
+    /** {@inheritDoc} */
+    public SpacecraftState mapArrayToState(final double[] stateVector, final AbsoluteDate date,
+                                           final double mu, final Frame frame) throws OrekitException {
+        final EquinoctialOrbit orbit =
+            new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2], stateVector[3],
+                                 stateVector[4], stateVector[5], EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
+                                 frame, date, mu);
+
+        return new SpacecraftState(orbit, attitudeLaw.getAttitude(orbit), stateVector[6]);
+
+    }
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquations.java b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquations.java
index 8f95bd0a87..0a3c6a89e1 100644
--- a/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquations.java
+++ b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquations.java
@@ -17,36 +17,32 @@
 package org.orekit.propagation.numerical;
 
 import java.io.Serializable;
-import java.util.Arrays;
+
 import org.apache.commons.math.geometry.Vector3D;
-import org.apache.commons.math.util.FastMath;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
 import org.orekit.errors.PropagationException;
 import org.orekit.frames.Frame;
-import org.orekit.frames.Transform;
-import org.orekit.orbits.EquinoctialOrbit;
-import org.orekit.utils.PVCoordinates;
-
+import org.orekit.orbits.Orbit;
 
-/** This class sums up the contribution of several forces into orbit and mass derivatives.
+/** Interface summing up the contribution of several forces into orbit and mass derivatives.
  *
- * <p>The aim of this class is to gather the contributions of various perturbing
+ * <p>The aim of this interface is to gather the contributions of various perturbing
  * forces expressed as accelerations into one set of time-derivatives of
- * {@link org.orekit.orbits.EquinoctialOrbit} plus one mass derivatives.
- * It implements Gauss equations for the equinoctial parameters.</p>
+ * {@link org.orekit.orbits.Orbit} plus one mass derivatives.
+ * It implements Gauss equations for different kind of parameters.</p>
  *  <p>
  * The state vector handled internally has the form that follows:
  *   <pre>
- *     y[0] = a
- *     y[1] = ex
- *     y[2] = ey
- *     y[3] = hx
- *     y[4] = hy
- *     y[5] = lv
- *     y[6] = mass
+ *     y[0] 
+ *     y[1]
+ *     y[2]
+ *     y[3]
+ *     y[4]
+ *     y[5]
+ *     y[6]
  *   </pre>
- * where the six firsts paramters stands for the equinoctial parameters and the 7th
+ * where the six firsts parameters stands for the chosen parameters and the 7th
  * for the mass (kg) at the current time.
  * </p>
  * <p>The proper way to use this class is to have the object implementing the
@@ -55,7 +51,7 @@ import org.orekit.utils.PVCoordinates;
  * <ul>
  *   <li>
  *     reinitialize the instance using the
- *     {@link #initDerivatives(double[], EquinoctialOrbit)} method
+ *     {@link #initDerivatives(double[], Orbit)} method
  *   </li>
  *   <li>
  *     pass the instance to each force model in turn so that they can put their
@@ -67,233 +63,45 @@ import org.orekit.utils.PVCoordinates;
  *   </li>
  * </ul>
  * </p>
- * @see org.orekit.orbits.EquinoctialOrbit
+ * @see org.orekit.orbits.Orbit
  * @see org.orekit.propagation.numerical.NumericalPropagator
  * @author Luc Maisonobe
  * @author Fabien Maussion
  * @author V&eacute;ronique Pommier-Maurussane
  * @version $Revision$ $Date$
  */
-public class TimeDerivativesEquations implements Serializable {
+public abstract class TimeDerivativesEquations implements Serializable {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = 1524631993375841290L;
+    private static final long serialVersionUID = 4183908052500627555L;
 
-    /** Orbital parameters. */
-    private EquinoctialOrbit storedParameters;
+    // CHECKSTYLE: stop VisibilityModifierCheck
 
     /** Reference to the derivatives array to initialize. */
-    private double[] storedYDot;
-
-    /** First vector of the (q, s, w) local orbital frame. */
-    private Vector3D lofQ;
-
-    /** Second vector of the (q, s, w) local orbital frame. */
-    private Vector3D lofS;
-
-    /** First vector of the (t, n, w) local orbital frame. */
-    private Vector3D lofT;
-
-    /** Second vector of the (t, n, w) local orbital frame. */
-    private Vector3D lofN;
-
-    /** Third vector of both the (q, s, w) and (t, n, w) local orbital frames. */
-    private Vector3D lofW;
-
-    // CHECKSTYLE: stop JavadocVariable check
+    protected double[] storedYDot;
 
-    /** Multiplicative coefficients for the perturbing accelerations along lofQ. */
-    private double aQ;
-    private double exQ;
-    private double eyQ;
-
-    /** Multiplicative coefficients for the perturbing accelerations along lofS. */
-    private double aS;
-    private double exS;
-    private double eyS;
-
-    /** Multiplicative coefficients for the perturbing accelerations along lofT. */
-    private double aT;
-    private double exT;
-    private double eyT;
-
-    /** Multiplicative coefficients for the perturbing accelerations along lofN. */
-    private double exN;
-    private double eyN;
-
-    /** Multiplicative coefficients for the perturbing accelerations along lofW. */
-    private double eyW;
-    private double exW;
-    private double hxW;
-    private double hyW;
-    private double lvW;
-
-    // CHECKSTYLE: resume JavadocVariable check
-
-    /** Kepler evolution on true latitude argument. */
-    private double lvKepler;
+    //CHECKSTYLE: resume VisibilityModifierCheck
 
     /** Create a new instance.
-     * @param orbit current orbit parameters
      */
-    protected TimeDerivativesEquations(final EquinoctialOrbit orbit) {
-        this.storedParameters = orbit;
-        lofQ = Vector3D.ZERO;
-        lofS = Vector3D.ZERO;
-        lofT = Vector3D.ZERO;
-        lofN = Vector3D.ZERO;
-        lofW = Vector3D.ZERO;
-        updateOrbitalFrames();
-    }
-
-    /** Update the orbital frames. */
-    private void updateOrbitalFrames() {
-
-        // get the position/velocity vectors
-        final PVCoordinates pvCoordinates = storedParameters.getPVCoordinates();
-
-        // compute orbital plane normal vector
-        lofW = pvCoordinates.getMomentum().normalize();
-
-        // compute (q, s, w) local orbital frame
-        lofQ = pvCoordinates.getPosition().normalize();
-        lofS = Vector3D.crossProduct(lofW, lofQ);
-
-        // compute (t, n, w) local orbital frame
-        lofT = pvCoordinates.getVelocity().normalize();
-        lofN = Vector3D.crossProduct(lofW, lofT);
-
+    protected TimeDerivativesEquations() {
     }
 
     /** Initialize all derivatives to zero.
      * @param yDot reference to the array where to put the derivatives.
-     * @param orbit current orbit parameters
+     * @param currentOrbit current orbit parameters
      * @exception PropagationException if the orbit evolve out of supported range
      */
-    protected void initDerivatives(final double[] yDot,
-                                   final EquinoctialOrbit orbit)
-        throws PropagationException {
-
-
-        this.storedParameters = orbit;
-        updateOrbitalFrames();
-
-        // store derivatives array reference
-        this.storedYDot = yDot;
-
-        // initialize derivatives to zero
-        Arrays.fill(storedYDot, 0.0);
-
-        // intermediate variables
-        final double ex  = storedParameters.getEquinoctialEx();
-        final double ey  = storedParameters.getEquinoctialEy();
-        final double ex2 = ex * ex;
-        final double ey2 = ey * ey;
-        final double e2  = ex2 + ey2;
-        final double e   = FastMath.sqrt(e2);
-        if (e >= 1) {
-            throw new PropagationException(OrekitMessages.ORBIT_BECOMES_HYPERBOLIC_UNABLE_TO_PROPAGATE_FURTHER, e);
-        }
-
-        // intermediate variables
-        final double oMe2        = (1 - e) * (1 + e);
-        final double epsilon     = FastMath.sqrt(oMe2);
-        final double a           = storedParameters.getA();
-        final double na          = FastMath.sqrt(orbit.getMu() / a);
-        final double n           = na / a;
-        final double lv          = storedParameters.getLv();
-        final double cLv         = FastMath.cos(lv);
-        final double sLv         = FastMath.sin(lv);
-        final double excLv       = ex * cLv;
-        final double eysLv       = ey * sLv;
-        final double excLvPeysLv = excLv + eysLv;
-        final double ksi         = 1 + excLvPeysLv;
-        final double nu          = ex * sLv - ey * cLv;
-        final double sqrt        = FastMath.sqrt(ksi * ksi + nu * nu);
-        final double oPksi       = 2 + excLvPeysLv;
-        final double hx          = storedParameters.getHx();
-        final double hy          = storedParameters.getHy();
-        final double h2          = hx * hx  + hy * hy;
-        final double oPh2        = 1 + h2;
-        final double hxsLvMhycLv = hx * sLv - hy * cLv;
-
-        final double epsilonOnNA        = epsilon / na;
-        final double epsilonOnNAKsi     = epsilonOnNA / ksi;
-        final double epsilonOnNAKsiSqrt = epsilonOnNAKsi / sqrt;
-        final double tOnEpsilonN        = 2 / (n * epsilon);
-        final double tEpsilonOnNASqrt   = 2 * epsilonOnNA / sqrt;
-        final double epsilonOnNAKsit    = epsilonOnNA / (2 * ksi);
-
-        // Kepler natural evolution
-        lvKepler = n * ksi * ksi / (oMe2 * epsilon);
-
-        // coefficients along T
-        aT  = tOnEpsilonN * sqrt;
-        exT = tEpsilonOnNASqrt * (ex + cLv);
-        eyT = tEpsilonOnNASqrt * (ey + sLv);
-
-        // coefficients along N
-        exN = -epsilonOnNAKsiSqrt * (2 * ey * ksi + oMe2 * sLv);
-        eyN =  epsilonOnNAKsiSqrt * (2 * ex * ksi + oMe2 * cLv);
-
-        // coefficients along Q
-        aQ  =  tOnEpsilonN * nu;
-        exQ =  epsilonOnNA * sLv;
-        eyQ = -epsilonOnNA * cLv;
-
-        // coefficients along S
-        aS  = tOnEpsilonN * ksi;
-        exS = epsilonOnNAKsi * (ex + oPksi * cLv);
-        eyS = epsilonOnNAKsi * (ey + oPksi * sLv);
-
-        // coefficients along W
-        lvW =  epsilonOnNAKsi * hxsLvMhycLv;
-        exW = -ey * lvW;
-        eyW =  ex * lvW;
-        hxW =  epsilonOnNAKsit * oPh2 * cLv;
-        hyW =  epsilonOnNAKsit * oPh2 * sLv;
-
-    }
+    abstract void initDerivatives(double[] yDot, Orbit currentOrbit)
+        throws PropagationException;
 
     /** Add the contribution of the Kepler evolution.
      * <p>Since the Kepler evolution is the most important, it should
      * be added after all the other ones, in order to improve
      * numerical accuracy.</p>
+     * @param mu central body gravitational constant
      */
-    protected void addKeplerContribution() {
-        storedYDot[5] += lvKepler;
-    }
-
-    /** Add the contribution of an acceleration expressed in (t, n, w)
-     * local orbital frame.
-     * @param t acceleration along the T axis (m/s<sup>2</sup>)
-     * @param n acceleration along the N axis (m/s<sup>2</sup>)
-     * @param w acceleration along the W axis (m/s<sup>2</sup>)
-     */
-    public void addTNWAcceleration(final double t, final double n, final double w) {
-        storedYDot[0] += aT  * t;
-        storedYDot[1] += exT * t + exN * n + exW * w;
-        storedYDot[2] += eyT * t + eyN * n + eyW * w;
-        storedYDot[3] += hxW * w;
-        storedYDot[4] += hyW * w;
-        storedYDot[5] += lvW * w;
-    }
-
-    /** Add the contribution of an acceleration expressed in (q, s, w)
-     * local orbital frame.
-     * @param q acceleration along the Q axis (m/s<sup>2</sup>)
-     * @param s acceleration along the S axis (m/s<sup>2</sup>)
-     * @param w acceleration along the W axis (m/s<sup>2</sup>)
-     */
-    public void addQSWAcceleration(final double q, final double s, final double w) {
-        storedYDot[0] += aQ  * q + aS  * s;
-        storedYDot[1] += exQ * q + exS * s + exW * w;
-        storedYDot[2] += eyQ * q + eyS * s + eyW * w;
-        storedYDot[3] += hxW * w;
-        storedYDot[4] += hyW * w;
-        storedYDot[5] += lvW * w;
-    }
-
+    public abstract void addKeplerContribution(final double mu);
 
     /** Add the contribution of an acceleration expressed in the inertial frame
      *  (it is important to make sure this acceleration is defined in the
@@ -302,26 +110,14 @@ public class TimeDerivativesEquations implements Serializable {
      * @param y acceleration along the Y axis (m/s<sup>2</sup>)
      * @param z acceleration along the Z axis (m/s<sup>2</sup>)
      */
-    public void addXYZAcceleration(final double x, final double y, final double z) {
-        addTNWAcceleration(x * lofT.getX() + y * lofT.getY() + z * lofT.getZ(),
-                           x * lofN.getX() + y * lofN.getY() + z * lofN.getZ(),
-                           x * lofW.getX() + y * lofW.getY() + z * lofW.getZ());
-    }
+    public abstract void addXYZAcceleration(final double x, final double y, final double z);
 
     /** Add the contribution of an acceleration expressed in some inertial frame.
      * @param gamma acceleration vector (m/s<sup>2</sup>)
      * @param frame frame in which acceleration is defined (must be an inertial frame)
      * @exception OrekitException if frame transforms cannot be computed
      */
-    public void addAcceleration(final Vector3D gamma, final Frame frame)
-        throws OrekitException {
-        final Transform t = frame.getTransformTo(storedParameters.getFrame(),
-                                                 storedParameters.getDate());
-        final Vector3D gammInRefFrame = t.transformVector(gamma);
-        addTNWAcceleration(Vector3D.dotProduct(gammInRefFrame, lofT),
-                           Vector3D.dotProduct(gammInRefFrame, lofN),
-                           Vector3D.dotProduct(gammInRefFrame, lofW));
-    }
+    public abstract void addAcceleration(final Vector3D gamma, final Frame frame) throws OrekitException;
 
     /** Add the contribution of the flow rate (dm/dt).
      * @param q the flow rate, must be negative (dm/dt)
@@ -334,37 +130,5 @@ public class TimeDerivativesEquations implements Serializable {
         storedYDot[6] += q;
     }
 
-    /** Get the first vector of the (q, s, w) local orbital frame.
-     * @return first vector of the (q, s, w) local orbital frame */
-    public Vector3D getQ() {
-        return lofQ;
-    }
-
-    /** Get the second vector of the (q, s, w) local orbital frame.
-     * @return second vector of the (q, s, w) local orbital frame */
-    public Vector3D getS() {
-        return lofS;
-    }
-
-    /** Get the first vector of the (t, n, w) local orbital frame.
-     * @return first vector of the (t, n, w) local orbital frame */
-    public Vector3D getT() {
-        return lofT;
-    }
-
-    /** Get the second vector of the (t, n, w) local orbital frame.
-     * @return second vector of the (t, n, w) local orbital frame */
-    public Vector3D getN() {
-        return lofN;
-    }
-
-    /** Get the third vector of both the (q, s, w) and (t, n, w) local orbital
-     * frames.
-     * @return third vector of both the (q, s, w) and (t, n, w) local orbital
-     * frames
-     */
-    public Vector3D getW() {
-        return lofW;
-    }
 
 }
diff --git a/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsCartesian.java b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsCartesian.java
new file mode 100644
index 0000000000..551a0b3dbe
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsCartesian.java
@@ -0,0 +1,114 @@
+/* Copyright 2002-2010 CS Centre National d'Études Spatiales
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.util.Arrays;
+
+import org.apache.commons.math.geometry.Vector3D;
+import org.apache.commons.math.util.FastMath;
+import org.orekit.errors.OrekitException;
+import org.orekit.errors.PropagationException;
+import org.orekit.frames.Frame;
+import org.orekit.frames.Transform;
+import org.orekit.orbits.CartesianOrbit;
+import org.orekit.orbits.Orbit;
+
+/** Implementation of the {@link TimeDerivativesEquations} interface for state arrays in cartesian coordinates
+*
+* <p>It implements Gauss equations for cartesian parameters. This implementation is specialized
+* for state vectors that have the following form:
+*   <pre>
+*     y[0] = x
+*     y[1] = y
+*     y[2] = z
+*     y[3] = v<sub>x</sub>
+*     y[4] = v<sub>y</sub>
+*     y[5] = v<sub>z</sub>
+*     y[6] = mass
+*   </pre>
+* where the six first parameters stands for the cartesian parameters and the 7<sup>th</sup>
+* for the mass (kg) at the current time.
+* </p>
+* @see org.orekit.orbits.CartesianOrbit
+* @see org.orekit.propagation.numerical.NumericalPropagator
+* @author Luc Maisonobe
+* @author Fabien Maussion
+* @author V&eacute;ronique Pommier-Maurussane
+* @version $Revision$ $Date$
+*/
+public class TimeDerivativesEquationsCartesian extends TimeDerivativesEquations {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = -1882870530923825699L;
+
+    /** Orbital parameters. */
+    private CartesianOrbit storedParameters;
+
+    /** Create a new instance.
+     * @param orbit current orbit parameters
+     */
+    public TimeDerivativesEquationsCartesian(final CartesianOrbit orbit) {
+        this.storedParameters = orbit;
+    }
+
+    /** {@inheritDoc} */
+    public void addAcceleration(final Vector3D gamma, final Frame frame)
+        throws OrekitException {
+        final Transform t = frame.getTransformTo(storedParameters.getFrame(),
+                                                 storedParameters.getDate());
+        final Vector3D gammInRefFrame = t.transformVector(gamma);
+        addXYZAcceleration(gammInRefFrame.getX(), gammInRefFrame.getY(), gammInRefFrame.getZ());
+    }
+
+    /** {@inheritDoc} */
+    public void addKeplerContribution(final double mu) {
+        final Vector3D position = storedParameters.getPVCoordinates().getPosition();
+        final double r2         = position.getNormSq();
+        final double coeff      = -mu / (r2 * FastMath.sqrt(r2));
+        storedYDot[3] += coeff * position.getX();
+        storedYDot[4] += coeff * position.getY();
+        storedYDot[5] += coeff * position.getZ();
+    }
+
+    /** {@inheritDoc} */
+    public void addXYZAcceleration(final double x, final double y, final double z) {
+        storedYDot[3] += x;
+        storedYDot[4] += y;
+        storedYDot[5] += z;
+    }
+
+    /** {@inheritDoc} */
+    void initDerivatives(final double[] yDot, final Orbit orbit)
+        throws PropagationException {
+
+        storedParameters = (CartesianOrbit) orbit;
+
+        // store derivatives array reference
+        this.storedYDot = yDot;
+
+        // initialize derivatives to zero
+        Arrays.fill(storedYDot, 0.0);
+
+        // position derivative is velocity
+        final Vector3D velocity = storedParameters.getPVCoordinates().getVelocity();
+        storedYDot[0] = velocity.getX();
+        storedYDot[1] = velocity.getY();
+        storedYDot[2] = velocity.getZ();
+
+    }
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsEquinoctial.java b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsEquinoctial.java
new file mode 100644
index 0000000000..c9c1d47550
--- /dev/null
+++ b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsEquinoctial.java
@@ -0,0 +1,280 @@
+/* Copyright 2002-2010 CS Communication & Systèmes
+ * Licensed to CS Communication & Systèmes (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS 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.orekit.propagation.numerical;
+
+import java.util.Arrays;
+
+import org.apache.commons.math.geometry.Vector3D;
+import org.apache.commons.math.util.FastMath;
+import org.orekit.errors.OrekitException;
+import org.orekit.errors.OrekitMessages;
+import org.orekit.errors.PropagationException;
+import org.orekit.frames.Frame;
+import org.orekit.frames.Transform;
+import org.orekit.orbits.EquinoctialOrbit;
+import org.orekit.orbits.Orbit;
+import org.orekit.utils.PVCoordinates;
+
+/** Implementation of the {@link TimeDerivativesEquations} interface for state arrays in cartesian coordinates
+ *
+ * <p>It implements Gauss equations for equinoctial parameters. This implementation is specialized for
+ * state vectors that have the following form:
+ *   <pre>
+ *     y[0] = a
+ *     y[1] = e<sub>x</sub>
+ *     y[2] = e<sub>y</sub>
+ *     y[3] = h<sub>x</sub>
+ *     y[4] = h<sub>y</sub>
+ *     y[5] = l<sub>v</sub>
+ *     y[6] = mass
+ *   </pre>
+ * where the six first parameters stands for the equinoctial parameters and the 7<sup>th</sup>
+ * for the mass (kg) at the current time.
+ * </p>
+ * @see org.orekit.orbits.EquinoctialOrbit
+ * @see org.orekit.propagation.numerical.NumericalPropagator
+ * @author Luc Maisonobe
+ * @author Fabien Maussion
+ * @author V&eacute;ronique Pommier-Maurussane
+ * @version $Revision$ $Date$
+ */
+public class TimeDerivativesEquationsEquinoctial extends TimeDerivativesEquations {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = -7676218190057010433L;
+
+    /** First vector of the (q, s, w) local orbital frame. */
+    private Vector3D lofQ;
+
+    /** Second vector of the (q, s, w) local orbital frame. */
+    private Vector3D lofS;
+
+    /** First vector of the (t, n, w) local orbital frame. */
+    private Vector3D lofT;
+
+    /** Second vector of the (t, n, w) local orbital frame. */
+    private Vector3D lofN;
+
+    /** Third vector of both the (q, s, w) and (t, n, w) local orbital frames. */
+    private Vector3D lofW;
+
+    // CHECKSTYLE: stop JavadocVariable check
+
+    /** Multiplicative coefficients for the perturbing accelerations along lofT. */
+    private double aT;
+    private double exT;
+    private double eyT;
+
+    /** Multiplicative coefficients for the perturbing accelerations along lofN. */
+    private double exN;
+    private double eyN;
+
+    /** Multiplicative coefficients for the perturbing accelerations along lofW. */
+    private double eyW;
+    private double exW;
+    private double hxW;
+    private double hyW;
+    private double lvW;
+
+    // CHECKSTYLE: resume JavadocVariable check
+
+    /** Kepler evolution on true latitude argument. */
+    private double lvKepler;
+
+    /** Orbital parameters. */
+    private EquinoctialOrbit storedParameters;
+
+    /** Create a new instance.
+     * @param orbit current orbit parameters
+     */
+    public TimeDerivativesEquationsEquinoctial(final EquinoctialOrbit orbit) {
+        this.storedParameters = orbit;
+        lofQ = Vector3D.ZERO;
+        lofS = Vector3D.ZERO;
+        lofT = Vector3D.ZERO;
+        lofN = Vector3D.ZERO;
+        lofW = Vector3D.ZERO;
+        updateOrbitalFrames();
+    }
+
+    /** Update the orbital frames. */
+    private void updateOrbitalFrames() {
+        // get the position/velocity vectors
+        final PVCoordinates pvCoordinates = storedParameters.getPVCoordinates();
+
+        // compute orbital plane normal vector
+        lofW = pvCoordinates.getMomentum().normalize();
+
+        // compute (q, s, w) local orbital frame
+        lofQ = pvCoordinates.getPosition().normalize();
+        lofS = Vector3D.crossProduct(lofW, lofQ);
+
+        // compute (t, n, w) local orbital frame
+        lofT = pvCoordinates.getVelocity().normalize();
+        lofN = Vector3D.crossProduct(lofW, lofT);
+    }
+
+
+    /** {@inheritDoc} */
+    public void initDerivatives(final double[] yDot, final Orbit orbit)
+        throws PropagationException {
+
+
+        storedParameters = (EquinoctialOrbit) orbit;
+        updateOrbitalFrames();
+
+        // store derivatives array reference
+        this.storedYDot = yDot;
+
+        // initialize derivatives to zero
+        Arrays.fill(storedYDot, 0.0);
+
+        // intermediate variables
+        final double ex  = storedParameters.getEquinoctialEx();
+        final double ey  = storedParameters.getEquinoctialEy();
+        final double ex2 = ex * ex;
+        final double ey2 = ey * ey;
+        final double e2  = ex2 + ey2;
+        final double e   = FastMath.sqrt(e2);
+        if (e >= 1) {
+            throw new PropagationException(OrekitMessages.ORBIT_BECOMES_HYPERBOLIC_UNABLE_TO_PROPAGATE_FURTHER, e);
+        }
+
+        // intermediate variables
+        final double oMe2        = (1 - e) * (1 + e);
+        final double epsilon     = FastMath.sqrt(oMe2);
+        final double a           = storedParameters.getA();
+        final double mu          = orbit.getMu();
+        final double na          = FastMath.sqrt(mu / a);
+        final double n           = na / a;
+        final double lv          = storedParameters.getLv();
+        final double cLv         = FastMath.cos(lv);
+        final double sLv         = FastMath.sin(lv);
+        final double excLv       = ex * cLv;
+        final double eysLv       = ey * sLv;
+        final double excLvPeysLv = excLv + eysLv;
+        final double ksi         = 1 + excLvPeysLv;
+        final double nu          = ex * sLv - ey * cLv;
+        final double sqrt        = FastMath.sqrt(ksi * ksi + nu * nu);
+        final double hx          = storedParameters.getHx();
+        final double hy          = storedParameters.getHy();
+        final double h2          = hx * hx  + hy * hy;
+        final double oPh2        = 1 + h2;
+        final double hxsLvMhycLv = hx * sLv - hy * cLv;
+
+        final double epsilonOnNA        = epsilon / na;
+        final double epsilonOnNAKsi     = epsilonOnNA / ksi;
+        final double epsilonOnNAKsiSqrt = epsilonOnNAKsi / sqrt;
+        final double tOnEpsilonN        = 2 / (n * epsilon);
+        final double tEpsilonOnNASqrt   = 2 * epsilonOnNA / sqrt;
+        final double epsilonOnNAKsit    = epsilonOnNA / (2 * ksi);
+
+        // Kepler natural evolution without the mu part
+        lvKepler = n * ksi * ksi / (FastMath.sqrt(mu) * oMe2 * epsilon);
+
+        // coefficients along T
+        aT  = tOnEpsilonN * sqrt;
+        exT = tEpsilonOnNASqrt * (ex + cLv);
+        eyT = tEpsilonOnNASqrt * (ey + sLv);
+
+        // coefficients along N
+        exN = -epsilonOnNAKsiSqrt * (2 * ey * ksi + oMe2 * sLv);
+        eyN =  epsilonOnNAKsiSqrt * (2 * ex * ksi + oMe2 * cLv);
+
+        // coefficients along W
+        lvW =  epsilonOnNAKsi * hxsLvMhycLv;
+        exW = -ey * lvW;
+        eyW =  ex * lvW;
+        hxW =  epsilonOnNAKsit * oPh2 * cLv;
+        hyW =  epsilonOnNAKsit * oPh2 * sLv;
+
+    }
+
+    /** {@inheritDoc} */
+    public void addKeplerContribution(final double mu) {
+        storedYDot[5] += lvKepler * FastMath.sqrt(mu);
+    }
+
+    /** Add the contribution of an acceleration expressed in (t, n, w)
+     * local orbital frame.
+     * @param t acceleration along the T axis (m/s<sup>2</sup>)
+     * @param n acceleration along the N axis (m/s<sup>2</sup>)
+     * @param w acceleration along the W axis (m/s<sup>2</sup>)
+     */
+    private void addTNWAcceleration(final double t, final double n, final double w) {
+        storedYDot[0] += aT  * t;
+        storedYDot[1] += exT * t + exN * n + exW * w;
+        storedYDot[2] += eyT * t + eyN * n + eyW * w;
+        storedYDot[3] += hxW * w;
+        storedYDot[4] += hyW * w;
+        storedYDot[5] += lvW * w;
+    }
+
+
+    /** {@inheritDoc} */
+    public void addXYZAcceleration(final double x, final double y, final double z) {
+        addTNWAcceleration(x * lofT.getX() + y * lofT.getY() + z * lofT.getZ(),
+                           x * lofN.getX() + y * lofN.getY() + z * lofN.getZ(),
+                           x * lofW.getX() + y * lofW.getY() + z * lofW.getZ());
+    }
+
+    /** {@inheritDoc} */
+    public void addAcceleration(final Vector3D gamma, final Frame frame)
+        throws OrekitException {
+        final Transform t = frame.getTransformTo(storedParameters.getFrame(),
+                                                 storedParameters.getDate());
+        final Vector3D gammInRefFrame = t.transformVector(gamma);
+        addTNWAcceleration(Vector3D.dotProduct(gammInRefFrame, lofT),
+                           Vector3D.dotProduct(gammInRefFrame, lofN),
+                           Vector3D.dotProduct(gammInRefFrame, lofW));
+    }
+
+
+    /** Get the first vector of the (q, s, w) local orbital frame.
+     * @return first vector of the (q, s, w) local orbital frame */
+    public Vector3D getQ() {
+        return lofQ;
+    }
+
+    /** Get the second vector of the (q, s, w) local orbital frame.
+     * @return second vector of the (q, s, w) local orbital frame */
+    public Vector3D getS() {
+        return lofS;
+    }
+
+    /** Get the first vector of the (t, n, w) local orbital frame.
+     * @return first vector of the (t, n, w) local orbital frame */
+    public Vector3D getT() {
+        return lofT;
+    }
+
+    /** Get the second vector of the (t, n, w) local orbital frame.
+     * @return second vector of the (t, n, w) local orbital frame */
+    public Vector3D getN() {
+        return lofN;
+    }
+
+    /** Get the third vector of both the (q, s, w) and (t, n, w) local orbital
+     * frames.
+     * @return third vector of both the (q, s, w) and (t, n, w) local orbital
+     * frames
+     */
+    public Vector3D getW() {
+        return lofW;
+    }
+
+}
diff --git a/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsWithJacobians.java b/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsWithJacobians.java
deleted file mode 100644
index a78c6cbb85..0000000000
--- a/src/main/java/org/orekit/propagation/numerical/TimeDerivativesEquationsWithJacobians.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright 2002-2010 CS Communication & Systèmes
- * Licensed to CS Communication & Systèmes (CS) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS 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.orekit.propagation.numerical;
-
-import java.util.Arrays;
-
-import org.orekit.errors.PropagationException;
-import org.orekit.orbits.EquinoctialOrbit;
-
-
-/** This class sums up the contribution of several forces into
- *  orbit and mass derivatives and partial derivatives.
- * <p>
- * As of 5.0, this class is still considered experimental, so use it with care.
- * </p>
- * <p>
- * It is related to {@link NumericalPropagatorWithJacobians} like
- * {@link TimeDerivativesEquations} to {@link NumericalPropagator}.
- * </p>
- *
- * @see TimeDerivativesEquations
- * @see NumericalPropagator
- * @see NumericalPropagatorWithJacobians
- *
- * @author Pascal Parraud
- * @version $Revision$ $Date$
- */
-public class TimeDerivativesEquationsWithJacobians extends TimeDerivativesEquations {
-
-    /** Serializable UID. */
-    private static final long serialVersionUID = -1378236382967204061L;
-
-    /** Reference to the orbital parameters jacobian array to initialize. */
-    private double[][] storedDFDY;
-
-    /** Reference to the force models parameters jacobian array to initialize. */
-    private double[][] storedDFDP;
-
-    /** Create a new instance.
-     * @param orbit current orbit parameters
-     */
-    protected TimeDerivativesEquationsWithJacobians(final EquinoctialOrbit orbit) {
-        super(orbit);
-    }
-
-    /** Initialize all derivatives and jacobians to zero.
-     * @param yDot reference to the array where to put the derivatives.
-     * @param dFdY placeholder array where to put the jacobian of the ODE with respect to the state vector
-     * @param dFdP placeholder array where to put the jacobian of the ODE with respect to the parameters
-     * @param orbit current orbit parameters
-     * @exception PropagationException if the orbit evolve out of supported range
-     */
-    protected void initDerivativesWithJacobians(final double[] yDot,
-                                                final double[][] dFdY,
-                                                final double[][] dFdP,
-                                                final EquinoctialOrbit orbit)
-        throws PropagationException {
-
-        initDerivatives(yDot, orbit);
-
-        // store jacobians reference
-        this.storedDFDY = dFdY;
-        this.storedDFDP = dFdP;
-
-        // initialize jacobians to zero
-        for (final double[] row : storedDFDY) {
-            Arrays.fill(row, 0.0);
-        }
-
-        for (final double[] row : storedDFDP) {
-            Arrays.fill(row, 0.0);
-        }
-
-    }
-
-}
diff --git a/src/main/java/org/orekit/propagation/package.html b/src/main/java/org/orekit/propagation/package.html
index 11ff5daa25..ffc19ef73c 100644
--- a/src/main/java/org/orekit/propagation/package.html
+++ b/src/main/java/org/orekit/propagation/package.html
@@ -57,10 +57,6 @@ This package provides tools to propagate orbital states with different methods.
  ask for the next first time derivative, etc. until it reaches the final 
  asked date.
 </p>
-<p> The {@link org.orekit.propagation.numerical.NumericalPropagatorWithJacobians}
- is a specialized class which enables to compute jacobians with respect to orbital
- parameters and force models parameters while propagating.
-</p>
 
 @author Luc Maisonobe
 @author Fabien Maussion
diff --git a/src/main/java/org/orekit/propagation/precomputed/IntegratedEphemeris.java b/src/main/java/org/orekit/propagation/precomputed/IntegratedEphemeris.java
index 0fab821dbf..f3080379f5 100644
--- a/src/main/java/org/orekit/propagation/precomputed/IntegratedEphemeris.java
+++ b/src/main/java/org/orekit/propagation/precomputed/IntegratedEphemeris.java
@@ -16,19 +16,21 @@
  */
 package org.orekit.propagation.precomputed;
 
+import java.util.List;
+
 import org.apache.commons.math.exception.MathUserException;
 import org.apache.commons.math.ode.ContinuousOutputModel;
 import org.apache.commons.math.ode.sampling.StepHandler;
 import org.apache.commons.math.ode.sampling.StepInterpolator;
-import org.orekit.attitudes.AttitudeLaw;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.OrekitMessages;
 import org.orekit.errors.PropagationException;
 import org.orekit.frames.Frame;
-import org.orekit.orbits.EquinoctialOrbit;
 import org.orekit.propagation.BoundedPropagator;
 import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.numerical.AdditionalStateAndEquations;
 import org.orekit.propagation.numerical.ModeHandler;
+import org.orekit.propagation.numerical.StateMapper;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.PVCoordinates;
 
@@ -70,7 +72,10 @@ public class IntegratedEphemeris
     implements BoundedPropagator, ModeHandler, StepHandler {
 
     /** Serializable UID. */
-    private static final long serialVersionUID = 3997196481383054719L;
+    private static final long serialVersionUID = -7217642644695032540L;
+
+    /** Mapper between spacecraft state and simple array. */
+    private StateMapper mapper;
 
     /** Reference date. */
     private AbsoluteDate initializedReference;
@@ -81,9 +86,6 @@ public class IntegratedEphemeris
     /** Central body gravitational constant. */
     private double initializedMu;
 
-    /** Attitude law. */
-    private AttitudeLaw initializedAttitudeLaw;
-
     /** Start date of the integration (can be min or max). */
     private AbsoluteDate startDate;
 
@@ -104,13 +106,12 @@ public class IntegratedEphemeris
     }
 
     /** {@inheritDoc} */
-    public void initialize(final AbsoluteDate reference,
-                           final Frame frame, final double mu,
-                           final AttitudeLaw attitudeLaw) {
-        this.initializedReference   = reference;
-        this.initializedFrame       = frame;
-        this.initializedMu          = mu;
-        this.initializedAttitudeLaw = attitudeLaw;
+    public void initialize(final StateMapper mapper, final List <AdditionalStateAndEquations> addStateAndEqu,
+                           final AbsoluteDate reference, final Frame frame, final double mu) {
+        this.mapper               = mapper;
+        this.initializedReference = reference;
+        this.initializedFrame     = frame;
+        this.initializedMu        = mu;
 
         // dates will be set when last step is handled
         startDate        = null;
@@ -128,18 +129,12 @@ public class IntegratedEphemeris
                                                date, minDate, maxDate);
             }
             model.setInterpolatedTime(date.durationFrom(startDate));
-            final double[] state = model.getInterpolatedState();
-
-            final EquinoctialOrbit eq =
-                new EquinoctialOrbit(state[0], state[1], state[2],
-                                     state[3], state[4], state[5], 2, initializedFrame, date, initializedMu);
-            final double mass = state[6];
-
-            return new SpacecraftState(eq, initializedAttitudeLaw.getAttitude(eq), mass);
-        } catch (OrekitException oe) {
-            throw new PropagationException(oe);
+            return mapper.mapArrayToState(model.getInterpolatedState(), date,
+                                          initializedMu, initializedFrame);
         } catch (MathUserException mue) {
             throw new PropagationException(mue, mue.getGeneralPattern(), mue.getArguments());
+        } catch (OrekitException oe) {
+            throw new PropagationException(oe);
         }
     }
 
@@ -164,13 +159,14 @@ public class IntegratedEphemeris
     }
 
     /** {@inheritDoc} */
-    public void handleStep(final StepInterpolator interpolator,
-                           final boolean isLast) {
+    public void handleStep(final StepInterpolator interpolator, final boolean isLast) {
         model.handleStep(interpolator, isLast);
         if (isLast) {
-            startDate = initializedReference.shiftedBy(model.getInitialTime());
-            maxDate   = initializedReference.shiftedBy(model.getFinalTime());
-            if (maxDate.durationFrom(startDate) < 0) {
+            final double tI = model.getInitialTime();
+            final double tF = model.getFinalTime();
+            startDate = initializedReference.shiftedBy(tI);
+            maxDate   = initializedReference.shiftedBy(tF);
+            if (tF < tI) {
                 minDate = maxDate;
                 maxDate = startDate;
             } else {
diff --git a/src/main/java/org/orekit/propagation/sampling/AdaptedStepHandler.java b/src/main/java/org/orekit/propagation/sampling/AdaptedStepHandler.java
index 5b8776eb35..8e8060ba92 100644
--- a/src/main/java/org/orekit/propagation/sampling/AdaptedStepHandler.java
+++ b/src/main/java/org/orekit/propagation/sampling/AdaptedStepHandler.java
@@ -17,18 +17,20 @@
 package org.orekit.propagation.sampling;
 
 import java.io.Serializable;
+import java.util.List;
 
 import org.apache.commons.math.exception.MathUserException;
 import org.apache.commons.math.ode.sampling.StepHandler;
 import org.apache.commons.math.ode.sampling.StepInterpolator;
-import org.orekit.attitudes.AttitudeLaw;
 import org.orekit.errors.OrekitException;
+import org.orekit.errors.OrekitMessages;
 import org.orekit.errors.PropagationException;
 import org.orekit.frames.Frame;
-import org.orekit.orbits.EquinoctialOrbit;
-import org.orekit.orbits.Orbit;
 import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.numerical.AdditionalEquations;
+import org.orekit.propagation.numerical.AdditionalStateAndEquations;
 import org.orekit.propagation.numerical.ModeHandler;
+import org.orekit.propagation.numerical.StateMapper;
 import org.orekit.time.AbsoluteDate;
 
 /** Adapt an {@link org.orekit.propagation.sampling.OrekitStepHandler}
@@ -42,6 +44,12 @@ public class AdaptedStepHandler
     /** Serializable UID. */
     private static final long serialVersionUID = -8067262257341902186L;
 
+    /** Mapper between spacecraft state and simple array. */
+    private StateMapper mapper;
+
+    /** Additional state and equations list. */
+    private List <AdditionalStateAndEquations> addStateAndEqu;
+
     /** Reference date. */
     private AbsoluteDate initializedReference;
 
@@ -51,9 +59,6 @@ public class AdaptedStepHandler
     /** Central body attraction coefficient. */
     private double initializedMu;
 
-    /** Attitude law. */
-    private AttitudeLaw initializedAttitudeLaw;
-
     /** Underlying handler. */
     private final OrekitStepHandler handler;
 
@@ -68,11 +73,12 @@ public class AdaptedStepHandler
     }
 
     /** {@inheritDoc} */
-    public void initialize(final AbsoluteDate reference, final Frame frame,
-                           final double mu, final AttitudeLaw attitudeLaw) {
+    public void initialize(final StateMapper stateMapper, final List <AdditionalStateAndEquations> stateAndEqu,
+                           final AbsoluteDate reference, final Frame frame, final double mu) {
+        this.mapper                 = stateMapper;
+        this.addStateAndEqu         = stateAndEqu;
         this.initializedReference   = reference;
         this.initializedFrame       = frame;
-        this.initializedAttitudeLaw = attitudeLaw;
         this.initializedMu          = mu;
     }
 
@@ -144,16 +150,46 @@ public class AdaptedStepHandler
         try {
             final double[] y = rawInterpolator.getInterpolatedState();
             final AbsoluteDate interpolatedDate = initializedReference.shiftedBy(rawInterpolator.getInterpolatedTime());
-            final Orbit orbit =
-                new EquinoctialOrbit(y[0], y[1], y[2], y[3], y[4], y[5],
-                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                     initializedFrame, interpolatedDate, initializedMu);
-            return new SpacecraftState(orbit, initializedAttitudeLaw.getAttitude(orbit), y[6]);
+            return mapper.mapArrayToState(y, interpolatedDate, initializedMu, initializedFrame);
         } catch (MathUserException mue) {
             throw new PropagationException(mue, mue.getGeneralPattern(), mue.getArguments());
         }
     }
 
+    /** Get the interpolated additional state corresponding to the additional equations.
+     * @param addEqu additional equation used as a reference for selection
+     * @return interpolated additional state at the current interpolation date
+     * @exception OrekitException if state cannot be interpolated or converted
+     * @see #getInterpolatedDate()
+     * @see #setInterpolatedDate(AbsoluteDate)
+     */
+    public double[] getInterpolatedAdditionalState(final AdditionalEquations addEqu)
+        throws OrekitException {
+        try {
+
+            // propagate the whole state vector
+            final double[] y = rawInterpolator.getInterpolatedState();
+
+            // get portion of additional state to update
+            int index = 7;
+            for (final AdditionalStateAndEquations stateAndEqu : addStateAndEqu) {
+                if (stateAndEqu.getAdditionalEquations() == addEqu) {
+                    final double[] state = stateAndEqu.getAdditionalState();
+                    System.arraycopy(y, index, state, 0, state.length);
+                    return state;
+                }
+                // incrementing index
+                index += stateAndEqu.getAdditionalState().length;
+            }
+
+            throw new OrekitException(OrekitMessages.UNKNOWN_ADDITIONAL_EQUATION);
+
+        } catch (MathUserException mue) {
+            throw new PropagationException(mue, mue.getGeneralPattern(), mue.getArguments());
+        }
+
+    }
+
     /** Check is integration direction is forward in date.
      * @return true if integration is forward in date
      */
diff --git a/src/main/java/org/orekit/propagation/sampling/BasicStepInterpolator.java b/src/main/java/org/orekit/propagation/sampling/BasicStepInterpolator.java
index c0a3bc696e..28ab851e32 100644
--- a/src/main/java/org/orekit/propagation/sampling/BasicStepInterpolator.java
+++ b/src/main/java/org/orekit/propagation/sampling/BasicStepInterpolator.java
@@ -20,6 +20,7 @@ import org.orekit.errors.OrekitException;
 import org.orekit.errors.PropagationException;
 import org.orekit.propagation.BasicPropagator;
 import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.numerical.AdditionalEquations;
 import org.orekit.time.AbsoluteDate;
 
 /** Implementation of the {@link OrekitStepInterpolator} interface based
@@ -87,6 +88,13 @@ public class BasicStepInterpolator implements OrekitStepInterpolator {
         interpolatedState = propagator.propagate(date);
     }
 
+    /** {@inheritDoc} */
+    public double[] getInterpolatedAdditionalState(final AdditionalEquations addEqu)
+        throws OrekitException {
+        // This should never happen
+        throw OrekitException.createInternalError(null);
+    }
+
     /** Shift one step forward.
      * Copy the current date into the previous date, hence preparing the
      * interpolator for future calls to {@link #storeDate storeDate}
@@ -106,4 +114,5 @@ public class BasicStepInterpolator implements OrekitStepInterpolator {
         setInterpolatedDate(currentDate);
     }
 
+
 }
diff --git a/src/main/java/org/orekit/propagation/sampling/OrekitStepInterpolator.java b/src/main/java/org/orekit/propagation/sampling/OrekitStepInterpolator.java
index 50e9cdf62a..96bb206c7c 100644
--- a/src/main/java/org/orekit/propagation/sampling/OrekitStepInterpolator.java
+++ b/src/main/java/org/orekit/propagation/sampling/OrekitStepInterpolator.java
@@ -21,6 +21,7 @@ import java.io.Serializable;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.PropagationException;
 import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.numerical.AdditionalEquations;
 import org.orekit.time.AbsoluteDate;
 
 /** This interface is a space-dynamics aware step interpolator.
@@ -73,6 +74,15 @@ public interface OrekitStepInterpolator extends Serializable {
      */
     SpacecraftState getInterpolatedState() throws OrekitException;
 
+    /** Get the interpolated additional state corresponding to the additional equations.
+     * @param addEqu additional equation used as a reference for selection
+     * @return interpolated additional state at the current interpolation date
+     * @exception OrekitException if state cannot be interpolated or converted
+     * @see #getInterpolatedDate()
+     * @see #setInterpolatedDate(AbsoluteDate)
+     */
+    double[] getInterpolatedAdditionalState(AdditionalEquations addEqu) throws OrekitException;
+
     /** Check is integration direction is forward in date.
      * @return true if integration is forward in date
      */
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_de.properties b/src/main/resources/META-INF/localization/OrekitMessages_de.properties
index e159329962..dd340dd297 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_de.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_de.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = <MISSING TRANSLATION!>
 # unknown parameter {0}
 UNKNOWN_PARAMETER = unbekannter Parameter {0}
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = <MISSING TRANSLATION!>
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = <MISSING TRANSLATION!>
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = <MISSING TRANSLATION!>
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = <MISSING TRANSLATION!>
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = <MISSING TRANSLATION!>
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = <MISSING TRANSLATION!>
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = <MISSING TRANSLATION!>
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = <MISSING TRANSLATION!>
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = <MISSING TRANSLATION!>
 
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_en.properties b/src/main/resources/META-INF/localization/OrekitMessages_en.properties
index c561165411..8c0ea681cb 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_en.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_en.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = unexpected two elevation value
 # unknown parameter {0}
 UNKNOWN_PARAMETER = unknown parameter {0}
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = unsupported parameter name {0}: supported names {1}, {2}
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = unknown additional equation
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = partial derivatives can be propagated only in cartesian parameters type
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = state jacobian has {0} rows but parameters jacobian has {1} rows
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = initial jacobian matrix has {0} columns, but {1} parameters have been selected
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = hyperbolic orbits cannot be handled as {0} instances
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = invalid preamble field in CCSDS date: {0}
 
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_es.properties b/src/main/resources/META-INF/localization/OrekitMessages_es.properties
index 03c77a7acd..d00979f6c1 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_es.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_es.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = <MISSING TRANSLATION!>
 # unknown parameter {0}
 UNKNOWN_PARAMETER = par\u00e1metro {0} desconocido
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = <MISSING TRANSLATION!>
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = <MISSING TRANSLATION!>
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = <MISSING TRANSLATION!>
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = <MISSING TRANSLATION!>
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = <MISSING TRANSLATION!>
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = <MISSING TRANSLATION!>
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = <MISSING TRANSLATION!>
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = <MISSING TRANSLATION!>
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = <MISSING TRANSLATION!>
 
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_fr.properties b/src/main/resources/META-INF/localization/OrekitMessages_fr.properties
index 704d41597d..0b8e7717e7 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_fr.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_fr.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = donn\u00e9es inattendues, deux
 # unknown parameter {0}
 UNKNOWN_PARAMETER = param\u00e8tre {0} inconnu
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = param\u00e8tre {0} inconnu : param\u00e8tres connus {1}, {2}
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = \u00e9quation additionelle inconnue
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = les d\u00e9riv\u00e9es partielles ne peuvent \u00eatre propag\u00e9es qu''en param\u00e8tres cart\u00e9siens
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = la jacobienne de l''\u00e9tat est une matrice {0}x{1}, alors qu''elle devrait \u00eatre soit une matrice 6x6 soit une matrice 7x7
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = la jacobienne de l''\u00e9tat a {0} lignes alors que la jacobienne des param\u00e8tres en a {1}
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = la matrice initiale a {0} colonnes alors que {1} param\u00e8tres ont \u00e9t\u00e9 s\u00e9lectionn\u00e9s
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = l''orbite devrait \u00eatre soit elliptique avec a > 0 et e < 1 ou hyperbolique avec a < 0 et e > 1, a = {0}, e = {1}
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = les orbites hyperboliques ne peuvent pas \u00eatre des instances de {0}
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = pr\u00e9ambule invalide dans une date CCSDS : {0}
 
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_gl.properties b/src/main/resources/META-INF/localization/OrekitMessages_gl.properties
index 6fe471ccf3..3c706a2f75 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_gl.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_gl.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = <MISSING TRANSLATION!>
 # unknown parameter {0}
 UNKNOWN_PARAMETER = par\u00e1metro {0} desco\u00f1ecido
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = <MISSING TRANSLATION!>
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = <MISSING TRANSLATION!>
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = <MISSING TRANSLATION!>
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = <MISSING TRANSLATION!>
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = <MISSING TRANSLATION!>
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = <MISSING TRANSLATION!>
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = <MISSING TRANSLATION!>
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = <MISSING TRANSLATION!>
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = <MISSING TRANSLATION!>
 
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_it.properties b/src/main/resources/META-INF/localization/OrekitMessages_it.properties
index 0988870357..55bf929bf6 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_it.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_it.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = <MISSING TRANSLATION!>
 # unknown parameter {0}
 UNKNOWN_PARAMETER = parametro {0} sconosciuto
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = <MISSING TRANSLATION!>
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = <MISSING TRANSLATION!>
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = <MISSING TRANSLATION!>
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = <MISSING TRANSLATION!>
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = <MISSING TRANSLATION!>
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = <MISSING TRANSLATION!>
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = <MISSING TRANSLATION!>
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = <MISSING TRANSLATION!>
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = <MISSING TRANSLATION!>
 
diff --git a/src/main/resources/META-INF/localization/OrekitMessages_no.properties b/src/main/resources/META-INF/localization/OrekitMessages_no.properties
index c44d3679ef..1e045e0524 100644
--- a/src/main/resources/META-INF/localization/OrekitMessages_no.properties
+++ b/src/main/resources/META-INF/localization/OrekitMessages_no.properties
@@ -220,6 +220,30 @@ UNEXPECTED_TWO_ELEVATION_VALUES_FOR_ONE_AZIMUTH = <MISSING TRANSLATION!>
 # unknown parameter {0}
 UNKNOWN_PARAMETER = ukjent parametere {0}
 
+# unsupported parameter name {0}: supported names {1}, {2}
+UNSUPPORTED_PARAMETER_1_2 = <MISSING TRANSLATION!>
+
+# unknown additional equation
+UNKNOWN_ADDITIONAL_EQUATION = <MISSING TRANSLATION!>
+
+# partial derivatives can be propagated only in cartesian parameters type
+PARTIAL_DERIVATIVES_ONLY_IN_CARTESIAN = <MISSING TRANSLATION!>
+
+# state jacobian is a {0}x{1} matrix, it should be either a 6x6 or a 7x7 matrix
+STATE_JACOBIAN_NEITHER_6X6_NOR_7X7 = <MISSING TRANSLATION!>
+
+# state jacobian has {0} rows but parameters jacobian has {1} rows
+STATE_AND_PARAMETERS_JACOBIANS_ROWS_MISMATCH = <MISSING TRANSLATION!>
+
+# initial jacobian matrix has {0} columns, but {1} parameters have been selected
+INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH = <MISSING TRANSLATION!>
+
+# orbit should be either elliptic with a > 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1}
+ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = <MISSING TRANSLATION!>
+
+# hyperbolic orbits cannot be handled as {0} instances
+HYPERBOLIC_ORBIT_NOT_HANDLED_AS = <MISSING TRANSLATION!>
+
 # invalid preamble field in CCSDS date: {0}
 CCSDS_DATE_INVALID_PREAMBLE_FIELD = <MISSING TRANSLATION!>
 
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 2765c28153..fca260b867 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -153,6 +153,33 @@
         fixed an error in FramesFactory when getting ITRF2005 and TIRF2000 frames:
         ignoreTidalEffects was handled wrong.
       </action>
+      <action dev="luc" type="update" >
+        removed serialization of some cached data in frames
+      </action>
+      <action dev="luc" type="fix" >
+        fixed deserialization problems of frame singletons, they were not unique any more
+      </action>
+      <action dev="v&#233;ronique" type="add" >
+        numerical propagation can now be done either using equinoctial parameters or
+        cartesian parameters, thus allowing propagation of any kind of trajectories,
+        including hyperbolic orbits used for interplanetary missions or atmospheric
+        re-entry trajectories
+      </action>
+      <action dev="v&#233;ronique" type="update" >
+        completely revamped the partial derivatives matrices computation using the additional
+        equations mechanism
+      </action>
+      <action dev="v&#233;ronique" type="add" >
+        added a mechanism to integrate user-supplied additional equations alongside with
+        orbital parameters during numerical propagation
+      </action>
+      <action dev="luc" type="update">
+        use A. W. Odell and R. H. Gooding (1986) fast and robust solver for Kepler equation
+      </action>
+      <action dev="luc" type="add">
+        keplerian and cartesian orbits now support hyperbolic orbits (i.e. eccentricity greater
+        than 1, and in this case negative semi major axis by convention)
+      </action>
       <action dev="luc" type="fix">
         fixed an error in LofOffset attitude mode: the computed attitude was reversed
         with respect to the specification
diff --git a/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java b/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java
index 87bfd4ed05..67c2664e82 100644
--- a/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java
+++ b/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java
@@ -140,7 +140,7 @@ public class LofOffsetPointingTest {
                                                    sPlus.getAttitude().getRotation(),
                                                    2 * h);
         Assert.assertTrue(spin0.getNorm() > 1.0e-3);
-        Assert.assertEquals(0.0, spin0.subtract(reference).getNorm(), 4.0e-11);
+        Assert.assertEquals(0.0, spin0.subtract(reference).getNorm(), 1.0e-10);
 
     }
 
diff --git a/src/test/java/org/orekit/attitudes/LofOffsetTest.java b/src/test/java/org/orekit/attitudes/LofOffsetTest.java
index 76a5c72634..4e014ac7bd 100644
--- a/src/test/java/org/orekit/attitudes/LofOffsetTest.java
+++ b/src/test/java/org/orekit/attitudes/LofOffsetTest.java
@@ -195,7 +195,7 @@ public class LofOffsetTest {
         Vector3D reference = Attitude.estimateSpin(sMinus.getAttitude().getRotation(),
                                                    sPlus.getAttitude().getRotation(),
                                                    2 * h);
-        Assert.assertEquals(0.0, spin0.subtract(reference).getNorm(), 4.0e-11);
+        Assert.assertEquals(0.0, spin0.subtract(reference).getNorm(), 1.0e-10);
 
     }
 
diff --git a/src/test/java/org/orekit/errors/OrekitMessagesTest.java b/src/test/java/org/orekit/errors/OrekitMessagesTest.java
index 799408fd41..97ba642664 100644
--- a/src/test/java/org/orekit/errors/OrekitMessagesTest.java
+++ b/src/test/java/org/orekit/errors/OrekitMessagesTest.java
@@ -30,7 +30,7 @@ public class OrekitMessagesTest {
 
     @Test
     public void testMessageNumber() {
-        Assert.assertEquals(89, OrekitMessages.values().length);
+        Assert.assertEquals(97, OrekitMessages.values().length);
     }
 
     @Test
diff --git a/src/test/java/org/orekit/frames/FrameTest.java b/src/test/java/org/orekit/frames/FrameTest.java
index 20ee53cf59..74f6a10c84 100644
--- a/src/test/java/org/orekit/frames/FrameTest.java
+++ b/src/test/java/org/orekit/frames/FrameTest.java
@@ -145,8 +145,8 @@ public class FrameTest {
         Frame rotatingPadFrame  = new TopocentricFrame(new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                                                                             Constants.WGS84_EARTH_FLATTENING,
                                                                             itrf),
-                                                       new GeodeticPoint(Math.toRadians(5.0),
-                                                                                              Math.toRadians(-100.0),
+                                                       new GeodeticPoint(FastMath.toRadians(5.0),
+                                                                                              FastMath.toRadians(-100.0),
                                                                                               0.0),
                                                        "launch pad");
 
diff --git a/src/test/java/org/orekit/frames/TODFrameAlternateConfigurationTest.java b/src/test/java/org/orekit/frames/TODFrameAlternateConfigurationTest.java
index 0fe8e7451a..193fcab5b3 100644
--- a/src/test/java/org/orekit/frames/TODFrameAlternateConfigurationTest.java
+++ b/src/test/java/org/orekit/frames/TODFrameAlternateConfigurationTest.java
@@ -142,8 +142,8 @@ public class TODFrameAlternateConfigurationTest {
             throws OrekitException {
             super(ignoreNutationCorrection, factoryKey);
         }
-        protected void setInterpolatedNutationElements(final double t) {
-            computeNutationElements(t);
+        public double[] getInterpolatedNutationElements(final double t) {
+            return computeNutationElements(t);
         }
     }
 
diff --git a/src/test/java/org/orekit/frames/TODFrameTest.java b/src/test/java/org/orekit/frames/TODFrameTest.java
index 740a51f095..14391d8739 100644
--- a/src/test/java/org/orekit/frames/TODFrameTest.java
+++ b/src/test/java/org/orekit/frames/TODFrameTest.java
@@ -46,7 +46,7 @@ public class TODFrameTest {
             double previousEQE = currentEQE;
             currentEQE = tod.getEquationOfEquinoxes(d);
             if (!Double.isNaN(previousEQE)) {
-                double deltaMicroAS = 3.6e9 * Math.toDegrees(currentEQE - previousEQE);
+                double deltaMicroAS = 3.6e9 * FastMath.toDegrees(currentEQE - previousEQE);
                 if ((dt - h) * dt > 0) {
                     // away from switch date, equation of equinox should decrease at
                     // about 1.06 micro arcsecond per second
diff --git a/src/test/java/org/orekit/orbits/CartesianParametersTest.java b/src/test/java/org/orekit/orbits/CartesianParametersTest.java
index eb37fb942b..d7af72d09b 100644
--- a/src/test/java/org/orekit/orbits/CartesianParametersTest.java
+++ b/src/test/java/org/orekit/orbits/CartesianParametersTest.java
@@ -16,6 +16,12 @@
  */
 package org.orekit.orbits;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
 import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.util.FastMath;
 import org.apache.commons.math.util.MathUtils;
@@ -167,6 +173,76 @@ public class CartesianParametersTest {
         }
     }
 
+    @Test
+    public void testSerialization()
+      throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
+        Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0);
+        Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0);
+        PVCoordinates pvCoordinates = new PVCoordinates( position, velocity);
+        CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu);
+        Assert.assertEquals(42255170.003, orbit.getA(), 1.0e-3);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream    oos = new ObjectOutputStream(bos);
+        oos.writeObject(orbit);
+
+        Assert.assertTrue(bos.size () >  1400);
+        Assert.assertTrue(bos.size () <  1500);
+
+        ByteArrayInputStream  bis = new ByteArrayInputStream(bos.toByteArray());
+        ObjectInputStream     ois = new ObjectInputStream(bis);
+        CartesianOrbit deserialized  = (CartesianOrbit) ois.readObject();
+        Vector3D dp = orbit.getPVCoordinates().getPosition().subtract(deserialized.getPVCoordinates().getPosition());
+        Vector3D dv = orbit.getPVCoordinates().getVelocity().subtract(deserialized.getPVCoordinates().getVelocity());
+        Assert.assertEquals(0.0, dp.getNorm(), 1.0e-10);
+        Assert.assertEquals(0.0, dv.getNorm(), 1.0e-10);
+
+    }
+
+    @Test
+    public void testShiftElliptic() {
+        Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0);
+        Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0);
+        PVCoordinates pvCoordinates = new PVCoordinates( position, velocity);
+        CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu);
+        testShift(orbit, new KeplerianOrbit(orbit), 1.0e-13);
+    }
+
+    @Test
+    public void testShiftCircular() {
+        Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0);
+        Vector3D velocity = new Vector3D(FastMath.sqrt(mu / position.getNorm()), position.orthogonal());
+        PVCoordinates pvCoordinates = new PVCoordinates( position, velocity);
+        CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu);
+        testShift(orbit, new CircularOrbit(orbit), 1.0e-15);
+    }
+
+    @Test
+    public void testShiftHyperbolic() {
+        Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0);
+        Vector3D velocity = new Vector3D(3 * FastMath.sqrt(mu / position.getNorm()), position.orthogonal());
+        PVCoordinates pvCoordinates = new PVCoordinates( position, velocity);
+        CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu);
+        testShift(orbit, new KeplerianOrbit(orbit), 1.0e-15);
+    }
+
+    private void testShift(CartesianOrbit tested, Orbit reference, double threshold) {
+        for (double dt = - 1000; dt < 1000; dt += 10.0) {
+
+            PVCoordinates pvTested    = tested.shiftedBy(dt).getPVCoordinates();
+            Vector3D      pTested     = pvTested.getPosition();
+            Vector3D      vTested     = pvTested.getVelocity();
+
+            PVCoordinates pvReference = reference.shiftedBy(dt).getPVCoordinates();
+            Vector3D      pReference  = pvReference.getPosition();
+            Vector3D      vReference  = pvReference.getVelocity();
+
+            Assert.assertEquals(0, pTested.subtract(pReference).getNorm(), threshold * pReference.getNorm());
+            Assert.assertEquals(0, vTested.subtract(vReference).getNorm(), threshold * vReference.getNorm());
+
+        }
+    }
+
     @Test(expected=IllegalArgumentException.class)
     public void testNonInertialFrame() throws IllegalArgumentException {
 
diff --git a/src/test/java/org/orekit/orbits/KeplerianParametersTest.java b/src/test/java/org/orekit/orbits/KeplerianParametersTest.java
index 15d0484293..7bab02c8c3 100644
--- a/src/test/java/org/orekit/orbits/KeplerianParametersTest.java
+++ b/src/test/java/org/orekit/orbits/KeplerianParametersTest.java
@@ -79,6 +79,24 @@ public class KeplerianParametersTest {
         Assert.assertEquals(MathUtils.normalizeAngle(paramCir.getLE(), kepCir.getLE()), kepCir.getLE(), Utils.epsilonAngle * FastMath.abs(kepCir.getLE()));
         Assert.assertEquals(MathUtils.normalizeAngle(paramCir.getLv(), kepCir.getLv()), kepCir.getLv(), Utils.epsilonAngle * FastMath.abs(kepCir.getLv()));
 
+        // hyperbolic orbit
+        KeplerianOrbit kepHyp =
+            new KeplerianOrbit(-24464560.0, 1.7311, 0.122138, 3.10686, 1.00681,
+                                    0.048363, KeplerianOrbit.MEAN_ANOMALY, 
+                                    FramesFactory.getEME2000(), date, mu);
+
+        Vector3D posHyp = kepHyp.getPVCoordinates().getPosition();
+        Vector3D vitHyp = kepHyp.getPVCoordinates().getVelocity();
+
+        KeplerianOrbit paramHyp = new KeplerianOrbit(new PVCoordinates(posHyp,vitHyp), 
+                                                  FramesFactory.getEME2000(), date, mu);
+        Assert.assertEquals(paramHyp.getA(), kepHyp.getA(), Utils.epsilonTest * FastMath.abs(kepHyp.getA()));
+        Assert.assertEquals(paramHyp.getE(), kepHyp.getE(), Utils.epsilonE * FastMath.abs(kepHyp.getE()));
+        Assert.assertEquals(MathUtils.normalizeAngle(paramHyp.getI(), kepHyp.getI()), kepHyp.getI(), Utils.epsilonAngle * FastMath.abs(kepHyp.getI()));
+        Assert.assertEquals(MathUtils.normalizeAngle(paramHyp.getPerigeeArgument(), kepHyp.getPerigeeArgument()), kepHyp.getPerigeeArgument(), Utils.epsilonAngle * FastMath.abs(kepHyp.getPerigeeArgument()));
+        Assert.assertEquals(MathUtils.normalizeAngle(paramHyp.getRightAscensionOfAscendingNode(), kepHyp.getRightAscensionOfAscendingNode()), kepHyp.getRightAscensionOfAscendingNode(), Utils.epsilonAngle * FastMath.abs(kepHyp.getRightAscensionOfAscendingNode()));
+        Assert.assertEquals(MathUtils.normalizeAngle(paramHyp.getMeanAnomaly(), kepHyp.getMeanAnomaly()), kepHyp.getMeanAnomaly(), Utils.epsilonAngle * FastMath.abs(kepHyp.getMeanAnomaly()));
+
     }
 
     public void testKeplerianToCartesian() {
@@ -377,7 +395,7 @@ public class KeplerianParametersTest {
     @Test
     public void testSymmetry() {
 
-        // elliptic and non equatorail orbit
+        // elliptic and non equatorial orbit
         Vector3D position = new Vector3D(-4947831., -3765382., -3708221.);
         Vector3D velocity = new Vector3D(-2079., 5291., -7842.);
         double mu = 3.9860047e14;
@@ -426,6 +444,53 @@ public class KeplerianParametersTest {
         Assert.assertEquals(0.00094277682051291315229, orbit.getKeplerianMeanMotion(), 1.0e-16);
     }
 
+    @Test
+    public void testHyperbola() {
+        KeplerianOrbit orbit = new KeplerianOrbit(-10000000.0, 2.5, 0.3, 0, 0, 0.0,
+                                                  KeplerianOrbit.TRUE_ANOMALY,
+                                                  FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH,
+                                                  mu);
+        Vector3D perigeeP  = orbit.getPVCoordinates().getPosition();
+        Vector3D u = perigeeP.normalize();
+        Vector3D focus1 = Vector3D.ZERO;
+        Vector3D focus2 = new Vector3D(-2 * orbit.getA() * orbit.getE(), u);
+        for (double dt = -5000; dt < 5000; dt += 60) {
+            PVCoordinates pv = orbit.shiftedBy(dt).getPVCoordinates();
+            double d1 = Vector3D.distance(pv.getPosition(), focus1);
+            double d2 = Vector3D.distance(pv.getPosition(), focus2);
+            Assert.assertEquals(-2 * orbit.getA(), FastMath.abs(d1 - d2), 1.0e-6);
+            KeplerianOrbit rebuilt =
+                new KeplerianOrbit(pv, orbit.getFrame(), orbit.getDate().shiftedBy(dt), mu);
+            Assert.assertEquals(-10000000.0, rebuilt.getA(), 1.0e-6);
+            Assert.assertEquals(2.5, rebuilt.getE(), 1.0e-13);
+        }
+    }
+
+    @Test
+    public void testKeplerEquation() {
+
+        for (double M = -6 * FastMath.PI; M < 6 * FastMath.PI; M += 0.01) {
+            KeplerianOrbit pElliptic =
+                new KeplerianOrbit(24464560.0, 0.7311, 2.1, 3.10686, 1.00681,
+                                   M, KeplerianOrbit.MEAN_ANOMALY, 
+                                   FramesFactory.getEME2000(), date, mu);
+            double E = pElliptic.getEccentricAnomaly();
+            double e = pElliptic.getE();
+            Assert.assertEquals(M, E - e * FastMath.sin(E), 2.0e-14);
+        }
+
+        for (double M = -6 * FastMath.PI; M < 6 * FastMath.PI; M += 0.01) {
+            KeplerianOrbit pAlmostParabolic =
+                new KeplerianOrbit(24464560.0, 0.9999, 2.1, 3.10686, 1.00681,
+                                   M, KeplerianOrbit.MEAN_ANOMALY, 
+                                   FramesFactory.getEME2000(), date, mu);
+            double E = pAlmostParabolic.getEccentricAnomaly();
+            double e = pAlmostParabolic.getE();
+            Assert.assertEquals(M, E - e * FastMath.sin(E), 3.0e-13);
+        }
+
+    }
+
     @Before
     public void setUp() {
 
diff --git a/src/test/java/org/orekit/propagation/SpacecraftStateTest.java b/src/test/java/org/orekit/propagation/SpacecraftStateTest.java
index 7f7804cf4e..ccaa10df78 100644
--- a/src/test/java/org/orekit/propagation/SpacecraftStateTest.java
+++ b/src/test/java/org/orekit/propagation/SpacecraftStateTest.java
@@ -24,7 +24,6 @@ import junit.framework.Assert;
 import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
 import org.apache.commons.math.geometry.Rotation;
 import org.apache.commons.math.geometry.Vector3D;
-import org.apache.commons.math.optimization.OptimizationException;
 import org.apache.commons.math.util.FastMath;
 import org.junit.After;
 import org.junit.Before;
@@ -50,7 +49,7 @@ public class SpacecraftStateTest {
 
     @Test
     public void testInterpolationError()
-        throws ParseException, OrekitException, OptimizationException {
+        throws ParseException, OrekitException {
 
 
         // polynomial models for interpolation error in position, velocity and attitude
@@ -110,7 +109,7 @@ public class SpacecraftStateTest {
 
     @Test
     public void testTransform()
-        throws ParseException, OrekitException, OptimizationException {
+        throws ParseException, OrekitException {
 
         double maxDP = 0;
         double maxDV = 0;
diff --git a/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java
index 71e180177c..05a3c4f181 100644
--- a/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java
+++ b/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java
@@ -488,7 +488,7 @@ public class EcksteinHechlerPropagatorTest {
     @Test(expected = PropagationException.class)
     public void hyperbolic() throws PropagationException {
         KeplerianOrbit hyperbolic =
-            new KeplerianOrbit(1.0e10, 2, 0, 0, 0, 0, KeplerianOrbit.TRUE_ANOMALY,
+            new KeplerianOrbit(-1.0e10, 2, 0, 0, 0, 0, KeplerianOrbit.TRUE_ANOMALY,
                                FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH, 3.986004415e14);
         EcksteinHechlerPropagator propagator =
             new EcksteinHechlerPropagator(hyperbolic, ae, mu, c20, c30, c40, c50, c60);
diff --git a/src/test/java/org/orekit/propagation/events/DetectorTest.java b/src/test/java/org/orekit/propagation/events/DetectorTest.java
index 6aa91050a1..edeba3e102 100644
--- a/src/test/java/org/orekit/propagation/events/DetectorTest.java
+++ b/src/test/java/org/orekit/propagation/events/DetectorTest.java
@@ -33,6 +33,7 @@ import org.orekit.propagation.sampling.OrekitFixedStepHandler;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.time.TimeScale;
 import org.orekit.time.TimeScalesFactory;
+import org.orekit.utils.Constants;
 import org.orekit.utils.PVCoordinates;
 
 public class DetectorTest {
@@ -98,6 +99,7 @@ public class DetectorTest {
     @Before
     public void setUp() {
         Utils.setDataRoot("regular-data");
+        mu = Constants.EIGEN5C_EARTH_MU;
     }
 
 }
diff --git a/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorTest.java b/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorTest.java
index 6d3f540417..3b9bf564a1 100644
--- a/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorTest.java
+++ b/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorTest.java
@@ -16,7 +16,10 @@
  */
 package org.orekit.propagation.numerical;
 
-import org.apache.commons.math.exception.util.DummyLocalizable;
+import java.io.IOException;
+import java.text.ParseException;
+
+import org.apache.commons.math.exception.util.LocalizedFormats;
 import org.apache.commons.math.geometry.Vector3D;
 import org.apache.commons.math.ode.nonstiff.AdaptiveStepsizeIntegrator;
 import org.apache.commons.math.ode.nonstiff.ClassicalRungeKuttaIntegrator;
@@ -26,16 +29,23 @@ import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.orekit.Utils;
 import org.orekit.errors.OrekitException;
 import org.orekit.errors.PropagationException;
+import org.orekit.frames.Frame;
 import org.orekit.frames.FramesFactory;
+import org.orekit.orbits.CartesianOrbit;
 import org.orekit.orbits.EquinoctialOrbit;
 import org.orekit.orbits.Orbit;
 import org.orekit.propagation.SpacecraftState;
+import org.orekit.propagation.events.ApsideDetector;
 import org.orekit.propagation.events.DateDetector;
+import org.orekit.propagation.numerical.NumericalPropagator.PropagationParametersType;
 import org.orekit.propagation.sampling.OrekitStepHandler;
 import org.orekit.propagation.sampling.OrekitStepInterpolator;
 import org.orekit.time.AbsoluteDate;
+import org.orekit.time.TimeScale;
+import org.orekit.time.TimeScalesFactory;
 import org.orekit.utils.PVCoordinates;
 
 
@@ -97,6 +107,26 @@ public class NumericalPropagatorTest {
 
     }
 
+    @Test
+    public void testCartesian() throws OrekitException {
+
+        // Propagation of the initial at t + dt
+        final double dt = 3200;
+        propagator.setPropagationParametersType(NumericalPropagator.PropagationParametersType.CARTESIAN);
+        final PVCoordinates finalState = 
+            propagator.propagate(initDate.shiftedBy(dt)).getPVCoordinates();
+        final Vector3D pFin = finalState.getPosition();
+        final Vector3D vFin = finalState.getVelocity();
+
+        // Check results
+        final PVCoordinates reference = initialState.shiftedBy(dt).getPVCoordinates();
+        final Vector3D pRef = reference.getPosition();
+        final Vector3D vRef = reference.getVelocity();
+        Assert.assertEquals(0, pRef.subtract(pFin).getNorm(), 0.4);
+        Assert.assertEquals(0, vRef.subtract(vFin).getNorm(), 0.0002);
+
+    }
+
     @Test(expected=OrekitException.class)
     public void testException() throws OrekitException {
         propagator.setMasterMode(new OrekitStepHandler() {
@@ -109,7 +139,7 @@ public class NumericalPropagatorTest {
                     Assert.assertTrue(interpolator.getInterpolatedDate().compareTo(previousCall) < 0);
                 }
                 if (--countDown == 0) {
-                    throw new PropagationException((Throwable) null, new DummyLocalizable("dummy error"));
+                    throw new PropagationException(LocalizedFormats.SIMPLE_MESSAGE, "dummy error");
                 }
             }
             public boolean requiresDenseOutput() {
@@ -211,8 +241,70 @@ public class NumericalPropagatorTest {
         this.gotHere = gotHere;
     }
 
+    @Test
+    public void testEventDetectionBug() throws OrekitException, IOException, ParseException {
+
+        TimeScale utc = TimeScalesFactory.getUTC();
+        AbsoluteDate initialDate = new AbsoluteDate(2005, 1, 1, 0, 0, 0.0, utc);
+        double duration = 100000.;
+        AbsoluteDate endDate = new AbsoluteDate(initialDate,duration);
+
+        // Initialization of the frame EME2000
+        Frame EME2000 = FramesFactory.getEME2000();
+
+
+        // Initial orbit            
+        double a = 35786000. + 6378137.0;
+        double e = 0.70;
+        double rApogee = a*(1+e);
+        double vApogee = FastMath.sqrt(mu*(1-e)/(a*(1+e)));
+        Orbit geo = new CartesianOrbit(new PVCoordinates(new Vector3D(rApogee, 0., 0.), 
+                                                         new Vector3D(0., vApogee, 0.)), EME2000, 
+                                                         initialDate, mu);
+
+
+        duration = geo.getKeplerianPeriod();
+        endDate = new AbsoluteDate(initialDate, duration);
+
+        // Numerical Integration
+        final double minStep  = 0.001;
+        final double maxStep  = 1000;
+        final double initStep = 60;
+        final double[] absTolerance = {
+            0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001};
+        final double[] relTolerance = {
+            1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7};
+
+        AdaptiveStepsizeIntegrator integrator =
+            new DormandPrince853Integrator(minStep, maxStep, absTolerance, relTolerance);
+        integrator.setInitialStepSize(initStep);
+
+        // Numerical propagator based on the integrator
+        propagator = new NumericalPropagator(integrator);
+        double mass = 1000.;
+        SpacecraftState initialState = new SpacecraftState(geo, mass);
+        propagator.setInitialState(initialState);
+        propagator.setPropagationParametersType(PropagationParametersType.CARTESIAN);
+
+
+        // Set the events Detectors
+        ApsideDetector event1 = new ApsideDetector(geo);
+        propagator.addEventDetector(event1);
+
+        // Set the propagation mode
+        propagator.setSlaveMode();          
+
+        // Propagate
+        SpacecraftState finalState = propagator.propagate(endDate);
+
+        // we should stop long before endDate
+        Assert.assertTrue(endDate.durationFrom(finalState.getDate()) > 40000.0);
+    }
+
+
     @Before
     public void setUp() {
+        Utils.setDataRoot("compressed-data");
         mu  = 3.9860047e14;
         final Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6);
         final Vector3D velocity = new Vector3D(-500.0, 8000.0, 1000.0);
diff --git a/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobiansTest.java b/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobiansTest.java
deleted file mode 100644
index 8b1cf93c34..0000000000
--- a/src/test/java/org/orekit/propagation/numerical/NumericalPropagatorWithJacobiansTest.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/* Copyright 2002-2010 CS Communication & Systèmes
- * Licensed to CS Communication & Systèmes (CS) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS 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.orekit.propagation.numerical;
-
-import org.apache.commons.math.ode.nonstiff.AdaptiveStepsizeIntegrator;
-import org.apache.commons.math.ode.nonstiff.DormandPrince853Integrator;
-import org.apache.commons.math.util.FastMath;
-import org.apache.commons.math.util.MathUtils;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.orekit.Utils;
-import org.orekit.bodies.CelestialBodyFactory;
-import org.orekit.errors.OrekitException;
-import org.orekit.errors.PropagationException;
-import org.orekit.forces.ForceModelWithJacobians;
-import org.orekit.forces.SphericalSpacecraft;
-import org.orekit.forces.drag.DragForce;
-import org.orekit.forces.radiation.SolarRadiationPressure;
-import org.orekit.frames.FramesFactory;
-import org.orekit.orbits.EquinoctialOrbit;
-import org.orekit.propagation.SpacecraftState;
-import org.orekit.time.AbsoluteDate;
-import org.orekit.time.TimeScalesFactory;
-import org.orekit.utils.Constants;
-
-
-public class NumericalPropagatorWithJacobiansTest {
-
-    private AbsoluteDate                     initDate;
-    private SphericalSpacecraft              spaceCraft;
-    private SpacecraftState                  initialState;
-    private NumericalPropagatorWithJacobians propagator;
-
-    // Integrator parameters
-    private final double minStep = 0.001;
-    private final double maxStep = 1000.0;
-    private final double[] absTolV = {0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001};
-    private final double[] relTolV = {1.0e-10, 1.0e-7, 1.0e-7, 1.0e-10, 1.0e-10, 1.0e-10, 1.0e-10};
-
-    // Orbit parameters : position = (7.0e6, 1.0e6, 4.0e6) ; velocity = (-500.0, 8000.0, 1000.0)
-    private final double a  =  1.2123382253763368E7;
-    private final double ex =  0.33088598908457206;
-    private final double ey = -0.119544860585116;
-    private final double hx =  0.07403074327464344;
-    private final double hy = -0.25499478239043855;
-    private final double lv =  0.1602263984451438;
-    private final double mu =  3.9860047e14;
-
-    // Force models parameters
-    private final double drag = 0.4; // drag coeff.
-    private final double srpr = 0.9; // solar radiation pressure coeff.
-
-    // Threshold for test acceptance
-    private final double ERRMAX = FastMath.sqrt(MathUtils.EPSILON);
-
-    @Test
-    public void testWithoutJacobian() throws OrekitException {
-
-        // Propagation of the initial at t + dt
-        // NumericalPropagatorWithJacobians behaves just the
-        // same as NumericalPropagator for simple propagation
-        final double dt = 300;
-        final SpacecraftState finalState = 
-            propagator.propagate(initDate.shiftedBy(dt));
-
-        // Check results
-        final double n = FastMath.sqrt(initialState.getMu() / initialState.getA()) / initialState.getA();
-        Assert.assertEquals(initialState.getA(),    finalState.getA(),    1.0e-10);
-        Assert.assertEquals(initialState.getEquinoctialEx(),    finalState.getEquinoctialEx(),    1.0e-10);
-        Assert.assertEquals(initialState.getEquinoctialEy(),    finalState.getEquinoctialEy(),    1.0e-10);
-        Assert.assertEquals(initialState.getHx(),    finalState.getHx(),    1.0e-10);
-        Assert.assertEquals(initialState.getHy(),    finalState.getHy(),    1.0e-10);
-        Assert.assertEquals(initialState.getLM() + n * dt, finalState.getLM(), 2.0e-8);
-    }
-
-    @Test
-    public void testKeplerianJacobian() throws OrekitException {
-    	double[][] dFdY = new double[7][7];
-    	double[][] dFdP = new double[7][0];
-        final double dt = 300;
-        propagator.setInitialState(initialState);
-        propagator.propagate(initDate.shiftedBy(dt), dFdY, dFdP);
-
-        // Check results
-        // without forces, the orbit is keplerian
-        // all elements but the latitude argument are constant 
-        for (int i = 0; i < dFdY.length; i++) {
-        	if (i != 5) {
-                for (int j = 0; j < dFdY[i].length; j++) {
-                	if (i != j) {
-                        Assert.assertEquals(dFdY[i][j], 0.0, MathUtils.EPSILON);
-                	} else {
-                        Assert.assertEquals(dFdY[i][j], 1.0, MathUtils.EPSILON);
-                	}
-                }
-        	}
-        }
-    }
-
-    @Test
-    public void testOrbitalParametersJacobian() throws OrekitException {
-
-    	double[][] dFdY = new double[7][7];
-    	double[][] dFdP = new double[7][0];
-    	final double dt = 3;
-
-    	ForceModelWithJacobians sunPressure =
-        	new SolarRadiationPressure(CelestialBodyFactory.getSun(),
-                                       Constants.WGS84_EARTH_EQUATORIAL_RADIUS, spaceCraft);
-        propagator.addForceModel(sunPressure);
-        propagator.setInitialState(initialState);
-        final SpacecraftState finalState = 
-            propagator.propagate(initDate.shiftedBy(dt), dFdY, dFdP);
-
-    	final double da = absTolV[0]*1.e1;
-        propagator.resetInitialState(
-            new SpacecraftState(new EquinoctialOrbit(a + da, ex, ey, hx, hy, lv,
-                                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                                     FramesFactory.getEME2000(), initDate, mu)));
-        final SpacecraftState endStateDa = propagator.propagate(initDate.shiftedBy(dt));
-        // Check results
-	    final double dAda0  = (endStateDa.getA() - finalState.getA()) / da;
-        final double dExda0 = (endStateDa.getEquinoctialEx() - finalState.getEquinoctialEx()) / da;
-        final double dEyda0 = (endStateDa.getEquinoctialEy() - finalState.getEquinoctialEy()) / da;
-        final double dHxda0 = (endStateDa.getHx() - finalState.getHx()) / da;
-        final double dHyda0 = (endStateDa.getHy() - finalState.getHy()) / da;
-        final double dLvda0 = (endStateDa.getLv() - finalState.getLv()) / da;
-        final double dMda0  = (endStateDa.getMass() - finalState.getMass()) / da;
-
-        Assert.assertTrue(FastMath.abs((dAda0  - dFdY[0][0])/finalState.getA()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dExda0 - dFdY[1][0])/finalState.getEquinoctialEx()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dEyda0 - dFdY[2][0])/finalState.getEquinoctialEy()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dHxda0 - dFdY[3][0])/finalState.getHx()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dHyda0 - dFdY[4][0])/finalState.getHy()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dLvda0 - dFdY[5][0])/finalState.getHy()) < ERRMAX);
-        Assert.assertEquals(dMda0, dFdY[6][0], 0.0);
-
-    	final double dex = absTolV[1]*1.e1;
-        propagator.resetInitialState(
-            new SpacecraftState(new EquinoctialOrbit(a, ex + dex, ey, hx, hy, lv,
-                                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                                     FramesFactory.getEME2000(), initDate, mu)));
-        final SpacecraftState endStateDex = propagator.propagate(initDate.shiftedBy(dt));
-        // Check results
-	    final double dAdex0  = (endStateDex.getA() - finalState.getA()) / dex;
-        final double dExdex0 = (endStateDex.getEquinoctialEx() - finalState.getEquinoctialEx()) / dex;
-        final double dEydex0 = (endStateDex.getEquinoctialEy() - finalState.getEquinoctialEy()) / dex;
-        final double dHxdex0 = (endStateDex.getHx() - finalState.getHx()) / dex;
-        final double dHydex0 = (endStateDex.getHy() - finalState.getHy()) / dex;
-        final double dLvdex0 = (endStateDex.getLv() - finalState.getLv()) / dex;
-        final double dMdex0  = (endStateDex.getMass() - finalState.getMass()) / dex;
-
-        Assert.assertTrue(FastMath.abs((dAdex0  - dFdY[0][1])/finalState.getA()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dExdex0 - dFdY[1][1])/finalState.getEquinoctialEx()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dEydex0 - dFdY[2][1])/finalState.getEquinoctialEy()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dHxdex0 - dFdY[3][1])/finalState.getHx()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dHydex0 - dFdY[4][1])/finalState.getHy()) < ERRMAX);
-        Assert.assertTrue(FastMath.abs((dLvdex0 - dFdY[5][1])/finalState.getHy()) < ERRMAX);
-        Assert.assertEquals(dMdex0, dFdY[6][1], 0.0);
-
-    	final double dey = absTolV[2]*1.e1;
-        propagator.resetInitialState(
-            new SpacecraftState(new EquinoctialOrbit(a, ex, ey + dey, hx, hy, lv,
-                                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                                     FramesFactory.getEME2000(), initDate, mu)));
-        final SpacecraftState endStateDey = propagator.propagate(initDate.shiftedBy(dt));
-        // Check results
-	    final double dAdey0  = (endStateDey.getA() - finalState.getA()) / dey;
-        final double dExdey0 = (endStateDey.getEquinoctialEx() - finalState.getEquinoctialEx()) / dey;
-        final double dEydey0 = (endStateDey.getEquinoctialEy() - finalState.getEquinoctialEy()) / dey;
-        final double dHxdey0 = (endStateDey.getHx() - finalState.getHx()) / dey;
-        final double dHydey0 = (endStateDey.getHy() - finalState.getHy()) / dey;
-        final double dLvdey0 = (endStateDey.getLv() - finalState.getLv()) / dey;
-        final double dMdey0  = (endStateDey.getMass() - finalState.getMass()) / dey;
-
-        Assert.assertTrue(FastMath.abs(dAdey0  - dFdY[0][2])/finalState.getA() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dExdey0 - dFdY[1][2])/finalState.getEquinoctialEx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dEydey0 - dFdY[2][2])/finalState.getEquinoctialEy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHxdey0 - dFdY[3][2])/finalState.getHx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHydey0 - dFdY[4][2])/finalState.getHy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dLvdey0 - dFdY[5][2])/finalState.getLv() < ERRMAX);
-        Assert.assertEquals(dMdey0, dFdY[6][2], 0.0);
-
-    	final double dhx = absTolV[3]*1.e1;
-        propagator.resetInitialState(
-            new SpacecraftState(new EquinoctialOrbit(a, ex, ey, hx + dhx, hy, lv,
-                                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                                     FramesFactory.getEME2000(), initDate, mu)));
-        final SpacecraftState endStateDhx = propagator.propagate(initDate.shiftedBy(dt));
-        // Check results
-	    final double dAdhx0  = (endStateDhx.getA() - finalState.getA()) / dhx;
-        final double dExdhx0 = (endStateDhx.getEquinoctialEx() - finalState.getEquinoctialEx()) / dhx;
-        final double dEydhx0 = (endStateDhx.getEquinoctialEy() - finalState.getEquinoctialEy()) / dhx;
-        final double dHxdhx0 = (endStateDhx.getHx() - finalState.getHx()) / dhx;
-        final double dHydhx0 = (endStateDhx.getHy() - finalState.getHy()) / dhx;
-        final double dLvdhx0 = (endStateDhx.getLv() - finalState.getLv()) / dhx;
-        final double dMdhx0  = (endStateDhx.getMass() - finalState.getMass()) / dhx;
-
-        Assert.assertTrue(FastMath.abs(dAdhx0  - dFdY[0][3])/finalState.getA() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dExdhx0 - dFdY[1][3])/finalState.getEquinoctialEx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dEydhx0 - dFdY[2][3])/finalState.getEquinoctialEy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHxdhx0 - dFdY[3][3])/finalState.getHx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHydhx0 - dFdY[4][3])/finalState.getHy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dLvdhx0 - dFdY[5][3])/finalState.getLv() < ERRMAX);
-        Assert.assertEquals(dMdhx0, dFdY[6][3], 0.0);
-
-    	final double dhy = absTolV[4]*1.e1;
-        propagator.resetInitialState(
-            new SpacecraftState(new EquinoctialOrbit(a, ex, ey, hx, hy + dhy, lv,
-                                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                                     FramesFactory.getEME2000(), initDate, mu)));
-        final SpacecraftState endStateDhy = propagator.propagate(initDate.shiftedBy(dt));
-        // Check results
-	    final double dAdhy0  = (endStateDhy.getA() - finalState.getA()) / dhy;
-        final double dExdhy0 = (endStateDhy.getEquinoctialEx() - finalState.getEquinoctialEx()) / dhy;
-        final double dEydhy0 = (endStateDhy.getEquinoctialEy() - finalState.getEquinoctialEy()) / dhy;
-        final double dHxdhy0 = (endStateDhy.getHx() - finalState.getHx()) / dhy;
-        final double dHydhy0 = (endStateDhy.getHy() - finalState.getHy()) / dhy;
-        final double dLvdhy0 = (endStateDhy.getLv() - finalState.getLv()) / dhy;
-        final double dMdhy0  = (endStateDhy.getMass() - finalState.getMass()) / dhy;
-
-        Assert.assertTrue(FastMath.abs(dAdhy0  - dFdY[0][4])/finalState.getA() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dExdhy0 - dFdY[1][4])/finalState.getEquinoctialEx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dEydhy0 - dFdY[2][4])/finalState.getEquinoctialEy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHxdhy0 - dFdY[3][4])/finalState.getHx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHydhy0 - dFdY[4][4])/finalState.getHy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dLvdhy0 - dFdY[5][4])/finalState.getLv() < ERRMAX);
-        Assert.assertEquals(dMdhy0, dFdY[6][4], 0.0);
-
-    	final double dlv = absTolV[5]*1.e1;
-        propagator.resetInitialState(
-            new SpacecraftState(new EquinoctialOrbit(a, ex, ey, hx, hy, lv + dlv,
-                                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                                     FramesFactory.getEME2000(), initDate, mu)));
-        final SpacecraftState endStateDlv = propagator.propagate(initDate.shiftedBy(dt));
-        // Check results
-	    final double dAdlv0  = (endStateDlv.getA() - finalState.getA()) / dlv;
-        final double dExdlv0 = (endStateDlv.getEquinoctialEx() - finalState.getEquinoctialEx()) / dlv;
-        final double dEydlv0 = (endStateDlv.getEquinoctialEy() - finalState.getEquinoctialEy()) / dlv;
-        final double dHxdlv0 = (endStateDlv.getHx() - finalState.getHx()) / dlv;
-        final double dHydlv0 = (endStateDlv.getHy() - finalState.getHy()) / dlv;
-        final double dLvdlv0 = (endStateDlv.getLv() - finalState.getLv()) / dlv;
-        final double dMdlv0  = (endStateDlv.getMass() - finalState.getMass()) / dlv;
-
-        Assert.assertTrue(FastMath.abs(dAdlv0  - dFdY[0][5])/finalState.getA() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dExdlv0 - dFdY[1][5])/finalState.getEquinoctialEx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dEydlv0 - dFdY[2][5])/finalState.getEquinoctialEy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHxdlv0 - dFdY[3][5])/finalState.getHx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHydlv0 - dFdY[4][5])/finalState.getHy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dLvdlv0 - dFdY[5][5])/finalState.getLv() < ERRMAX);
-        Assert.assertEquals(dMdlv0, dFdY[6][5], 0.0);
-    }
-
-    @Test
-    public void testForceParameterJacobian() throws OrekitException {
-    	double[][] dFdY = new double[7][7];
-    	double[][] dFdP = new double[7][1];
-        final double dt = 300;
-
-        ForceModelWithJacobians sunPressure =
-        	new SolarRadiationPressure(CelestialBodyFactory.getSun(),
-                                       Constants.WGS84_EARTH_EQUATORIAL_RADIUS, spaceCraft);
-        propagator.addForceModel(sunPressure);
-    	propagator.selectParameters(new String[] {SolarRadiationPressure.ABSORPTION_COEFFICIENT});
-        propagator.setInitialState(initialState);
-        final SpacecraftState finalState = propagator.propagate(initDate.shiftedBy(dt), dFdY, dFdP);
-
-    	propagator.removeForceModels();
-        final double dp = srpr * 0.1;
-        final double srprDP = srpr + dp;
-    	sunPressure.setParameter(SolarRadiationPressure.ABSORPTION_COEFFICIENT, srprDP);
-        propagator.addForceModel(sunPressure);
-        propagator.setInitialState(initialState);
-        final SpacecraftState endStateDP = propagator.propagate(initDate.shiftedBy(dt));
-
-        // Check results
-        final double dAdP  = (endStateDP.getA() - finalState.getA()) / dp;
-        final double dExdP = (endStateDP.getEquinoctialEx() - finalState.getEquinoctialEx()) / dp;
-        final double dEydP = (endStateDP.getEquinoctialEy() - finalState.getEquinoctialEy()) / dp;
-        final double dHxdP = (endStateDP.getHx() - finalState.getHx()) / dp;
-        final double dHydP = (endStateDP.getHy() - finalState.getHy()) / dp;
-        final double dLvdP = (endStateDP.getLv() - finalState.getLv()) / dp;
-
-        Assert.assertTrue(FastMath.abs(dAdP  - dFdP[0][0])/finalState.getA() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dExdP - dFdP[1][0])/finalState.getEquinoctialEx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dEydP - dFdP[2][0])/finalState.getEquinoctialEy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHxdP - dFdP[3][0])/finalState.getHx() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dHydP - dFdP[4][0])/finalState.getHy() < ERRMAX);
-        Assert.assertTrue(FastMath.abs(dLvdP - dFdP[5][0])/finalState.getLv() < ERRMAX);
-    }
-
-    @Test(expected=PropagationException.class)
-    public void testException() throws OrekitException {
-    	double[][] dFdY = null;
-    	double[][] dFdP = null;
-        final double dt = 300;
-    	propagator.removeForceModels();
-    	propagator.selectParameters(new String[] {DragForce.DRAG_COEFFICIENT});
-        propagator.propagate(initDate.shiftedBy(dt), dFdY, dFdP);
-    }
-
-    @Before
-    public void setUp() {
-
-    	Utils.setDataRoot("regular-data");
-
-        initDate = new AbsoluteDate(2003, 1, 1, TimeScalesFactory.getTAI());
-        initialState =
-            new SpacecraftState(
-                new EquinoctialOrbit(a, ex, ey, hx, hy, lv,
-                                     EquinoctialOrbit.TRUE_LATITUDE_ARGUMENT,
-                                     FramesFactory.getEME2000(), initDate, mu));
-        AdaptiveStepsizeIntegrator integrator =
-            new DormandPrince853Integrator(minStep, maxStep, absTolV, relTolV);
-        propagator = new NumericalPropagatorWithJacobians(integrator);
-        propagator.setInitialState(initialState);
-
-        // Spacecraft definition for force models
-        final double surf = 25.;
-        spaceCraft = new SphericalSpacecraft(surf, drag, srpr, srpr);
-    }
-
-    @After
-    public void tearDown() {
-        initDate = null;
-        initialState = null;
-        propagator = null;
-    }
-
-}
-
diff --git a/src/test/java/org/orekit/propagation/numerical/IntegratedEphemerisTest.java b/src/test/java/org/orekit/propagation/precomputed/IntegratedEphemerisTest.java
similarity index 97%
rename from src/test/java/org/orekit/propagation/numerical/IntegratedEphemerisTest.java
rename to src/test/java/org/orekit/propagation/precomputed/IntegratedEphemerisTest.java
index 59e8058f85..bf832d23ea 100644
--- a/src/test/java/org/orekit/propagation/numerical/IntegratedEphemerisTest.java
+++ b/src/test/java/org/orekit/propagation/precomputed/IntegratedEphemerisTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.orekit.propagation.numerical;
+package org.orekit.propagation.precomputed;
 
 import java.io.FileNotFoundException;
 
@@ -30,6 +30,7 @@ import org.orekit.orbits.Orbit;
 import org.orekit.propagation.BoundedPropagator;
 import org.orekit.propagation.SpacecraftState;
 import org.orekit.propagation.analytical.KeplerianPropagator;
+import org.orekit.propagation.numerical.NumericalPropagator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.Constants;
 import org.orekit.utils.PVCoordinates;
diff --git a/src/test/java/org/orekit/time/AbsoluteDateTest.java b/src/test/java/org/orekit/time/AbsoluteDateTest.java
index 71c93529cc..2959237671 100644
--- a/src/test/java/org/orekit/time/AbsoluteDateTest.java
+++ b/src/test/java/org/orekit/time/AbsoluteDateTest.java
@@ -248,7 +248,7 @@ public class AbsoluteDateTest {
     public void testCCSDSUnsegmented() throws OrekitException {
 
         AbsoluteDate reference = new AbsoluteDate("2002-05-23T12:34:56.789", TimeScalesFactory.getUTC());
-        double lsb = Math.pow(2.0, -24);
+        double lsb = FastMath.pow(2.0, -24);
 
         byte[] timeCCSDSEpoch = new byte[] { 0x53, 0x7F, 0x40, -0x70, -0x37, -0x05, -0x19 };
         for (int preamble = 0x00; preamble < 0x100; ++preamble) {
-- 
GitLab