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.estimation.measurements.generation;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.Comparator;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.SortedSet;
27  import java.util.TreeSet;
28  
29  import org.orekit.estimation.measurements.ObservableSatellite;
30  import org.orekit.estimation.measurements.ObservedMeasurement;
31  import org.orekit.propagation.Propagator;
32  import org.orekit.propagation.PropagatorsParallelizer;
33  import org.orekit.propagation.SpacecraftState;
34  import org.orekit.propagation.sampling.MultiSatStepHandler;
35  import org.orekit.propagation.sampling.OrekitStepHandler;
36  import org.orekit.propagation.sampling.OrekitStepInterpolator;
37  import org.orekit.propagation.sampling.StepHandlerMultiplexer;
38  import org.orekit.time.AbsoluteDate;
39  
40  
41  /** Main generator for {@link ObservedMeasurement observed measurements}.
42   * @author Luc Maisonobe
43   * @since 9.3
44   */
45  public class Generator {
46  
47      /** Observable satellites.
48       * @since 12.0
49       */
50      private final List<ObservableSatellite> observableSatellites;
51  
52      /** Propagators. */
53      private final List<Propagator> propagators;
54  
55      /** Schedulers for multiple satellites measurements. */
56      private final List<Scheduler<? extends ObservedMeasurement<?>>> multiSatSchedulers;
57  
58      /** Schedulers for single satellite measurements. */
59      private final Map<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> singleSatSchedulers;
60  
61      /** Subscribers for generated measurements events.
62       * @since 12.0
63       */
64      private final List<GeneratedMeasurementSubscriber> subscribers;
65  
66      /** Build a generator with no sequences generator.
67       */
68      public Generator() {
69          this.observableSatellites = new ArrayList<>();
70          this.propagators          = new ArrayList<>();
71          this.multiSatSchedulers   = new ArrayList<>();
72          this.singleSatSchedulers  = new HashMap<>();
73          this.subscribers          = new ArrayList<>();
74      }
75  
76      /** Add a propagator.
77       * @param propagator to add
78       * @return satellite satellite propagated by the propagator
79       */
80      public ObservableSatellite addPropagator(final Propagator propagator) {
81          final ObservableSatellite os = new ObservableSatellite(propagators.size());
82          observableSatellites.add(os);
83          propagators.add(propagator);
84          return os;
85      }
86  
87      /** Get a registered propagator.
88       * @param satellite satellite propagated by the propagator {@link #addPropagator(Propagator)}
89       * @return propagator corresponding to satellite
90       */
91      public Propagator getPropagator(final ObservableSatellite satellite) {
92          return propagators.get(satellite.getPropagatorIndex());
93      }
94  
95      /** Add a sequences generator for a specific measurement type.
96       * @param scheduler sequences generator to add
97       * @param <T> the type of the measurement
98       */
99      public <T extends ObservedMeasurement<T>> void addScheduler(final Scheduler<T> scheduler) {
100         final ObservableSatellite[] satellites = scheduler.getBuilder().getSatellites();
101         if (satellites.length == 1) {
102             // this scheduler manages only one satellite
103             // we can let the individual propagator handle it
104             List<Scheduler<? extends ObservedMeasurement<?>>> list = singleSatSchedulers.get(satellites[0]);
105             if (list == null) {
106                 list = new ArrayList<>();
107                 singleSatSchedulers.put(satellites[0], list);
108             }
109             list.add(scheduler);
110         } else {
111             // this scheduler manages several satellites at once
112             // we need to handle it at top level
113             multiSatSchedulers.add(scheduler);
114         }
115     }
116 
117     /** Add a subscriber.
118      * @param subscriber to add
119      * @see GatheringSubscriber
120      * @since 12.0
121      */
122     public void addSubscriber(final GeneratedMeasurementSubscriber subscriber) {
123         subscribers.add(subscriber);
124     }
125 
126     /** Generate measurements.
127      * @param start start of the measurements time span
128      * @param end end of the measurements time span
129      */
130     public void generate(final AbsoluteDate start, final AbsoluteDate end) {
131 
132         // set up top level handler
133         final MultipleSatGeneratorHandler globalHandler =
134                         new MultipleSatGeneratorHandler(multiSatSchedulers, subscribers,
135                                                         observableSatellites, end.isAfterOrEqualTo(start));
136 
137         // set up low level handlers
138         for (final Map.Entry<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> entry : singleSatSchedulers.entrySet()) {
139             final StepHandlerMultiplexer multiplexer = propagators.get(entry.getKey().getPropagatorIndex()).getMultiplexer();
140             for (final Scheduler<?> scheduler : entry.getValue()) {
141                 multiplexer.add(new SingleSatGeneratorHandler<>(scheduler, globalHandler));
142             }
143         }
144 
145         // prepare parallelized generation
146         final PropagatorsParallelizer parallelizer = new PropagatorsParallelizer(propagators, globalHandler);
147 
148         // generate the measurements
149         parallelizer.propagate(start, end);
150 
151         // clean up low level handlers
152         for (final Map.Entry<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> entry : singleSatSchedulers.entrySet()) {
153             // we need to clean up the step handlers in two loops to avoid concurrent modification exception
154             final StepHandlerMultiplexer multiplexer = propagators.get(entry.getKey().getPropagatorIndex()).getMultiplexer();
155             final List<OrekitStepHandler> toBeRemoved = new ArrayList<>();
156             for (final OrekitStepHandler handler : multiplexer.getHandlers()) {
157                 if (handler instanceof SingleSatGeneratorHandler &&
158                     ((SingleSatGeneratorHandler<?>) handler).globalHandler == globalHandler) {
159                     toBeRemoved.add(handler);
160                 }
161             }
162             for (final OrekitStepHandler handler : toBeRemoved) {
163                 multiplexer.remove(handler);
164             }
165         }
166 
167     }
168 
169     /** Handler for measurements generation steps, single satellite case.
170      * <p>
171      * These handlers are called from the individual propagators threads.
172      * This means they generate measurements in parallel.
173      * </p>
174      * @param <T> the type of the measurement
175      * @since 12.0
176      */
177     private static class SingleSatGeneratorHandler<T extends ObservedMeasurement<T>> implements OrekitStepHandler {
178 
179         /** Scheduler. */
180         private final Scheduler<T> scheduler;
181 
182         /** Satellite related to this scheduler. */
183         private final ObservableSatellite satellite;
184 
185         /** Global handler. */
186         private final MultipleSatGeneratorHandler globalHandler;
187 
188         /** Simple constructor.
189          * @param scheduler scheduler
190          * @param globalHandler global handler
191          */
192         SingleSatGeneratorHandler(final Scheduler<T> scheduler, final MultipleSatGeneratorHandler globalHandler) {
193             this.scheduler     = scheduler;
194             this.satellite     = scheduler.getBuilder().getSatellites()[0];
195             this.globalHandler = globalHandler;
196         }
197 
198         /** {@inheritDoc} */
199         @Override
200         public void init(final SpacecraftState state0, final AbsoluteDate t) {
201             scheduler.init(state0.getDate(), t);
202         }
203 
204         /** {@inheritDoc} */
205         @Override
206         public void handleStep(final OrekitStepInterpolator interpolator) {
207             globalHandler.addMeasurements(scheduler.generate(Collections.singletonMap(satellite, interpolator)));
208         }
209 
210     }
211 
212     /** Handler for measurements generation steps.
213      * <p>
214      * This handler is called from the propagator parallelizer thread.
215      * The parallelizer thread is called after the individual propagators thread,
216      * which may already have produced measurements ahead of time, so we must
217      * take care than within each step we handle only the measurements that belong
218      * to this step.
219      * </p>
220      */
221     private static class MultipleSatGeneratorHandler implements MultiSatStepHandler {
222 
223         /** Sequences generators. */
224         private final List<Scheduler<? extends ObservedMeasurement<?>>> schedulers;
225 
226         /** Subscribers for generated measurements events.
227          * @since 12.0
228          */
229         private final List<GeneratedMeasurementSubscriber> subscribers;
230 
231         /** Observable satellites.
232          * @since 12.0
233          */
234         private final List<ObservableSatellite> observableSatellites;
235 
236         /** Storage for sorted measurements within one step.
237          * @since 12.0
238          */
239         private final SortedSet<ObservedMeasurement<?>> generated;
240 
241         /** Forward generation indicator.
242          * @since 12.0
243          */
244         private final boolean forward;
245 
246         /** Simple constructor.
247          * @param schedulers sequences generators
248          * @param subscribers subscribers for generated measurements events
249          * @param observableSatellites observable satellites
250          * @param forward if true, generation is forward
251          * @since 12.0
252          */
253         MultipleSatGeneratorHandler(final List<Scheduler<? extends ObservedMeasurement<?>>> schedulers,
254                                     final List<GeneratedMeasurementSubscriber> subscribers,
255                                     final List<ObservableSatellite> observableSatellites, final boolean forward) {
256 
257             // measurements comparator, consistent with generation direction
258             final Comparator<ObservedMeasurement<?>> comparator = forward ? Comparator.naturalOrder() : Comparator.reverseOrder();
259 
260             this.schedulers           = schedulers;
261             this.subscribers          = subscribers;
262             this.observableSatellites = observableSatellites;
263             this.generated            = new TreeSet<>(comparator);
264             this.forward              = forward;
265 
266         }
267 
268         /** {@inheritDoc} */
269         @Override
270         public void init(final List<SpacecraftState> states0, final AbsoluteDate t) {
271 
272             final AbsoluteDate start = states0.get(0).getDate();
273 
274             // initialize schedulers
275             for (final Scheduler<?> scheduler : schedulers) {
276                 scheduler.init(start, t);
277             }
278 
279             // initialize subscribers
280             for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
281                 subscriber.init(start, t);
282             }
283 
284         }
285 
286         /** {@inheritDoc} */
287         @Override
288         public void handleStep(final List<OrekitStepInterpolator> interpolators) {
289 
290             // prepare interpolators map
291             final Map<ObservableSatellite, OrekitStepInterpolator> interpolatorsMap =
292                             new HashMap<>(interpolators.size());
293             for (int i = 0; i < interpolators.size(); ++i) {
294                 interpolatorsMap.put(observableSatellites.get(i), interpolators.get(i));
295             }
296             final AbsoluteDate lastDate = interpolators.get(0).getCurrentState().getDate();
297 
298             synchronized (generated) {
299 
300                 // generate measurements, looping over schedulers
301                 for (final Scheduler<? extends ObservedMeasurement<?>> scheduler : schedulers) {
302                     generated.addAll(scheduler.generate(interpolatorsMap));
303                 }
304 
305                 // now that we have all measurements properly sorted, we can feed them to subscribers
306                 for (final Iterator<ObservedMeasurement<?>> iterator = generated.iterator(); iterator.hasNext();) {
307                     final ObservedMeasurement<?> measurement = iterator.next();
308                     if (forward == lastDate.isAfterOrEqualTo(measurement)) {
309                         // this measurement belongs to the current step
310                         for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
311                             subscriber.handleGeneratedMeasurement(measurement);
312                         }
313                         iterator.remove();
314                     } else {
315                         // this measurement belongs to an upcoming step ; we don't handle it yet as more
316                         // intermediate measurements may be produced by low level propagators threads
317                         break;
318                     }
319                 }
320 
321             }
322 
323         }
324 
325         /** {@inheritDoc} */
326         public void finish(final List<SpacecraftState> finalStates) {
327             synchronized (generated) {
328                 for (final ObservedMeasurement<?> measurement : generated) {
329                     for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
330                         subscriber.handleGeneratedMeasurement(measurement);
331                     }
332                 }
333                 generated.clear();
334             }
335         }
336 
337         /** Add measurements performed by a low level handler.
338          * @param measurements measurements to add
339          * @since 12.0
340          */
341         private void addMeasurements(final SortedSet<? extends ObservedMeasurement<?>> measurements) {
342             synchronized (generated) {
343                 generated.addAll(measurements);
344             }
345         }
346 
347     }
348 
349 }