AlignedAndConstrained.java

  1. /* Copyright 2022-2025 Luc Maisonobe
  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.attitudes;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
  21. import org.hipparchus.analysis.differentiation.UnivariateDerivative2;
  22. import org.hipparchus.analysis.differentiation.UnivariateDerivative2Field;
  23. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  24. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  25. import org.hipparchus.geometry.euclidean.threed.Rotation;
  26. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  27. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  28. import org.orekit.annotation.DefaultDataContext;
  29. import org.orekit.bodies.OneAxisEllipsoid;
  30. import org.orekit.errors.OrekitException;
  31. import org.orekit.errors.OrekitMessages;
  32. import org.orekit.frames.Frame;
  33. import org.orekit.frames.FramesFactory;
  34. import org.orekit.time.AbsoluteDate;
  35. import org.orekit.time.FieldAbsoluteDate;
  36. import org.orekit.utils.AngularCoordinates;
  37. import org.orekit.utils.ExtendedPositionProvider;
  38. import org.orekit.utils.FieldAngularCoordinates;
  39. import org.orekit.utils.FieldPVCoordinatesProvider;
  40. import org.orekit.utils.PVCoordinatesProvider;
  41. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  42. import org.orekit.utils.TimeStampedPVCoordinates;

  43. import java.util.HashMap;
  44. import java.util.Map;

  45. /**
  46.  * Attitude provider with one satellite vector aligned and another one constrained to two targets.
  47.  * @author Luc Maisonobe
  48.  * @since 12.2
  49.  */
  50. public class AlignedAndConstrained implements AttitudeProvider
  51. {

  52.     /** Satellite vector for primary target. */
  53.     private final FieldVector3D<UnivariateDerivative2> primarySat;

  54.     /** Primary target. */
  55.     private final TargetProvider primaryTarget;

  56.     /** Satellite vector for secondary target. */
  57.     private final FieldVector3D<UnivariateDerivative2> secondarySat;

  58.     /** Secondary target. */
  59.     private final TargetProvider secondaryTarget;

  60.     /** Sun model. */
  61.     private final ExtendedPositionProvider sun;

  62.     /** Earth model. */
  63.     private final OneAxisEllipsoid earth;

  64.     /** Reference inertial frame. */
  65.     private final Frame inertialFrame;

  66.     /** Cached field-based satellite vectors. */
  67.     private final transient Map<Field<? extends CalculusFieldElement<?>>, Cache<? extends CalculusFieldElement<?>>>
  68.         cachedSatelliteVectors;

  69.     /**
  70.      * Simple constructor.
  71.      * @param primarySat      satellite vector for primary target
  72.      * @param primaryTarget   primary target
  73.      * @param secondarySat    satellite vector for secondary target
  74.      * @param secondaryTarget secondary target
  75.      * @param inertialFrame   reference inertial frame
  76.      * @param sun             Sun model
  77.      * @param earth           Earth model
  78.      * @since 13.0
  79.      */
  80.     public AlignedAndConstrained(final Vector3D primarySat, final TargetProvider primaryTarget,
  81.                                  final Vector3D secondarySat, final TargetProvider secondaryTarget,
  82.                                  final Frame inertialFrame, final ExtendedPositionProvider sun,
  83.                                  final OneAxisEllipsoid earth) {
  84.         if (!inertialFrame.isPseudoInertial()) {
  85.             throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, inertialFrame.getName());
  86.         }
  87.         this.primarySat             = new FieldVector3D<>(UnivariateDerivative2Field.getInstance(), primarySat);
  88.         this.primaryTarget          = primaryTarget;
  89.         this.secondarySat           = new FieldVector3D<>(UnivariateDerivative2Field.getInstance(), secondarySat);
  90.         this.secondaryTarget        = secondaryTarget;
  91.         this.inertialFrame          = inertialFrame;
  92.         this.sun                    = sun;
  93.         this.earth                  = earth;
  94.         this.cachedSatelliteVectors = new HashMap<>();
  95.     }

  96.     /**
  97.      * Constructor with default inertial frame.
  98.      * @param primarySat      satellite vector for primary target
  99.      * @param primaryTarget   primary target
  100.      * @param secondarySat    satellite vector for secondary target
  101.      * @param secondaryTarget secondary target
  102.      * @param sun             Sun model
  103.      * @param earth           Earth model
  104.      */
  105.     @DefaultDataContext
  106.     public AlignedAndConstrained(final Vector3D primarySat, final TargetProvider primaryTarget,
  107.                                  final Vector3D secondarySat, final TargetProvider secondaryTarget,
  108.                                  final ExtendedPositionProvider sun,
  109.                                  final OneAxisEllipsoid earth)
  110.     {
  111.         this(primarySat, primaryTarget, secondarySat, secondaryTarget, FramesFactory.getGCRF(), sun, earth);
  112.     }

  113.     /** {@inheritDoc} */
  114.     @Override
  115.     public Rotation getAttitudeRotation(final PVCoordinatesProvider pvProv, final AbsoluteDate date, final Frame frame) {
  116.         final TimeStampedPVCoordinates satPV = pvProv.getPVCoordinates(date, inertialFrame);

  117.         // compute targets references at the specified date
  118.         final Vector3D primaryDirection   = primaryTarget.getTargetDirection(sun, earth, satPV, inertialFrame);
  119.         final Vector3D secondaryDirection = secondaryTarget.getTargetDirection(sun, earth, satPV, inertialFrame);

  120.         // compute transform from inertial frame to satellite frame
  121.         final Rotation rotation = new Rotation(primaryDirection, secondaryDirection, primarySat.toVector3D(),
  122.                 secondarySat.toVector3D());
  123.         if (inertialFrame != frame) {
  124.             // prepend transform from specified frame to inertial frame
  125.             final Rotation prepended = frame.getStaticTransformTo(inertialFrame, date).getRotation();
  126.             return rotation.compose(prepended, RotationConvention.VECTOR_OPERATOR);
  127.         }
  128.         return rotation;
  129.     }

  130.     /** {@inheritDoc} */
  131.     @Override
  132.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  133.                                 final AbsoluteDate date,
  134.                                 final Frame frame)
  135.     {
  136.         final TimeStampedPVCoordinates satPV = pvProv.getPVCoordinates(date, inertialFrame);

  137.         // compute targets references at the specified date
  138.         final FieldVector3D<UnivariateDerivative2> primaryDirection   = primaryTarget.getDerivative2TargetDirection(sun,
  139.                 earth, satPV, inertialFrame);
  140.         final FieldVector3D<UnivariateDerivative2> secondaryDirection = secondaryTarget.getDerivative2TargetDirection(sun,
  141.                 earth, satPV, inertialFrame);

  142.         // compute transform from inertial frame to satellite frame
  143.         final FieldRotation<UnivariateDerivative2> inertToSatRotation =
  144.             new FieldRotation<>(primaryDirection, secondaryDirection, primarySat, secondarySat);

  145.         // build the angular coordinates
  146.         final AngularCoordinates angularCoordinates = new AngularCoordinates(inertToSatRotation);
  147.         final Attitude attitude = new Attitude(date, inertialFrame, angularCoordinates);
  148.         return attitude.withReferenceFrame(frame);
  149.     }

  150.     /** {@inheritDoc} */
  151.     @Override
  152.     public <T extends CalculusFieldElement<T>> FieldRotation<T> getAttitudeRotation(final FieldPVCoordinatesProvider<T> pvProv,
  153.                                                                                     final FieldAbsoluteDate<T> date,
  154.                                                                                     final Frame frame) {
  155.         final TimeStampedFieldPVCoordinates<T> satPV = pvProv.getPVCoordinates(date, inertialFrame);

  156.         // compute targets references at the specified date
  157.         final FieldVector3D<T> primaryDirection   = primaryTarget.getTargetDirection(sun, earth, satPV, inertialFrame);
  158.         final FieldVector3D<T> secondaryDirection = secondaryTarget.getTargetDirection(sun, earth, satPV, inertialFrame);

  159.         // compute transform from inertial frame to satellite frame
  160.         final Field<T> field = date.getField();
  161.         final FieldRotation<T> rotation = new FieldRotation<>(primaryDirection, secondaryDirection,
  162.                 new FieldVector3D<>(field, primarySat.toVector3D()), new FieldVector3D<>(field, secondarySat.toVector3D()));
  163.         if (inertialFrame != frame) {
  164.             // prepend transform from specified frame to inertial frame
  165.             final FieldRotation<T> prepended = frame.getStaticTransformTo(inertialFrame, date).getRotation();
  166.             return rotation.compose(prepended, RotationConvention.VECTOR_OPERATOR);
  167.         }
  168.         return rotation;
  169.     }

  170.     /** {@inheritDoc} */
  171.     @Override
  172.     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
  173.                                                                             final FieldAbsoluteDate<T> date,
  174.                                                                             final Frame frame)
  175.     {
  176.         // get the satellite vectors for specified field
  177.         @SuppressWarnings("unchecked")
  178.         final Cache<T> satVectors =
  179.             (Cache<T>) cachedSatelliteVectors.computeIfAbsent(date.getField(),
  180.                                                               f -> new Cache<>(date.getField(), primarySat, secondarySat));

  181.         final TimeStampedFieldPVCoordinates<T> satPV = pvProv.getPVCoordinates(date, inertialFrame);

  182.         // compute targets references at the specified date
  183.         final FieldVector3D<FieldUnivariateDerivative2<T>> primaryDirection   = primaryTarget.getDerivative2TargetDirection(sun,
  184.                 earth, satPV, inertialFrame);
  185.         final FieldVector3D<FieldUnivariateDerivative2<T>> secondaryDirection = secondaryTarget.getDerivative2TargetDirection(sun,
  186.                 earth, satPV, inertialFrame);

  187.         // compute transform from inertial frame to satellite frame
  188.         final FieldRotation<FieldUnivariateDerivative2<T>> inertToSatRotation =
  189.             new FieldRotation<>(primaryDirection, secondaryDirection, satVectors.primarySat, satVectors.secondarySat);

  190.         // build the attitude
  191.         final FieldAngularCoordinates<T> angularCoordinates = new FieldAngularCoordinates<>(inertToSatRotation);
  192.         final FieldAttitude<T> attitude = new FieldAttitude<>(date, inertialFrame, angularCoordinates);
  193.         return attitude.withReferenceFrame(frame);
  194.     }

  195.     /** Container for cached satellite vectors. */
  196.     private static class Cache<T extends CalculusFieldElement<T>> {

  197.         /** Satellite vector for primary target. */
  198.         private final FieldVector3D<FieldUnivariateDerivative2<T>> primarySat;

  199.         /** Satellite vector for primary target. */
  200.         private final FieldVector3D<FieldUnivariateDerivative2<T>> secondarySat;

  201.         /** Simple constructor.
  202.          * @param field field to which the elements belong
  203.          * @param primarySat satellite vector for primary target
  204.          * @param secondarySat satellite vector for primary target
  205.          */
  206.         Cache(final Field<T> field,
  207.               final FieldVector3D<UnivariateDerivative2> primarySat,
  208.               final FieldVector3D<UnivariateDerivative2> secondarySat) {
  209.             final FieldUnivariateDerivative2<T> zero =
  210.                 new FieldUnivariateDerivative2<>(field.getZero(), field.getZero(), field.getZero());
  211.             this.primarySat   = new FieldVector3D<>(zero.newInstance(primarySat.getX().getValue()),
  212.                                                     zero.newInstance(primarySat.getY().getValue()),
  213.                                                     zero.newInstance(primarySat.getZ().getValue()));
  214.             this.secondarySat = new FieldVector3D<>(zero.newInstance(secondarySat.getX().getValue()),
  215.                                                     zero.newInstance(secondarySat.getY().getValue()),
  216.                                                     zero.newInstance(secondarySat.getZ().getValue()));
  217.         }

  218.     }

  219. }