Generator.java

  1. /* Copyright 2002-2025 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.EstimatedMeasurementBase;
  28. import org.orekit.estimation.measurements.ObservableSatellite;
  29. import org.orekit.estimation.measurements.ObservedMeasurement;
  30. import org.orekit.propagation.Propagator;
  31. import org.orekit.propagation.PropagatorsParallelizer;
  32. import org.orekit.propagation.SpacecraftState;
  33. import org.orekit.propagation.sampling.MultiSatStepHandler;
  34. import org.orekit.propagation.sampling.OrekitStepHandler;
  35. import org.orekit.propagation.sampling.OrekitStepInterpolator;
  36. import org.orekit.propagation.sampling.StepHandlerMultiplexer;
  37. import org.orekit.time.AbsoluteDate;


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

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

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

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

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

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

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

  66.     /** Add a propagator.
  67.      * @param propagator to add
  68.      * @return satellite satellite propagated by the propagator
  69.      */
  70.     public ObservableSatellite addPropagator(final Propagator propagator) {
  71.         return addPropagator(propagator, null);
  72.     }

  73.     /** Add a propagator.
  74.      * @param propagator to add
  75.      * @param name satellite name (if null, a default name built from index will be used)
  76.      * @return satellite satellite propagated by the propagator
  77.      * @since 13.0
  78.      */
  79.     public ObservableSatellite addPropagator(final Propagator propagator, final String name) {
  80.         final ObservableSatellite os = new ObservableSatellite(propagators.size(), name);
  81.         observableSatellites.add(os);
  82.         propagators.add(propagator);
  83.         return os;
  84.     }

  85.     /** Get a registered propagator.
  86.      * @param satellite satellite propagated by the propagator {@link #addPropagator(Propagator)}
  87.      * @return propagator corresponding to satellite
  88.      */
  89.     public Propagator getPropagator(final ObservableSatellite satellite) {
  90.         return propagators.get(satellite.getPropagatorIndex());
  91.     }

  92.     /** Add a sequences generator for a specific measurement type.
  93.      * @param scheduler sequences generator to add
  94.      * @param <T> the type of the measurement
  95.      */
  96.     public <T extends ObservedMeasurement<T>> void addScheduler(final Scheduler<T> scheduler) {
  97.         final ObservableSatellite[] satellites = scheduler.getBuilder().getSatellites();
  98.         if (satellites.length == 1) {
  99.             // this scheduler manages only one satellite
  100.             // we can let the individual propagator handle it
  101.             final List<Scheduler<? extends ObservedMeasurement<?>>> list =
  102.                 singleSatSchedulers.computeIfAbsent(satellites[0], k -> new ArrayList<>());
  103.             list.add(scheduler);
  104.         } else {
  105.             // this scheduler manages several satellites at once
  106.             // we need to handle it at top level
  107.             multiSatSchedulers.add(scheduler);
  108.         }
  109.     }

  110.     /** Add a subscriber.
  111.      * @param subscriber to add
  112.      * @see GatheringSubscriber
  113.      * @since 12.0
  114.      */
  115.     public void addSubscriber(final GeneratedMeasurementSubscriber subscriber) {
  116.         subscribers.add(subscriber);
  117.     }

  118.     /** Generate measurements.
  119.      * @param start start of the measurements time span
  120.      * @param end end of the measurements time span
  121.      */
  122.     public void generate(final AbsoluteDate start, final AbsoluteDate end) {

  123.         // set up top level handler
  124.         final MultipleSatGeneratorHandler globalHandler =
  125.                         new MultipleSatGeneratorHandler(multiSatSchedulers, subscribers,
  126.                                                         observableSatellites, end.isAfterOrEqualTo(start));

  127.         // set up low level handlers
  128.         for (final Map.Entry<ObservableSatellite, List<Scheduler<? extends ObservedMeasurement<?>>>> entry : singleSatSchedulers.entrySet()) {
  129.             final StepHandlerMultiplexer multiplexer = propagators.get(entry.getKey().getPropagatorIndex()).getMultiplexer();
  130.             for (final Scheduler<?> scheduler : entry.getValue()) {
  131.                 multiplexer.add(new SingleSatGeneratorHandler<>(scheduler, globalHandler));
  132.             }
  133.         }

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

  136.         // generate the measurements
  137.         parallelizer.propagate(start, end);

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

  153.     }

  154.     /** Handler for measurements generation steps, single satellite case.
  155.      * <p>
  156.      * These handlers are called from the individual propagators threads.
  157.      * This means they generate measurements in parallel.
  158.      * </p>
  159.      * @param <T> the type of the measurement
  160.      * @since 12.0
  161.      */
  162.     private static class SingleSatGeneratorHandler<T extends ObservedMeasurement<T>> implements OrekitStepHandler {

  163.         /** Scheduler. */
  164.         private final Scheduler<T> scheduler;

  165.         /** Satellite related to this scheduler. */
  166.         private final ObservableSatellite satellite;

  167.         /** Global handler. */
  168.         private final MultipleSatGeneratorHandler globalHandler;

  169.         /** Simple constructor.
  170.          * @param scheduler scheduler
  171.          * @param globalHandler global handler
  172.          */
  173.         SingleSatGeneratorHandler(final Scheduler<T> scheduler, final MultipleSatGeneratorHandler globalHandler) {
  174.             this.scheduler     = scheduler;
  175.             this.satellite     = scheduler.getBuilder().getSatellites()[0];
  176.             this.globalHandler = globalHandler;
  177.         }

  178.         /** {@inheritDoc} */
  179.         @Override
  180.         public void init(final SpacecraftState state0, final AbsoluteDate t) {
  181.             scheduler.init(state0.getDate(), t);
  182.         }

  183.         /** {@inheritDoc} */
  184.         @Override
  185.         public void handleStep(final OrekitStepInterpolator interpolator) {
  186.             globalHandler.addMeasurements(scheduler.generate(Collections.singletonMap(satellite, interpolator)));
  187.         }

  188.     }

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

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

  201.         /** Subscribers for generated measurements events.
  202.          * @since 12.0
  203.          */
  204.         private final List<GeneratedMeasurementSubscriber> subscribers;

  205.         /** Observable satellites.
  206.          * @since 12.0
  207.          */
  208.         private final List<ObservableSatellite> observableSatellites;

  209.         /** Storage for sorted measurements within one step.
  210.          * @since 12.0
  211.          */
  212.         private final SortedSet<EstimatedMeasurementBase<?>> generated;

  213.         /** Forward generation indicator.
  214.          * @since 12.0
  215.          */
  216.         private final boolean forward;

  217.         /** Simple constructor.
  218.          * @param schedulers sequences generators
  219.          * @param subscribers subscribers for generated measurements events
  220.          * @param observableSatellites observable satellites
  221.          * @param forward if true, generation is forward
  222.          * @since 12.0
  223.          */
  224.         MultipleSatGeneratorHandler(final List<Scheduler<? extends ObservedMeasurement<?>>> schedulers,
  225.                                     final List<GeneratedMeasurementSubscriber> subscribers,
  226.                                     final List<ObservableSatellite> observableSatellites, final boolean forward) {

  227.             // measurements comparator, consistent with generation direction
  228.             final Comparator<EstimatedMeasurementBase<?>> comparator = forward ? Comparator.naturalOrder() : Comparator.reverseOrder();

  229.             this.schedulers           = schedulers;
  230.             this.subscribers          = subscribers;
  231.             this.observableSatellites = observableSatellites;
  232.             this.generated            = new TreeSet<>(comparator);
  233.             this.forward              = forward;

  234.         }

  235.         /** {@inheritDoc} */
  236.         @Override
  237.         public void init(final List<SpacecraftState> states0, final AbsoluteDate t) {

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

  239.             // initialize schedulers
  240.             for (final Scheduler<?> scheduler : schedulers) {
  241.                 scheduler.init(start, t);
  242.             }

  243.             // initialize subscribers
  244.             for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
  245.                 subscriber.init(start, t);
  246.             }

  247.         }

  248.         /** {@inheritDoc} */
  249.         @Override
  250.         public void handleStep(final List<OrekitStepInterpolator> interpolators) {

  251.             // prepare interpolators map
  252.             final Map<ObservableSatellite, OrekitStepInterpolator> interpolatorsMap =
  253.                             new HashMap<>(interpolators.size());
  254.             for (int i = 0; i < interpolators.size(); ++i) {
  255.                 interpolatorsMap.put(observableSatellites.get(i), interpolators.get(i));
  256.             }
  257.             final AbsoluteDate lastDate = interpolators.get(0).getCurrentState().getDate();

  258.             synchronized (generated) {

  259.                 // generate measurements, looping over schedulers
  260.                 for (final Scheduler<? extends ObservedMeasurement<?>> scheduler : schedulers) {
  261.                     generated.addAll(scheduler.generate(interpolatorsMap));
  262.                 }

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

  278.             }

  279.         }

  280.         /** {@inheritDoc} */
  281.         public void finish(final List<SpacecraftState> finalStates) {
  282.             synchronized (generated) {
  283.                 for (final EstimatedMeasurementBase<?> measurement : generated) {
  284.                     for (final GeneratedMeasurementSubscriber subscriber : subscribers) {
  285.                         subscriber.handleGeneratedMeasurement(measurement);
  286.                     }
  287.                 }
  288.                 generated.clear();
  289.             }
  290.         }

  291.         /** Add measurements performed by a low level handler.
  292.          * @param measurements measurements to add
  293.          * @since 12.0
  294.          */
  295.         private void addMeasurements(final SortedSet<? extends EstimatedMeasurementBase<?>> measurements) {
  296.             synchronized (generated) {
  297.                 generated.addAll(measurements);
  298.             }
  299.         }

  300.     }

  301. }