1 /* Copyright 2002-2024 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.sampling;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import org.hipparchus.CalculusFieldElement;
25 import org.orekit.propagation.FieldSpacecraftState;
26 import org.orekit.time.FieldAbsoluteDate;
27
28 /** This class gathers several {@link OrekitStepHandler} instances into one.
29 *
30 * @author Luc Maisonobe
31 * @param <T> type of the field elements
32 */
33 public class FieldStepHandlerMultiplexer<T extends CalculusFieldElement<T>> implements FieldOrekitStepHandler<T> {
34
35 /** Underlying step handlers. */
36 private final List<FieldOrekitStepHandler<T>> handlers;
37
38 /** Target time. */
39 private FieldAbsoluteDate<T> target;
40
41 /** Last known state. */
42 private FieldSpacecraftState<T> last;
43
44 /** Simple constructor.
45 */
46 public FieldStepHandlerMultiplexer() {
47 handlers = new ArrayList<>();
48 }
49
50 /** Add a handler for variable size step.
51 * <p>
52 * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
53 * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
54 * yet), then the local {@link FieldOrekitStepHandler#init(FieldSpacecraftState, FieldAbsoluteDate)
55 * FieldOrekitStepHandler.init} method of the added handler will be called with the last
56 * known state, so the handler starts properly.
57 * </p>
58 * @param handler step handler to add
59 */
60 public void add(final FieldOrekitStepHandler<T> handler) {
61 handlers.add(handler);
62 if (last != null) {
63 // propagation is ongoing, we need to call init now for this handler
64 handler.init(last, target);
65 }
66 }
67
68 /** Add a handler for fixed size step.
69 * <p>
70 * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
71 * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
72 * yet), then the local {@link FieldOrekitFixedStepHandler#init(FieldSpacecraftState, FieldAbsoluteDate,
73 * CalculusFieldElement) FieldOrekitStepHandler.init} method of the added handler will be
74 * called with the last known state, so the handler starts properly.
75 * </p>
76 * @param h fixed stepsize (s)
77 * @param handler handler called at the end of each finalized step
78 * @since 11.0
79 */
80 public void add(final T h, final FieldOrekitFixedStepHandler<T> handler) {
81 final FieldOrekitStepHandler<T> normalized = new FieldOrekitStepNormalizer<>(h, handler);
82 handlers.add(normalized);
83 if (last != null) {
84 // propagation is ongoing, we need to call init now for this handler
85 normalized.init(last, target);
86 }
87 }
88
89 /** Get an unmodifiable view of all handlers.
90 * <p>
91 * Note that if {@link FieldOrekitFixedStepHandler fixed step handlers} have
92 * been {@link #add(CalculusFieldElement, FieldOrekitFixedStepHandler)}, then they will
93 * show up wrapped within {@link FieldOrekitStepNormalizer step normalizers}.
94 * </p>
95 * @return an unmodifiable view of all handlers
96 * @since 11.0
97 */
98 public List<FieldOrekitStepHandler<T>> getHandlers() {
99 return Collections.unmodifiableList(handlers);
100 }
101
102 /** Remove a handler.
103 * <p>
104 * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
105 * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
106 * yet), then the local {@link FieldOrekitStepHandler#finish(FieldSpacecraftState)
107 * FieldOrekitStepHandler.finish} method of the removed handler will be called with the last
108 * known state, so the handler stops properly.
109 * </p>
110 * @param handler step handler to remove
111 * @since 11.0
112 */
113 public void remove(final FieldOrekitStepHandler<T> handler) {
114 final Iterator<FieldOrekitStepHandler<T>> iterator = handlers.iterator();
115 while (iterator.hasNext()) {
116 if (iterator.next() == handler) {
117 if (last != null) {
118 // propagation is ongoing, we need to call finish now for this handler
119 handler.finish(last);
120 }
121 iterator.remove();
122 return;
123 }
124 }
125 }
126
127 /** Remove a handler.
128 * <p>
129 * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
130 * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
131 * yet), then the local {@link FieldOrekitFixedStepHandler#finish(FieldSpacecraftState)
132 * FieldOrekitFixedStepHandler.finish} method of the removed handler will be called with the last
133 * known state, so the handler stops properly.
134 * </p>
135 * @param handler step handler to remove
136 * @since 11.0
137 */
138 public void remove(final FieldOrekitFixedStepHandler<T> handler) {
139 final Iterator<FieldOrekitStepHandler<T>> iterator = handlers.iterator();
140 while (iterator.hasNext()) {
141 final FieldOrekitStepHandler<T> current = iterator.next();
142 if (current instanceof FieldOrekitStepNormalizer &&
143 ((FieldOrekitStepNormalizer<T>) current).getFixedStepHandler() == handler) {
144 if (last != null) {
145 // propagation is ongoing, we need to call finish now for this handler
146 current.finish(last);
147 }
148 iterator.remove();
149 return;
150 }
151 }
152 }
153
154 /** Remove all handlers managed by this multiplexer.
155 * <p>
156 * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
157 * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
158 * yet), then the local {@link FieldOrekitStepHandler#finish(FieldSpacecraftState)
159 * FieldOrekitStepHandler.finish} and {@link FieldOrekitFixedStepHandler#finish(FieldSpacecraftState)
160 * FieldOrekitFixedStepHandler.finish} methods of the removed handlers will be called with the last
161 * known state, so the handlers stop properly.
162 * </p>
163 * @since 11.0
164 */
165 public void clear() {
166 if (last != null) {
167 // propagation is ongoing, we need to call finish now for all handlers
168 handlers.forEach(h -> h.finish(last));
169 }
170 handlers.clear();
171 }
172
173 /** {@inheritDoc} */
174 public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
175 this.target = t;
176 this.last = s0;
177 for (final FieldOrekitStepHandler<T> handler : handlers) {
178 handler.init(s0, t);
179 }
180 }
181
182 /** {@inheritDoc} */
183 public void handleStep(final FieldOrekitStepInterpolator<T> interpolator) {
184 this.last = interpolator.getCurrentState();
185 for (final FieldOrekitStepHandler<T> handler : handlers) {
186 handler.handleStep(interpolator);
187 }
188 }
189
190 /** {@inheritDoc} */
191 public void finish(final FieldSpacecraftState<T> finalState) {
192 this.target = null;
193 this.last = null;
194 for (final FieldOrekitStepHandler<T> handler : handlers) {
195 handler.finish(finalState);
196 }
197 }
198
199 }