JacobianPropagatorConverter.java

  1. /* Copyright 2002-2018 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.propagation.conversion;

  18. import java.util.List;

  19. import org.hipparchus.analysis.MultivariateVectorFunction;
  20. import org.hipparchus.linear.ArrayRealVector;
  21. import org.hipparchus.linear.MatrixUtils;
  22. import org.hipparchus.linear.RealMatrix;
  23. import org.hipparchus.linear.RealVector;
  24. import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
  25. import org.hipparchus.util.Pair;
  26. import org.orekit.errors.OrekitException;
  27. import org.orekit.errors.OrekitExceptionWrapper;
  28. import org.orekit.errors.OrekitMessages;
  29. import org.orekit.orbits.OrbitType;
  30. import org.orekit.propagation.SpacecraftState;
  31. import org.orekit.propagation.events.DateDetector;
  32. import org.orekit.propagation.events.handlers.EventHandler;
  33. import org.orekit.propagation.numerical.JacobiansMapper;
  34. import org.orekit.propagation.numerical.NumericalPropagator;
  35. import org.orekit.propagation.numerical.PartialDerivativesEquations;
  36. import org.orekit.utils.PVCoordinates;
  37. import org.orekit.utils.ParameterDriver;
  38. import org.orekit.utils.ParameterDriversList;

  39. /** Propagator converter using the real Jacobian.
  40.  * @author Pascal Parraud
  41.  * @since 6.0
  42.  */
  43. public class JacobianPropagatorConverter extends AbstractPropagatorConverter {

  44.     /** Numerical propagator builder. */
  45.     private final NumericalPropagatorBuilder builder;

  46.     /** Simple constructor.
  47.      * @param builder builder for adapted propagator, it <em>must</em>
  48.      * be configured to generate {@link OrbitType#CARTESIAN} states
  49.      * @param threshold absolute threshold for optimization algorithm
  50.      * @param maxIterations maximum number of iterations for fitting
  51.      * @exception OrekitException if the builder {@link
  52.      * NumericalPropagatorBuilder#getOrbitType() orbit type} is not
  53.      * {@link OrbitType#CARTESIAN}
  54.      */
  55.     public JacobianPropagatorConverter(final NumericalPropagatorBuilder builder,
  56.                                        final double threshold,
  57.                                        final int maxIterations)
  58.         throws OrekitException {
  59.         super(builder, threshold, maxIterations);
  60.         if (builder.getOrbitType() != OrbitType.CARTESIAN) {
  61.             throw new OrekitException(OrekitMessages.ORBIT_TYPE_NOT_ALLOWED,
  62.                                       builder.getOrbitType(), OrbitType.CARTESIAN);
  63.         }
  64.         this.builder = builder;
  65.     }

  66.     /** {@inheritDoc} */
  67.     protected MultivariateVectorFunction getObjectiveFunction() {
  68.         return new MultivariateVectorFunction() {

  69.             /** {@inheritDoc} */
  70.             public double[] value(final double[] arg)
  71.                 throws IllegalArgumentException, OrekitExceptionWrapper {
  72.                 try {
  73.                     final double[] value = new double[getTargetSize()];

  74.                     final NumericalPropagator prop = builder.buildPropagator(arg);

  75.                     final int stateSize = isOnlyPosition() ? 3 : 6;
  76.                     final List<SpacecraftState> sample = getSample();
  77.                     for (int i = 0; i < sample.size(); ++i) {
  78.                         final int row = i * stateSize;
  79.                         if (prop.getInitialState().getDate().equals(sample.get(i).getDate())) {
  80.                             // use initial state
  81.                             fillRows(value, row, prop.getInitialState());
  82.                         } else {
  83.                             // use a date detector to pick up states
  84.                             prop.addEventDetector(new DateDetector(sample.get(i).getDate()).withHandler(new EventHandler<DateDetector>() {
  85.                                 /** {@inheritDoc} */
  86.                                 @Override
  87.                                 public Action eventOccurred(final SpacecraftState state, final DateDetector detector,
  88.                                                             final boolean increasing)
  89.                                     throws OrekitException {
  90.                                     fillRows(value, row, state);
  91.                                     return row + stateSize >= getTargetSize() ? Action.STOP : Action.CONTINUE;
  92.                                 }
  93.                             }));
  94.                         }
  95.                     }

  96.                     prop.propagate(sample.get(sample.size() - 1).getDate().shiftedBy(10.0));

  97.                     return value;

  98.                 } catch (OrekitException ex) {
  99.                     throw new OrekitExceptionWrapper(ex);
  100.                 }
  101.             }

  102.         };
  103.     }

  104.     /** {@inheritDoc} */
  105.     protected MultivariateJacobianFunction getModel() {
  106.         return new MultivariateJacobianFunction() {

  107.             /** {@inheritDoc} */
  108.             public Pair<RealVector, RealMatrix> value(final RealVector point)
  109.                 throws IllegalArgumentException, OrekitExceptionWrapper {
  110.                 try {

  111.                     final RealVector value    = new ArrayRealVector(getTargetSize());
  112.                     final RealMatrix jacobian = MatrixUtils.createRealMatrix(getTargetSize(), point.getDimension());

  113.                     final NumericalPropagator prop  = builder.buildPropagator(point.toArray());
  114.                     final int stateSize = isOnlyPosition() ? 3 : 6;
  115.                     final ParameterDriversList orbitalParameters = builder.getOrbitalParametersDrivers();
  116.                     final PartialDerivativesEquations pde = new PartialDerivativesEquations("pde", prop);
  117.                     final ParameterDriversList propagationParameters = pde.getSelectedParameters();
  118.                     prop.setInitialState(pde.setInitialJacobians(prop.getInitialState()));
  119.                     final JacobiansMapper mapper  = pde.getMapper();

  120.                     final List<SpacecraftState> sample = getSample();
  121.                     for (int i = 0; i < sample.size(); ++i) {
  122.                         final int row = i * stateSize;
  123.                         if (prop.getInitialState().getDate().equals(sample.get(i).getDate())) {
  124.                             // use initial state and Jacobians
  125.                             fillRows(value, jacobian, row, prop.getInitialState(), stateSize,
  126.                                      orbitalParameters, propagationParameters, mapper);
  127.                         } else {
  128.                             // use a date detector to pick up state and Jacobians
  129.                             prop.addEventDetector(new DateDetector(sample.get(i).getDate()).withHandler(new EventHandler<DateDetector>() {
  130.                                 /** {@inheritDoc} */
  131.                                 @Override
  132.                                 public Action eventOccurred(final SpacecraftState state, final DateDetector detector,
  133.                                                             final boolean increasing)
  134.                                     throws OrekitException {
  135.                                     fillRows(value, jacobian, row, state, stateSize,
  136.                                              orbitalParameters, propagationParameters, mapper);
  137.                                     return row + stateSize >= getTargetSize() ? Action.STOP : Action.CONTINUE;
  138.                                 }
  139.                             }));
  140.                         }
  141.                     }

  142.                     prop.propagate(sample.get(sample.size() - 1).getDate().shiftedBy(10.0));

  143.                     return new Pair<RealVector, RealMatrix>(value, jacobian);

  144.                 } catch (OrekitException ex) {
  145.                     throw new OrekitExceptionWrapper(ex);
  146.                 }
  147.             }

  148.         };
  149.     }

  150.     /** Fill up a few value rows (either 6 or 3 depending on velocities used or not).
  151.      * @param value values array
  152.      * @param row first row index
  153.      * @param state spacecraft state
  154.      * @exception OrekitException if Jacobians matrices cannot be retrieved
  155.      */
  156.     private void fillRows(final double[] value, final int row, final SpacecraftState state)
  157.         throws OrekitException {
  158.         final PVCoordinates pv = state.getPVCoordinates(getFrame());
  159.         value[row    ] = pv.getPosition().getX();
  160.         value[row + 1] = pv.getPosition().getY();
  161.         value[row + 2] = pv.getPosition().getZ();
  162.         if (!isOnlyPosition()) {
  163.             value[row + 3] = pv.getVelocity().getX();
  164.             value[row + 4] = pv.getVelocity().getY();
  165.             value[row + 5] = pv.getVelocity().getZ();
  166.         }
  167.     }

  168.     /** Fill up a few Jacobian rows (either 6 or 3 depending on velocities used or not).
  169.      * @param value values vector
  170.      * @param jacobian Jacobian matrix
  171.      * @param row first row index
  172.      * @param state spacecraft state
  173.      * @param stateSize state size
  174.      * @param orbitalParameters drivers for the orbital parameters
  175.      * @param propagationParameters drivers for the propagation model parameters
  176.      * @param mapper state mapper
  177.      * @exception OrekitException if Jacobians matrices cannot be retrieved
  178.      */
  179.     private void fillRows(final RealVector value, final RealMatrix jacobian, final int row,
  180.                           final SpacecraftState state, final int stateSize,
  181.                           final ParameterDriversList orbitalParameters,
  182.                           final ParameterDriversList propagationParameters,
  183.                           final JacobiansMapper mapper)
  184.         throws OrekitException {

  185.         // value part
  186.         final PVCoordinates pv = state.getPVCoordinates(getFrame());
  187.         value.setEntry(row,     pv.getPosition().getX());
  188.         value.setEntry(row + 1, pv.getPosition().getY());
  189.         value.setEntry(row + 2, pv.getPosition().getZ());
  190.         if (!isOnlyPosition()) {
  191.             value.setEntry(row + 3, pv.getVelocity().getX());
  192.             value.setEntry(row + 4, pv.getVelocity().getY());
  193.             value.setEntry(row + 5, pv.getVelocity().getZ());
  194.         }

  195.         // Jacobian part
  196.         final double[][] dYdY0 = new double[JacobiansMapper.STATE_DIMENSION][JacobiansMapper.STATE_DIMENSION];
  197.         final double[][] dYdP  = new double[JacobiansMapper.STATE_DIMENSION][mapper.getParameters()];
  198.         mapper.getStateJacobian(state, dYdY0);
  199.         mapper.getParametersJacobian(state, dYdP);
  200.         for (int k = 0; k < stateSize; k++) {
  201.             int index = 0;
  202.             for (int j = 0; j < orbitalParameters.getNbParams(); ++j) {
  203.                 final ParameterDriver driver = orbitalParameters.getDrivers().get(j);
  204.                 if (driver.isSelected()) {
  205.                     jacobian.setEntry(row + k, index++, dYdY0[k][j] * driver.getScale());
  206.                 }
  207.             }
  208.             for (int j = 0; j < propagationParameters.getNbParams(); ++j) {
  209.                 final ParameterDriver driver = propagationParameters.getDrivers().get(j);
  210.                 jacobian.setEntry(row + k, index++, dYdP[k][j] * driver.getScale());
  211.             }
  212.         }

  213.     }

  214. }