AbstractAnalyticalMatricesHarvester.java
- /* Copyright 2002-2024 CS GROUP
- * Licensed to CS GROUP (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.analytical;
- import java.util.Arrays;
- import java.util.List;
- import org.hipparchus.analysis.differentiation.Gradient;
- import org.hipparchus.linear.MatrixUtils;
- import org.hipparchus.linear.RealMatrix;
- import org.orekit.orbits.FieldOrbit;
- import org.orekit.orbits.OrbitType;
- import org.orekit.orbits.PositionAngleType;
- import org.orekit.propagation.AbstractMatricesHarvester;
- import org.orekit.propagation.AdditionalStateProvider;
- import org.orekit.propagation.FieldSpacecraftState;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.FieldAbsoluteDate;
- import org.orekit.utils.DoubleArrayDictionary;
- import org.orekit.utils.FieldPVCoordinates;
- import org.orekit.utils.ParameterDriver;
- import org.orekit.utils.TimeSpanMap;
- import org.orekit.utils.TimeSpanMap.Span;
- /**
- * Base class harvester between two-dimensional Jacobian
- * matrices and analytical orbit propagator.
- * @author Thomas Paulet
- * @author Bryan Cazabonne
- * @since 11.1
- */
- public abstract class AbstractAnalyticalMatricesHarvester extends AbstractMatricesHarvester implements AdditionalStateProvider {
- /** Columns names for parameters. */
- private List<String> columnsNames;
- /** Epoch of the last computed state transition matrix. */
- private AbsoluteDate epoch;
- /** Analytical derivatives that apply to State Transition Matrix. */
- private final double[][] analyticalDerivativesStm;
- /** Analytical derivatives that apply to Jacobians columns. */
- private final DoubleArrayDictionary analyticalDerivativesJacobianColumns;
- /** Propagator bound to this harvester. */
- private final AbstractAnalyticalPropagator propagator;
- /** Simple constructor.
- * <p>
- * The arguments for initial matrices <em>must</em> be compatible with the
- * {@link org.orekit.orbits.OrbitType orbit type}
- * and {@link PositionAngleType position angle} that will be used by propagator
- * </p>
- * @param propagator propagator bound to this harvester
- * @param stmName State Transition Matrix state name
- * @param initialStm initial State Transition Matrix ∂Y/∂Y₀,
- * if null (which is the most frequent case), assumed to be 6x6 identity
- * @param initialJacobianColumns initial columns of the Jacobians matrix with respect to parameters,
- * if null or if some selected parameters are missing from the dictionary, the corresponding
- * initial column is assumed to be 0
- */
- protected AbstractAnalyticalMatricesHarvester(final AbstractAnalyticalPropagator propagator, final String stmName,
- final RealMatrix initialStm, final DoubleArrayDictionary initialJacobianColumns) {
- super(stmName, initialStm, initialJacobianColumns);
- this.propagator = propagator;
- this.epoch = propagator.getInitialState().getDate();
- this.columnsNames = null;
- this.analyticalDerivativesStm = getInitialStateTransitionMatrix().getData();
- this.analyticalDerivativesJacobianColumns = new DoubleArrayDictionary();
- }
- /** {@inheritDoc} */
- @Override
- public List<String> getJacobiansColumnsNames() {
- return columnsNames == null ? propagator.getJacobiansColumnsNames() : columnsNames;
- }
- /** {@inheritDoc} */
- @Override
- public void freezeColumnsNames() {
- columnsNames = getJacobiansColumnsNames();
- }
- /** {@inheritDoc} */
- @Override
- public String getName() {
- return getStmName();
- }
- /** {@inheritDoc} */
- @Override
- public double[] getAdditionalState(final SpacecraftState state) {
- // Update the partial derivatives if needed
- updateDerivativesIfNeeded(state);
- // Return the state transition matrix in an array
- return toArray(analyticalDerivativesStm);
- }
- /** {@inheritDoc} */
- @Override
- public RealMatrix getStateTransitionMatrix(final SpacecraftState state) {
- // Check if additional state is defined
- if (!state.hasAdditionalState(getName())) {
- return null;
- }
- // Return the state transition matrix
- return toRealMatrix(state.getAdditionalState(getName()));
- }
- /** {@inheritDoc} */
- @Override
- public RealMatrix getParametersJacobian(final SpacecraftState state) {
- // Update the partial derivatives if needed
- updateDerivativesIfNeeded(state);
- // Estimated parameters
- final List<String> names = getJacobiansColumnsNames();
- if (names == null || names.isEmpty()) {
- return null;
- }
- // Initialize Jacobian
- final RealMatrix dYdP = MatrixUtils.createRealMatrix(STATE_DIMENSION, names.size());
- // Add the derivatives
- for (int j = 0; j < names.size(); ++j) {
- final double[] column = analyticalDerivativesJacobianColumns.get(names.get(j));
- if (column != null) {
- for (int i = 0; i < STATE_DIMENSION; i++) {
- dYdP.addToEntry(i, j, column[i]);
- }
- }
- }
- // Return
- return dYdP;
- }
- /** {@inheritDoc} */
- @Override
- public void setReferenceState(final SpacecraftState reference) {
- // reset derivatives to zero
- for (final double[] row : analyticalDerivativesStm) {
- Arrays.fill(row, 0.0);
- }
- analyticalDerivativesJacobianColumns.clear();
- final AbstractAnalyticalGradientConverter converter = getGradientConverter();
- final FieldSpacecraftState<Gradient> gState = converter.getState();
- final Gradient[] gParameters = converter.getParameters(gState, converter);
- final FieldAbstractAnalyticalPropagator<Gradient> gPropagator = converter.getPropagator(gState, gParameters);
- // Compute Jacobian
- final AbsoluteDate target = reference.getDate();
- final FieldAbsoluteDate<Gradient> start = gPropagator.getInitialState().getDate();
- final double dt = target.durationFrom(start.toAbsoluteDate());
- final FieldOrbit<Gradient> gOrbit = gPropagator.propagateOrbit(start.shiftedBy(dt), gParameters);
- final FieldPVCoordinates<Gradient> gPv = gOrbit.getPVCoordinates();
- final double[] derivativesX = gPv.getPosition().getX().getGradient();
- final double[] derivativesY = gPv.getPosition().getY().getGradient();
- final double[] derivativesZ = gPv.getPosition().getZ().getGradient();
- final double[] derivativesVx = gPv.getVelocity().getX().getGradient();
- final double[] derivativesVy = gPv.getVelocity().getY().getGradient();
- final double[] derivativesVz = gPv.getVelocity().getZ().getGradient();
- // Update Jacobian with respect to state
- addToRow(derivativesX, 0);
- addToRow(derivativesY, 1);
- addToRow(derivativesZ, 2);
- addToRow(derivativesVx, 3);
- addToRow(derivativesVy, 4);
- addToRow(derivativesVz, 5);
- // Partial derivatives of the state with respect to propagation parameters
- int paramsIndex = converter.getFreeStateParameters();
- for (ParameterDriver driver : converter.getParametersDrivers()) {
- if (driver.isSelected()) {
- final TimeSpanMap<String> driverNameSpanMap = driver.getNamesSpanMap();
- // for each span (for each estimated value) corresponding name is added
- for (Span<String> span = driverNameSpanMap.getFirstSpan(); span != null; span = span.next()) {
- // get the partials derivatives for this driver
- DoubleArrayDictionary.Entry entry = analyticalDerivativesJacobianColumns.getEntry(span.getData());
- if (entry == null) {
- // create an entry filled with zeroes
- analyticalDerivativesJacobianColumns.put(span.getData(), new double[STATE_DIMENSION]);
- entry = analyticalDerivativesJacobianColumns.getEntry(span.getData());
- }
- // add the contribution of the current force model
- entry.increment(new double[] {
- derivativesX[paramsIndex], derivativesY[paramsIndex], derivativesZ[paramsIndex],
- derivativesVx[paramsIndex], derivativesVy[paramsIndex], derivativesVz[paramsIndex]
- });
- ++paramsIndex;
- }
- }
- }
- // Update the epoch of the last computed partial derivatives
- epoch = target;
- }
- /** Update the partial derivatives (if needed).
- * @param state current spacecraft state
- */
- private void updateDerivativesIfNeeded(final SpacecraftState state) {
- if (!state.getDate().isEqualTo(epoch)) {
- setReferenceState(state);
- }
- }
- /** Fill State Transition Matrix rows.
- * @param derivatives derivatives of a component
- * @param index component index
- */
- private void addToRow(final double[] derivatives, final int index) {
- for (int i = 0; i < 6; i++) {
- analyticalDerivativesStm[index][i] += derivatives[i];
- }
- }
- /** Convert an array to a matrix (6x6 dimension).
- * @param array input array
- * @return the corresponding matrix
- */
- private RealMatrix toRealMatrix(final double[] array) {
- final RealMatrix matrix = MatrixUtils.createRealMatrix(STATE_DIMENSION, STATE_DIMENSION);
- int index = 0;
- for (int i = 0; i < STATE_DIMENSION; ++i) {
- for (int j = 0; j < STATE_DIMENSION; ++j) {
- matrix.setEntry(i, j, array[index++]);
- }
- }
- return matrix;
- }
- /** Set the STM data into an array.
- * @param matrix STM matrix
- * @return an array containing the STM data
- */
- private double[] toArray(final double[][] matrix) {
- final double[] array = new double[STATE_DIMENSION * STATE_DIMENSION];
- int index = 0;
- for (int i = 0; i < STATE_DIMENSION; ++i) {
- final double[] row = matrix[i];
- for (int j = 0; j < STATE_DIMENSION; ++j) {
- array[index++] = row[j];
- }
- }
- return array;
- }
- /** {@inheritDoc} */
- @Override
- public OrbitType getOrbitType() {
- // Set to CARTESIAN because analytical gradient converter uses cartesian representation
- return OrbitType.CARTESIAN;
- }
- /** {@inheritDoc} */
- @Override
- public PositionAngleType getPositionAngleType() {
- // Irrelevant: set a default value
- return PositionAngleType.MEAN;
- }
- /**
- * Get the gradient converter related to the analytical orbit propagator.
- * @return the gradient converter
- */
- public abstract AbstractAnalyticalGradientConverter getGradientConverter();
- }