All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.orekit.bodies.JPLCelestialBody Maven / Gradle / Ivy

Go to download

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 ...).

There is a newer version: 12.2.1
Show newest version
/* 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