@Test
  public void testUnsupportedParameter() throws OrekitException {
    Orbit initialOrbit =
        new KeplerianOrbit(
            8000000.0,
            0.01,
            0.1,
            0.7,
            0,
            1.2,
            PositionAngle.TRUE,
            FramesFactory.getEME2000(),
            AbsoluteDate.J2000_EPOCH,
            Constants.EIGEN5C_EARTH_MU);

    double dP = 0.001;
    NumericalPropagator propagator =
        setUpPropagator(
            initialOrbit,
            dP,
            OrbitType.EQUINOCTIAL,
            PositionAngle.TRUE,
            new ThirdBodyAttraction(CelestialBodyFactory.getSun()),
            new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
    PartialDerivativesEquations partials = new PartialDerivativesEquations("partials", propagator);
    partials.selectParamAndStep("non-existent", 1.0);
    try {
      partials.computeDerivatives(new SpacecraftState(initialOrbit), new double[6]);
      Assert.fail("an exception should have been thrown");
    } catch (OrekitException oe) {
      Assert.assertEquals(OrekitMessages.UNSUPPORTED_PARAMETER_NAME, oe.getSpecifier());
    }
  }
  @Test(expected = OrekitException.class)
  public void testMismatchedDimensions() throws OrekitException {
    Orbit initialOrbit =
        new KeplerianOrbit(
            8000000.0,
            0.01,
            0.1,
            0.7,
            0,
            1.2,
            PositionAngle.TRUE,
            FramesFactory.getEME2000(),
            AbsoluteDate.J2000_EPOCH,
            Constants.EIGEN5C_EARTH_MU);

    double dP = 0.001;
    NumericalPropagator propagator =
        setUpPropagator(initialOrbit, dP, OrbitType.EQUINOCTIAL, PositionAngle.TRUE);
    PartialDerivativesEquations partials = new PartialDerivativesEquations("partials", propagator);
    partials.setInitialJacobians(
        new SpacecraftState(initialOrbit), new double[6][6], new double[7][2]);
  }
  @Test
  public void testWrongParametersDimension() throws OrekitException {
    Orbit initialOrbit =
        new KeplerianOrbit(
            8000000.0,
            0.01,
            0.1,
            0.7,
            0,
            1.2,
            PositionAngle.TRUE,
            FramesFactory.getEME2000(),
            AbsoluteDate.J2000_EPOCH,
            Constants.EIGEN5C_EARTH_MU);

    double dP = 0.001;
    NumericalPropagator propagator =
        setUpPropagator(
            initialOrbit,
            dP,
            OrbitType.EQUINOCTIAL,
            PositionAngle.TRUE,
            new ThirdBodyAttraction(CelestialBodyFactory.getSun()),
            new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
    PartialDerivativesEquations partials = new PartialDerivativesEquations("partials", propagator);
    partials.setInitialJacobians(
        new SpacecraftState(initialOrbit), new double[6][6], new double[6][3]);
    partials.selectParameters("Sun attraction coefficient");
    try {
      partials.computeDerivatives(new SpacecraftState(initialOrbit), new double[6]);
      Assert.fail("an exception should have been thrown");
    } catch (OrekitException oe) {
      Assert.assertEquals(
          OrekitMessages.INITIAL_MATRIX_AND_PARAMETERS_NUMBER_MISMATCH, oe.getSpecifier());
    }
  }
  @Test
  public void testPropagationTypesElliptical() throws OrekitException, ParseException, IOException {

    NormalizedSphericalHarmonicsProvider provider = GravityFieldFactory.getNormalizedProvider(5, 5);
    ForceModel gravityField =
        new HolmesFeatherstoneAttractionModel(
            FramesFactory.getITRF(IERSConventions.IERS_2010, true), provider);
    Orbit initialOrbit =
        new KeplerianOrbit(
            8000000.0,
            0.01,
            0.1,
            0.7,
            0,
            1.2,
            PositionAngle.TRUE,
            FramesFactory.getEME2000(),
            AbsoluteDate.J2000_EPOCH,
            provider.getMu());

    double dt = 900;
    double dP = 0.001;
    for (OrbitType orbitType : OrbitType.values()) {
      for (PositionAngle angleType : PositionAngle.values()) {

        // compute state Jacobian using PartialDerivatives
        NumericalPropagator propagator =
            setUpPropagator(initialOrbit, dP, orbitType, angleType, gravityField);
        PartialDerivativesEquations partials =
            new PartialDerivativesEquations("partials", propagator);
        final SpacecraftState initialState =
            partials.setInitialJacobians(new SpacecraftState(initialOrbit), 6, 0);
        propagator.setInitialState(initialState);
        final JacobiansMapper mapper = partials.getMapper();
        PickUpHandler pickUp = new PickUpHandler(mapper, null);
        propagator.setMasterMode(pickUp);
        propagator.propagate(initialState.getDate().shiftedBy(dt));
        double[][] dYdY0 = pickUp.getdYdY0();

        // compute reference state Jacobian using finite differences
        double[][] dYdY0Ref = new double[6][6];
        AbstractIntegratedPropagator propagator2 =
            setUpPropagator(initialOrbit, dP, orbitType, angleType, gravityField);
        double[] steps = NumericalPropagator.tolerances(1000000 * dP, initialOrbit, orbitType)[0];
        for (int i = 0; i < 6; ++i) {
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, -4 * steps[i], i));
          SpacecraftState sM4h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, -3 * steps[i], i));
          SpacecraftState sM3h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, -2 * steps[i], i));
          SpacecraftState sM2h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, -1 * steps[i], i));
          SpacecraftState sM1h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, 1 * steps[i], i));
          SpacecraftState sP1h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, 2 * steps[i], i));
          SpacecraftState sP2h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, 3 * steps[i], i));
          SpacecraftState sP3h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          propagator2.resetInitialState(
              shiftState(initialState, orbitType, angleType, 4 * steps[i], i));
          SpacecraftState sP4h = propagator2.propagate(initialState.getDate().shiftedBy(dt));
          fillJacobianColumn(
              dYdY0Ref, i, orbitType, angleType, steps[i], sM4h, sM3h, sM2h, sM1h, sP1h, sP2h, sP3h,
              sP4h);
        }

        for (int i = 0; i < 6; ++i) {
          for (int j = 0; j < 6; ++j) {
            double error = FastMath.abs((dYdY0[i][j] - dYdY0Ref[i][j]) / dYdY0Ref[i][j]);
            Assert.assertEquals(0, error, 6.0e-2);
          }
        }
      }
    }
  }
  @Test
  public void testJacobianIssue18() throws OrekitException {

    // Body mu
    final double mu = 3.9860047e14;

    final double isp = 318;
    final double mass = 2500;
    final double a = 24396159;
    final double e = 0.72831215;
    final double i = FastMath.toRadians(7);
    final double omega = FastMath.toRadians(180);
    final double OMEGA = FastMath.toRadians(261);
    final double lv = 0;

    final double duration = 3653.99;
    final double f = 420;
    final double delta = FastMath.toRadians(-7.4978);
    final double alpha = FastMath.toRadians(351);
    final AttitudeProvider law =
        new InertialProvider(new Rotation(new Vector3D(alpha, delta), Vector3D.PLUS_I));

    final AbsoluteDate initDate =
        new AbsoluteDate(
            new DateComponents(2004, 01, 01),
            new TimeComponents(23, 30, 00.000),
            TimeScalesFactory.getUTC());
    final Orbit orbit =
        new KeplerianOrbit(
            a,
            e,
            i,
            omega,
            OMEGA,
            lv,
            PositionAngle.TRUE,
            FramesFactory.getEME2000(),
            initDate,
            mu);
    final SpacecraftState initialState =
        new SpacecraftState(orbit, law.getAttitude(orbit, orbit.getDate(), orbit.getFrame()), mass);

    final AbsoluteDate fireDate =
        new AbsoluteDate(
            new DateComponents(2004, 01, 02),
            new TimeComponents(04, 15, 34.080),
            TimeScalesFactory.getUTC());
    final ConstantThrustManeuver maneuver =
        new ConstantThrustManeuver(fireDate, duration, f, isp, Vector3D.PLUS_I);

    double[] absTolerance = {0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001};
    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(0.001, 1000, absTolerance, relTolerance);
    integrator.setInitialStepSize(60);
    final NumericalPropagator propagator = new NumericalPropagator(integrator);

    propagator.setAttitudeProvider(law);
    propagator.addForceModel(maneuver);

    propagator.setOrbitType(OrbitType.CARTESIAN);
    PartialDerivativesEquations PDE = new PartialDerivativesEquations("derivatives", propagator);
    PDE.selectParamAndStep("thrust", Double.NaN);
    Assert.assertEquals(3, PDE.getAvailableParameters().size());
    Assert.assertEquals("central attraction coefficient", PDE.getAvailableParameters().get(0));
    Assert.assertEquals("thrust", PDE.getAvailableParameters().get(1));
    Assert.assertEquals("flow rate", PDE.getAvailableParameters().get(2));
    propagator.setInitialState(PDE.setInitialJacobians(initialState, 7, 1));

    final AbsoluteDate finalDate = fireDate.shiftedBy(3800);
    final SpacecraftState finalorb = propagator.propagate(finalDate);
    Assert.assertEquals(0, finalDate.durationFrom(finalorb.getDate()), 1.0e-11);
  }