FieldAdditionalDataProvider.java

  1. /* Copyright 2002-2025 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;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.orekit.time.FieldAbsoluteDate;

  20. /** This interface allows to modify {@link FieldSpacecraftState} and set up additional data.
  21.  * <p>
  22.  * {@link FieldPropagator Propagators} generate {@link FieldSpacecraftState states} that contain at
  23.  * least orbit, attitude, and mass. These states may however also contain {@link
  24.  * FieldSpacecraftState#addAdditionalData(String, Object)}  additional data}.
  25.  * Instances of classes implementing this interface are intended to be registered to propagators
  26.  * so they can either modify the basic components (orbit, attitude and mass) or add additional
  27.  * data incrementally after having computed the basic components.
  28.  * </p>
  29.  * <p>
  30.  * Some additional data may depend on previous additional data to
  31.  * be already available the before they can be computed. It may even be impossible to compute some
  32.  * of these additional data at some time if they depend on conditions that are fulfilled only
  33.  * after propagation as started or some event has occurred. As the propagator builds the complete
  34.  * state incrementally, looping over the registered providers, it must call their {@link
  35.  * #update(FieldSpacecraftState) update} methods in an order that fulfill these dependencies that
  36.  * may be time-dependent and are not related to the order in which the providers are registered to
  37.  * the propagator. This reordering is performed each time the complete state is built, using a yield
  38.  * mechanism. The propagator first pushes all providers in a stack and then empty the stack, one provider
  39.  * at a time, taking care to select only providers that do <em>not</em> {@link
  40.  * #yields(FieldSpacecraftState) yield} when asked. Consider for example a case where providers A, B and C
  41.  * have been registered and provider B needs in fact the additional data generated by provider C. Then
  42.  * when a complete state is built, the propagator puts the three providers in a new stack, and then starts the incremental
  43.  * generation of additional data. It first checks provider A which does not yield so it is popped from
  44.  * the stack and the additional data it generates is added. Then provider B is checked, but it yields
  45.  * because data from provider C is not yet available. So propagator checks provider C which does not
  46.  * yield, so it is popped out of the stack and applied. At this stage, provider B is the only remaining one
  47.  * in the stack, so it is checked again, but this time it does not yield because the data from provider
  48.  * C is available as it has just been added, so provider B is popped from the stack and applied. The stack
  49.  * is now empty and the propagator can return the completed state.
  50.  * </p>
  51.  * <p>
  52.  * It is possible that at some stages in the propagation, a subset of the providers registered to a
  53.  * propagator all yield and cannot {@link #update(FieldSpacecraftState) update} the data.
  54.  * This happens for example during the initialization phase of a propagator that
  55.  * computes State Transition Matrices or Jacobian matrices. These features are managed as secondary equations
  56.  * in the ODE integrator, and initialized after the primary equations (which correspond to orbit) have
  57.  * been initialized. So when the primary equation are initialized, the providers that depend on the secondary
  58.  * data will all yield. This behavior is expected. Another case occurs when users set up additional data
  59.  * that induce a dependency loop (data A depending on data B which depends on data C which depends on
  60.  * data A). In this case, the three corresponding providers will wait for each other and indefinitely yield.
  61.  * This second case is a deadlock and results from a design error of the additional data management at
  62.  * application level. The propagator cannot know it in advance if a subset of providers that all yield is
  63.  * normal or not. So at propagator level, when either situation is detected, the propagator just gives up and
  64.  * returns the most complete state it was able to compute, without generating any error. Errors will indeed
  65.  * not be triggered in the first case (once the primary equations have been initialized, the secondary
  66.  * equations will be initialized too), and they will be triggered in the second case as soon as user attempts
  67.  * to retrieve an additional data that was not added.
  68.  * </p>
  69.  * @see org.orekit.propagation.FieldPropagator
  70.  * @see org.orekit.propagation.integration.FieldAdditionalDerivativesProvider
  71.  * @see FieldAbstractStateModifier
  72.  * @author Luc Maisonobe
  73.  * @param <O> type of the additional data
  74.  * @param <T> type of the field elements
  75.  * @since 13.0
  76.  */
  77. public interface FieldAdditionalDataProvider<O, T extends CalculusFieldElement<T>> {

  78.     /** Get the name of the additional data.
  79.      * <p>
  80.      * If a provider just modifies one of the basic elements (orbit, attitude
  81.      * or mass) without adding any new data, it should return the empty string
  82.      * as its name.
  83.      * </p>
  84.      * @return name of the additional data (names containing "orekit"
  85.      * with any case are reserved for the library internal use)
  86.      */
  87.     String getName();

  88.     /** Initialize the additional state provider at the start of propagation.
  89.      * @param initialState initial state information at the start of propagation
  90.      * @param target       date of propagation
  91.      * @since 11.2
  92.      */
  93.     default void init(final FieldSpacecraftState<T> initialState, final FieldAbsoluteDate<T> target) {
  94.         // nothing by default
  95.     }

  96.     /** Check if this provider should yield so another provider has an opportunity to add missing parts.
  97.      * <p>
  98.      * Decision to yield is often based on an additional data being {@link FieldSpacecraftState#hasAdditionalData(String)
  99.      * already available} in the provided {@code state} (but it could theoretically also depend on
  100.      * an additional state derivative being {@link FieldSpacecraftState#hasAdditionalStateDerivative(String)
  101.      * already available}, or any other criterion). If for example a provider needs the state transition
  102.      * matrix, it could implement this method as:
  103.      * </p>
  104.      * <pre>{@code
  105.      * public boolean yields(final FieldSpacecraftState state) {
  106.      *     return state.hasAdditionalData("STM");
  107.      * }
  108.      * }</pre>
  109.      * <p>
  110.      * The default implementation returns {@code false}, meaning that the data can be
  111.      * {@link #getAdditionalData(FieldSpacecraftState) generated} immediately.
  112.      * </p>
  113.      * @param state state to handle
  114.      * @return true if this provider should yield so another provider has an opportunity to add missing parts
  115.      * as the state is incrementally built up
  116.      * @since 11.1
  117.      */
  118.     default boolean yields(FieldSpacecraftState<T> state) {
  119.         return false;
  120.     }

  121.     /** Get the additional data.
  122.      * @param state spacecraft state to which additional data should correspond
  123.      * @return additional data corresponding to spacecraft state
  124.      */
  125.     O getAdditionalData(FieldSpacecraftState<T> state);

  126.     /** Update a state.
  127.      * @param state spacecraft state to update
  128.      * @return updated state
  129.      * @since 12.1
  130.      */
  131.     default FieldSpacecraftState<T> update(final FieldSpacecraftState<T> state) {
  132.         return state.addAdditionalData(getName(), getAdditionalData(state));
  133.     }

  134. }