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.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.FieldStaticTransform;
25 import org.orekit.frames.TopocentricFrame;
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 * @param <T> type of the field elements
44 */
45 public class FieldElevationDetector<T extends CalculusFieldElement<T>>
46 extends FieldAbstractTopocentricDetector<FieldElevationDetector<T>, T> {
47
48 /** Elevation mask used for calculations, if defined. */
49 private final ElevationMask elevationMask;
50
51 /** Minimum elevation value used if mask is not defined. */
52 private final double minElevation;
53
54 /** Atmospheric Model used for calculations, if defined. */
55 private final AtmosphericRefractionModel refractionModel;
56
57 /**
58 * Creates an instance of Elevation detector based on passed in topocentric frame
59 * and the minimum elevation angle.
60 * <p>
61 * uses default values for maximal checking interval ({@link #DEFAULT_MAX_CHECK})
62 * and convergence threshold ({@link #DEFAULT_THRESHOLD}).</p>
63 * @param field type of the elements
64 * @param topo reference to a topocentric model
65 * @see #withConstantElevation(double)
66 * @see #withElevationMask(ElevationMask)
67 * @see #withRefraction(AtmosphericRefractionModel)
68 */
69 public FieldElevationDetector(final Field<T> field, final TopocentricFrame topo) {
70 this(new FieldEventDetectionSettings<>(field, EventDetectionSettings.getDefaultEventDetectionSettings()),
71 new FieldStopOnDecreasing<>(),
72 0.0, null, null, topo);
73 }
74
75 /**
76 * Creates an instance of Elevation detector based on passed in topocentric frame
77 * and overrides of default maximal checking interval and convergence threshold values.
78 * @param maxCheck maximum checking interval (s)
79 * @param threshold maximum divergence threshold (s)
80 * @param topo reference to a topocentric model
81 * @see #withConstantElevation(double)
82 * @see #withElevationMask(ElevationMask)
83 * @see #withRefraction(AtmosphericRefractionModel)
84 */
85 public FieldElevationDetector(final T maxCheck, final T threshold, final TopocentricFrame topo) {
86 this(new FieldEventDetectionSettings<>(maxCheck.getReal(), threshold, DEFAULT_MAX_ITER),
87 new FieldStopOnDecreasing<>(), 0.0, null, null, topo);
88 }
89
90 /** Protected constructor with full parameters.
91 * <p>
92 * This constructor is not public as users are expected to use the builder
93 * API with the various {@code withXxx()} methods to set up the instance
94 * in a readable manner without using a huge amount of parameters.
95 * </p>
96 * @param detectionSettings detection settings
97 * @param handler event handler to call at event occurrences
98 * @param minElevation minimum elevation in radians (rad)
99 * @param mask reference to elevation mask
100 * @param refractionModel reference to refraction model
101 * @param topo reference to a topocentric model
102 * @since 12.2
103 */
104 protected FieldElevationDetector(final FieldEventDetectionSettings<T> detectionSettings, final FieldEventHandler<T> handler,
105 final double minElevation, final ElevationMask mask,
106 final AtmosphericRefractionModel refractionModel,
107 final TopocentricFrame topo) {
108 super(detectionSettings, handler, topo);
109 this.minElevation = minElevation;
110 this.elevationMask = mask;
111 this.refractionModel = refractionModel;
112 }
113
114 /** {@inheritDoc} */
115 @Override
116 protected FieldElevationDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
117 final FieldEventHandler<T> newHandler) {
118 return new FieldElevationDetector<>(detectionSettings, newHandler,
119 minElevation, elevationMask, refractionModel, getTopocentricFrame());
120 }
121
122 /**
123 * Returns the currently configured elevation mask.
124 * @return elevation mask
125 * (null if instance has been configured with {@link #withConstantElevation(double)}
126 * @see #withElevationMask(ElevationMask)
127 */
128 public ElevationMask getElevationMask() {
129 return this.elevationMask;
130 }
131
132 /**
133 * Returns the currently configured minimum valid elevation value.
134 * @return minimum elevation value
135 * ({@code Double.NaN} if instance has been configured with {@link #withElevationMask(ElevationMask)}
136 * @see #withConstantElevation(double)
137 */
138 public double getMinElevation() {
139 return this.minElevation;
140 }
141
142 /**
143 * Returns the currently configured refraction model.
144 * @return refraction model
145 * @see #withRefraction(AtmosphericRefractionModel)
146 */
147 public AtmosphericRefractionModel getRefractionModel() {
148 return this.refractionModel;
149 }
150
151 /** Compute the value of the switching function.
152 * This function measures the difference between the current elevation
153 * (and azimuth if necessary) and the reference mask or minimum value.
154 * @param s the current state information: date, kinematics, attitude
155 * @return value of the switching function
156 */
157 @Override
158 public T g(final FieldSpacecraftState<T> s) {
159
160 final FieldStaticTransform<T> t = s.getFrame().getStaticTransformTo(getTopocentricFrame(), s.getDate());
161 final FieldVector3D<T> extPointTopo = t.transformPosition(s.getPosition());
162 final T trueElevation = extPointTopo.getDelta();
163
164 final T calculatedElevation;
165 if (refractionModel != null) {
166 calculatedElevation = trueElevation.add(refractionModel.getRefraction(trueElevation.getReal()));
167 } else {
168 calculatedElevation = trueElevation;
169 }
170
171 if (elevationMask != null) {
172 final double azimuth = FastMath.atan2(extPointTopo.getY().getReal(), extPointTopo.getX().getReal());
173 return calculatedElevation.subtract(elevationMask.getElevation(azimuth));
174 } else {
175 return calculatedElevation.subtract(minElevation);
176 }
177
178 }
179
180 /**
181 * Setup the minimum elevation for detection.
182 * <p>
183 * This will override an elevation mask if it has been configured as such previously.
184 * </p>
185 * @param newMinElevation minimum elevation for visibility in radians (rad)
186 * @return a new detector with updated configuration (the instance is not changed)
187 * @see #getMinElevation()
188 * @since 6.1
189 */
190 public FieldElevationDetector<T> withConstantElevation(final double newMinElevation) {
191 return new FieldElevationDetector<>(getDetectionSettings(), getHandler(),
192 newMinElevation, null, refractionModel, getTopocentricFrame());
193 }
194
195 /**
196 * Setup the elevation mask for detection using the passed in mask object.
197 * @param newElevationMask elevation mask to use for the computation
198 * @return a new detector with updated configuration (the instance is not changed)
199 * @since 6.1
200 * @see #getElevationMask()
201 */
202 public FieldElevationDetector<T> withElevationMask(final ElevationMask newElevationMask) {
203 return new FieldElevationDetector<>(getDetectionSettings(), getHandler(),
204 Double.NaN, newElevationMask, refractionModel, getTopocentricFrame());
205 }
206
207 /**
208 * Setup the elevation detector to use an atmospheric refraction model in its
209 * calculations.
210 * <p>
211 * To disable the refraction when copying an existing elevation
212 * detector, call this method with a null argument.
213 * </p>
214 * @param newRefractionModel refraction model to use for the computation
215 * @return a new detector with updated configuration (the instance is not changed)
216 * @since 6.1
217 * @see #getRefractionModel()
218 */
219 public FieldElevationDetector<T> withRefraction(final AtmosphericRefractionModel newRefractionModel) {
220 return new FieldElevationDetector<>(getDetectionSettings(), getHandler(),
221 minElevation, elevationMask, newRefractionModel, getTopocentricFrame());
222 }
223
224 }