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