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.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.ode.events.Action;
22 import org.orekit.bodies.OneAxisEllipsoid;
23 import org.orekit.propagation.FieldSpacecraftState;
24 import org.orekit.propagation.events.handlers.FieldEventHandler;
25 import org.orekit.propagation.events.handlers.FieldStopOnIncreasing;
26 import org.orekit.utils.ExtendedPositionProvider;
27 import org.orekit.utils.OccultationEngine;
28
29 /** Finder for satellite eclipse related events.
30 * <p>This class finds eclipse events, i.e. satellite within umbra (total
31 * eclipse) or penumbra (partial eclipse).</p>
32 * <p>The default implementation behavior is to {@link Action#CONTINUE continue}
33 * propagation when entering the eclipse and to {@link Action#STOP stop} propagation
34 * when exiting the eclipse. This can be changed by calling {@link
35 * #withHandler(FieldEventHandler)} after construction.</p>
36 * @param <T> the type of the field elements
37 * @see org.orekit.propagation.FieldPropagator#addEventDetector(FieldEventDetector)
38 * @author Pascal Parraud
39 */
40 public class FieldEclipseDetector<T extends CalculusFieldElement<T>> extends FieldAbstractDetector<FieldEclipseDetector<T>, T> {
41
42 /** Occultation engine.
43 * @since 12.0
44 */
45 private final OccultationEngine occultationEngine;
46
47 /** Umbra, if true, or penumbra, if false, detection flag. */
48 private final boolean totalEclipse;
49
50 /** Margin to apply to eclipse angle. */
51 private final T margin;
52
53 /** Build a new eclipse detector.
54 * <p>The new instance is a total eclipse (umbra) detector with default
55 * values for maximal checking interval ({@link #DEFAULT_MAX_CHECK})
56 * and convergence threshold ({@link #DEFAULT_THRESHOLD}).</p>
57 * @param field field used by default
58 * @param occulted the body to be occulted
59 * @param occultedRadius the radius of the body to be occulted (m)
60 * @param occulting the occulting body
61 * @since 12.0
62 */
63 public FieldEclipseDetector(final Field<T> field,
64 final ExtendedPositionProvider occulted, final double occultedRadius,
65 final OneAxisEllipsoid occulting) {
66 this(field, new OccultationEngine(occulted, occultedRadius, occulting));
67 }
68
69 /** Build a new eclipse detector.
70 * <p>The new instance is a total eclipse (umbra) detector with default
71 * values for maximal checking interval ({@link #DEFAULT_MAX_CHECK})
72 * and convergence threshold ({@link #DEFAULT_THRESHOLD}).</p>
73 * @param field field used by default
74 * @param occultationEngine occultation engine
75 * @since 12.0
76 */
77 public FieldEclipseDetector(final Field<T> field, final OccultationEngine occultationEngine) {
78 this(new FieldEventDetectionSettings<>(field, EventDetectionSettings.getDefaultEventDetectionSettings()),
79 new FieldStopOnIncreasing<>(), occultationEngine, field.getZero(), true);
80 }
81
82 /** Protected constructor with full parameters.
83 * <p>
84 * This constructor is not public as users are expected to use the builder
85 * API with the various {@code withXxx()} methods to set up the instance
86 * in a readable manner without using a huge amount of parameters.
87 * </p>
88 * @param detectionSettings event detection settings
89 * @param handler event handler to call at event occurrences
90 * @param occultationEngine occultation engine
91 * @param margin to apply to eclipse angle (rad)
92 * @param totalEclipse umbra (true) or penumbra (false) detection flag
93 * @since 13.0
94 */
95 protected FieldEclipseDetector(final FieldEventDetectionSettings<T> detectionSettings, final FieldEventHandler<T> handler,
96 final OccultationEngine occultationEngine, final T margin, final boolean totalEclipse) {
97 super(detectionSettings, handler);
98 this.occultationEngine = occultationEngine;
99 this.margin = margin;
100 this.totalEclipse = totalEclipse;
101 }
102
103 /** {@inheritDoc} */
104 @Override
105 protected FieldEclipseDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
106 final FieldEventHandler<T> newHandler) {
107 return new FieldEclipseDetector<>(detectionSettings, newHandler, occultationEngine, margin, totalEclipse);
108 }
109
110 /**
111 * Setup the detector to full umbra detection.
112 * <p>
113 * This will override a penumbra/umbra flag if it has been configured previously.
114 * </p>
115 * @return a new detector with updated configuration (the instance is not changed)
116 * @see #withPenumbra()
117 * @since 6.1
118 */
119 public FieldEclipseDetector<T> withUmbra() {
120 return new FieldEclipseDetector<>(getDetectionSettings(), getHandler(),
121 occultationEngine, margin, true);
122 }
123
124 /**
125 * Setup the detector to penumbra detection.
126 * <p>
127 * This will override a penumbra/umbra flag if it has been configured previously.
128 * </p>
129 * @return a new detector with updated configuration (the instance is not changed)
130 * @see #withUmbra()
131 * @since 6.1
132 */
133 public FieldEclipseDetector<T> withPenumbra() {
134 return new FieldEclipseDetector<>(getDetectionSettings(), getHandler(),
135 occultationEngine, margin, false);
136 }
137
138 /**
139 * Setup a margin to angle detection.
140 * <p>
141 * A positive margin implies eclipses are "larger" hence entry occurs earlier and exit occurs later
142 * than a detector with 0 margin.
143 * </p>
144 * @param newMargin angular margin to apply to eclipse detection (rad)
145 * @return a new detector with updated configuration (the instance is not changed)
146 * @since 12.0
147 */
148 public FieldEclipseDetector<T> withMargin(final T newMargin) {
149 return new FieldEclipseDetector<>(getDetectionSettings(), getHandler(),
150 occultationEngine, newMargin, totalEclipse);
151 }
152
153 /** Get the angular margin used for eclipse detection.
154 * @return angular margin used for eclipse detection (rad)
155 * @since 12.0
156 */
157 public T getMargin() {
158 return margin;
159 }
160
161 /** Get the occultation engine.
162 * @return occultation engine
163 * @since 12.0
164 */
165 public OccultationEngine getOccultationEngine() {
166 return occultationEngine;
167 }
168
169 /** Get the total eclipse detection flag.
170 * @return the total eclipse detection flag (true for umbra events detection,
171 * false for penumbra events detection)
172 */
173 public boolean getTotalEclipse() {
174 return totalEclipse;
175 }
176
177 /** Compute the value of the switching function.
178 * This function becomes negative when entering the region of shadow
179 * and positive when exiting.
180 * @param s the current state information: date, kinematics, attitude
181 * @return value of the switching function
182 */
183 public T g(final FieldSpacecraftState<T> s) {
184 final OccultationEngine.FieldOccultationAngles<T> angles = occultationEngine.angles(s);
185 return totalEclipse ?
186 angles.getSeparation().subtract(angles.getLimbRadius()).add(angles.getOccultedApparentRadius().add(margin)) :
187 angles.getSeparation().subtract(angles.getLimbRadius()).subtract(angles.getOccultedApparentRadius().add(margin));
188 }
189
190 }