
org.orekit.bodies.JPLCelestialBody Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of orekit Show documentation
Show all versions of orekit Show documentation
OREKIT is a low level space dynamics library.
It provides basic elements (orbits, dates, attitude, frames ...) and
various algorithms to handle them (conversions, analytical and numerical
propagation, pointing ...).
/* Copyright 2002-2023 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.bodies;
import java.io.Serializable;
import org.hipparchus.CalculusFieldElement;
import org.hipparchus.Field;
import org.hipparchus.geometry.euclidean.threed.FieldRotation;
import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.Precision;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.bodies.JPLEphemeridesLoader.EphemerisType;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitInternalError;
import org.orekit.frames.FieldStaticTransform;
import org.orekit.frames.FieldTransform;
import org.orekit.frames.Frame;
import org.orekit.frames.StaticTransform;
import org.orekit.frames.Transform;
import org.orekit.frames.TransformProvider;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.FieldPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/** Implementation of the {@link CelestialBody} interface using JPL or INPOP ephemerides.
* @author Luc Maisonobe
*/
class JPLCelestialBody implements CelestialBody {
/** Serializable UID. */
private static final long serialVersionUID = 3809787672779740923L;
/** Name of the body. */
private final String name;
/** Regular expression for supported files names. */
private final String supportedNames;
/** Ephemeris type to generate. */
private final JPLEphemeridesLoader.EphemerisType generateType;
/** Raw position-velocity provider. */
private final transient JPLEphemeridesLoader.RawPVProvider rawPVProvider;
/** Attraction coefficient of the body (m³/s²). */
private final double gm;
/** Scaling factor for position-velocity. */
private final double scale;
/** IAU pole. */
private final IAUPole iauPole;
/** Inertially oriented, body-centered frame. */
private final Frame inertialFrame;
/** Body oriented, body-centered frame. */
private final Frame bodyFrame;
/** Build an instance and the underlying frame.
* @param name name of the body
* @param supportedNames regular expression for supported files names
* @param generateType ephemeris type to generate
* @param rawPVProvider raw position-velocity provider
* @param gm attraction coefficient (in m³/s²)
* @param scale scaling factor for position-velocity
* @param iauPole IAU pole implementation
* @param definingFrameAlignedWithICRF frame in which celestial body coordinates are defined,
* this frame must be aligned with ICRF
* @param inertialFrameName name to use for inertial frame (if null a default name will be built)
* @param bodyOrientedFrameName name to use for body-oriented frame (if null a default name will be built)
*/
JPLCelestialBody(final String name, final String supportedNames,
final JPLEphemeridesLoader.EphemerisType generateType,
final JPLEphemeridesLoader.RawPVProvider rawPVProvider,
final double gm, final double scale,
final IAUPole iauPole, final Frame definingFrameAlignedWithICRF,
final String inertialFrameName, final String bodyOrientedFrameName) {
this.name = name;
this.gm = gm;
this.scale = scale;
this.supportedNames = supportedNames;
this.generateType = generateType;
this.rawPVProvider = rawPVProvider;
this.iauPole = iauPole;
this.inertialFrame = new InertiallyOriented(definingFrameAlignedWithICRF, inertialFrameName);
this.bodyFrame = new BodyOriented(bodyOrientedFrameName);
}
/** {@inheritDoc} */
public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
// apply the scale factor to raw position-velocity
final PVCoordinates rawPV = rawPVProvider.getRawPV(date);
final TimeStampedPVCoordinates scaledPV = new TimeStampedPVCoordinates(date, scale, rawPV);
// the raw PV are relative to the parent of the body centered inertially oriented frame
final Transform transform = getInertiallyOrientedFrame().getParent().getTransformTo(frame, date);
// convert to requested frame
return transform.transformPVCoordinates(scaledPV);
}
/** Get the {@link FieldPVCoordinates} of the body in the selected frame.
* @param date current date
* @param frame the frame where to define the position
* @param type of the field elements
* @return time-stamped position/velocity of the body (m and m/s)
*/
public > TimeStampedFieldPVCoordinates getPVCoordinates(final FieldAbsoluteDate date,
final Frame frame) {
// apply the scale factor to raw position-velocity
final FieldPVCoordinates rawPV = rawPVProvider.getRawPV(date);
final TimeStampedFieldPVCoordinates scaledPV = new TimeStampedFieldPVCoordinates<>(date, scale, rawPV);
// the raw PV are relative to the parent of the body centered inertially oriented frame
final FieldTransform transform = getInertiallyOrientedFrame().getParent().getTransformTo(frame, date);
// convert to requested frame
return transform.transformPVCoordinates(scaledPV);
}
/** {@inheritDoc} */
@Override
public Vector3D getPosition(final AbsoluteDate date, final Frame frame) {
// apply the scale factor to raw position
final Vector3D rawPosition = rawPVProvider.getRawPosition(date);
final Vector3D scaledPosition = rawPosition.scalarMultiply(scale);
// the raw position is relative to the parent of the body centered inertially oriented frame
final StaticTransform transform = getInertiallyOrientedFrame().getParent().getStaticTransformTo(frame, date);
// convert to requested frame
return transform.transformPosition(scaledPosition);
}
/** {@inheritDoc} */
@Override
public > FieldVector3D getPosition(final FieldAbsoluteDate date, final Frame frame) {
// apply the scale factor to raw position
final FieldVector3D rawPosition = rawPVProvider.getRawPosition(date);
final FieldVector3D scaledPosition = rawPosition.scalarMultiply(scale);
// the raw position is relative to the parent of the body centered inertially oriented frame
final FieldStaticTransform transform = getInertiallyOrientedFrame().getParent().getStaticTransformTo(frame, date);
// convert to requested frame
return transform.transformPosition(scaledPosition);
}
/** Replace the instance with a data transfer object for serialization.
*
* This intermediate class serializes the files supported names, the ephemeris type
* and the body name.
*
* @return data transfer object that will be serialized
*/
@DefaultDataContext
private Object writeReplace() {
return new DTOCelestialBody(supportedNames, generateType, name);
}
/** {@inheritDoc} */
public String getName() {
return name;
}
/** {@inheritDoc} */
public double getGM() {
return gm;
}
/** {@inheritDoc} */
public Frame getInertiallyOrientedFrame() {
return inertialFrame;
}
/** {@inheritDoc} */
public Frame getBodyOrientedFrame() {
return bodyFrame;
}
/** Inertially oriented body centered frame. */
private class InertiallyOriented extends Frame {
/** Serializable UID. */
private static final long serialVersionUID = -8849993808761896559L;
/** Suffix for inertial frame name. */
private static final String INERTIAL_FRAME_SUFFIX = "/inertial";
/** Simple constructor.
* @param definingFrame frame in which celestial body coordinates are defined
* @param frameName name to use (if null a default name will be built)
*/
InertiallyOriented(final Frame definingFrame, final String frameName) {
super(definingFrame, new TransformProvider() {
/** Serializable UID. */
private static final long serialVersionUID = -8610328386110652400L;
/** {@inheritDoc} */
public Transform getTransform(final AbsoluteDate date) {
// compute translation from parent frame to self
final PVCoordinates pv = getPVCoordinates(date, definingFrame);
final Transform translation = new Transform(date, pv.negate());
// compute rotation from ICRF frame to self,
// as per the "Report of the IAU/IAG Working Group on Cartographic
// Coordinates and Rotational Elements of the Planets and Satellites"
// These definitions are common for all recent versions of this report
// published every three years, the precise values of pole direction
// and W angle coefficients may vary from publication year as models are
// adjusted. These coefficients are not in this class, they are in the
// specialized classes that do implement the getPole and getPrimeMeridianAngle
// methods
final Vector3D pole = iauPole.getPole(date);
final Vector3D qNode = iauPole.getNode(date);
final Transform rotation =
new Transform(date, new Rotation(pole, qNode, Vector3D.PLUS_K, Vector3D.PLUS_I));
// update transform from parent to self
return new Transform(date, translation, rotation);
}
@Override
public StaticTransform getStaticTransform(final AbsoluteDate date) {
// compute translation from parent frame to self
final PVCoordinates pv = getPVCoordinates(date, definingFrame);
// compute rotation from ICRF frame to self,
// as per the "Report of the IAU/IAG Working Group on Cartographic
// Coordinates and Rotational Elements of the Planets and Satellites"
// These definitions are common for all recent versions of this report
// published every three years, the precise values of pole direction
// and W angle coefficients may vary from publication year as models are
// adjusted. These coefficients are not in this class, they are in the
// specialized classes that do implement the getPole and getPrimeMeridianAngle
// methods
final Vector3D pole = iauPole.getPole(date);
final Vector3D qNode = iauPole.getNode(date);
final Rotation rotation =
new Rotation(pole, qNode, Vector3D.PLUS_K, Vector3D.PLUS_I);
// update transform from parent to self
return StaticTransform.of(date, pv.getPosition().negate(), rotation);
}
/** {@inheritDoc} */
public > FieldTransform getTransform(final FieldAbsoluteDate date) {
// compute translation from parent frame to self
final FieldPVCoordinates pv = getPVCoordinates(date, definingFrame);
final FieldTransform translation = new FieldTransform<>(date, pv.negate());
// compute rotation from ICRF frame to self,
// as per the "Report of the IAU/IAG Working Group on Cartographic
// Coordinates and Rotational Elements of the Planets and Satellites"
// These definitions are common for all recent versions of this report
// published every three years, the precise values of pole direction
// and W angle coefficients may vary from publication year as models are
// adjusted. These coefficients are not in this class, they are in the
// specialized classes that do implement the getPole and getPrimeMeridianAngle
// methods
final FieldVector3D pole = iauPole.getPole(date);
FieldVector3D qNode = FieldVector3D.crossProduct(Vector3D.PLUS_K, pole);
if (qNode.getNormSq().getReal() < Precision.SAFE_MIN) {
qNode = FieldVector3D.getPlusI(date.getField());
}
final FieldTransform rotation =
new FieldTransform<>(date,
new FieldRotation<>(pole,
qNode,
FieldVector3D.getPlusK(date.getField()),
FieldVector3D.getPlusI(date.getField())));
// update transform from parent to self
return new FieldTransform<>(date, translation, rotation);
}
@Override
public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) {
// field
final Field field = date.getField();
// compute translation from parent frame to self
final FieldPVCoordinates pv = getPVCoordinates(date, definingFrame);
// compute rotation from ICRF frame to self,
// as per the "Report of the IAU/IAG Working Group on Cartographic
// Coordinates and Rotational Elements of the Planets and Satellites"
// These definitions are common for all recent versions of this report
// published every three years, the precise values of pole direction
// and W angle coefficients may vary from publication year as models are
// adjusted. These coefficients are not in this class, they are in the
// specialized classes that do implement the getPole and getPrimeMeridianAngle
// methods
final FieldVector3D pole = iauPole.getPole(date);
final FieldVector3D qNode = iauPole.getNode(date);
final FieldRotation rotation =
new FieldRotation<>(pole, qNode, FieldVector3D.getPlusK(field), FieldVector3D.getPlusI(field));
// update transform from parent to self
return FieldStaticTransform.of(date, pv.getPosition().negate(), rotation);
}
}, frameName == null ? name + INERTIAL_FRAME_SUFFIX : frameName, true);
}
/** Replace the instance with a data transfer object for serialization.
*
* This intermediate class serializes the files supported names, the ephemeris type
* and the body name.
*
* @return data transfer object that will be serialized
*/
@DefaultDataContext
private Object writeReplace() {
return new DTOInertialFrame(supportedNames, generateType, name);
}
}
/** Body oriented body centered frame. */
private class BodyOriented extends Frame {
/** Serializable UID. */
private static final long serialVersionUID = 20170109L;
/** Suffix for body frame name. */
private static final String BODY_FRAME_SUFFIX = "/rotating";
/** Simple constructor.
* @param frameName name to use (if null a default name will be built)
*/
BodyOriented(final String frameName) {
super(inertialFrame, new TransformProvider() {
/** Serializable UID. */
private static final long serialVersionUID = 20170109L;
/** {@inheritDoc} */
public Transform getTransform(final AbsoluteDate date) {
final double dt = 10.0;
final double w0 = iauPole.getPrimeMeridianAngle(date);
final double w1 = iauPole.getPrimeMeridianAngle(date.shiftedBy(dt));
return new Transform(date,
new Rotation(Vector3D.PLUS_K, w0, RotationConvention.FRAME_TRANSFORM),
new Vector3D((w1 - w0) / dt, Vector3D.PLUS_K));
}
/** {@inheritDoc} */
public > FieldTransform getTransform(final FieldAbsoluteDate date) {
final double dt = 10.0;
final T w0 = iauPole.getPrimeMeridianAngle(date);
final T w1 = iauPole.getPrimeMeridianAngle(date.shiftedBy(dt));
return new FieldTransform<>(date,
new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), w0,
RotationConvention.FRAME_TRANSFORM),
new FieldVector3D<>(w1.subtract(w0).divide(dt), Vector3D.PLUS_K));
}
}, frameName == null ? name + BODY_FRAME_SUFFIX : frameName, false);
}
/** Replace the instance with a data transfer object for serialization.
*
* This intermediate class serializes the files supported names, the ephemeris type
* and the body name.
*
* @return data transfer object that will be serialized
*/
@DefaultDataContext
private Object writeReplace() {
return new DTOBodyFrame(supportedNames, generateType, name);
}
}
/** Internal class used only for serialization. */
@DefaultDataContext
private abstract static class DataTransferObject implements Serializable {
/** Serializable UID. */
private static final long serialVersionUID = 674742836536072422L;
/** Regular expression for supported files names. */
private final String supportedNames;
/** Ephemeris type to generate. */
private final EphemerisType generateType;
/** Name of the body. */
private final String name;
/** Simple constructor.
* @param supportedNames regular expression for supported files names
* @param generateType ephemeris type to generate
* @param name name of the body
*/
DataTransferObject(final String supportedNames, final EphemerisType generateType, final String name) {
this.supportedNames = supportedNames;
this.generateType = generateType;
this.name = name;
}
/** Get the body associated with the serialized data.
* @return body associated with the serialized data
*/
protected JPLCelestialBody getBody() {
try {
// first try to use the factory, in order to avoid building a new instance
// each time we deserialize and have the object properly cached
final CelestialBody factoryProvided =
DataContext.getDefault().getCelestialBodies().getBody(name);
if (factoryProvided instanceof JPLCelestialBody) {
final JPLCelestialBody jplBody = (JPLCelestialBody) factoryProvided;
if (supportedNames.equals(jplBody.supportedNames) && generateType == jplBody.generateType) {
// the factory created exactly the object we needed, just return it
return jplBody;
}
}
// the factory does not return the object we want
// we create a new one from scratch and don't cache it
return (JPLCelestialBody) new JPLEphemeridesLoader(supportedNames, generateType).loadCelestialBody(name);
} catch (OrekitException oe) {
throw new OrekitInternalError(oe);
}
}
}
/** Specialization of the data transfer object for complete celestial body serialization. */
@DefaultDataContext
private static class DTOCelestialBody extends DataTransferObject {
/** Serializable UID. */
private static final long serialVersionUID = -8287341529741045958L;
/** Simple constructor.
* @param supportedNames regular expression for supported files names
* @param generateType ephemeris type to generate
* @param name name of the body
*/
DTOCelestialBody(final String supportedNames, final EphemerisType generateType, final String name) {
super(supportedNames, generateType, name);
}
/** Replace the deserialized data transfer object with a {@link JPLCelestialBody}.
* @return replacement {@link JPLCelestialBody}
*/
private Object readResolve() {
return getBody();
}
}
/** Specialization of the data transfer object for inertially oriented frame serialization. */
@DefaultDataContext
private static class DTOInertialFrame extends DataTransferObject {
/** Serializable UID. */
private static final long serialVersionUID = 7915071664444154948L;
/** Simple constructor.
* @param supportedNames regular expression for supported files names
* @param generateType ephemeris type to generate
* @param name name of the body
*/
DTOInertialFrame(final String supportedNames, final EphemerisType generateType, final String name) {
super(supportedNames, generateType, name);
}
/** Replace the deserialized data transfer object with a {@link Frame}.
* @return replacement {@link Frame}
*/
private Object readResolve() {
return getBody().inertialFrame;
}
}
/** Specialization of the data transfer object for body oriented frame serialization. */
@DefaultDataContext
private static class DTOBodyFrame extends DataTransferObject {
/** Serializable UID. */
private static final long serialVersionUID = -3194195019557081000L;
/** Simple constructor.
* @param supportedNames regular expression for supported files names
* @param generateType ephemeris type to generate
* @param name name of the body
*/
DTOBodyFrame(final String supportedNames, final EphemerisType generateType, final String name) {
super(supportedNames, generateType, name);
}
/** Replace the deserialized data transfer object with a {@link Frame}.
* @return replacement {@link Frame}
*/
private Object readResolve() {
return getBody().bodyFrame;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy