AttitudesSequence.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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 java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.HashMap;
  21. import java.util.Map;

  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.frames.Frame;
  24. import org.orekit.propagation.Propagator;
  25. import org.orekit.propagation.SpacecraftState;
  26. import org.orekit.propagation.events.AbstractReconfigurableDetector;
  27. import org.orekit.propagation.events.EventDetector;
  28. import org.orekit.propagation.events.handlers.EventHandler;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.utils.PVCoordinatesProvider;

  31. /** This classes manages a sequence of different attitude providers that are activated
  32.  * in turn according to switching events.
  33.  * <p>Only one attitude provider in the sequence is in an active state. When one of
  34.  * the switch event associated with the active provider occurs, the active provider becomes
  35.  * the one specified with the event. A simple example is a provider for the sun lighted part
  36.  * of the orbit and another provider for the eclipse time. When the sun lighted provider is active,
  37.  * the eclipse entry event is checked and when it occurs the eclipse provider is activated.
  38.  * When the eclipse provider is active, the eclipse exit event is checked and when it occurs
  39.  * the sun lighted provider is activated again. This sequence is a simple loop.</p>
  40.  * <p>An active attitude provider may have several switch events and next provider settings, leading
  41.  * to different activation patterns depending on which events are triggered first. An example
  42.  * of this feature is handling switches to safe mode if some contingency condition is met, in
  43.  * addition to the nominal switches that correspond to proper operations. Another example
  44.  * is handling of maneuver mode.<p>
  45.  * @author Luc Maisonobe
  46.  * @since 5.1
  47.  */
  48. public class AttitudesSequence implements AttitudeProvider {

  49.     /** Serializable UID. */
  50.     private static final long serialVersionUID = 5140034224175180354L;

  51.     /** Active provider. */
  52.     private AttitudeProvider active;

  53.     /** Switching events map. */
  54.     private final Map<AttitudeProvider, Collection<Switch<?>>> switchingMap;

  55.     /** Constructor for an initially empty sequence.
  56.      */
  57.     public AttitudesSequence() {
  58.         active = null;
  59.         switchingMap = new HashMap<AttitudeProvider, Collection<Switch<?>>>();
  60.     }

  61.     /** Reset the active provider.
  62.      * @param provider providerprovider to activate
  63.      */
  64.     public void resetActiveProvider(final AttitudeProvider provider) {

  65.         // add the provider if not already known
  66.         if (!switchingMap.containsKey(provider)) {
  67.             switchingMap.put(provider, new ArrayList<Switch<?>>());
  68.         }

  69.         active = provider;

  70.     }

  71.     /** Register all wrapped switch events to the propagator.
  72.      * <p>
  73.      * This method must be called once before propagation, after the
  74.      * switching conditions have been set up by calls to {@link
  75.      * #addSwitchingCondition(AttitudeProvider, EventDetector, boolean, boolean, AttitudeProvider)}.
  76.      * </p>
  77.      * @param propagator propagator that will handle the events
  78.      */
  79.     public void registerSwitchEvents(final Propagator propagator) {
  80.         for (final Collection<Switch<?>> collection : switchingMap.values()) {
  81.             for (final Switch<?> s : collection) {
  82.                 propagator.addEventDetector(s);
  83.             }
  84.         }
  85.     }

  86.     /** Add a switching condition between two attitude providers.
  87.      * <p>
  88.      * An attitude provider may have several different switch events associated to
  89.      * it. Depending on which event is triggered, the appropriate provider is
  90.      * switched to.
  91.      * </p>
  92.      * <p>
  93.      * The switch events specified here must <em>not</em> be registered to the
  94.      * propagator directly. The proper way to register these events is to
  95.      * call {@link #registerSwitchEvents(Propagator)} once after all switching
  96.      * conditions have been set up. The reason for this is that the events will
  97.      * be wrapped before being registered.
  98.      * </p>
  99.      * @param before attitude provider before the switch event occurrence
  100.      * @param switchEvent event triggering the attitude providers switch (may be null
  101.      * for a provider without any ending condition, in this case the after provider
  102.      * is not referenced and may be null too)
  103.      * @param switchOnIncrease if true, switch is triggered on increasing event
  104.      * @param switchOnDecrease if true, switch is triggered on decreasing event
  105.      * @param after attitude provider to activate after the switch event occurrence
  106.      * (used only if switchEvent is non null)
  107.      * @param <T> class type for the generic version
  108.      */
  109.     public <T extends EventDetector> void addSwitchingCondition(final AttitudeProvider before,
  110.                                                                 final T switchEvent,
  111.                                                                 final boolean switchOnIncrease,
  112.                                                                 final boolean switchOnDecrease,
  113.                                                                 final AttitudeProvider after) {

  114.         // add the before provider if not already known
  115.         if (!switchingMap.containsKey(before)) {
  116.             switchingMap.put(before, new ArrayList<Switch<?>>());
  117.             if (active == null) {
  118.                 active = before;
  119.             }
  120.         }

  121.         if (switchEvent != null) {

  122.             // add the after provider if not already known
  123.             if (!switchingMap.containsKey(after)) {
  124.                 switchingMap.put(after, new ArrayList<Switch<?>>());
  125.             }

  126.             // add the switching condition
  127.             switchingMap.get(before).add(new Switch<T>(switchEvent, switchOnIncrease, switchOnDecrease, after));

  128.         }

  129.     }

  130.     /** {@inheritDoc} */
  131.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  132.                                 final AbsoluteDate date, final Frame frame)
  133.         throws OrekitException {
  134.         // delegate attitude computation to the active provider
  135.         return active.getAttitude(pvProv, date, frame);
  136.     }

  137.     /** Switch specification.
  138.      * @param <T> class type for the generic version
  139.      */
  140.     private class Switch<T extends EventDetector> extends AbstractReconfigurableDetector<Switch<T>> {

  141.         /** Serializable UID. */
  142.         private static final long serialVersionUID = 20131118L;

  143.         /** Event. */
  144.         private final T event;

  145.         /** Event direction triggering the switch. */
  146.         private final boolean switchOnIncrease;

  147.         /** Event direction triggering the switch. */
  148.         private final boolean switchOnDecrease;

  149.         /** Next attitude provider. */
  150.         private final AttitudeProvider next;

  151.         /** Simple constructor.
  152.          * @param event event
  153.          * @param switchOnIncrease if true, switch is triggered on increasing event
  154.          * @param switchOnDecrease if true, switch is triggered on decreasing event
  155.          * otherwise switch is triggered on decreasing event
  156.          * @param next next attitude provider
  157.          */
  158.         public Switch(final T event,
  159.                       final boolean switchOnIncrease,
  160.                       final boolean switchOnDecrease,
  161.                       final AttitudeProvider next) {
  162.             this(event.getMaxCheckInterval(), event.getThreshold(), event.getMaxIterationCount(),
  163.                  new LocalHandler<T>(), event, switchOnIncrease, switchOnDecrease, next);
  164.         }

  165.         /** Private constructor with full parameters.
  166.          * <p>
  167.          * This constructor is private as users are expected to use the builder
  168.          * API with the various {@code withXxx()} methods to set up the instance
  169.          * in a readable manner without using a huge amount of parameters.
  170.          * </p>
  171.          * @param maxCheck maximum checking interval (s)
  172.          * @param threshold convergence threshold (s)
  173.          * @param maxIter maximum number of iterations in the event time search
  174.          * @param handler event handler to call at event occurrences
  175.          * @param event event
  176.          * @param switchOnIncrease if true, switch is triggered on increasing event
  177.          * @param switchOnDecrease if true, switch is triggered on decreasing event
  178.          * otherwise switch is triggered on decreasing event
  179.          * @param next next attitude provider
  180.          * @since 6.1
  181.          */
  182.         private Switch(final double maxCheck, final double threshold,
  183.                        final int maxIter, final EventHandler<Switch<T>> handler, final T event,
  184.                        final boolean switchOnIncrease, final boolean switchOnDecrease,
  185.                        final AttitudeProvider next) {
  186.             super(maxCheck, threshold, maxIter, handler);
  187.             this.event            = event;
  188.             this.switchOnIncrease = switchOnIncrease;
  189.             this.switchOnDecrease = switchOnDecrease;
  190.             this.next             = next;
  191.         }

  192.         /** {@inheritDoc} */
  193.         @Override
  194.         protected Switch<T> create(final double newMaxCheck, final double newThreshold,
  195.                                    final int newMaxIter, final EventHandler<Switch<T>> newHandler) {
  196.             return new Switch<T>(newMaxCheck, newThreshold, newMaxIter, newHandler,
  197.                                  event, switchOnIncrease, switchOnDecrease, next);
  198.         }

  199.         /** Perform the switch.
  200.          */
  201.         public void performSwitch() {
  202.             active = next;
  203.         }

  204.         /** {@inheritDoc} */
  205.         public void init(final SpacecraftState s0, final AbsoluteDate t) {
  206.             event.init(s0, t);
  207.         }

  208.         /** {@inheritDoc} */
  209.         public double g(final SpacecraftState s)
  210.             throws OrekitException {
  211.             return event.g(s);
  212.         }

  213.     }

  214.     /** Local handler.
  215.      * @param <T> class type for the generic version
  216.      */
  217.     private static class LocalHandler<T extends EventDetector> implements EventHandler<Switch<T>> {

  218.         /** {@inheritDoc} */
  219.         public EventHandler.Action eventOccurred(final SpacecraftState s, final Switch<T> sw, final boolean increasing)
  220.             throws OrekitException {

  221.             if ((increasing && sw.switchOnIncrease) || (!increasing && sw.switchOnDecrease)) {
  222.                 // switch to next attitude provider
  223.                 sw.performSwitch();
  224.             }

  225.             if (sw.event instanceof AbstractReconfigurableDetector) {
  226.                 @SuppressWarnings("unchecked")
  227.                 final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) sw.event).getHandler();
  228.                 return handler.eventOccurred(s, sw.event, increasing);
  229.             } else {
  230.                 @SuppressWarnings("deprecation")
  231.                 final EventDetector.Action a = sw.event.eventOccurred(s, increasing);
  232.                 return AbstractReconfigurableDetector.convert(a);
  233.             }

  234.         }

  235.         /** {@inheritDoc} */
  236.         @Override
  237.         public SpacecraftState resetState(final Switch<T> sw, final SpacecraftState oldState)
  238.             throws OrekitException {
  239.             if (sw.event instanceof AbstractReconfigurableDetector) {
  240.                 @SuppressWarnings("unchecked")
  241.                 final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) sw.event).getHandler();
  242.                 return handler.resetState(sw.event, oldState);
  243.             } else {
  244.                 @SuppressWarnings("deprecation")
  245.                 final SpacecraftState newState = sw.event.resetState(oldState);
  246.                 return newState;
  247.             }
  248.         }

  249.     }

  250. }