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