JacobianPropagatorConverter.java

  1. /* Copyright 2002-2019 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.OrekitMessages;
  28. import org.orekit.orbits.OrbitType;
  29. import org.orekit.propagation.SpacecraftState;
  30. import org.orekit.propagation.events.DateDetector;
  31. import org.orekit.propagation.events.handlers.EventHandler;
  32. import org.orekit.propagation.numerical.JacobiansMapper;
  33. import org.orekit.propagation.numerical.NumericalPropagator;
  34. import org.orekit.propagation.numerical.PartialDerivativesEquations;
  35. import org.orekit.utils.PVCoordinates;
  36. import org.orekit.utils.ParameterDriver;
  37. import org.orekit.utils.ParameterDriversList;

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

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

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

  61.     /** {@inheritDoc} */
  62.     protected MultivariateVectorFunction getObjectiveFunction() {
  63.         return new MultivariateVectorFunction() {

  64.             /** {@inheritDoc} */
  65.             public double[] value(final double[] arg)
  66.                 throws IllegalArgumentException, OrekitException {

  67.                 final double[] value = new double[getTargetSize()];

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

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

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

  90.                 return value;
  91.             }
  92.         };
  93.     }

  94.     /** {@inheritDoc} */
  95.     protected MultivariateJacobianFunction getModel() {
  96.         return new MultivariateJacobianFunction() {

  97.             /** {@inheritDoc} */
  98.             public Pair<RealVector, RealMatrix> value(final RealVector point)
  99.                 throws IllegalArgumentException, OrekitException {

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

  102.                 final NumericalPropagator prop  = builder.buildPropagator(point.toArray());
  103.                 final int stateSize = isOnlyPosition() ? 3 : 6;
  104.                 final ParameterDriversList orbitalParameters = builder.getOrbitalParametersDrivers();
  105.                 final PartialDerivativesEquations pde = new PartialDerivativesEquations("pde", prop);
  106.                 final ParameterDriversList propagationParameters = pde.getSelectedParameters();
  107.                 prop.setInitialState(pde.setInitialJacobians(prop.getInitialState()));
  108.                 final JacobiansMapper mapper  = pde.getMapper();

  109.                 final List<SpacecraftState> sample = getSample();
  110.                 for (int i = 0; i < sample.size(); ++i) {
  111.                     final int row = i * stateSize;
  112.                     if (prop.getInitialState().getDate().equals(sample.get(i).getDate())) {
  113.                         // use initial state and Jacobians
  114.                         fillRows(value, jacobian, row, prop.getInitialState(), stateSize,
  115.                                  orbitalParameters, propagationParameters, mapper);
  116.                     } else {
  117.                         // use a date detector to pick up state and Jacobians
  118.                         prop.addEventDetector(new DateDetector(sample.get(i).getDate()).withHandler(new EventHandler<DateDetector>() {
  119.                             /** {@inheritDoc} */
  120.                             @Override
  121.                             public Action eventOccurred(final SpacecraftState state, final DateDetector detector,
  122.                                                         final boolean increasing) {
  123.                                 fillRows(value, jacobian, row, state, stateSize,
  124.                                          orbitalParameters, propagationParameters, mapper);
  125.                                 return row + stateSize >= getTargetSize() ? Action.STOP : Action.CONTINUE;
  126.                             }
  127.                         }));
  128.                     }
  129.                 }

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

  131.                 return new Pair<RealVector, RealMatrix>(value, jacobian);
  132.             }
  133.         };
  134.     }

  135.     /** Fill up a few value rows (either 6 or 3 depending on velocities used or not).
  136.      * @param value values array
  137.      * @param row first row index
  138.      * @param state spacecraft state
  139.      */
  140.     private void fillRows(final double[] value, final int row, final SpacecraftState state) {
  141.         final PVCoordinates pv = state.getPVCoordinates(getFrame());
  142.         value[row    ] = pv.getPosition().getX();
  143.         value[row + 1] = pv.getPosition().getY();
  144.         value[row + 2] = pv.getPosition().getZ();
  145.         if (!isOnlyPosition()) {
  146.             value[row + 3] = pv.getVelocity().getX();
  147.             value[row + 4] = pv.getVelocity().getY();
  148.             value[row + 5] = pv.getVelocity().getZ();
  149.         }
  150.     }

  151.     /** Fill up a few Jacobian rows (either 6 or 3 depending on velocities used or not).
  152.      * @param value values vector
  153.      * @param jacobian Jacobian matrix
  154.      * @param row first row index
  155.      * @param state spacecraft state
  156.      * @param stateSize state size
  157.      * @param orbitalParameters drivers for the orbital parameters
  158.      * @param propagationParameters drivers for the propagation model parameters
  159.      * @param mapper state mapper
  160.      */
  161.     private void fillRows(final RealVector value, final RealMatrix jacobian, final int row,
  162.                           final SpacecraftState state, final int stateSize,
  163.                           final ParameterDriversList orbitalParameters,
  164.                           final ParameterDriversList propagationParameters,
  165.                           final JacobiansMapper mapper) {

  166.         // value part
  167.         final PVCoordinates pv = state.getPVCoordinates(getFrame());
  168.         value.setEntry(row,     pv.getPosition().getX());
  169.         value.setEntry(row + 1, pv.getPosition().getY());
  170.         value.setEntry(row + 2, pv.getPosition().getZ());
  171.         if (!isOnlyPosition()) {
  172.             value.setEntry(row + 3, pv.getVelocity().getX());
  173.             value.setEntry(row + 4, pv.getVelocity().getY());
  174.             value.setEntry(row + 5, pv.getVelocity().getZ());
  175.         }

  176.         // Jacobian part
  177.         final double[][] dYdY0 = new double[JacobiansMapper.STATE_DIMENSION][JacobiansMapper.STATE_DIMENSION];
  178.         final double[][] dYdP  = new double[JacobiansMapper.STATE_DIMENSION][mapper.getParameters()];
  179.         mapper.getStateJacobian(state, dYdY0);
  180.         mapper.getParametersJacobian(state, dYdP);
  181.         for (int k = 0; k < stateSize; k++) {
  182.             int index = 0;
  183.             for (int j = 0; j < orbitalParameters.getNbParams(); ++j) {
  184.                 final ParameterDriver driver = orbitalParameters.getDrivers().get(j);
  185.                 if (driver.isSelected()) {
  186.                     jacobian.setEntry(row + k, index++, dYdY0[k][j] * driver.getScale());
  187.                 }
  188.             }
  189.             for (int j = 0; j < propagationParameters.getNbParams(); ++j) {
  190.                 final ParameterDriver driver = propagationParameters.getDrivers().get(j);
  191.                 jacobian.setEntry(row + k, index++, dYdP[k][j] * driver.getScale());
  192.             }
  193.         }

  194.     }

  195. }