OrbitType.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.orbits;
import java.util.Arrays;
import org.hipparchus.CalculusFieldElement;
import org.hipparchus.Field;
import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.MathUtils;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.FieldPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.ParameterDriver;
import org.orekit.utils.ParameterDriversList;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
/** Enumerate for {@link Orbit} and {@link FieldOrbit} parameters types.
*/
public enum OrbitType {
/** Type for orbital representation in {@link CartesianOrbit} and {@link FieldCartesianOrbit} parameters. */
CARTESIAN {
/** {@inheritDoc} */
@Override
public CartesianOrbit convertType(final Orbit orbit) {
return (orbit.getType() == this) ? (CartesianOrbit) orbit : new CartesianOrbit(orbit);
}
/** {@inheritDoc} */
@Override
public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
final double[] stateVector, final double[] stateVectorDot) {
final PVCoordinates pv = orbit.getPVCoordinates();
final Vector3D p = pv.getPosition();
final Vector3D v = pv.getVelocity();
stateVector[0] = p.getX();
stateVector[1] = p.getY();
stateVector[2] = p.getZ();
stateVector[3] = v.getX();
stateVector[4] = v.getY();
stateVector[5] = v.getZ();
if (stateVectorDot != null) {
final Vector3D a = pv.getAcceleration();
stateVectorDot[0] = v.getX();
stateVectorDot[1] = v.getY();
stateVectorDot[2] = v.getZ();
stateVectorDot[3] = a.getX();
stateVectorDot[4] = a.getY();
stateVectorDot[5] = a.getZ();
}
}
/** {@inheritDoc} */
@Override
public CartesianOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
final AbsoluteDate date, final double mu, final Frame frame) {
final Vector3D p = new Vector3D(stateVector[0], stateVector[1], stateVector[2]);
final Vector3D v = new Vector3D(stateVector[3], stateVector[4], stateVector[5]);
final Vector3D a;
if (stateVectorDot == null) {
// we don't have data about acceleration
return new CartesianOrbit(new PVCoordinates(p, v), frame, date, mu);
} else {
// we do have an acceleration
a = new Vector3D(stateVectorDot[3], stateVectorDot[4], stateVectorDot[5]);
return new CartesianOrbit(new PVCoordinates(p, v, a), frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> convertType(final FieldOrbit<T> orbit) {
return (orbit.getType() == this) ? (FieldCartesianOrbit<T>) orbit : new FieldCartesianOrbit<>(orbit);
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
final PositionAngleType type,
final T[] stateVector,
final T[] stateVectorDot) {
final TimeStampedFieldPVCoordinates<T> pv = orbit.getPVCoordinates();
final FieldVector3D<T> p = pv.getPosition();
final FieldVector3D<T> v = pv.getVelocity();
stateVector[0] = p.getX();
stateVector[1] = p.getY();
stateVector[2] = p.getZ();
stateVector[3] = v.getX();
stateVector[4] = v.getY();
stateVector[5] = v.getZ();
if (stateVectorDot != null) {
final FieldVector3D<T> a = pv.getAcceleration();
stateVectorDot[0] = v.getX();
stateVectorDot[1] = v.getY();
stateVectorDot[2] = v.getZ();
stateVectorDot[3] = a.getX();
stateVectorDot[4] = a.getY();
stateVectorDot[5] = a.getZ();
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> mapArrayToOrbit(final T[] stateVector,
final T[] stateVectorDot,
final PositionAngleType type,
final FieldAbsoluteDate<T> date,
final T mu, final Frame frame) {
final FieldVector3D<T> p = new FieldVector3D<>(stateVector[0], stateVector[1], stateVector[2]);
final FieldVector3D<T> v = new FieldVector3D<>(stateVector[3], stateVector[4], stateVector[5]);
final FieldVector3D<T> a;
if (stateVectorDot == null) {
// we don't have data about acceleration
return new FieldCartesianOrbit<>(new FieldPVCoordinates<>(p, v), frame, date, mu);
} else {
// we do have an acceleration
a = new FieldVector3D<>(stateVectorDot[3], stateVectorDot[4], stateVectorDot[5]);
return new FieldCartesianOrbit<>(new FieldPVCoordinates<>(p, v, a), frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> convertToFieldOrbit(final Field<T> field,
final Orbit orbit) {
return new FieldCartesianOrbit<>(field, CARTESIAN.convertType(orbit));
}
/** {@inheritDoc} */
@Override
public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
final ParameterDriversList drivers = new ParameterDriversList();
final double[] array = new double[6];
mapOrbitToArray(orbit, type, array, null);
final double[] scale = scale(dP, orbit);
drivers.add(new ParameterDriver(POS_X, array[0], scale[0], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(POS_Y, array[1], scale[1], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(POS_Z, array[2], scale[2], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(VEL_X, array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(VEL_Y, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(VEL_Z, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
return drivers;
}
/** {@inheritDoc} */
@Override
public CartesianOrbit normalize(final Orbit orbit, final Orbit reference) {
// no angular parameters need normalization
return convertType(orbit);
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {
// no angular parameters need normalization
return convertType(orbit);
}
/** {@inheritDoc} */
@Override
public boolean isPositionAngleBased() {
return false;
}
},
/** Type for orbital representation in {@link CircularOrbit} and {@link FieldCircularOrbit} parameters. */
CIRCULAR {
/** {@inheritDoc} */
@Override
public CircularOrbit convertType(final Orbit orbit) {
return (orbit.getType() == this) ? (CircularOrbit) orbit : new CircularOrbit(orbit);
}
/** {@inheritDoc} */
@Override
public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
final double[] stateVector, final double[] stateVectorDot) {
final CircularOrbit circularOrbit = (CircularOrbit) OrbitType.CIRCULAR.convertType(orbit);
stateVector[0] = circularOrbit.getA();
stateVector[1] = circularOrbit.getCircularEx();
stateVector[2] = circularOrbit.getCircularEy();
stateVector[3] = circularOrbit.getI();
stateVector[4] = circularOrbit.getRightAscensionOfAscendingNode();
stateVector[5] = circularOrbit.getAlpha(type);
if (stateVectorDot != null) {
if (orbit.hasDerivatives()) {
stateVectorDot[0] = circularOrbit.getADot();
stateVectorDot[1] = circularOrbit.getCircularExDot();
stateVectorDot[2] = circularOrbit.getCircularEyDot();
stateVectorDot[3] = circularOrbit.getIDot();
stateVectorDot[4] = circularOrbit.getRightAscensionOfAscendingNodeDot();
stateVectorDot[5] = circularOrbit.getAlphaDot(type);
} else {
Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
}
}
}
/** {@inheritDoc} */
@Override
public CircularOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
final AbsoluteDate date, final double mu, final Frame frame) {
if (stateVectorDot == null) {
// we don't have orbit derivatives
return new CircularOrbit(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
type, frame, date, mu);
} else {
// we have orbit derivatives
return new CircularOrbit(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
type, frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> convertType(final FieldOrbit<T> orbit) {
return (orbit.getType() == this) ? (FieldCircularOrbit<T>) orbit : new FieldCircularOrbit<>(orbit);
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
final PositionAngleType type,
final T[] stateVector,
final T[] stateVectorDot) {
final FieldCircularOrbit<T> circularOrbit = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(orbit);
stateVector[0] = circularOrbit.getA();
stateVector[1] = circularOrbit.getCircularEx();
stateVector[2] = circularOrbit.getCircularEy();
stateVector[3] = circularOrbit.getI();
stateVector[4] = circularOrbit.getRightAscensionOfAscendingNode();
stateVector[5] = circularOrbit.getAlpha(type);
if (stateVectorDot != null) {
if (orbit.hasDerivatives()) {
stateVectorDot[0] = circularOrbit.getADot();
stateVectorDot[1] = circularOrbit.getCircularExDot();
stateVectorDot[2] = circularOrbit.getCircularEyDot();
stateVectorDot[3] = circularOrbit.getIDot();
stateVectorDot[4] = circularOrbit.getRightAscensionOfAscendingNodeDot();
stateVectorDot[5] = circularOrbit.getAlphaDot(type);
} else {
Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
}
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> mapArrayToOrbit(final T[] stateVector,
final T[] stateVectorDot, final PositionAngleType type,
final FieldAbsoluteDate<T> date,
final T mu, final Frame frame) {
if (stateVectorDot == null) {
// we don't have orbit derivatives
return new FieldCircularOrbit<>(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
type, frame, date, mu);
} else {
// we have orbit derivatives
return new FieldCircularOrbit<>(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
type, frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> convertToFieldOrbit(final Field<T> field,
final Orbit orbit) {
return new FieldCircularOrbit<>(field, CIRCULAR.convertType(orbit));
}
/** {@inheritDoc} */
@Override
public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
final ParameterDriversList drivers = new ParameterDriversList();
final double[] array = new double[6];
mapOrbitToArray(orbit, type, array, null);
final double[] scale = scale(dP, orbit);
final String name = type == PositionAngleType.MEAN ?
MEAN_LAT_ARG :
type == PositionAngleType.ECCENTRIC ? ECC_LAT_ARG : TRUE_LAT_ARG;
drivers.add(new ParameterDriver(A, array[0], scale[0], 0.0, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(E_X, array[1], scale[1], -1.0, 1.0));
drivers.add(new ParameterDriver(E_Y, array[2], scale[2], -1.0, 1.0));
drivers.add(new ParameterDriver(INC, array[3], scale[3], 0.0, FastMath.PI));
drivers.add(new ParameterDriver(RAAN, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
return drivers;
}
/** {@inheritDoc} */
@Override
public CircularOrbit normalize(final Orbit orbit, final Orbit reference) {
// convert input to proper type
final CircularOrbit cO = convertType(orbit);
final CircularOrbit cR = convertType(reference);
final PositionAngleType cachedPositionAngleType = cO.getCachedPositionAngleType();
// perform normalization
if (cO.hasDerivatives()) {
return new CircularOrbit(cO.getA(),
cO.getCircularEx(),
cO.getCircularEy(),
cO.getI(),
MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
cR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngleType),
cR.getAlpha(cachedPositionAngleType)),
cO.getADot(),
cO.getCircularExDot(),
cO.getCircularEyDot(),
cO.getIDot(),
cO.getRightAscensionOfAscendingNodeDot(),
cO.getAlphaDot(cachedPositionAngleType),
cachedPositionAngleType,
cO.getFrame(),
cO.getDate(),
cO.getMu());
} else {
return new CircularOrbit(cO.getA(),
cO.getCircularEx(),
cO.getCircularEy(),
cO.getI(),
MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
cR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngleType),
cR.getAlpha(cachedPositionAngleType)),
cachedPositionAngleType,
cO.getFrame(),
cO.getDate(),
cO.getMu());
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {
// convert input to proper type
final FieldCircularOrbit<T> cO = convertType(orbit);
final FieldCircularOrbit<T> cR = convertType(reference);
final PositionAngleType positionAngleType = cO.getCachedPositionAngleType();
// perform normalization
if (cO.hasDerivatives()) {
return new FieldCircularOrbit<>(cO.getA(),
cO.getCircularEx(),
cO.getCircularEy(),
cO.getI(),
MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
cR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(cO.getAlpha(positionAngleType),
cR.getAlpha(positionAngleType)),
cO.getADot(),
cO.getCircularExDot(),
cO.getCircularEyDot(),
cO.getIDot(),
cO.getRightAscensionOfAscendingNodeDot(),
cO.getAlphaDot(positionAngleType),
positionAngleType,
cO.getFrame(),
cO.getDate(),
cO.getMu());
} else {
return new FieldCircularOrbit<>(cO.getA(),
cO.getCircularEx(),
cO.getCircularEy(),
cO.getI(),
MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
cR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(cO.getAlpha(positionAngleType),
cR.getAlpha(positionAngleType)),
positionAngleType,
cO.getFrame(),
cO.getDate(),
cO.getMu());
}
}
/** {@inheritDoc} */
@Override
public boolean isPositionAngleBased() {
return true;
}
},
/** Type for orbital representation in {@link EquinoctialOrbit} and {@link FieldEquinoctialOrbit} parameters. */
EQUINOCTIAL {
/** {@inheritDoc} */
@Override
public EquinoctialOrbit convertType(final Orbit orbit) {
return (orbit.getType() == this) ? (EquinoctialOrbit) orbit : new EquinoctialOrbit(orbit);
}
/** {@inheritDoc} */
@Override
public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
final double[] stateVector, final double[] stateVectorDot) {
final EquinoctialOrbit equinoctialOrbit =
(EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit);
stateVector[0] = equinoctialOrbit.getA();
stateVector[1] = equinoctialOrbit.getEquinoctialEx();
stateVector[2] = equinoctialOrbit.getEquinoctialEy();
stateVector[3] = equinoctialOrbit.getHx();
stateVector[4] = equinoctialOrbit.getHy();
stateVector[5] = equinoctialOrbit.getL(type);
if (stateVectorDot != null) {
if (orbit.hasDerivatives()) {
stateVectorDot[0] = equinoctialOrbit.getADot();
stateVectorDot[1] = equinoctialOrbit.getEquinoctialExDot();
stateVectorDot[2] = equinoctialOrbit.getEquinoctialEyDot();
stateVectorDot[3] = equinoctialOrbit.getHxDot();
stateVectorDot[4] = equinoctialOrbit.getHyDot();
stateVectorDot[5] = equinoctialOrbit.getLDot(type);
} else {
Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
}
}
}
/** {@inheritDoc} */
@Override
public EquinoctialOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
final AbsoluteDate date, final double mu, final Frame frame) {
if (stateVectorDot == null) {
// we don't have orbit derivatives
return new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
type, frame, date, mu);
} else {
// we have orbit derivatives
return new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
type, frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convertType(final FieldOrbit<T> orbit) {
return (orbit.getType() == this) ? (FieldEquinoctialOrbit<T>) orbit : new FieldEquinoctialOrbit<>(orbit);
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
final PositionAngleType type,
final T[] stateVector,
final T[] stateVectorDot) {
final FieldEquinoctialOrbit<T> equinoctialOrbit =
(FieldEquinoctialOrbit<T>) OrbitType.EQUINOCTIAL.convertType(orbit);
stateVector[0] = equinoctialOrbit.getA();
stateVector[1] = equinoctialOrbit.getEquinoctialEx();
stateVector[2] = equinoctialOrbit.getEquinoctialEy();
stateVector[3] = equinoctialOrbit.getHx();
stateVector[4] = equinoctialOrbit.getHy();
stateVector[5] = equinoctialOrbit.getL(type);
if (stateVectorDot != null) {
if (orbit.hasDerivatives()) {
stateVectorDot[0] = equinoctialOrbit.getADot();
stateVectorDot[1] = equinoctialOrbit.getEquinoctialExDot();
stateVectorDot[2] = equinoctialOrbit.getEquinoctialEyDot();
stateVectorDot[3] = equinoctialOrbit.getHxDot();
stateVectorDot[4] = equinoctialOrbit.getHyDot();
stateVectorDot[5] = equinoctialOrbit.getLDot(type);
} else {
Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
}
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> mapArrayToOrbit(final T[] stateVector,
final T[] stateVectorDot,
final PositionAngleType type,
final FieldAbsoluteDate<T> date,
final T mu, final Frame frame) {
if (stateVectorDot == null) {
// we don't have orbit derivatives
return new FieldEquinoctialOrbit<>(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
type, frame, date, mu);
} else {
// we have orbit derivatives
return new FieldEquinoctialOrbit<>(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
type, frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convertToFieldOrbit(final Field<T> field,
final Orbit orbit) {
return new FieldEquinoctialOrbit<>(field, EQUINOCTIAL.convertType(orbit));
}
/** {@inheritDoc} */
@Override
public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
final ParameterDriversList drivers = new ParameterDriversList();
final double[] array = new double[6];
mapOrbitToArray(orbit, type, array, null);
final double[] scale = scale(dP, orbit);
final String name = type == PositionAngleType.MEAN ?
MEAN_LON_ARG :
type == PositionAngleType.ECCENTRIC ? ECC_LON_ARG : TRUE_LON_ARG;
drivers.add(new ParameterDriver(A, array[0], scale[0], 0.0, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(E_X, array[1], scale[1], -1.0, 1.0));
drivers.add(new ParameterDriver(E_Y, array[2], scale[2], -1.0, 1.0));
drivers.add(new ParameterDriver(H_X, array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(H_Y, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
return drivers;
}
/** {@inheritDoc} */
@Override
public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) {
// convert input to proper type
final EquinoctialOrbit eO = convertType(orbit);
final EquinoctialOrbit eR = convertType(reference);
final PositionAngleType cachedPositionAngleType = eO.getCachedPositionAngleType();
// perform normalization
if (eO.hasDerivatives()) {
return new EquinoctialOrbit(eO.getA(),
eO.getEquinoctialEx(),
eO.getEquinoctialEy(),
eO.getHx(),
eO.getHy(),
MathUtils.normalizeAngle(eO.getL(cachedPositionAngleType),
eR.getL(cachedPositionAngleType)),
eO.getADot(),
eO.getEquinoctialExDot(),
eO.getEquinoctialEyDot(),
eO.getHxDot(),
eO.getHyDot(),
eO.getLDot(cachedPositionAngleType),
cachedPositionAngleType,
eO.getFrame(),
eO.getDate(),
eO.getMu());
} else {
return new EquinoctialOrbit(eO.getA(),
eO.getEquinoctialEx(),
eO.getEquinoctialEy(),
eO.getHx(),
eO.getHy(),
MathUtils.normalizeAngle(eO.getL(cachedPositionAngleType),
eR.getL(cachedPositionAngleType)),
cachedPositionAngleType,
eO.getFrame(),
eO.getDate(),
eO.getMu());
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {
// convert input to proper type
final FieldEquinoctialOrbit<T> eO = convertType(orbit);
final FieldEquinoctialOrbit<T> eR = convertType(reference);
final PositionAngleType positionAngleType = eO.getCachedPositionAngleType();
// perform normalization
if (eO.hasDerivatives()) {
return new FieldEquinoctialOrbit<>(eO.getA(),
eO.getEquinoctialEx(),
eO.getEquinoctialEy(),
eO.getHx(),
eO.getHy(),
MathUtils.normalizeAngle(eO.getL(positionAngleType),
eR.getL(positionAngleType)),
eO.getADot(),
eO.getEquinoctialExDot(),
eO.getEquinoctialEyDot(),
eO.getHxDot(),
eO.getHyDot(),
eO.getLDot(positionAngleType),
positionAngleType,
eO.getFrame(),
eO.getDate(),
eO.getMu());
} else {
return new FieldEquinoctialOrbit<>(eO.getA(),
eO.getEquinoctialEx(),
eO.getEquinoctialEy(),
eO.getHx(),
eO.getHy(),
MathUtils.normalizeAngle(eO.getL(positionAngleType),
eR.getL(positionAngleType)),
positionAngleType,
eO.getFrame(),
eO.getDate(),
eO.getMu());
}
}
/** {@inheritDoc} */
@Override
public boolean isPositionAngleBased() {
return true;
}
},
/** Type for orbital representation in {@link KeplerianOrbit} and {@link FieldKeplerianOrbit} parameters. */
KEPLERIAN {
/** {@inheritDoc} */
@Override
public KeplerianOrbit convertType(final Orbit orbit) {
return (orbit.getType() == this) ? (KeplerianOrbit) orbit : new KeplerianOrbit(orbit);
}
/** {@inheritDoc} */
@Override
public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
final double[] stateVector, final double[] stateVectorDot) {
final KeplerianOrbit keplerianOrbit =
(KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit);
stateVector[0] = keplerianOrbit.getA();
stateVector[1] = keplerianOrbit.getE();
stateVector[2] = keplerianOrbit.getI();
stateVector[3] = keplerianOrbit.getPerigeeArgument();
stateVector[4] = keplerianOrbit.getRightAscensionOfAscendingNode();
stateVector[5] = keplerianOrbit.getAnomaly(type);
if (stateVectorDot != null) {
if (orbit.hasDerivatives()) {
stateVectorDot[0] = keplerianOrbit.getADot();
stateVectorDot[1] = keplerianOrbit.getEDot();
stateVectorDot[2] = keplerianOrbit.getIDot();
stateVectorDot[3] = keplerianOrbit.getPerigeeArgumentDot();
stateVectorDot[4] = keplerianOrbit.getRightAscensionOfAscendingNodeDot();
stateVectorDot[5] = keplerianOrbit.getAnomalyDot(type);
} else {
Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
}
}
}
/** {@inheritDoc} */
@Override
public KeplerianOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
final AbsoluteDate date, final double mu, final Frame frame) {
if (stateVectorDot == null) {
// we don't have orbit derivatives
return new KeplerianOrbit(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
type, frame, date, mu);
} else {
// we have orbit derivatives
return new KeplerianOrbit(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
type, frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> convertType(final FieldOrbit<T> orbit) {
return (orbit.getType() == this) ? (FieldKeplerianOrbit<T>) orbit : new FieldKeplerianOrbit<>(orbit);
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
final PositionAngleType type,
final T[] stateVector,
final T[] stateVectorDot) {
final FieldKeplerianOrbit<T> keplerianOrbit =
(FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(orbit);
stateVector[0] = keplerianOrbit.getA();
stateVector[1] = keplerianOrbit.getE();
stateVector[2] = keplerianOrbit.getI();
stateVector[3] = keplerianOrbit.getPerigeeArgument();
stateVector[4] = keplerianOrbit.getRightAscensionOfAscendingNode();
stateVector[5] = keplerianOrbit.getAnomaly(type);
if (stateVectorDot != null) {
if (orbit.hasDerivatives()) {
stateVectorDot[0] = keplerianOrbit.getADot();
stateVectorDot[1] = keplerianOrbit.getEDot();
stateVectorDot[2] = keplerianOrbit.getIDot();
stateVectorDot[3] = keplerianOrbit.getPerigeeArgumentDot();
stateVectorDot[4] = keplerianOrbit.getRightAscensionOfAscendingNodeDot();
stateVectorDot[5] = keplerianOrbit.getAnomalyDot(type);
} else {
Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
}
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> mapArrayToOrbit(final T[] stateVector,
final T[] stateVectorDot,
final PositionAngleType type,
final FieldAbsoluteDate<T> date,
final T mu, final Frame frame) {
if (stateVectorDot == null) {
// we don't have orbit derivatives
return new FieldKeplerianOrbit<>(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
type, frame, date, mu);
} else {
// we have orbit derivatives
return new FieldKeplerianOrbit<>(stateVector[0], stateVector[1], stateVector[2],
stateVector[3], stateVector[4], stateVector[5],
stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
type, frame, date, mu);
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> convertToFieldOrbit(final Field<T> field,
final Orbit orbit) {
return new FieldKeplerianOrbit<>(field, KEPLERIAN.convertType(orbit));
}
/** {@inheritDoc} */
@Override
public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
final ParameterDriversList drivers = new ParameterDriversList();
final double[] array = new double[6];
mapOrbitToArray(orbit, type, array, null);
final double[] scale = scale(dP, orbit);
final String name = type == PositionAngleType.MEAN ?
MEAN_ANOM :
type == PositionAngleType.ECCENTRIC ? ECC_ANOM : TRUE_ANOM;
drivers.add(new ParameterDriver(A, array[0], scale[0], 0.0, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(ECC, array[1], scale[1], 0.0, 1.0));
drivers.add(new ParameterDriver(INC, array[2], scale[2], 0.0, FastMath.PI));
drivers.add(new ParameterDriver(PA, array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(RAAN, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
return drivers;
}
/** {@inheritDoc} */
@Override
public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) {
// convert input to proper type
final KeplerianOrbit kO = convertType(orbit);
final KeplerianOrbit kR = convertType(reference);
final PositionAngleType cachedPositionAngleType = kO.getCachedPositionAngleType();
// perform normalization
if (kO.hasDerivatives()) {
return new KeplerianOrbit(kO.getA(),
kO.getE(),
kO.getI(),
MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(),
kR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType),
kR.getAnomaly(cachedPositionAngleType)),
kO.getADot(),
kO.getEDot(),
kO.getIDot(),
kO.getPerigeeArgumentDot(),
kO.getRightAscensionOfAscendingNodeDot(),
kO.getAnomalyDot(cachedPositionAngleType),
cachedPositionAngleType,
kO.getFrame(),
kO.getDate(),
kO.getMu());
} else {
return new KeplerianOrbit(kO.getA(),
kO.getE(),
kO.getI(),
MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType),
kR.getAnomaly(cachedPositionAngleType)),
cachedPositionAngleType,
kO.getFrame(),
kO.getDate(),
kO.getMu());
}
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {
// convert input to proper type
final FieldKeplerianOrbit<T> kO = convertType(orbit);
final FieldKeplerianOrbit<T> kR = convertType(reference);
final PositionAngleType positionAngleType = kO.getCachedPositionAngleType();
// perform normalization
if (kO.hasDerivatives()) {
return new FieldKeplerianOrbit<>(kO.getA(),
kO.getE(),
kO.getI(),
MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(),
kR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(kO.getAnomaly(positionAngleType),
kR.getAnomaly(positionAngleType)),
kO.getADot(),
kO.getEDot(),
kO.getIDot(),
kO.getPerigeeArgumentDot(),
kO.getRightAscensionOfAscendingNodeDot(),
kO.getAnomalyDot(positionAngleType),
positionAngleType,
kO.getFrame(),
kO.getDate(),
kO.getMu());
} else {
return new FieldKeplerianOrbit<>(kO.getA(),
kO.getE(),
kO.getI(),
MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(),
kR.getRightAscensionOfAscendingNode()),
MathUtils.normalizeAngle(kO.getAnomaly(positionAngleType),
kR.getAnomaly(positionAngleType)),
positionAngleType,
kO.getFrame(),
kO.getDate(),
kO.getMu());
}
}
/** {@inheritDoc} */
@Override
public boolean isPositionAngleBased() {
return true;
}
};
/** Name for position along X. */
public static final String POS_X = "Px";
/** Name for position along Y. */
public static final String POS_Y = "Py";
/** Name for position along Z. */
public static final String POS_Z = "Pz";
/** Name for velocity along X. */
public static final String VEL_X = "Vx";
/** Name for velocity along Y. */
public static final String VEL_Y = "Vy";
/** Name for velocity along Z. */
public static final String VEL_Z = "Vz";
/** Name for semi major axis. */
public static final String A = "a";
/** Name for eccentricity. */
public static final String ECC = "e";
/** Name for eccentricity vector first component. */
public static final String E_X = "ex";
/** Name for eccentricity vector second component. */
public static final String E_Y = "ey";
/** Name for inclination. */
public static final String INC = "i";
/** Name for inclination vector first component. */
public static final String H_X = "hx";
/** Name for inclination vector second component . */
public static final String H_Y = "hy";
/** Name for perigee argument. */
public static final String PA = "ω";
/** Name for right ascension of ascending node. */
public static final String RAAN = "Ω";
/** Name for mean anomaly. */
public static final String MEAN_ANOM = "M";
/** Name for eccentric anomaly. */
public static final String ECC_ANOM = "E";
/** Name for mean anomaly. */
public static final String TRUE_ANOM = "v";
/** Name for mean argument of latitude. */
public static final String MEAN_LAT_ARG = "αM";
/** Name for eccentric argument of latitude. */
public static final String ECC_LAT_ARG = "αE";
/** Name for mean argument of latitude. */
public static final String TRUE_LAT_ARG = "αv";
/** Name for mean argument of longitude. */
public static final String MEAN_LON_ARG = "λM";
/** Name for eccentric argument of longitude. */
public static final String ECC_LON_ARG = "λE";
/** Name for mean argument of longitude. */
public static final String TRUE_LON_ARG = "λv";
/** Convert an orbit to the instance type.
* <p>
* The returned orbit is the specified instance itself if its type already matches,
* otherwise, a new orbit of the proper type created
* </p>
* @param orbit orbit to convert
* @return converted orbit with type guaranteed to match (so it can be cast safely)
*/
public abstract Orbit convertType(Orbit orbit);
/** Convert orbit to state array.
* <p>
* Note that all implementations of this method <em>must</em> be consistent with the
* implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
* PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
* method for the corresponding orbit type in terms of parameters order and meaning.
* </p>
* @param orbit orbit to map
* @param type type of the angle
* @param stateVector flat array into which the state vector should be mapped
* (it can have more than 6 elements, extra elements are untouched)
* @param stateVectorDot flat array into which the state vector derivative should be mapped
* (it can be null if derivatives are not desired, and it can have more than 6 elements, extra elements are untouched)
*/
public abstract void mapOrbitToArray(Orbit orbit, PositionAngleType type, double[] stateVector, double[] stateVectorDot);
/** Convert state array to orbital parameters.
* <p>
* Note that all implementations of this method <em>must</em> be consistent with the
* implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
* PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
* method for the corresponding orbit type in terms of parameters order and meaning.
* </p>
* @param array state as a flat array
* (it can have more than 6 elements, extra elements are ignored)
* @param arrayDot state derivative as a flat array
* (it can be null, in which case Keplerian motion is assumed,
* and it can have more than 6 elements, extra elements are ignored)
* @param type type of the angle
* @param date integration date
* @param mu central attraction coefficient used for propagation (m³/s²)
* @param frame frame in which integration is performed
* @return orbit corresponding to the flat array as a space dynamics object
*/
public abstract Orbit mapArrayToOrbit(double[] array, double[] arrayDot, PositionAngleType type,
AbsoluteDate date, double mu, Frame frame);
/** Convert an orbit to the instance type.
* <p>
* The returned orbit is the specified instance itself if its type already matches,
* otherwise, a new orbit of the proper type created
* </p>
* @param <T> CalculusFieldElement used
* @param orbit orbit to convert
* @return converted orbit with type guaranteed to match (so it can be cast safely)
*/
public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> convertType(FieldOrbit<T> orbit);
/** Convert orbit to state array.
* <p>
* Note that all implementations of this method <em>must</em> be consistent with the
* implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
* PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
* method for the corresponding orbit type in terms of parameters order and meaning.
* </p>
* @param <T> CalculusFieldElement used
* @param orbit orbit to map
* @param type type of the angle
* @param stateVector flat array into which the state vector should be mapped
* (it can have more than 6 elements, extra elements are untouched)
* @param stateVectorDot flat array into which the state vector derivative should be mapped
* (it can be null if derivatives are not desired, and it can have more than 6 elements, extra elements are untouched)
*/
public abstract <T extends CalculusFieldElement<T>>void mapOrbitToArray(FieldOrbit<T> orbit, PositionAngleType type,
T[] stateVector, T[] stateVectorDot);
/** Convert state array to orbital parameters.
* <p>
* Note that all implementations of this method <em>must</em> be consistent with the
* implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
* PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
* method for the corresponding orbit type in terms of parameters order and meaning.
* </p>
* @param <T> CalculusFieldElement used
* @param array state as a flat array
* (it can have more than 6 elements, extra elements are ignored)
* @param arrayDot state derivative as a flat array
* (it can be null, in which case Keplerian motion is assumed,
* @param type type of the angle
* @param date integration date
* @param mu central attraction coefficient used for propagation (m³/s²)
* @param frame frame in which integration is performed
* @return orbit corresponding to the flat array as a space dynamics object
*/
public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> mapArrayToOrbit(T[] array,
T[] arrayDot,
PositionAngleType type,
FieldAbsoluteDate<T> date,
T mu, Frame frame);
/** Convert an orbit to the "Fielded" instance type.
* @param <T> CalculusFieldElement used
* @param field CalculusField
* @param orbit base orbit
* @return converted FieldOrbit with type guaranteed to match (so it can be cast safely)
* @since 12.0
*/
public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> convertToFieldOrbit(Field<T> field,
Orbit orbit);
/** Get parameters drivers initialized from a reference orbit.
* @param dP user specified position error
* @param orbit reference orbit
* @param type type of the angle
* @return parameters drivers initialized from reference orbit
*/
public abstract ParameterDriversList getDrivers(double dP, Orbit orbit,
PositionAngleType type);
/** Normalize one orbit with respect to a reference one.
* <p>
* Given a, angular component ζ of an orbit and the corresponding
* angular component ζᵣ in the reference orbit, the angular component
* ζₙ of the normalized orbit will be ζₙ = ζ + 2kπ
* where k is chosen such that ζᵣ - π ≤ ζₙ ≤ ζᵣ + π. This is intended
* to avoid too large discontinuities and is particularly useful
* for normalizing the orbit after an impulsive maneuver with respect
* to the reference picked up before the maneuver.
* </p>
* @param <T> CalculusFieldElement used
* @param orbit orbit to normalize
* @param reference reference orbit
* @return normalized orbit (the type is guaranteed to match {@link OrbitType})
* @since 11.1
*/
public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> normalize(FieldOrbit<T> orbit,
FieldOrbit<T> reference);
/** Normalize one orbit with respect to a reference one.
* <p>
* Given a, angular component ζ of an orbit and the corresponding
* angular component ζᵣ in the reference orbit, the angular component
* ζₙ of the normalized orbit will be ζₙ = ζ + 2kπ
* where k is chosen such that ζᵣ - π ≤ ζₙ ≤ ζᵣ + π. This is intended
* to avoid too large discontinuities and is particularly useful
* for normalizing the orbit after an impulsive maneuver with respect
* to the reference picked up before the maneuver.
* </p>
* @param orbit orbit to normalize
* @param reference reference orbit
* @return normalized orbit (the type is guaranteed to match {@link OrbitType})
* @since 11.1
*/
public abstract Orbit normalize(Orbit orbit, Orbit reference);
/** Tells if the orbit type is based on position angles or not.
* @return true if based on {@link PositionAngleType}
* @since 12.0
*/
public abstract boolean isPositionAngleBased();
/** Compute scaling factor for parameters drivers.
* <p>
* The scales are estimated from partial derivatives properties of orbits,
* starting from a scalar position error specified by the user.
* Considering the energy conservation equation V = sqrt(mu (2/r - 1/a)),
* we get at constant energy (i.e. on a Keplerian trajectory):
* <pre>
* V r² |dV| = mu |dr|
* </pre>
* <p> So we deduce a scalar velocity error consistent with the position error.
* From here, we apply orbits Jacobians matrices to get consistent scales
* on orbital parameters.
*
* @param dP user specified position error
* @param orbit reference orbit
* @return scaling factor array
*/
protected double[] scale(final double dP, final Orbit orbit) {
// estimate the scalar velocity error
final PVCoordinates pv = orbit.getPVCoordinates();
final double r2 = pv.getPosition().getNormSq();
final double v = pv.getVelocity().getNorm();
final double dV = orbit.getMu() * dP / (v * r2);
final double[] scale = new double[6];
// convert the orbit to the desired type
final double[][] jacobian = new double[6][6];
final Orbit converted = convertType(orbit);
converted.getJacobianWrtCartesian(PositionAngleType.TRUE, jacobian);
for (int i = 0; i < 6; ++i) {
final double[] row = jacobian[i];
scale[i] = FastMath.abs(row[0]) * dP +
FastMath.abs(row[1]) * dP +
FastMath.abs(row[2]) * dP +
FastMath.abs(row[3]) * dV +
FastMath.abs(row[4]) * dV +
FastMath.abs(row[5]) * dV;
if (Double.isNaN(scale[i])) {
throw new OrekitException(OrekitMessages.SINGULAR_JACOBIAN_FOR_ORBIT_TYPE, this);
}
}
return scale;
}
}