1   /* Copyright 2002-2026 CS GROUP
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.propagation.relative;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
21  import org.orekit.frames.Frame;
22  import org.orekit.time.FieldAbsoluteDate;
23  import org.orekit.time.TimeUtils;
24  import org.orekit.utils.FieldPVCoordinates;
25  import org.orekit.utils.TimeStampedFieldPVCoordinates;
26  
27  /**
28   * This class stores the solution of a two-impulse rendez-vous. All the contained variables are expressed in the same
29   * frame, accessible through the method getFrame(). Since the PVT of the chaser on both ends of the transfer orbit are
30   * stored in this object in addition to the ΔV vectors, it is possible to reconstruct the orbit of the chaser before and
31   * after the transfer.
32   *
33   * @param <T> Any scalar field
34   *
35   * @author Jérôme Tabeaud
36   * @author Romain Cuvillon
37   * @since 14.0
38   */
39  public class FieldTwoImpulseTransfer<T extends CalculusFieldElement<T>> {
40  
41      /**
42       * PVT of the chaser just after the first maneuver.
43       */
44      private final TimeStampedFieldPVCoordinates<T> pvt1;
45  
46      /**
47       * PVT of the chaser just before the second maneuver.
48       */
49      private final TimeStampedFieldPVCoordinates<T> pvt2;
50  
51      /**
52       * ΔV vector of first maneuver.
53       */
54      private final FieldVector3D<T> deltaV1;
55  
56      /**
57       * ΔV vector of second maneuver.
58       */
59      private final FieldVector3D<T> deltaV2;
60  
61      /**
62       * Frame in which the PVT and ΔV are expressed.
63       */
64      private final Frame frame;
65  
66      /**
67       * Creates a new TwoImpulseTransfer object from the given PVT and ΔV vectors.
68       *
69       * @param pvt1    PVT at the start of the transfer
70       * @param pvt2    PVT at the end of the transfer
71       * @param deltaV1 ΔV to enter the transfer orbit
72       * @param deltaV2 ΔV to exit the transfer orbit
73       * @param frame   Frame in which the PVT and ΔV vector are expressed
74       */
75      public FieldTwoImpulseTransfer(final TimeStampedFieldPVCoordinates<T> pvt1,
76                                     final TimeStampedFieldPVCoordinates<T> pvt2,
77                                     final FieldVector3D<T> deltaV1,
78                                     final FieldVector3D<T> deltaV2,
79                                     final Frame frame) {
80          this.pvt1    = pvt1;
81          this.pvt2    = pvt2;
82          this.deltaV1 = deltaV1;
83          this.deltaV2 = deltaV2;
84          this.frame   = frame;
85      }
86  
87      /**
88       * Creates a new {@link TwoImpulseTransfer} object from the given PVT before the first maneuver and after the second
89       * maneuver (on the initial and final orbits), as well as the velocity vectors after the first maneuver and before
90       * the second maneuver (on the transfer orbit).
91       *
92       * @param pvt1BeforeMan PVT before the departure maneuver
93       * @param v1AfterMan    Velocity after the departure maneuver
94       * @param pvt2AfterMan  PVT after the rendez-vous maneuver
95       * @param v2BeforeMan   Velocity before the rendez-vous maneuver
96       * @param inputFrame    Frame in which the PVT and velocity vectors are expressed
97       * @return TwoImpulseTransfer object that corresponds to the inputs
98       */
99      public FieldTwoImpulseTransfer<T> fromPVTAndVelocities(final TimeStampedFieldPVCoordinates<T> pvt1BeforeMan,
100                                                            final FieldVector3D<T> v1AfterMan,
101                                                            final TimeStampedFieldPVCoordinates<T> pvt2AfterMan,
102                                                            final FieldVector3D<T> v2BeforeMan,
103                                                            final Frame inputFrame) {
104         final TimeStampedFieldPVCoordinates<T> pvt1AfterMan  =
105                         new TimeStampedFieldPVCoordinates<>(pvt1BeforeMan.getDate(),
106                                                             new FieldPVCoordinates<>(pvt1BeforeMan.getPosition(),
107                                                                                      v1AfterMan));
108         final TimeStampedFieldPVCoordinates<T> pvt2BeforeMan =
109                         new TimeStampedFieldPVCoordinates<>(pvt2AfterMan.getDate(),
110                                                             new FieldPVCoordinates<>(pvt2AfterMan.getPosition(),
111                                                                                      v2BeforeMan));
112         final FieldVector3D<T> delta_V1 = pvt1AfterMan.getVelocity().subtract(pvt1BeforeMan.getVelocity());
113         final FieldVector3D<T> delta_V2 = pvt2AfterMan.getVelocity().subtract(pvt2BeforeMan.getVelocity());
114         return new FieldTwoImpulseTransfer<>(pvt1AfterMan, pvt2BeforeMan, delta_V1, delta_V2, inputFrame);
115     }
116 
117     /**
118      * Gets the PVT of the chaser just after the first maneuver, i.e. at the start of the transfer orbit.
119      *
120      * @return PVT of the chaser just after the first maneuver
121      */
122     public TimeStampedFieldPVCoordinates<T> getPvt1() {
123         return pvt1;
124     }
125 
126     /**
127      * Gets the PVT of the chaser just before the second maneuver, i.e. at the end of the transfer orbit.
128      *
129      * @return PVT of the chaser just before the second maneuver
130      */
131     public TimeStampedFieldPVCoordinates<T> getPvt2() {
132         return pvt2;
133     }
134 
135     /**
136      * Gets the ΔV vector of the first maneuver.
137      *
138      * @return The ΔV vector of first maneuver
139      */
140     public FieldVector3D<T> getDeltaV1() {
141         return deltaV1;
142     }
143 
144     /**
145      * Get the ΔV vector of the second maneuver.
146      *
147      * @return The ΔV vector of second maneuver
148      */
149     public FieldVector3D<T> getDeltaV2() {
150         return deltaV2;
151     }
152 
153     /**
154      * Get the PVT of the chaser just after the first maneuver expressed in the given frame.
155      *
156      * @param outputFrame given frame for the first maneuver
157      * @return PVT of the chaser just after the first maneuver
158      */
159     public TimeStampedFieldPVCoordinates<T> getPvt1(final Frame outputFrame) {
160         return frame.getTransformTo(outputFrame, pvt1.getDate()).transformPVCoordinates(pvt1);
161     }
162 
163     /**
164      * Get the PVT of the chaser just before the second maneuver expressed in the given frame.
165      *
166      * @param outputFrame given frame for the 2nd maneuver
167      * @return PVT of the chaser just before the second maneuver
168      */
169     public TimeStampedFieldPVCoordinates<T> getPvt2(final Frame outputFrame) {
170         return frame.getTransformTo(outputFrame, pvt2.getDate()).transformPVCoordinates(pvt2);
171     }
172 
173     /**
174      * Get the ΔV vector of first maneuver in the given frame.
175      *
176      * @param outputFrame given frame for the first maneuver
177      * @return The ΔV vector of first maneuver in the given frame at the given date
178      */
179     public FieldVector3D<T> getDeltaV1(final Frame outputFrame) {
180         return frame.getTransformTo(outputFrame, pvt1.getDate()).transformVector(deltaV1);
181     }
182 
183     /**
184      * Get the ΔV vector of second maneuver in the given frame.
185      *
186      * @param outputFrame given frame for the 2nd maneuver
187      * @return The ΔV vector of second maneuver in the given frame at the given date
188      */
189     public FieldVector3D<T> getDeltaV2(final Frame outputFrame) {
190         return frame.getTransformTo(outputFrame, pvt2.getDate()).transformVector(deltaV2);
191     }
192 
193     /**
194      * Computes the total ΔV of the transfer.
195      *
196      * @return ||ΔV_total|| = ||ΔV1|| + ||ΔV2||
197      */
198     public T getTotalDeltaV() {
199         return deltaV1.getNorm().add(deltaV2.getNorm());
200     }
201 
202     /**
203      * Returns the duration of the transfer between the two impulses.
204      * @return The duration of the transfer between the two impulses
205      */
206     public T getDuration() {
207         return pvt2.durationFrom(pvt1);
208     }
209 
210     /**
211      * Returns the departure date.
212      *
213      * @return the departure date
214      */
215     public FieldAbsoluteDate<T> getDepartureDate() {
216         return pvt1.getDate();
217     }
218 
219     /**
220      * Returns the arrival date.
221      *
222      * @return the arrival date
223      */
224     public FieldAbsoluteDate<T> getArrivalDate() {
225         return pvt2.getDate();
226     }
227 
228     /**
229      * Returns the frame in which all elements contained in the object are expressed.
230      *
231      * @return The frame of the elements of the object
232      */
233     public Frame getFrame() {
234         return frame;
235     }
236 
237     /**
238      * Get the PVT before the injection maneuver into the transfer orbit.
239      *
240      * @return The PVT before the injection maneuver into the transfer orbit
241      */
242     public TimeStampedFieldPVCoordinates<T> getPvt1BeforeMan() {
243         return new TimeStampedFieldPVCoordinates<>(pvt1.getDate(),
244                                                    new FieldPVCoordinates<>(pvt1.getPosition(),
245                                                                             pvt1.getVelocity().subtract(deltaV1)));
246     }
247 
248     /**
249      * Get the PVT after the velocity-synchronization maneuver into the target orbit.
250      *
251      * @return The PVT after the velocity-synchronization maneuver into the target orbit
252      */
253     public TimeStampedFieldPVCoordinates<T> getPvt2AfterMan() {
254         return new TimeStampedFieldPVCoordinates<>(pvt2.getDate(),
255                                                    new FieldPVCoordinates<>(pvt2.getPosition(),
256                                                                             pvt2.getVelocity().add(deltaV2)));
257     }
258 
259     /**
260      * Converts all the PVT and ΔV vectors to the desired frame.
261      *
262      * @param outputFrame Desired output frame
263      * @return TwoImpulseTransfer object expressed in the desired frame
264      */
265     public FieldTwoImpulseTransfer<T> expressInFrame(final Frame outputFrame) {
266         return new FieldTwoImpulseTransfer<>(getPvt1(outputFrame),
267                                              getPvt2(outputFrame),
268                                              getDeltaV1(outputFrame),
269                                              getDeltaV2(outputFrame),
270                                              outputFrame);
271     }
272 
273     /**
274      * Writes a string summarizing the transfer characteristics (PVT and ΔV vectors).
275      * <p>
276      *     Only the real value is printed, not the field one.
277      * </p>
278      *
279      * @return The string summary
280      */
281     public String toString() {
282         return "Two impulse transfer\n" +
283                "\n    Frame:                       " + getFrame().getName() +
284                "\n    PVT after first manoeuvre:   " + getPvt1() +
285                "\n    PVT before second manoeuvre: " + getPvt2() +
286                "\n    ΔV of first manoeuvre:       " + getDeltaV1() + " ; ‖ΔV₁‖ = " + getDeltaV1().getNorm() +
287                "\n    ΔV of second manoeuvre:      " + getDeltaV2() + " ; ‖ΔV₂‖ = " + getDeltaV2().getNorm() +
288                "\n    Total ΔV:                    " + getTotalDeltaV() +
289                "\n    Duration:                    " + TimeUtils.secondsToDHMS(getDuration().getReal()) + "\n";
290     }
291 }