AnalyticalSolarPositionProvider.java

  1. /* Copyright 2022-2025 Romain Serra
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.orekit.bodies;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  20. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  21. import org.hipparchus.util.FastMath;
  22. import org.hipparchus.util.FieldSinCos;
  23. import org.hipparchus.util.SinCos;
  24. import org.orekit.annotation.DefaultDataContext;
  25. import org.orekit.data.DataContext;
  26. import org.orekit.frames.Frame;
  27. import org.orekit.frames.FieldStaticTransform;
  28. import org.orekit.frames.StaticTransform;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.time.FieldAbsoluteDate;
  31. import org.orekit.time.TimeScale;
  32. import org.orekit.utils.ExtendedPositionProvider;

  33. /**
  34.  * Class computing low-fidelity positions for the Sun. They should only be used in the decades around the year 2000.
  35.  * <br> Reference: Montenbruck, Oliver, and Gill, Eberhard. Satellite orbits : models, methods, and
  36.  * applications. Berlin New York: Springer, 2000.
  37.  *
  38.  * @author Romain Serra
  39.  * @since 12.2
  40.  */
  41. public class AnalyticalSolarPositionProvider implements ExtendedPositionProvider {

  42.     /** Sine anc cosine of approximate ecliptic angle used when converting from ecliptic to EME2000. */
  43.     private static final SinCos SIN_COS_ECLIPTIC_ANGLE_EME2000 = FastMath.sinCos(FastMath.toRadians(23.43929111));

  44.     /** Precomputed constant angle used in calculations. */
  45.     private static final double INTERMEDIATE_ANGLE = FastMath.toRadians(282.9400);

  46.     /** EME2000 frame. */
  47.     private final Frame eme2000;

  48.     /** Time scale for Julian date. */
  49.     private final TimeScale timeScale;

  50.     /**
  51.      * Constructor.
  52.      * @param dataContext data context
  53.      */
  54.     public AnalyticalSolarPositionProvider(final DataContext dataContext) {
  55.         this.eme2000 = dataContext.getFrames().getEME2000();
  56.         this.timeScale = dataContext.getTimeScales().getUTC();
  57.     }

  58.     /**
  59.      * Constructor with default data context.
  60.      */
  61.     @DefaultDataContext
  62.     public AnalyticalSolarPositionProvider() {
  63.         this(DataContext.getDefault());
  64.     }

  65.     /** {@inheritDoc} */
  66.     @Override
  67.     public Vector3D getPosition(final AbsoluteDate date, final Frame frame) {
  68.         final Vector3D eme2000Position = getEME2000Position(date);
  69.         if (frame.equals(eme2000)) {
  70.             return eme2000Position;
  71.         } else {
  72.             final StaticTransform transform = eme2000.getStaticTransformTo(frame, date);
  73.             return transform.transformPosition(eme2000Position);
  74.         }
  75.     }

  76.     /**
  77.      * Computes the Sun's position vector in EME2000.
  78.      * @param date date
  79.      * @return solar position
  80.      */
  81.     private Vector3D getEME2000Position(final AbsoluteDate date) {
  82.         final double tt = (date.getJD(timeScale) - 2451545.0) / 36525.0;
  83.         final double M = FastMath.toRadians(357.5256 + 35999.049 * tt);
  84.         final SinCos sinCosM = FastMath.sinCos(M);
  85.         final SinCos sinCos2M = FastMath.sinCos(2 * M);
  86.         final double r = (149.619 - 2.499 * sinCosM.cos() - 0.021 * sinCos2M.cos()) * 1.0e9;
  87.         final double lambda = INTERMEDIATE_ANGLE + M + FastMath.toRadians(6892.0 * sinCosM.sin() + 72.0 * sinCos2M.sin()) / 3600.0;
  88.         final SinCos sinCosLambda = FastMath.sinCos(lambda);
  89.         return new Vector3D(r * sinCosLambda.cos(), r * sinCosLambda.sin() * SIN_COS_ECLIPTIC_ANGLE_EME2000.cos(),
  90.             r * sinCosLambda.sin() * SIN_COS_ECLIPTIC_ANGLE_EME2000.sin());
  91.     }

  92.     /** {@inheritDoc} */
  93.     @Override
  94.     public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPosition(final FieldAbsoluteDate<T> date,
  95.                                                                             final Frame frame) {
  96.         final FieldVector3D<T> eme2000Position = getFieldEME2000Position(date);
  97.         if (frame.equals(eme2000)) {
  98.             return eme2000Position;
  99.         } else {
  100.             final FieldStaticTransform<T> transform = eme2000.getStaticTransformTo(frame, date);
  101.             return transform.transformPosition(eme2000Position);
  102.         }
  103.     }

  104.     /**
  105.      * Computes the Sun's position vector in EME2000.
  106.      * @param date date
  107.      * @param <T> field type
  108.      * @return solar position
  109.      */
  110.     private <T extends CalculusFieldElement<T>> FieldVector3D<T> getFieldEME2000Position(final FieldAbsoluteDate<T> date) {
  111.         final T tt = date.getJD(timeScale).subtract(2451545.0).divide(36525.0);
  112.         final T M = FastMath.toRadians(tt.multiply(35999.049).add(357.5256));
  113.         final FieldSinCos<T> sinCosM = FastMath.sinCos(M);
  114.         final FieldSinCos<T> sinCos2M = FastMath.sinCos(M.multiply(2));
  115.         final T r = (sinCosM.cos().multiply(-2.499).subtract(sinCos2M.cos().multiply(0.021)).add(149.619)).multiply(1.0e9);
  116.         final T lambda = M.add(INTERMEDIATE_ANGLE).add(FastMath.toRadians(
  117.             sinCosM.sin().multiply(6892.0).add(sinCos2M.sin().multiply(72.0)).divide(3600.0)));
  118.         final FieldSinCos<T> sinCosLambda = FastMath.sinCos(lambda);
  119.         return new FieldVector3D<>(r.multiply(sinCosLambda.cos()),
  120.             r.multiply(sinCosLambda.sin()).multiply(SIN_COS_ECLIPTIC_ANGLE_EME2000.cos()),
  121.             r.multiply(sinCosLambda.sin()).multiply(SIN_COS_ECLIPTIC_ANGLE_EME2000.sin()));
  122.     }
  123. }