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 }