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.time; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import org.hipparchus.util.FastMath; 23 24 25 /** Selector generating high rate bursts of dates separated by some rest period. 26 * <p> 27 * The dates can be aligned to whole steps in some time scale. So for example 28 * if a rest period of 3600s is used and the alignment time scale is set to 29 * {@link org.orekit.time.TimeScales#getUTC() UTC}, the earliest date of 30 * each burst will occur at whole hours in UTC time. 31 * </p> 32 * <p> 33 * BEWARE! This class stores internally the last selected dates, so it is <em>neither</em> 34 * reusable across several {@link org.orekit.estimation.measurements.generation.EventBasedScheduler 35 * fixed step} or {@link org.orekit.estimation.measurements.generation.ContinuousScheduler 36 * continuous} schedulers, <em>nor</em> thread-safe. A separate selector should be used for each 37 * scheduler and for each thread in multi-threading context. 38 * </p> 39 * @author Luc Maisonobe 40 * @since 9.3 41 */ 42 public class BurstSelector implements DatesSelector { 43 44 /** Maximum number of selected dates in a burst. */ 45 private final int maxBurstSize; 46 47 /** Step between two consecutive dates within a burst. */ 48 private final double highRateStep; 49 50 /** Period between the start of each burst. */ 51 private final double burstPeriod; 52 53 /** Alignment time scale (null is alignment is not needed). */ 54 private final TimeScale alignmentTimeScale; 55 56 /** First date in last burst. */ 57 private AbsoluteDate first; 58 59 /** Last selected date. */ 60 private AbsoluteDate last; 61 62 /** Index of last selected date in current burst. */ 63 private int index; 64 65 /** Simple constructor. 66 * <p> 67 * The {@code burstPeriod} ignores the duration of the burst itself. This 68 * means that if burst of {@code maxBurstSize=256} dates each separated by 69 * {@code highRateStep=100ms} should be selected with {@code burstPeriod=300s}, 70 * then the first burst would contain 256 dates from {@code t0} to {@code t0+25.5s} 71 * and the second burst would start at {@code t0+300s}, <em>not</em> at 72 * {@code t0+325.5s}. 73 * </p> 74 * <p> 75 * If alignment to some time scale is needed, it applies only to the first date in 76 * each burst. 77 * </p> 78 * @param maxBurstSize maximum number of selected dates in a burst 79 * @param highRateStep step between two consecutive dates within a burst (s) 80 * @param burstPeriod period between the start of each burst (s) 81 * @param alignmentTimeScale alignment time scale for first date in burst 82 * (null is alignment is not needed) 83 */ 84 public BurstSelector(final int maxBurstSize, final double highRateStep, 85 final double burstPeriod, final TimeScale alignmentTimeScale) { 86 this.maxBurstSize = maxBurstSize; 87 this.highRateStep = highRateStep; 88 this.burstPeriod = burstPeriod; 89 this.alignmentTimeScale = alignmentTimeScale; 90 this.last = null; 91 this.first = null; 92 this.index = 0; 93 } 94 95 /** {@inheritDoc} */ 96 @Override 97 public List<AbsoluteDate> selectDates(final AbsoluteDate start, final AbsoluteDate end) { 98 99 final int increment = end.durationFrom(start) > 0 ? +1 : -1; 100 final int firstIndex = increment > 0 ? 0 : maxBurstSize - 1; 101 final int lastIndex = maxBurstSize - 1 - firstIndex; 102 final double signedHighRateStep = FastMath.copySign(highRateStep, increment); 103 final double signedBurstPeriod = FastMath.copySign(burstPeriod, increment); 104 105 final List<AbsoluteDate> selected = new ArrayList<>(); 106 107 final boolean reset = first == null || increment * start.durationFrom(first) > burstPeriod; 108 if (reset) { 109 first = null; 110 index = firstIndex; 111 } 112 113 for (AbsoluteDate next = reset ? start : last.shiftedBy(signedHighRateStep); 114 increment * next.durationFrom(end) <= 0; 115 next = last.shiftedBy(signedHighRateStep)) { 116 117 if (index == lastIndex + increment) { 118 // we have exceeded burst size, jump to next burst 119 next = first.shiftedBy(signedBurstPeriod); 120 first = null; 121 index = firstIndex; 122 if (increment * next.durationFrom(end) > 0) { 123 // next burst is out of current interval 124 break; 125 } 126 } 127 128 if (first == null && alignmentTimeScale != null) { 129 // align earliest burst date to time scale 130 final double offset = firstIndex * highRateStep; 131 final double t = next.getComponents(alignmentTimeScale).getTime().getSecondsInLocalDay() - offset; 132 final double dt = burstPeriod * FastMath.round(t / burstPeriod) - t; 133 next = next.shiftedBy(dt); 134 while (index != lastIndex && increment * next.durationFrom(start) < 0) { 135 next = next.shiftedBy(signedHighRateStep); 136 index += increment; 137 } 138 if (increment * next.durationFrom(start) < 0) { 139 // alignment shifted date out of interval 140 next = next.shiftedBy(signedBurstPeriod - (maxBurstSize - 1) * signedHighRateStep); 141 index = firstIndex; 142 } 143 } 144 145 if (increment * next.durationFrom(start) >= 0) { 146 if (increment * next.durationFrom(end) <= 0) { 147 // the date is within range, select it 148 if (first == null) { 149 first = next.shiftedBy(-signedHighRateStep * index); 150 } 151 selected.add(next); 152 } else { 153 // we have exceeded date range 154 break; 155 } 156 } 157 last = next; 158 index += increment; 159 160 } 161 162 return selected; 163 164 } 165 166 }