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