Generator.java

  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. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.Comparator;
  21. import java.util.HashMap;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.SortedSet;
  26. import java.util.TreeSet;

  27. import org.orekit.estimation.measurements.ObservableSatellite;
  28. import org.orekit.estimation.measurements.ObservedMeasurement;
  29. import org.orekit.propagation.Propagator;
  30. import org.orekit.propagation.PropagatorsParallelizer;
  31. import org.orekit.propagation.SpacecraftState;
  32. import org.orekit.propagation.sampling.MultiSatStepHandler;
  33. import org.orekit.propagation.sampling.OrekitStepHandler;
  34. import org.orekit.propagation.sampling.OrekitStepInterpolator;
  35. import org.orekit.propagation.sampling.StepHandlerMultiplexer;
  36. import org.orekit.time.AbsoluteDate;


  37. /** Main generator for {@link ObservedMeasurement observed measurements}.
  38.  * @author Luc Maisonobe
  39.  * @since 9.3
  40.  */
  41. public class Generator {

  42.     /** Observable satellites.
  43.      * @since 12.0
  44.      */
  45.     private final List<ObservableSatellite> observableSatellites;

  46.     /** Propagators. */
  47.     private final List<Propagator> propagators;

  48.     /** Schedulers for multiple satellites measurements. */
  49.     private final List<Scheduler<? extends ObservedMeasurement<?>>> multiSatSchedulers;

  50.     /** Schedulers for single satellite measurements. */
  51.     private final Map<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> singleSatSchedulers;

  52.     /** Subscribers for generated measurements events.
  53.      * @since 12.0
  54.      */
  55.     private final List<GeneratedMeasurementSubscriber> subscribers;

  56.     /** Build a generator with no sequences generator.
  57.      */
  58.     public Generator() {
  59.         this.observableSatellites = new ArrayList<>();
  60.         this.propagators          = new ArrayList<>();
  61.         this.multiSatSchedulers   = new ArrayList<>();
  62.         this.singleSatSchedulers  = new HashMap<>();
  63.         this.subscribers          = new ArrayList<>();
  64.     }

  65.     /** Add a propagator.
  66.      * @param propagator to add
  67.      * @return satellite satellite propagated by the propagator
  68.      */
  69.     public ObservableSatellite addPropagator(final Propagator propagator) {
  70.         final ObservableSatellite os = new ObservableSatellite(propagators.size());
  71.         observableSatellites.add(os);
  72.         propagators.add(propagator);
  73.         return os;
  74.     }

  75.     /** Get a registered propagator.
  76.      * @param satellite satellite propagated by the propagator {@link #addPropagator(Propagator)}
  77.      * @return propagator corresponding to satellite
  78.      */
  79.     public Propagator getPropagator(final ObservableSatellite satellite) {
  80.         return propagators.get(satellite.getPropagatorIndex());
  81.     }

  82.     /** Add a sequences generator for a specific measurement type.
  83.      * @param scheduler sequences generator to add
  84.      * @param <T> the type of the measurement
  85.      */
  86.     public <T extends ObservedMeasurement<T>> void addScheduler(final Scheduler<T> scheduler) {
  87.         final ObservableSatellite[] satellites = scheduler.getBuilder().getSatellites();
  88.         if (satellites.length == 1) {
  89.             // this scheduler manages only one satellite
  90.             // we can let the individual propagator handle it
  91.             List<Scheduler<? extends ObservedMeasurement<?>>> list = singleSatSchedulers.get(satellites[0]);
  92.             if (list == null) {
  93.                 list = new ArrayList<>();
  94.                 singleSatSchedulers.put(satellites[0], list);
  95.             }
  96.             list.add(scheduler);
  97.         } else {
  98.             // this scheduler manages several satellites at once
  99.             // we need to handle it at top level
  100.             multiSatSchedulers.add(scheduler);
  101.         }
  102.     }

  103.     /** Add a subscriber.
  104.      * @param subscriber to add
  105.      * @see GatheringSubscriber
  106.      * @since 12.0
  107.      */
  108.     public void addSubscriber(final GeneratedMeasurementSubscriber subscriber) {
  109.         subscribers.add(subscriber);
  110.     }

  111.     /** Generate measurements.
  112.      * @param start start of the measurements time span
  113.      * @param end end of the measurements time span
  114.      */
  115.     public void generate(final AbsoluteDate start, final AbsoluteDate end) {

  116.         // set up top level handler
  117.         final MultipleSatGeneratorHandler globalHandler =
  118.                         new MultipleSatGeneratorHandler(multiSatSchedulers, subscribers,
  119.                                                         observableSatellites, end.isAfterOrEqualTo(start));

  120.         // set up low level handlers
  121.         for (final Map.Entry<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> entry : singleSatSchedulers.entrySet()) {
  122.             final StepHandlerMultiplexer multiplexer = propagators.get(entry.getKey().getPropagatorIndex()).getMultiplexer();
  123.             for (final Scheduler<?> scheduler : entry.getValue()) {
  124.                 multiplexer.add(new SingleSatGeneratorHandler<>(scheduler, globalHandler));
  125.             }
  126.         }

  127.         // prepare parallelized generation
  128.         final PropagatorsParallelizer parallelizer = new PropagatorsParallelizer(propagators, globalHandler);

  129.         // generate the measurements
  130.         parallelizer.propagate(start, end);

  131.         // clean up low level handlers
  132.         for (final Map.Entry<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> entry : singleSatSchedulers.entrySet()) {
  133.             // we need to clean up the step handlers in two loops to avoid concurrent modification exception
  134.             final StepHandlerMultiplexer multiplexer = propagators.get(entry.getKey().getPropagatorIndex()).getMultiplexer();
  135.             final List<OrekitStepHandler> toBeRemoved = new ArrayList<>();
  136.             for (final OrekitStepHandler handler : multiplexer.getHandlers()) {
  137.                 if (handler instanceof SingleSatGeneratorHandler &&
  138.                     ((SingleSatGeneratorHandler<?>) handler).globalHandler == globalHandler) {
  139.                     toBeRemoved.add(handler);
  140.                 }
  141.             }
  142.             for (final OrekitStepHandler handler : toBeRemoved) {
  143.                 multiplexer.remove(handler);
  144.             }
  145.         }

  146.     }

  147.     /** Handler for measurements generation steps, single satellite case.
  148.      * <p>
  149.      * These handlers are called from the individual propagators threads.
  150.      * This means they generate measurements in parallel.
  151.      * </p>
  152.      * @param <T> the type of the measurement
  153.      * @since 12.0
  154.      */
  155.     private static class SingleSatGeneratorHandler<T extends ObservedMeasurement<T>> implements OrekitStepHandler {

  156.         /** Scheduler. */
  157.         private final Scheduler<T> scheduler;

  158.         /** Satellite related to this scheduler. */
  159.         private final ObservableSatellite satellite;

  160.         /** Global handler. */
  161.         private final MultipleSatGeneratorHandler globalHandler;

  162.         /** Simple constructor.
  163.          * @param scheduler scheduler
  164.          * @param globalHandler global handler
  165.          */
  166.         SingleSatGeneratorHandler(final Scheduler<T> scheduler, final MultipleSatGeneratorHandler globalHandler) {
  167.             this.scheduler     = scheduler;
  168.             this.satellite     = scheduler.getBuilder().getSatellites()[0];
  169.             this.globalHandler = globalHandler;
  170.         }

  171.         /** {@inheritDoc} */
  172.         @Override
  173.         public void init(final SpacecraftState state0, final AbsoluteDate t) {
  174.             scheduler.init(state0.getDate(), t);
  175.         }

  176.         /** {@inheritDoc} */
  177.         @Override
  178.         public void handleStep(final OrekitStepInterpolator interpolator) {
  179.             globalHandler.addMeasurements(scheduler.generate(Collections.singletonMap(satellite, interpolator)));
  180.         }

  181.     }

  182.     /** Handler for measurements generation steps.
  183.      * <p>
  184.      * This handler is called from the propagator parallelizer thread.
  185.      * The parallelizer thread is called after the individual propagators thread,
  186.      * which may already have produced measurements ahead of time, so we must
  187.      * take care than within each step we handle only the measurements that belong
  188.      * to this step.
  189.      * </p>
  190.      */
  191.     private static class MultipleSatGeneratorHandler implements MultiSatStepHandler {

  192.         /** Sequences generators. */
  193.         private final List<Scheduler<? extends ObservedMeasurement<?>>> schedulers;

  194.         /** Subscribers for generated measurements events.
  195.          * @since 12.0
  196.          */
  197.         private final List<GeneratedMeasurementSubscriber> subscribers;

  198.         /** Observable satellites.
  199.          * @since 12.0
  200.          */
  201.         private final List<ObservableSatellite> observableSatellites;

  202.         /** Storage for sorted measurements within one step.
  203.          * @since 12.0
  204.          */
  205.         private final SortedSet<ObservedMeasurement<?>> generated;

  206.         /** Forward generation indicator.
  207.          * @since 12.0
  208.          */
  209.         private final boolean forward;

  210.         /** Simple constructor.
  211.          * @param schedulers sequences generators
  212.          * @param subscribers subscribers for generated measurements events
  213.          * @param observableSatellites observable satellites
  214.          * @param forward if true, generation is forward
  215.          * @since 12.0
  216.          */
  217.         MultipleSatGeneratorHandler(final List<Scheduler<? extends ObservedMeasurement<?>>> schedulers,
  218.                                     final List<GeneratedMeasurementSubscriber> subscribers,
  219.                                     final List<ObservableSatellite> observableSatellites, final boolean forward) {

  220.             // measurements comparator, consistent with generation direction
  221.             final Comparator<ObservedMeasurement<?>> comparator = forward ? Comparator.naturalOrder() : Comparator.reverseOrder();

  222.             this.schedulers           = schedulers;
  223.             this.subscribers          = subscribers;
  224.             this.observableSatellites = observableSatellites;
  225.             this.generated            = new TreeSet<>(comparator);
  226.             this.forward              = forward;

  227.         }

  228.         /** {@inheritDoc} */
  229.         @Override
  230.         public void init(final List<SpacecraftState> states0, final AbsoluteDate t) {

  231.             final AbsoluteDate start = states0.get(0).getDate();

  232.             // initialize schedulers
  233.             for (final Scheduler<?> scheduler : schedulers) {
  234.                 scheduler.init(start, t);
  235.             }

  236.             // initialize subscribers
  237.             for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
  238.                 subscriber.init(start, t);
  239.             }

  240.         }

  241.         /** {@inheritDoc} */
  242.         @Override
  243.         public void handleStep(final List<OrekitStepInterpolator> interpolators) {

  244.             // prepare interpolators map
  245.             final Map<ObservableSatellite, OrekitStepInterpolator> interpolatorsMap =
  246.                             new HashMap<>(interpolators.size());
  247.             for (int i = 0; i < interpolators.size(); ++i) {
  248.                 interpolatorsMap.put(observableSatellites.get(i), interpolators.get(i));
  249.             }
  250.             final AbsoluteDate lastDate = interpolators.get(0).getCurrentState().getDate();

  251.             synchronized (generated) {

  252.                 // generate measurements, looping over schedulers
  253.                 for (final Scheduler<? extends ObservedMeasurement<?>> scheduler : schedulers) {
  254.                     generated.addAll(scheduler.generate(interpolatorsMap));
  255.                 }

  256.                 // now that we have all measurements properly sorted, we can feed them to subscribers
  257.                 for (final Iterator<ObservedMeasurement<?>> iterator = generated.iterator(); iterator.hasNext();) {
  258.                     final ObservedMeasurement<?> measurement = iterator.next();
  259.                     if (forward == lastDate.isAfterOrEqualTo(measurement)) {
  260.                         // this measurement belongs to the current step
  261.                         for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
  262.                             subscriber.handleGeneratedMeasurement(measurement);
  263.                         }
  264.                         iterator.remove();
  265.                     } else {
  266.                         // this measurement belongs to an upcoming step ; we don't handle it yet as more
  267.                         // intermediate measurements may be produced by low level propagators threads
  268.                         break;
  269.                     }
  270.                 }

  271.             }

  272.         }

  273.         /** {@inheritDoc} */
  274.         public void finish(final List<SpacecraftState> finalStates) {
  275.             synchronized (generated) {
  276.                 for (final ObservedMeasurement<?> measurement : generated) {
  277.                     for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
  278.                         subscriber.handleGeneratedMeasurement(measurement);
  279.                     }
  280.                 }
  281.                 generated.clear();
  282.             }
  283.         }

  284.         /** Add measurements performed by a low level handler.
  285.          * @param measurements measurements to add
  286.          * @since 12.0
  287.          */
  288.         private void addMeasurements(final SortedSet<? extends ObservedMeasurement<?>> measurements) {
  289.             synchronized (generated) {
  290.                 generated.addAll(measurements);
  291.             }
  292.         }

  293.     }

  294. }