JacobianPropagatorConverter.java

  1. /* Copyright 2002-2020 CS GROUP
  2.  * Licensed to CS GROUP (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.ode.events.Action;
  25. import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
  26. import org.hipparchus.util.Pair;
  27. import org.orekit.errors.OrekitException;
  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.      */
  52.     public JacobianPropagatorConverter(final NumericalPropagatorBuilder builder,
  53.                                        final double threshold,
  54.                                        final int maxIterations) {
  55.         super(builder, threshold, maxIterations);
  56.         if (builder.getOrbitType() != OrbitType.CARTESIAN) {
  57.             throw new OrekitException(OrekitMessages.ORBIT_TYPE_NOT_ALLOWED,
  58.                                       builder.getOrbitType(), OrbitType.CARTESIAN);
  59.         }
  60.         this.builder = builder;
  61.     }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  195.     }

  196. }