1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF 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.sampling;
18  
19  import org.apache.commons.math3.util.FastMath;
20  import org.orekit.errors.OrekitException;
21  import org.orekit.errors.PropagationException;
22  import org.orekit.propagation.SpacecraftState;
23  import org.orekit.time.AbsoluteDate;
24  
25  /**
26   * This class wraps an object implementing {@link OrekitFixedStepHandler}
27   * into a {@link OrekitStepHandler}.
28  
29   * <p>It mirrors the <code>StepNormalizer</code> interface from <a
30   * href="http://commons.apache.org/math/">commons-math</a> but
31   * provides a space-dynamics interface to the methods.</p>
32   * @author Luc Maisonobe
33   */
34  public class OrekitStepNormalizer implements OrekitStepHandler {
35  
36      /** Fixed time step. */
37      private double h;
38  
39      /** Underlying step handler. */
40      private OrekitFixedStepHandler handler;
41  
42      /** Last step date. */
43      private AbsoluteDate lastDate;
44  
45      /** Last State vector. */
46      private SpacecraftState lastState;
47  
48      /** Integration direction indicator. */
49      private boolean forward;
50  
51      /** Simple constructor.
52       * @param h fixed time step (sign is not used)
53       * @param handler fixed time step handler to wrap
54       */
55      public OrekitStepNormalizer(final double h, final OrekitFixedStepHandler handler) {
56          this.h       = FastMath.abs(h);
57          this.handler = handler;
58          lastDate  = null;
59          lastState = null;
60          forward   = true;
61      }
62  
63      /** Determines whether this handler needs dense output.
64       * This handler needs dense output in order to provide data at
65       * regularly spaced steps regardless of the steps the propagator
66       * uses, so this method always returns true.
67       * @return always true
68       */
69      public boolean requiresDenseOutput() {
70          return true;
71      }
72  
73      /** {@inheritDoc} */
74      public void init(final SpacecraftState s0, final AbsoluteDate t)
75          throws PropagationException {
76          lastDate  = null;
77          lastState = null;
78          forward   = true;
79          handler.init(s0, t);
80      }
81  
82      /**
83       * Handle the last accepted step.
84       * @param interpolator interpolator for the last accepted step. For
85       * efficiency purposes, the various propagators reuse the same
86       * object on each call, so if the instance wants to keep it across
87       * all calls (for example to provide at the end of the propagation a
88       * continuous model valid throughout the propagation range), it
89       * should build a local copy using the clone method and store this
90       * copy.
91       * @param isLast true if the step is the last one
92       * @throws PropagationException this exception is propagated to the
93       * caller if the underlying user function triggers one
94       */
95      public void handleStep(final OrekitStepInterpolator interpolator, final boolean isLast)
96          throws PropagationException {
97          try {
98  
99              if (lastState == null) {
100                 // initialize lastState in the first step case
101 
102                 lastDate = interpolator.getPreviousDate();
103                 interpolator.setInterpolatedDate(lastDate);
104                 lastState = interpolator.getInterpolatedState();
105 
106                 // take the propagation direction into account
107                 forward = interpolator.getCurrentDate().compareTo(lastDate) >= 0;
108                 if (!forward) {
109                     h = -h;
110                 }
111 
112             }
113 
114             // use the interpolator to push fixed steps events to the underlying handler
115             AbsoluteDate nextTime = lastDate.shiftedBy(h);
116             boolean nextInStep = forward ^ (nextTime.compareTo(interpolator.getCurrentDate()) > 0);
117             while (nextInStep) {
118 
119                 // output the stored previous step
120                 handler.handleStep(lastState, false);
121 
122                 // store the next step
123                 lastDate = nextTime;
124                 interpolator.setInterpolatedDate(lastDate);
125                 lastState = interpolator.getInterpolatedState();
126 
127                 // prepare next iteration
128                 nextTime = nextTime.shiftedBy(h);
129                 nextInStep = forward ^ (nextTime.compareTo(interpolator.getCurrentDate()) > 0);
130 
131             }
132 
133             if (isLast) {
134                 // there will be no more steps,
135                 // the stored one should be flagged as being the last
136                 handler.handleStep(lastState, true);
137             }
138 
139         } catch (OrekitException oe) {
140 
141             // recover a possible embedded PropagationException
142             for (Throwable t = oe; t != null; t = t.getCause()) {
143                 if (t instanceof PropagationException) {
144                     throw (PropagationException) t;
145                 }
146             }
147 
148             throw new PropagationException(oe);
149 
150         }
151     }
152 
153 }