BurstSelector.java

  1. /* Copyright 2002-2019 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.time;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.util.FastMath;


  21. /** Selector generating high rate bursts of dates separated by some rest period.
  22.  * <p>
  23.  * The dates can be aligned to whole steps in some time scale. So for example
  24.  * if a rest period of 3600s is used and the alignment time scale is set to
  25.  * {@link org.orekit.time.TimeScalesFactory#getUTC() UTC}, the earliest date of
  26.  * each burst will occur at whole hours in UTC time.
  27.  * </p>
  28.  * <p>
  29.  * This class stores internally the last selected dates, so it is <em>not</em>
  30.  * thread-safe. A separate selector should be used for each thread in multi-threading
  31.  * context.
  32.  * </p>
  33.  * @author Luc Maisonobe
  34.  * @since 9.3
  35.  */
  36. public class BurstSelector implements DatesSelector {

  37.     /** Maximum number of selected dates in a burst. */
  38.     private final int maxBurstSize;

  39.     /** Step between two consecutive dates within a burst. */
  40.     private final double highRateStep;

  41.     /** Period between the start of each burst. */
  42.     private final double burstPeriod;

  43.     /** Alignment time scale (null is alignment is not needed). */
  44.     private final TimeScale alignmentTimeScale;

  45.     /** First date in last burst. */
  46.     private AbsoluteDate first;

  47.     /** Last selected date. */
  48.     private AbsoluteDate last;

  49.     /** Index of last selected date in current burst. */
  50.     private int index;

  51.     /** Simple constructor.
  52.      * <p>
  53.      * The {@code burstPeriod} ignores the duration of the burst itself. This
  54.      * means that if burst of {@code maxBurstSize=256} dates each separated by
  55.      * {@code highRateStep=100ms} should be selected with {@code burstPeriod=300s},
  56.      * then the first burst would contain 256 dates from {@code t0} to {@code t0+25.5s}
  57.      * and the second burst would start at {@code t0+300s}, <em>not</em> at
  58.      * {@code t0+325.5s}.
  59.      * </p>
  60.      * <p>
  61.      * If alignment to some time scale is needed, it applies only to the first date in
  62.      * each burst.
  63.      * </p>
  64.      * @param maxBurstSize maximum number of selected dates in a burst
  65.      * @param highRateStep step between two consecutive dates within a burst (s)
  66.      * @param burstPeriod period between the start of each burst (s)
  67.      * @param alignmentTimeScale alignment time scale for first date in burst
  68.      * (null is alignment is not needed)
  69.      */
  70.     public BurstSelector(final int maxBurstSize, final double highRateStep,
  71.                          final double burstPeriod, final TimeScale alignmentTimeScale) {
  72.         this.maxBurstSize       = maxBurstSize;
  73.         this.highRateStep       = highRateStep;
  74.         this.burstPeriod        = burstPeriod;
  75.         this.alignmentTimeScale = alignmentTimeScale;
  76.         this.last               = null;
  77.         this.first              = null;
  78.         this.index              = 0;
  79.     }

  80.     /** {@inheritDoc} */
  81.     @Override
  82.     public List<AbsoluteDate> selectDates(final AbsoluteDate start, final AbsoluteDate end) {

  83.         final int    increment          = end.durationFrom(start) > 0 ? +1 : -1;
  84.         final int    firstIndex         = increment > 0 ? 0 : maxBurstSize - 1;
  85.         final int    lastIndex          = maxBurstSize - 1 - firstIndex;
  86.         final double signedHighRateStep = FastMath.copySign(highRateStep, increment);
  87.         final double signedBurstPeriod  = FastMath.copySign(burstPeriod, increment);

  88.         final List<AbsoluteDate> selected = new ArrayList<>();

  89.         final boolean reset = first == null || increment * start.durationFrom(first) > burstPeriod;
  90.         if (reset) {
  91.             first = null;
  92.             index = firstIndex;
  93.         }

  94.         for (AbsoluteDate next = reset ? start : last.shiftedBy(signedHighRateStep);
  95.              increment * next.durationFrom(end) <= 0;
  96.              next = last.shiftedBy(signedHighRateStep)) {

  97.             if (index == lastIndex + increment) {
  98.                 // we have exceeded burst size, jump to next burst
  99.                 next  = first.shiftedBy(signedBurstPeriod);
  100.                 first = null;
  101.                 index = firstIndex;
  102.                 if (increment * next.durationFrom(end) > 0) {
  103.                     // next burst is out of current interval
  104.                     break;
  105.                 }
  106.             }

  107.             if (first == null && alignmentTimeScale != null) {
  108.                 // align earliest burst date to time scale
  109.                 final double offset = firstIndex * highRateStep;
  110.                 final double t      = next.getComponents(alignmentTimeScale).getTime().getSecondsInLocalDay() - offset;
  111.                 final double dt     = burstPeriod * FastMath.round(t / burstPeriod) - t;
  112.                 next = next.shiftedBy(dt);
  113.                 while (index != lastIndex && increment * next.durationFrom(start) < 0) {
  114.                     next = next.shiftedBy(signedHighRateStep);
  115.                     index += increment;
  116.                 }
  117.                 if (increment * next.durationFrom(start) < 0) {
  118.                     // alignment shifted date out of interval
  119.                     next  = next.shiftedBy(signedBurstPeriod - (maxBurstSize - 1) * signedHighRateStep);
  120.                     index = firstIndex;
  121.                 }
  122.             }

  123.             if (increment * next.durationFrom(start) >= 0) {
  124.                 if (increment * next.durationFrom(end) <= 0) {
  125.                     // the date is within range, select it
  126.                     if (first == null) {
  127.                         first = next.shiftedBy(-signedHighRateStep * index);
  128.                     }
  129.                     selected.add(next);
  130.                 } else {
  131.                     // we have exceeded date range
  132.                     break;
  133.                 }
  134.             }
  135.             last   = next;
  136.             index += increment;

  137.         }

  138.         return selected;

  139.     }

  140. }