FieldAbstractPropagator.java

  1. /* Copyright 2002-2023 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 java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.LinkedList;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Queue;

  25. import org.hipparchus.CalculusFieldElement;
  26. import org.hipparchus.Field;
  27. import org.orekit.attitudes.AttitudeProvider;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.frames.Frame;
  31. import org.orekit.propagation.sampling.FieldStepHandlerMultiplexer;
  32. import org.orekit.time.FieldAbsoluteDate;
  33. import org.orekit.utils.FieldArrayDictionary;
  34. import org.orekit.utils.FieldTimeSpanMap;
  35. import org.orekit.utils.TimeStampedFieldPVCoordinates;

  36. /** Common handling of {@link Propagator} methods for analytical propagators.
  37.  * <p>
  38.  * This abstract class allows to provide easily the full set of {@link Propagator}
  39.  * methods, including all propagation modes support and discrete events support for
  40.  * any simple propagation method.
  41.  * </p>
  42.  * @param <T> the type of the field elements
  43.  * @author Luc Maisonobe
  44.  */
  45. public abstract class FieldAbstractPropagator<T extends CalculusFieldElement<T>> implements FieldPropagator<T> {

  46.     /** Multiplexer for step handlers. */
  47.     private FieldStepHandlerMultiplexer<T> multiplexer;

  48.     /** Start date. */
  49.     private FieldAbsoluteDate<T> startDate;

  50.     /** Attitude provider. */
  51.     private AttitudeProvider attitudeProvider;

  52.     /** Additional state providers. */
  53.     private final List<FieldAdditionalStateProvider<T>> additionalStateProviders;

  54.     /** States managed by neither additional equations nor state providers. */
  55.     private final Map<String, FieldTimeSpanMap<T[], T>> unmanagedStates;

  56.     /** Field used.*/
  57.     private final Field<T> field;

  58.     /** Initial state. */
  59.     private FieldSpacecraftState<T> initialState;

  60.     /** Build a new instance.
  61.      * @param field setting the field
  62.      */
  63.     protected FieldAbstractPropagator(final Field<T> field) {
  64.         this.field               = field;
  65.         multiplexer              = new FieldStepHandlerMultiplexer<>();
  66.         additionalStateProviders = new ArrayList<>();
  67.         unmanagedStates          = new HashMap<>();
  68.     }

  69.     /** Set a start date.
  70.      * @param startDate start date
  71.      */
  72.     protected void setStartDate(final FieldAbsoluteDate<T> startDate) {
  73.         this.startDate = startDate;
  74.     }

  75.     /** Get the start date.
  76.      * @return start date
  77.      */
  78.     protected FieldAbsoluteDate<T> getStartDate() {
  79.         return startDate;
  80.     }

  81.     /**  {@inheritDoc} */
  82.     public AttitudeProvider getAttitudeProvider() {
  83.         return attitudeProvider;
  84.     }

  85.     /**  {@inheritDoc} */
  86.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  87.         this.attitudeProvider = attitudeProvider;
  88.     }

  89.     /** Field getter.
  90.      * @return field used*/
  91.     public Field<T> getField() {
  92.         return field;
  93.     }

  94.     /** {@inheritDoc} */
  95.     public FieldSpacecraftState<T> getInitialState() {
  96.         return initialState;
  97.     }

  98.     /** {@inheritDoc} */
  99.     public Frame getFrame() {
  100.         return initialState.getFrame();
  101.     }

  102.     /** {@inheritDoc} */
  103.     public void resetInitialState(final FieldSpacecraftState<T> state) {
  104.         initialState = state;
  105.         setStartDate(state.getDate());
  106.     }

  107.     /** {@inheritDoc} */
  108.     public FieldStepHandlerMultiplexer<T> getMultiplexer() {
  109.         return multiplexer;
  110.     }

  111.     /** {@inheritDoc} */
  112.     public void addAdditionalStateProvider(final FieldAdditionalStateProvider<T> additionalStateProvider) {

  113.         // check if the name is already used
  114.         if (isAdditionalStateManaged(additionalStateProvider.getName())) {
  115.             // this additional state is already registered, complain
  116.             throw new OrekitException(OrekitMessages.ADDITIONAL_STATE_NAME_ALREADY_IN_USE,
  117.                                       additionalStateProvider.getName());
  118.         }

  119.         // this is really a new name, add it
  120.         additionalStateProviders.add(additionalStateProvider);

  121.     }

  122.     /** {@inheritDoc} */
  123.     public List<FieldAdditionalStateProvider<T>> getAdditionalStateProviders() {
  124.         return Collections.unmodifiableList(additionalStateProviders);
  125.     }

  126.     /** Update state by adding unmanaged states.
  127.      * @param original original state
  128.      * @return updated state, with unmanaged states included
  129.      * @see #updateAdditionalStates(FieldSpacecraftState)
  130.      */
  131.     protected FieldSpacecraftState<T> updateUnmanagedStates(final FieldSpacecraftState<T> original) {

  132.         // start with original state,
  133.         // which may already contain additional states, for example in interpolated ephemerides
  134.         FieldSpacecraftState<T> updated = original;

  135.         // update the states not managed by providers
  136.         for (final Map.Entry<String, FieldTimeSpanMap<T[], T>> entry : unmanagedStates.entrySet()) {
  137.             updated = updated.addAdditionalState(entry.getKey(),
  138.                                                  entry.getValue().get(original.getDate()));
  139.         }

  140.         return updated;

  141.     }

  142.     /** Update state by adding all additional states.
  143.      * @param original original state
  144.      * @return updated state, with all additional states included
  145.      * @see #addAdditionalStateProvider(FieldAdditionalStateProvider)
  146.      */
  147.     protected FieldSpacecraftState<T> updateAdditionalStates(final FieldSpacecraftState<T> original) {

  148.         // start with original state and unmanaged states
  149.         FieldSpacecraftState<T> updated = updateUnmanagedStates(original);

  150.         // set up queue for providers
  151.         final Queue<FieldAdditionalStateProvider<T>> pending = new LinkedList<>(getAdditionalStateProviders());

  152.         // update the additional states managed by providers, taking care of dependencies
  153.         int yieldCount = 0;
  154.         while (!pending.isEmpty()) {
  155.             final FieldAdditionalStateProvider<T> provider = pending.remove();
  156.             if (provider.yields(updated)) {
  157.                 // this generator has to wait for another one,
  158.                 // we put it again in the pending queue
  159.                 pending.add(provider);
  160.                 if (++yieldCount >= pending.size()) {
  161.                     // all pending providers yielded!, they probably need data not yet initialized
  162.                     // we let the propagation proceed, if these data are really needed right now
  163.                     // an appropriate exception will be triggered when caller tries to access them
  164.                     break;
  165.                 }
  166.             } else {
  167.                 // we can use this provider right now
  168.                 updated    = updated.addAdditionalState(provider.getName(), provider.getAdditionalState(updated));
  169.                 yieldCount = 0;
  170.             }
  171.         }

  172.         return updated;

  173.     }

  174.     /**
  175.      * Initialize the additional state providers at the start of propagation.
  176.      * @param target date of propagation. Not equal to {@code initialState.getDate()}.
  177.      * @since 11.2
  178.      */
  179.     protected void initializeAdditionalStates(final FieldAbsoluteDate<T> target) {
  180.         for (final FieldAdditionalStateProvider<T> provider : additionalStateProviders) {
  181.             provider.init(initialState, target);
  182.         }
  183.     }

  184.     /** {@inheritDoc} */
  185.     public boolean isAdditionalStateManaged(final String name) {
  186.         for (final FieldAdditionalStateProvider<T> provider : additionalStateProviders) {
  187.             if (provider.getName().equals(name)) {
  188.                 return true;
  189.             }
  190.         }
  191.         return false;
  192.     }

  193.     /** {@inheritDoc} */
  194.     public String[] getManagedAdditionalStates() {
  195.         final String[] managed = new String[additionalStateProviders.size()];
  196.         for (int i = 0; i < managed.length; ++i) {
  197.             managed[i] = additionalStateProviders.get(i).getName();
  198.         }
  199.         return managed;
  200.     }

  201.     /** {@inheritDoc} */
  202.     public FieldSpacecraftState<T> propagate(final FieldAbsoluteDate<T> target) {
  203.         if (startDate == null) {
  204.             startDate = getInitialState().getDate();
  205.         }
  206.         return propagate(startDate, target);
  207.     }

  208.     /** {@inheritDoc} */
  209.     public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final Frame frame) {
  210.         return propagate(date).getPVCoordinates(frame);
  211.     }

  212.     /** Initialize propagation.
  213.      * @since 10.1
  214.      */
  215.     protected void initializePropagation() {

  216.         unmanagedStates.clear();

  217.         if (initialState != null) {
  218.             // there is an initial state
  219.             // (null initial states occur for example in interpolated ephemerides)
  220.             // copy the additional states present in initialState but otherwise not managed
  221.             for (final FieldArrayDictionary<T>.Entry initial : initialState.getAdditionalStatesValues().getData()) {
  222.                 if (!isAdditionalStateManaged(initial.getKey())) {
  223.                     // this additional state is in the initial state, but is unknown to the propagator
  224.                     // we store it in a way event handlers may change it
  225.                     unmanagedStates.put(initial.getKey(),
  226.                                         new FieldTimeSpanMap<>(initial.getValue(),
  227.                                                                initialState.getDate().getField()));
  228.                 }
  229.             }
  230.         }
  231.     }

  232.     /** Notify about a state change.
  233.      * @param state new state
  234.      */
  235.     protected void stateChanged(final FieldSpacecraftState<T> state) {
  236.         final FieldAbsoluteDate<T> date    = state.getDate();
  237.         final boolean              forward = date.durationFrom(getStartDate()).getReal() >= 0.0;
  238.         for (final  FieldArrayDictionary<T>.Entry changed : state.getAdditionalStatesValues().getData()) {
  239.             final FieldTimeSpanMap<T[], T> tsm = unmanagedStates.get(changed.getKey());
  240.             if (tsm != null) {
  241.                 // this is an unmanaged state
  242.                 if (forward) {
  243.                     tsm.addValidAfter(changed.getValue(), date);
  244.                 } else {
  245.                     tsm.addValidBefore(changed.getValue(), date);
  246.                 }
  247.             }
  248.         }
  249.     }

  250. }