DSSTTheory.java
/* Copyright 2002-2025 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.conversion.osc2mean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.hipparchus.CalculusFieldElement;
import org.hipparchus.Field;
import org.hipparchus.util.MathArrays;
import org.orekit.attitudes.Attitude;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.FieldAttitude;
import org.orekit.attitudes.FrameAlignedProvider;
import org.orekit.orbits.FieldOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.OrbitType;
import org.orekit.orbits.PositionAngleType;
import org.orekit.propagation.FieldSpacecraftState;
import org.orekit.propagation.PropagationType;
import org.orekit.propagation.Propagator;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
import org.orekit.propagation.semianalytical.dsst.forces.FieldShortPeriodTerms;
import org.orekit.propagation.semianalytical.dsst.forces.ShortPeriodTerms;
import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.Constants;
/**
* DSST theory for osculating to mean orbit conversion.
*
* @author Pascal Parraud
* @since 13.0
*/
public class DSSTTheory implements MeanTheory {
/** Theory used for converting from osculating to mean orbit. */
public static final String THEORY = "DSST";
/** Force models used to compute short periodic terms. */
private final Collection<DSSTForceModel> forceModels;
/** Spacecraft mass (kg). */
private final double mass;
/** Attitude provider. */
private AttitudeProvider attitudeProvider;
/**
* Constructor with default values.
* @param forceModels the force models
*/
public DSSTTheory(final Collection<DSSTForceModel> forceModels) {
this(forceModels, null, Propagator.DEFAULT_MASS);
}
/**
* Full constructor.
* @param forceModels the force models
* @param attitudeProvider the attitude law
* @param mass the mass (kg)
*/
public DSSTTheory(final Collection<DSSTForceModel> forceModels,
final AttitudeProvider attitudeProvider,
final double mass) {
this.forceModels = forceModels;
this.attitudeProvider = attitudeProvider;
this.mass = mass;
}
/** {@inheritDoc} */
@Override
public String getTheoryName() {
return THEORY;
}
/** {@inheritDoc} */
@Override
public double getReferenceRadius() {
return Constants.IERS2010_EARTH_EQUATORIAL_RADIUS;
};
/** {@inheritDoc} */
@Override
public Orbit preprocessing(final Orbit osculating) {
// If not defined
if (attitudeProvider == null) {
// Creates a default attitude provider
attitudeProvider = FrameAlignedProvider.of(osculating.getFrame());
}
// ensure all Gaussian force models can rely on attitude
for (final DSSTForceModel force : forceModels) {
force.registerAttitudeProvider(attitudeProvider);
}
// Returns an equinoctial orbit
return OrbitType.EQUINOCTIAL.convertType(osculating);
}
/** {@inheritDoc} */
@Override
public Orbit meanToOsculating(final Orbit mean) {
// Create the spacecraft state
final Attitude attitude = attitudeProvider.getAttitude(mean, mean.getDate(), mean.getFrame());
final SpacecraftState meanState = new SpacecraftState(mean, attitude).withMass(mass);
// Create the auxiliary object
final AuxiliaryElements aux = new AuxiliaryElements(mean, +1);
// Set the force models
final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<>();
for (final DSSTForceModel force : forceModels) {
shortPeriodTerms.addAll(force.initializeShortPeriodTerms(aux, PropagationType.OSCULATING,
force.getParameters(mean.getDate())));
force.updateShortPeriodTerms(force.getParametersAllValues(), meanState);
}
// recompute the osculating parameters from the current mean parameters
return computeOsculatingOrbit(mean, shortPeriodTerms);
}
/** Compute osculating orbit from mean orbit.
* <p>
* Compute and add the short periodic variation to the mean orbit.
* </p>
* @param meanOrbit initial mean orbit
* @param shortPeriodTerms short period terms
* @return osculating orbit
*/
private Orbit computeOsculatingOrbit(final Orbit meanOrbit,
final List<ShortPeriodTerms> shortPeriodTerms) {
final double[] mean = new double[6];
final double[] meanDot = new double[6];
OrbitType.EQUINOCTIAL.mapOrbitToArray(meanOrbit, PositionAngleType.MEAN, mean, meanDot);
final double[] y = mean.clone();
for (final ShortPeriodTerms spt : shortPeriodTerms) {
final double[] shortPeriodic = spt.value(meanOrbit);
for (int i = 0; i < shortPeriodic.length; i++) {
y[i] += shortPeriodic[i];
}
}
return OrbitType.EQUINOCTIAL.mapArrayToOrbit(y, meanDot, PositionAngleType.MEAN,
meanOrbit.getDate(), meanOrbit.getMu(),
meanOrbit.getFrame());
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldOrbit<T> preprocessing(final FieldOrbit<T> osculating) {
// If not defined
if (attitudeProvider == null) {
// Creates a default attitude provider
attitudeProvider = FrameAlignedProvider.of(osculating.getFrame());
}
// ensure all Gaussian force models can rely on attitude
for (final DSSTForceModel force : forceModels) {
force.registerAttitudeProvider(attitudeProvider);
}
// Returns an equinoctial orbit
return OrbitType.EQUINOCTIAL.convertType(osculating);
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public <T extends CalculusFieldElement<T>> FieldOrbit<T> meanToOsculating(final FieldOrbit<T> mean) {
final FieldAbsoluteDate<T> date = mean.getDate();
final Field<T> field = date.getField();
// Create the spacecraft state
final T fieldMass = field.getZero().newInstance(mass);
final FieldAttitude<T> attitude = attitudeProvider.getAttitude(mean, mean.getDate(), mean.getFrame());
final FieldSpacecraftState<T> meanState = new FieldSpacecraftState<>(mean, attitude).withMass(fieldMass);
//Create the auxiliary object
final FieldAuxiliaryElements<T> aux = new FieldAuxiliaryElements<>(mean, +1);
// Set the force models
final List<FieldShortPeriodTerms<T>> shortPeriodTerms = new ArrayList<>();
for (final DSSTForceModel force : forceModels) {
shortPeriodTerms.addAll(force.initializeShortPeriodTerms(aux, PropagationType.OSCULATING,
force.getParameters(field, date)));
force.updateShortPeriodTerms(force.getParametersAllValues(field), meanState);
}
// recompute the osculating parameters from the current mean parameters
return computeOsculatingOrbit(mean, shortPeriodTerms);
}
/** Compute osculating orbit from mean orbit.
* <p>
* Compute and add the short periodic variation to the mean {@link SpacecraftState}.
* </p>
* @param meanOrbit initial mean orbit
* @param shortPeriodTerms short period terms
* @param <T> type of the elements
* @return osculating orbit
*/
private <T extends CalculusFieldElement<T>> FieldOrbit<T> computeOsculatingOrbit(final FieldOrbit<T> meanOrbit,
final List<FieldShortPeriodTerms<T>> shortPeriodTerms) {
final T[] mean = MathArrays.buildArray(meanOrbit.getDate().getField(), 6);
final T[] meanDot = MathArrays.buildArray(meanOrbit.getDate().getField(), 6);
OrbitType.EQUINOCTIAL.mapOrbitToArray(meanOrbit, PositionAngleType.MEAN, mean, meanDot);
final T[] y = mean.clone();
for (final FieldShortPeriodTerms<T> spt : shortPeriodTerms) {
final T[] shortPeriodic = spt.value(meanOrbit);
for (int i = 0; i < shortPeriodic.length; i++) {
y[i] = y[i].add(shortPeriodic[i]);
}
}
return OrbitType.EQUINOCTIAL.mapArrayToOrbit(y, meanDot,
PositionAngleType.MEAN,
meanOrbit.getDate(),
meanOrbit.getMu(),
meanOrbit.getFrame());
}
}