1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.numerical;
18
19
20 import org.hipparchus.analysis.differentiation.Gradient;
21 import org.hipparchus.analysis.differentiation.GradientField;
22 import org.hipparchus.linear.MatrixUtils;
23 import org.hipparchus.linear.RealMatrix;
24 import org.hipparchus.linear.RealVector;
25 import org.hipparchus.ode.events.Action;
26 import org.hipparchus.util.FastMath;
27 import org.orekit.attitudes.Attitude;
28 import org.orekit.attitudes.AttitudeProvider;
29 import org.orekit.frames.Frame;
30 import org.orekit.orbits.CartesianOrbit;
31 import org.orekit.orbits.Orbit;
32 import org.orekit.propagation.FieldSpacecraftState;
33 import org.orekit.propagation.SpacecraftState;
34 import org.orekit.propagation.events.EventDetector;
35 import org.orekit.propagation.events.FieldEventDetector;
36 import org.orekit.propagation.events.handlers.EventHandler;
37 import org.orekit.time.AbsoluteDate;
38 import org.orekit.time.FieldAbsoluteDate;
39 import org.orekit.utils.AbsolutePVCoordinates;
40 import org.orekit.utils.DataDictionary;
41 import org.orekit.utils.DerivativeStateUtils;
42 import org.orekit.utils.PVCoordinates;
43 import org.orekit.utils.TimeStampedPVCoordinates;
44
45 import java.util.Arrays;
46 import java.util.List;
47
48
49
50
51
52
53
54
55
56
57 class SwitchEventHandler implements EventHandler {
58
59
60 private final EventHandler wrappedHandler;
61
62
63 private final NumericalPropagationHarvester matricesHarvester;
64
65
66 private final NumericalTimeDerivativesEquations timeDerivativesEquations;
67
68
69 private final AttitudeProvider attitudeProvider;
70
71
72 private final List<FieldEventDetector<Gradient>> fieldDetectors;
73
74
75 private boolean isForward;
76
77
78 private FieldEventDetector<Gradient> switchFieldDetector;
79
80
81
82
83
84
85
86
87
88 SwitchEventHandler(final EventHandler wrappedHandler, final NumericalPropagationHarvester matricesHarvester,
89 final NumericalTimeDerivativesEquations timeDerivativesEquations,
90 final AttitudeProvider attitudeProvider, final List<FieldEventDetector<Gradient>> fieldDetectors) {
91 this.wrappedHandler = wrappedHandler;
92 this.matricesHarvester = matricesHarvester;
93 this.timeDerivativesEquations = timeDerivativesEquations;
94 this.attitudeProvider = attitudeProvider;
95 this.fieldDetectors = fieldDetectors;
96 }
97
98 @Override
99 public SpacecraftState resetState(final EventDetector detector, final SpacecraftState oldState) {
100 if (switchFieldDetector == null) {
101
102 return wrappedHandler.resetState(detector, oldState);
103 } else {
104 final SpacecraftState newState = updateState(oldState);
105 switchFieldDetector = null;
106 return newState;
107 }
108 }
109
110 @Override
111 public void init(final SpacecraftState initialState, final AbsoluteDate target, final EventDetector detector) {
112 isForward = initialState.getDate().isBeforeOrEqualTo(target);
113 switchFieldDetector = null;
114 final GradientField field = fieldDetectors.get(0).getThreshold().getField();
115 final FieldAbsoluteDate<Gradient> fieldTarget = new FieldAbsoluteDate<>(field, target);
116 final FieldSpacecraftState<Gradient> fieldState = new FieldSpacecraftState<>(field, initialState);
117 fieldDetectors.forEach(fieldEventDetector -> fieldEventDetector.init(fieldState, fieldTarget));
118 EventHandler.super.init(initialState, target, detector);
119 }
120
121 @Override
122 public Action eventOccurred(final SpacecraftState s, final EventDetector detector, final boolean increasing) {
123 final Action action = wrappedHandler.eventOccurred(s, detector, increasing);
124 if (action == Action.RESET_DERIVATIVES) {
125 switchFieldDetector = findSwitchDetector(detector, s);
126 if (switchFieldDetector != null) {
127 return Action.RESET_STATE;
128 }
129 }
130 return action;
131 }
132
133
134
135
136
137
138
139 private FieldEventDetector<Gradient> findSwitchDetector(final EventDetector detector, final SpacecraftState state) {
140 final GradientField field = fieldDetectors.get(0).getThreshold().getField();
141 final FieldSpacecraftState<Gradient> fieldState = new FieldSpacecraftState<>(field, state);
142 fieldDetectors.forEach(fieldDetector -> fieldDetector.reset(fieldState, fieldState.getDate()));
143 final double g = detector.g(state);
144 return findSwitchDetector(g, fieldState);
145 }
146
147
148
149
150
151
152
153 private FieldEventDetector<Gradient> findSwitchDetector(final double g,
154 final FieldSpacecraftState<Gradient> fieldState) {
155 for (final FieldEventDetector<Gradient> fieldDetector : fieldDetectors) {
156 final Gradient fieldG = fieldDetector.g(fieldState);
157 if (FastMath.abs(fieldG.getValue() - g) < 1e-11) {
158 return fieldDetector;
159 }
160 }
161 return null;
162 }
163
164
165
166
167
168
169 private SpacecraftState updateState(final SpacecraftState stateAtSwitch) {
170 final RealMatrix cartesianFactorMatrix = computeUpdateMatrix(stateAtSwitch);
171
172 final String stmName = matricesHarvester.getStmName();
173 final RealMatrix oldStm = matricesHarvester.toSquareMatrix(stateAtSwitch.getAdditionalState(stmName));
174 final RealMatrix stm = cartesianFactorMatrix.multiply(oldStm).add(oldStm);
175 final DataDictionary additionalData = new DataDictionary(stateAtSwitch.getAdditionalDataValues());
176 additionalData.put(stmName, matricesHarvester.toArray(stm.getData()));
177
178 if (!matricesHarvester.getJacobiansColumnsNames().isEmpty()) {
179 for (final String parameterName : matricesHarvester.getJacobiansColumnsNames()) {
180 final RealVector oldJacobian = MatrixUtils.createRealVector(stateAtSwitch.getAdditionalState(parameterName));
181 final RealVector jacobian = cartesianFactorMatrix.operate(oldJacobian).add(oldJacobian);
182 additionalData.put(parameterName, jacobian.toArray());
183 }
184 }
185 return stateAtSwitch.withAdditionalData(additionalData);
186 }
187
188
189
190
191
192
193 private RealMatrix computeUpdateMatrix(final SpacecraftState state) {
194 final double twoThreshold = switchFieldDetector.getThreshold().getValue() * 2.;
195 final double dt = isForward ? -twoThreshold : twoThreshold;
196 final SpacecraftState stateBefore = shift(state, dt);
197 final double[] derivativesBefore = timeDerivativesEquations.computeTimeDerivatives(stateBefore);
198 final SpacecraftState stateAfter = shift(state, -dt);
199 final double[] derivativesAfter = timeDerivativesEquations.computeTimeDerivatives(stateAfter);
200 final int stateDimension = matricesHarvester.getStateDimension();
201 final double[] deltaDerivatives = new double[stateDimension];
202 for (int i = 3; i < deltaDerivatives.length; i++) {
203 deltaDerivatives[i] = derivativesAfter[i] - derivativesBefore[i];
204 }
205 final Gradient g = evaluateG(buildCartesianState(state, state.getPVCoordinates()));
206 final double gLastDerivative = g.getPartialDerivative(stateDimension);
207 final double gDot = isForward ? gLastDerivative : -gLastDerivative;
208 final double[] gGradientState = Arrays.copyOfRange(g.getGradient(), 0, stateDimension);
209 final RealVector lhs = MatrixUtils.createRealVector(deltaDerivatives);
210 final RealVector rhs = MatrixUtils.createRealVector(gGradientState).mapMultiply(1. / gDot);
211 return lhs.outerProduct(rhs);
212 }
213
214
215
216
217
218
219
220 private SpacecraftState shift(final SpacecraftState stateAtSwitch, final double dt) {
221 final PVCoordinates pvCoordinates = stateAtSwitch.getPVCoordinates();
222 final AbsoluteDate shiftedDate = stateAtSwitch.getDate().shiftedBy(dt);
223 final TimeStampedPVCoordinates shiftedPV = new TimeStampedPVCoordinates(shiftedDate,
224 pvCoordinates.getPosition().add(pvCoordinates.getVelocity().scalarMultiply(dt)), pvCoordinates.getVelocity());
225 return buildCartesianState(stateAtSwitch, shiftedPV);
226 }
227
228
229
230
231
232
233
234 private SpacecraftState buildCartesianState(final SpacecraftState templateState,
235 final TimeStampedPVCoordinates pvCoordinates) {
236 final SpacecraftState state;
237 final Frame frame = templateState.getFrame();
238 if (templateState.isOrbitDefined()) {
239 final Orbit templateOrbit = templateState.getOrbit();
240 final CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, frame, templateOrbit.getMu());
241 final Attitude attitude = attitudeProvider.getAttitude(orbit, pvCoordinates.getDate(), frame);
242 state = new SpacecraftState(orbit, attitude);
243 } else {
244 final AbsolutePVCoordinates absolutePVCoordinates = new AbsolutePVCoordinates(frame, pvCoordinates);
245 final Attitude attitude = attitudeProvider.getAttitude(absolutePVCoordinates,
246 pvCoordinates.getDate(), frame);
247 state = new SpacecraftState(absolutePVCoordinates, attitude);
248 }
249 return state.withMass(templateState.getMass())
250 .withAdditionalData(templateState.getAdditionalDataValues())
251 .withAdditionalStatesDerivatives(templateState.getAdditionalStatesDerivatives());
252 }
253
254
255
256
257
258
259 private Gradient evaluateG(final SpacecraftState state) {
260 final int stateDimension = matricesHarvester.getStateDimension();
261 Gradient time = Gradient.variable(stateDimension + 1, stateDimension, 0);
262 if (!isForward) {
263 time = time.negate();
264 }
265 final GradientField field = time.getField();
266 final FieldSpacecraftState<Gradient> fieldState = DerivativeStateUtils.buildSpacecraftStateGradient(field,
267 state, attitudeProvider);
268 return switchFieldDetector.g(fieldState.shiftedBy(time));
269 }
270
271 }
272