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.propagation.events;
18
19 import org.hipparchus.ode.events.Action;
20 import org.orekit.frames.TopocentricFrame;
21 import org.orekit.models.AtmosphericRefractionModel;
22 import org.orekit.propagation.SpacecraftState;
23 import org.orekit.propagation.events.handlers.EventHandler;
24 import org.orekit.propagation.events.handlers.StopOnDecreasing;
25 import org.orekit.utils.ElevationMask;
26 import org.orekit.utils.TrackingCoordinates;
27
28
29 /**
30 * Finder for satellite raising/setting events that allows for the
31 * setting of azimuth and/or elevation bounds or a ground azimuth/elevation
32 * mask input. Each calculation be configured to use atmospheric refraction
33 * as well.
34 * <p>The default implementation behavior is to {@link Action#CONTINUE continue}
35 * propagation at raising and to {@link Action#STOP stop} propagation
36 * at setting. This can be changed by calling
37 * {@link #withHandler(EventHandler)} after construction.</p>
38 * @author Hank Grabowski
39 * @since 6.1
40 */
41 public class ElevationDetector extends AbstractDetector<ElevationDetector> {
42
43 /** Elevation mask used for calculations, if defined. */
44 private final ElevationMask elevationMask;
45
46 /** Minimum elevation value used if mask is not defined. */
47 private final double minElevation;
48
49 /** Atmospheric Model used for calculations, if defined. */
50 private final AtmosphericRefractionModel refractionModel;
51
52 /** Topocentric frame in which elevation should be evaluated. */
53 private final TopocentricFrame topo;
54
55 /**
56 * Creates an instance of Elevation detector based on passed in topocentric frame
57 * and the minimum elevation angle.
58 * <p>
59 * uses default values for maximal checking interval ({@link #DEFAULT_MAXCHECK})
60 * and convergence threshold ({@link #DEFAULT_THRESHOLD}).</p>
61 * @param topo reference to a topocentric model
62 * @see #withConstantElevation(double)
63 * @see #withElevationMask(ElevationMask)
64 * @see #withRefraction(AtmosphericRefractionModel)
65 */
66 public ElevationDetector(final TopocentricFrame topo) {
67 this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, topo);
68 }
69
70 /**
71 * Creates an instance of Elevation detector based on passed in topocentric frame
72 * and overrides of default maximal checking interval and convergence threshold values.
73 * @param maxCheck maximum checking interval (s)
74 * @param threshold maximum convergence threshold (s)
75 * @param topo reference to a topocentric model
76 * @see #withConstantElevation(double)
77 * @see #withElevationMask(ElevationMask)
78 * @see #withRefraction(AtmosphericRefractionModel)
79 */
80 public ElevationDetector(final double maxCheck, final double threshold,
81 final TopocentricFrame topo) {
82 this(AdaptableInterval.of(maxCheck), threshold, topo);
83 }
84
85 /**
86 * Creates an instance of Elevation detector based on passed in topocentric frame
87 * and overrides of default maximal checking interval and convergence threshold values.
88 * @param maxCheck maximum checking adaptable interval
89 * @param threshold maximum convergence threshold (s)
90 * @param topo reference to a topocentric model
91 * @see org.orekit.propagation.events.intervals.ElevationDetectionAdaptableIntervalFactory
92 * @see #withConstantElevation(double)
93 * @see #withElevationMask(ElevationMask)
94 * @see #withRefraction(AtmosphericRefractionModel)
95 * @since 12.1
96 */
97 public ElevationDetector(final AdaptableInterval maxCheck, final double threshold,
98 final TopocentricFrame topo) {
99 this(maxCheck, threshold, DEFAULT_MAX_ITER,
100 new StopOnDecreasing(),
101 0.0, null, null, topo);
102 }
103
104 /** Protected constructor with full parameters.
105 * <p>
106 * This constructor is not public as users are expected to use the builder
107 * API with the various {@code withXxx()} methods to set up the instance
108 * in a readable manner without using a huge amount of parameters.
109 * </p>
110 * @param maxCheck maximum checking interval
111 * @param threshold convergence threshold (s)
112 * @param maxIter maximum number of iterations in the event time search
113 * @param handler event handler to call at event occurrences
114 * @param minElevation minimum elevation in radians (rad)
115 * @param mask reference to elevation mask
116 * @param refractionModel reference to refraction model
117 * @param topo reference to a topocentric model
118 */
119 protected ElevationDetector(final AdaptableInterval maxCheck, final double threshold,
120 final int maxIter, final EventHandler handler,
121 final double minElevation, final ElevationMask mask,
122 final AtmosphericRefractionModel refractionModel,
123 final TopocentricFrame topo) {
124 super(maxCheck, threshold, maxIter, handler);
125 this.minElevation = minElevation;
126 this.elevationMask = mask;
127 this.refractionModel = refractionModel;
128 this.topo = topo;
129 }
130
131 /** {@inheritDoc} */
132 @Override
133 protected ElevationDetector create(final AdaptableInterval newMaxCheck, final double newThreshold,
134 final int newMaxIter, final EventHandler newHandler) {
135 return new ElevationDetector(newMaxCheck, newThreshold, newMaxIter, newHandler,
136 minElevation, elevationMask, refractionModel, topo);
137 }
138
139 /**
140 * Returns the currently configured elevation mask.
141 * @return elevation mask
142 * (null if instance has been configured with {@link #withConstantElevation(double)}
143 * @see #withElevationMask(ElevationMask)
144 */
145 public ElevationMask getElevationMask() {
146 return this.elevationMask;
147 }
148
149 /**
150 * Returns the currently configured minimum valid elevation value.
151 * @return minimum elevation value
152 * ({@code Double.NaN} if instance has been configured with {@link #withElevationMask(ElevationMask)}
153 * @see #withConstantElevation(double)
154 */
155 public double getMinElevation() {
156 return this.minElevation;
157 }
158
159 /**
160 * Returns the currently configured refraction model.
161 * @return refraction model
162 * @see #withRefraction(AtmosphericRefractionModel)
163 */
164 public AtmosphericRefractionModel getRefractionModel() {
165 return this.refractionModel;
166 }
167
168 /**
169 * Returns the currently configured topocentric frame definitions.
170 * @return topocentric frame definition
171 */
172 public TopocentricFrame getTopocentricFrame() {
173 return this.topo;
174 }
175
176 /** Compute the value of the switching function.
177 * This function measures the difference between the current elevation
178 * (and azimuth if necessary) and the reference mask or minimum value.
179 * @param s the current state information: date, kinematics, attitude
180 * @return value of the switching function
181 */
182 @Override
183 public double g(final SpacecraftState s) {
184
185 final TrackingCoordinates tc = topo.getTrackingCoordinates(s.getPosition(), s.getFrame(), s.getDate());
186
187 final double calculatedElevation;
188 if (refractionModel != null) {
189 calculatedElevation = tc.getElevation() + refractionModel.getRefraction(tc.getElevation());
190 } else {
191 calculatedElevation = tc.getElevation();
192 }
193
194 if (elevationMask != null) {
195 return calculatedElevation - elevationMask.getElevation(tc.getAzimuth());
196 } else {
197 return calculatedElevation - minElevation;
198 }
199
200 }
201
202 /**
203 * Setup the minimum elevation for detection.
204 * <p>
205 * This will override an elevation mask if it has been configured as such previously.
206 * </p>
207 * @param newMinElevation minimum elevation for visibility in radians (rad)
208 * @return a new detector with updated configuration (the instance is not changed)
209 * @see #getMinElevation()
210 * @since 6.1
211 */
212 public ElevationDetector withConstantElevation(final double newMinElevation) {
213 return new ElevationDetector(getMaxCheckInterval(), getThreshold(), getMaxIterationCount(), getHandler(),
214 newMinElevation, null, refractionModel, topo);
215 }
216
217 /**
218 * Setup the elevation mask for detection using the passed in mask object.
219 * @param newElevationMask elevation mask to use for the computation
220 * @return a new detector with updated configuration (the instance is not changed)
221 * @since 6.1
222 * @see #getElevationMask()
223 */
224 public ElevationDetector withElevationMask(final ElevationMask newElevationMask) {
225 return new ElevationDetector(getMaxCheckInterval(), getThreshold(), getMaxIterationCount(), getHandler(),
226 Double.NaN, newElevationMask, refractionModel, topo);
227 }
228
229 /**
230 * Setup the elevation detector to use an atmospheric refraction model in its
231 * calculations.
232 * <p>
233 * To disable the refraction when copying an existing elevation
234 * detector, call this method with a null argument.
235 * </p>
236 * @param newRefractionModel refraction model to use for the computation
237 * @return a new detector with updated configuration (the instance is not changed)
238 * @since 6.1
239 * @see #getRefractionModel()
240 */
241 public ElevationDetector withRefraction(final AtmosphericRefractionModel newRefractionModel) {
242 return new ElevationDetector(getMaxCheckInterval(), getThreshold(), getMaxIterationCount(), getHandler(),
243 minElevation, elevationMask, newRefractionModel, topo);
244 }
245
246 }