1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.control.indirect.adjoint.cost;
18
19 import org.hipparchus.geometry.euclidean.threed.Vector3D;
20 import org.hipparchus.util.FastMath;
21 import org.orekit.propagation.SpacecraftState;
22 import org.orekit.propagation.events.EventDetectionSettings;
23 import org.orekit.propagation.events.EventDetector;
24
25 import java.util.stream.Stream;
26
27
28
29
30
31
32
33
34 public class QuadraticPenaltyCartesianFuel extends PenalizedCartesianFuelCost {
35
36
37 private final EventDetectionSettings eventDetectionSettings;
38
39
40
41
42
43
44
45
46
47
48 public QuadraticPenaltyCartesianFuel(final String name, final double massFlowRateFactor,
49 final double maximumThrustMagnitude, final double epsilon,
50 final EventDetectionSettings eventDetectionSettings) {
51 super(name, massFlowRateFactor, maximumThrustMagnitude, epsilon);
52 this.eventDetectionSettings = eventDetectionSettings;
53 }
54
55
56
57
58
59
60
61
62
63 public QuadraticPenaltyCartesianFuel(final String name, final double massFlowRateFactor,
64 final double maximumThrustMagnitude, final double epsilon) {
65 this(name, massFlowRateFactor, maximumThrustMagnitude, epsilon,
66 EventDetectionSettings.getDefaultEventDetectionSettings());
67 }
68
69
70
71
72
73 public EventDetectionSettings getEventDetectionSettings() {
74 return eventDetectionSettings;
75 }
76
77
78 @Override
79 public double evaluatePenaltyFunction(final double controlNorm) {
80 return controlNorm * (controlNorm * getMaximumThrustMagnitude() / 2 - 1.);
81 }
82
83
84 @Override
85 public Vector3D getThrustAccelerationVector(final double[] adjointVariables, final double mass) {
86 final double switchFunction = evaluateSwitchFunction(adjointVariables, mass);
87 if (switchFunction > 0) {
88 final double thrustForceMagnitude = FastMath.min(switchFunction, getMaximumThrustMagnitude());
89 return getThrustDirection(adjointVariables).scalarMultiply(thrustForceMagnitude / mass);
90 } else {
91 return Vector3D.ZERO;
92 }
93 }
94
95
96 @Override
97 public void updateAdjointDerivatives(final double[] adjointVariables, final double mass,
98 final double[] adjointDerivatives) {
99 if (getAdjointDimension() > 6) {
100 final double switchFunction = evaluateSwitchFunction(adjointVariables, mass);
101 if (switchFunction > 0.) {
102 adjointDerivatives[6] += getAdjointVelocityNorm(adjointVariables) *
103 FastMath.min(switchFunction, getMaximumThrustMagnitude()) / (mass * mass);
104 }
105 }
106 }
107
108
109
110
111
112
113
114 private double evaluateSwitchFunction(final double[] adjointVariables, final double mass) {
115 double epsilonIndependentTerm = getAdjointVelocityNorm(adjointVariables) / mass - 1.;
116 if (getAdjointDimension() > 6) {
117 epsilonIndependentTerm -= getMassFlowRateFactor() * adjointVariables[6];
118 }
119 return epsilonIndependentTerm / getEpsilon() + 1.;
120 }
121
122
123 @Override
124 public Stream<EventDetector> getEventDetectors() {
125 return Stream.of(new QuadraticPenalizedSwitchDetector(getEventDetectionSettings(), 0),
126 new QuadraticPenalizedSwitchDetector(getEventDetectionSettings(), getMaximumThrustMagnitude()));
127 }
128
129
130
131
132 private class QuadraticPenalizedSwitchDetector extends ControlSwitchDetector {
133
134
135 private final double criticalValue;
136
137
138
139
140
141
142 QuadraticPenalizedSwitchDetector(final EventDetectionSettings detectionSettings,
143 final double criticalValue) {
144 super(detectionSettings);
145 this.criticalValue = criticalValue;
146 }
147
148
149 @Override
150 public double g(final SpacecraftState state) {
151 final double[] adjoint = state.getAdditionalState(getAdjointName());
152 return evaluateSwitchFunction(adjoint, state.getMass()) - criticalValue;
153 }
154 }
155 }