Commit d64ebe44 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Moved around classes for maneuvers jacobians.

parent 92ce876f
...@@ -14,7 +14,10 @@ ...@@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.orekit.propagation; package org.orekit.forces.maneuvers.jacobians;
import org.orekit.propagation.AdditionalStateProvider;
import org.orekit.propagation.SpacecraftState;
/** Generator for one column of a Jacobian matrix for special case of maneuver duration. /** Generator for one column of a Jacobian matrix for special case of maneuver duration.
* <p> * <p>
...@@ -23,10 +26,10 @@ package org.orekit.propagation; ...@@ -23,10 +26,10 @@ package org.orekit.propagation;
* </p> * </p>
* @author Luc Maisonobe * @author Luc Maisonobe
* @since 11.1 * @since 11.1
* @see MedianDateJacobianColumnGenerator * @see MedianDate
* @see TriggerDateJacobianColumnGenerator * @see TriggerDate
*/ */
public class DurationJacobianColumnGenerator implements AdditionalStateProvider { public class Duration implements AdditionalStateProvider {
/** Name of the parameter corresponding to the start date. */ /** Name of the parameter corresponding to the start date. */
private final String startName; private final String startName;
...@@ -42,7 +45,7 @@ public class DurationJacobianColumnGenerator implements AdditionalStateProvider ...@@ -42,7 +45,7 @@ public class DurationJacobianColumnGenerator implements AdditionalStateProvider
* @param stopName name of the parameter corresponding to the stop date * @param stopName name of the parameter corresponding to the stop date
* @param columnName name of the parameter corresponding to the column * @param columnName name of the parameter corresponding to the column
*/ */
public DurationJacobianColumnGenerator(final String startName, final String stopName, final String columnName) { public Duration(final String startName, final String stopName, final String columnName) {
this.startName = startName; this.startName = startName;
this.stopName = stopName; this.stopName = stopName;
this.columnName = columnName; this.columnName = columnName;
......
...@@ -14,7 +14,10 @@ ...@@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.orekit.propagation; package org.orekit.forces.maneuvers.jacobians;
import org.orekit.propagation.AdditionalStateProvider;
import org.orekit.propagation.SpacecraftState;
/** Generator for one column of a Jacobian matrix for special case of maneuver median date. /** Generator for one column of a Jacobian matrix for special case of maneuver median date.
* <p> * <p>
...@@ -23,10 +26,10 @@ package org.orekit.propagation; ...@@ -23,10 +26,10 @@ package org.orekit.propagation;
* </p> * </p>
* @author Luc Maisonobe * @author Luc Maisonobe
* @since 11.1 * @since 11.1
* @see DurationJacobianColumnGenerator * @see Duration
* @see TriggerDateJacobianColumnGenerator * @see TriggerDate
*/ */
public class MedianDateJacobianColumnGenerator implements AdditionalStateProvider { public class MedianDate implements AdditionalStateProvider {
/** Name of the parameter corresponding to the start date. */ /** Name of the parameter corresponding to the start date. */
private final String startName; private final String startName;
...@@ -42,7 +45,7 @@ public class MedianDateJacobianColumnGenerator implements AdditionalStateProvide ...@@ -42,7 +45,7 @@ public class MedianDateJacobianColumnGenerator implements AdditionalStateProvide
* @param stopName name of the parameter corresponding to the stop date * @param stopName name of the parameter corresponding to the stop date
* @param columnName name of the parameter corresponding to the column * @param columnName name of the parameter corresponding to the column
*/ */
public MedianDateJacobianColumnGenerator(final String startName, final String stopName, final String columnName) { public MedianDate(final String startName, final String stopName, final String columnName) {
this.startName = startName; this.startName = startName;
this.stopName = stopName; this.stopName = stopName;
this.columnName = columnName; this.columnName = columnName;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.orekit.propagation; package org.orekit.forces.maneuvers.jacobians;
import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.linear.MatrixUtils; import org.hipparchus.linear.MatrixUtils;
...@@ -23,6 +23,8 @@ import org.hipparchus.linear.RealMatrix; ...@@ -23,6 +23,8 @@ import org.hipparchus.linear.RealMatrix;
import org.hipparchus.linear.RealVector; import org.hipparchus.linear.RealVector;
import org.orekit.forces.maneuvers.Maneuver; import org.orekit.forces.maneuvers.Maneuver;
import org.orekit.forces.maneuvers.trigger.ManeuverTriggersResetter; import org.orekit.forces.maneuvers.trigger.ManeuverTriggersResetter;
import org.orekit.propagation.AdditionalStateProvider;
import org.orekit.propagation.SpacecraftState;
import org.orekit.time.AbsoluteDate; import org.orekit.time.AbsoluteDate;
import org.orekit.utils.TimeSpanMap; import org.orekit.utils.TimeSpanMap;
...@@ -78,10 +80,10 @@ import org.orekit.utils.TimeSpanMap; ...@@ -78,10 +80,10 @@ import org.orekit.utils.TimeSpanMap;
* </p> * </p>
* @author Luc Maisonobe * @author Luc Maisonobe
* @since 11.1 * @since 11.1
* @see MedianDateJacobianColumnGenerator * @see MedianDate
* @see DurationJacobianColumnGenerator * @see Duration
*/ */
public class TriggerDateJacobianColumnGenerator public class TriggerDate
implements AdditionalStateProvider, ManeuverTriggersResetter { implements AdditionalStateProvider, ManeuverTriggersResetter {
/** Dimension of the state. */ /** Dimension of the state. */
...@@ -97,10 +99,13 @@ public class TriggerDateJacobianColumnGenerator ...@@ -97,10 +99,13 @@ public class TriggerDateJacobianColumnGenerator
private final String stmName; private final String stmName;
/** Name of the parameter corresponding to the column. */ /** Name of the parameter corresponding to the column. */
private final String columnName; private final String triggerName;
/** Mass depletion effect. */
private final MassDepletionDelay massDepletionDelay;
/** Start/stop management flag. */ /** Start/stop management flag. */
private boolean manageStart; private final boolean manageStart;
/** Maneuver force model. */ /** Maneuver force model. */
private final Maneuver maneuver; private final Maneuver maneuver;
...@@ -119,28 +124,28 @@ public class TriggerDateJacobianColumnGenerator ...@@ -119,28 +124,28 @@ public class TriggerDateJacobianColumnGenerator
/** Simple constructor. /** Simple constructor.
* @param stmName name of State Transition Matrix state * @param stmName name of State Transition Matrix state
* @param columnName name of the parameter corresponding to the column * @param triggerName name of the parameter corresponding to the trigger date column
* @param manageStart if true, we compute derivatives with respect to maneuver start * @param manageStart if true, we compute derivatives with respect to maneuver start
* @param maneuver maneuver force model * @param maneuver maneuver force model
* @param threshold event detector threshold * @param threshold event detector threshold
*/ */
public TriggerDateJacobianColumnGenerator(final String stmName, final String columnName, public TriggerDate(final String stmName, final String triggerName, final boolean manageStart,
final boolean manageStart, final Maneuver maneuver, final Maneuver maneuver, final double threshold) {
final double threshold) { this.stmName = stmName;
this.stmName = stmName; this.triggerName = triggerName;
this.columnName = columnName; this.massDepletionDelay = new MassDepletionDelay(triggerName, manageStart, maneuver);
this.manageStart = manageStart; this.manageStart = manageStart;
this.maneuver = maneuver; this.maneuver = maneuver;
this.threshold = threshold; this.threshold = threshold;
this.contribution = null; this.contribution = null;
this.trigger = null; this.trigger = null;
this.forward = true; this.forward = true;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public String getName() { public String getName() {
return columnName; return triggerName;
} }
/** {@inheritDoc} /** {@inheritDoc}
...@@ -150,7 +155,14 @@ public class TriggerDateJacobianColumnGenerator ...@@ -150,7 +155,14 @@ public class TriggerDateJacobianColumnGenerator
*/ */
@Override @Override
public boolean yield(final SpacecraftState state) { public boolean yield(final SpacecraftState state) {
return !state.hasAdditionalState(stmName); return !(state.hasAdditionalState(stmName) && state.hasAdditionalState(massDepletionDelay.getName()));
}
/** Get the mass depletion effect processor.
* @return mass depletion effect processor
*/
public MassDepletionDelay getMassDepletionDelay() {
return massDepletionDelay;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
...@@ -174,34 +186,29 @@ public class TriggerDateJacobianColumnGenerator ...@@ -174,34 +186,29 @@ public class TriggerDateJacobianColumnGenerator
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public double[] getAdditionalState(final SpacecraftState state) { public double[] getAdditionalState(final SpacecraftState state) {
// we check contribution rather than triggered because this method // we check contribution rather than triggered because this method
// is called after maneuverTriggered and before resetState, // is called after maneuverTriggered and before resetState,
// when preparing the old state to be reset // when preparing the old state to be reset
final double[] c = contribution == null ? null : contribution.get(state.getDate()); final double[] c = contribution == null ? null : contribution.get(state.getDate());
if (c == null) { if (c == null) {
// no thrust, no effect
return ZERO; return ZERO;
} else { } else {
// part of the effect due to the acceleration performed at trigger time // primary effect: full maneuver contribution at (delayed) trigger date
final double[] effect = getStm(state).operate(c); final double[] effect = getStm(state).operate(c);
if (trigger != null) { // secondary effect: maneuver change throughout thrust as mass depletion is delayed
// part of the effect due to mass change influence on current acceleration final double[] secondary = state.getAdditionalState(massDepletionDelay.getName());
final double[] parameters = maneuver.getParameters();
final Vector3D acceleration = maneuver.acceleration(state, parameters); // sum up both effects
final double flowRate = maneuver.getPropulsionModel().getMassDerivatives(state, parameters); for (int i = 0; i < effect.length; ++i) {
final double ratio = state.getDate().durationFrom(trigger) * flowRate / state.getMass(); effect[i] += secondary[i];
effect[3] += ratio * acceleration.getX();
effect[4] += ratio * acceleration.getY();
effect[5] += ratio * acceleration.getZ();
} }
return effect; return effect;
} }
} }
/** {@inheritDoc}*/ /** {@inheritDoc}*/
...@@ -224,7 +231,7 @@ public class TriggerDateJacobianColumnGenerator ...@@ -224,7 +231,7 @@ public class TriggerDateJacobianColumnGenerator
final Vector3D acceleration = maneuver.acceleration(stateWhenFiring, maneuver.getParameters()); final Vector3D acceleration = maneuver.acceleration(stateWhenFiring, maneuver.getParameters());
// initialize derivatives computation // initialize derivatives computation
final double sign = (forward ^ manageStart) ? +1 : -1; final double sign = (forward == manageStart) ? -1 : +1;
final RealVector rhs = MatrixUtils.createRealVector(STATE_DIMENSION); final RealVector rhs = MatrixUtils.createRealVector(STATE_DIMENSION);
rhs.setEntry(3, sign * acceleration.getX()); rhs.setEntry(3, sign * acceleration.getX());
rhs.setEntry(4, sign * acceleration.getY()); rhs.setEntry(4, sign * acceleration.getY());
......
...@@ -41,6 +41,9 @@ import org.orekit.forces.ForceModel; ...@@ -41,6 +41,9 @@ import org.orekit.forces.ForceModel;
import org.orekit.forces.gravity.NewtonianAttraction; import org.orekit.forces.gravity.NewtonianAttraction;
import org.orekit.forces.inertia.InertialForces; import org.orekit.forces.inertia.InertialForces;
import org.orekit.forces.maneuvers.Maneuver; import org.orekit.forces.maneuvers.Maneuver;
import org.orekit.forces.maneuvers.jacobians.Duration;
import org.orekit.forces.maneuvers.jacobians.MedianDate;
import org.orekit.forces.maneuvers.jacobians.TriggerDate;
import org.orekit.forces.maneuvers.trigger.AbstractManeuverTriggers; import org.orekit.forces.maneuvers.trigger.AbstractManeuverTriggers;
import org.orekit.forces.maneuvers.trigger.ManeuverTriggers; import org.orekit.forces.maneuvers.trigger.ManeuverTriggers;
import org.orekit.frames.Frame; import org.orekit.frames.Frame;
...@@ -49,13 +52,10 @@ import org.orekit.orbits.OrbitType; ...@@ -49,13 +52,10 @@ import org.orekit.orbits.OrbitType;
import org.orekit.orbits.PositionAngle; import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.AbstractMatricesHarvester; import org.orekit.propagation.AbstractMatricesHarvester;
import org.orekit.propagation.AdditionalStateProvider; import org.orekit.propagation.AdditionalStateProvider;
import org.orekit.propagation.DurationJacobianColumnGenerator;
import org.orekit.propagation.MatricesHarvester; import org.orekit.propagation.MatricesHarvester;
import org.orekit.propagation.MedianDateJacobianColumnGenerator;
import org.orekit.propagation.PropagationType; import org.orekit.propagation.PropagationType;
import org.orekit.propagation.Propagator; import org.orekit.propagation.Propagator;
import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.TriggerDateJacobianColumnGenerator;
import org.orekit.propagation.events.EventDetector; import org.orekit.propagation.events.EventDetector;
import org.orekit.propagation.events.ParameterDrivenDateIntervalDetector; import org.orekit.propagation.events.ParameterDrivenDateIntervalDetector;
import org.orekit.propagation.integration.AbstractIntegratedPropagator; import org.orekit.propagation.integration.AbstractIntegratedPropagator;
...@@ -503,22 +503,22 @@ public class NumericalPropagator extends AbstractIntegratedPropagator { ...@@ -503,22 +503,22 @@ public class NumericalPropagator extends AbstractIntegratedPropagator {
map (d -> (ParameterDrivenDateIntervalDetector) d). map (d -> (ParameterDrivenDateIntervalDetector) d).
forEach(d -> { forEach(d -> {
if (d.getStartDriver().isSelected() || d.getMedianDriver().isSelected() || d.getDurationDriver().isSelected()) { if (d.getStartDriver().isSelected() || d.getMedianDriver().isSelected() || d.getDurationDriver().isSelected()) {
final TriggerDateJacobianColumnGenerator start = final TriggerDate start =
manageTriggerDate(stmName, maneuver, amt, d.getStartDriver().getName(), true, d.getThreshold()); manageTriggerDate(stmName, maneuver, amt, d.getStartDriver().getName(), true, d.getThreshold());
names.add(start.getName()); names.add(start.getName());
} }
if (d.getStopDriver().isSelected() || d.getMedianDriver().isSelected() || d.getDurationDriver().isSelected()) { if (d.getStopDriver().isSelected() || d.getMedianDriver().isSelected() || d.getDurationDriver().isSelected()) {
final TriggerDateJacobianColumnGenerator stop = final TriggerDate stop =
manageTriggerDate(stmName, maneuver, amt, d.getStopDriver().getName(), false, d.getThreshold()); manageTriggerDate(stmName, maneuver, amt, d.getStopDriver().getName(), false, d.getThreshold());
names.add(stop.getName()); names.add(stop.getName());
} }
if (d.getMedianDriver().isSelected()) { if (d.getMedianDriver().isSelected()) {
final MedianDateJacobianColumnGenerator median = final MedianDate median =
manageMedianDate(d.getStartDriver().getName(), d.getStopDriver().getName(), d.getMedianDriver().getName()); manageMedianDate(d.getStartDriver().getName(), d.getStopDriver().getName(), d.getMedianDriver().getName());
names.add(median.getName()); names.add(median.getName());
} }
if (d.getDurationDriver().isSelected()) { if (d.getDurationDriver().isSelected()) {
final DurationJacobianColumnGenerator duration = final Duration duration =
manageManeuverDuration(d.getStartDriver().getName(), d.getStopDriver().getName(), d.getDurationDriver().getName()); manageManeuverDuration(d.getStartDriver().getName(), d.getStopDriver().getName(), d.getDurationDriver().getName());
names.add(duration.getName()); names.add(duration.getName());
} }
...@@ -542,36 +542,37 @@ public class NumericalPropagator extends AbstractIntegratedPropagator { ...@@ -542,36 +542,37 @@ public class NumericalPropagator extends AbstractIntegratedPropagator {
* @return generator for the date driver * @return generator for the date driver
* @since 11.1 * @since 11.1
*/ */
private TriggerDateJacobianColumnGenerator manageTriggerDate(final String stmName, private TriggerDate manageTriggerDate(final String stmName,
final Maneuver maneuver, final Maneuver maneuver,
final AbstractManeuverTriggers amt, final AbstractManeuverTriggers amt,
final String driverName, final String driverName,
final boolean start, final boolean start,
final double threshold) { final double threshold) {
TriggerDateJacobianColumnGenerator triggerGenerator = null; TriggerDate triggerGenerator = null;
// check if we already have set up the provider // check if we already have set up the provider
for (final AdditionalStateProvider provider : getAdditionalStateProviders()) { for (final AdditionalStateProvider provider : getAdditionalStateProviders()) {
if (provider instanceof TriggerDateJacobianColumnGenerator && if (provider instanceof TriggerDate &&
provider.getName().equals(driverName)) { provider.getName().equals(driverName)) {
// the Jacobian column generator has already been set up in a previous propagation // the Jacobian column generator has already been set up in a previous propagation
triggerGenerator = (TriggerDateJacobianColumnGenerator) provider; triggerGenerator = (TriggerDate) provider;
break; break;
} }
} }
if (triggerGenerator == null) { if (triggerGenerator == null) {
// this is the first time we need the Jacobian column generator, create it // this is the first time we need the Jacobian column generator, create it
triggerGenerator = new TriggerDateJacobianColumnGenerator(stmName, driverName, triggerGenerator = new TriggerDate(stmName, driverName, start, maneuver, threshold);
start, maneuver, threshold);
amt.addResetter(triggerGenerator); amt.addResetter(triggerGenerator);
addAdditionalDerivativesProvider(triggerGenerator.getMassDepletionDelay());
addAdditionalStateProvider(triggerGenerator); addAdditionalStateProvider(triggerGenerator);
} }
if (!getInitialIntegrationState().hasAdditionalState(driverName)) { if (!getInitialIntegrationState().hasAdditionalState(driverName)) {
// add the initial Jacobian column if it is not already there // add the initial Jacobian column if it is not already there
// (perhaps due to a previous propagation) // (perhaps due to a previous propagation)
setInitialColumn(triggerGenerator.getMassDepletionDelay().getName(), new double[6]);
setInitialColumn(driverName, getHarvester().getInitialJacobianColumn(driverName)); setInitialColumn(driverName, getHarvester().getInitialJacobianColumn(driverName));
} }
...@@ -586,23 +587,23 @@ public class NumericalPropagator extends AbstractIntegratedPropagator { ...@@ -586,23 +587,23 @@ public class NumericalPropagator extends AbstractIntegratedPropagator {
* @return generator for the median driver * @return generator for the median driver
* @since 11.1 * @since 11.1
*/ */
private MedianDateJacobianColumnGenerator manageMedianDate(final String startName, final String stopName, final String medianName) { private MedianDate manageMedianDate(final String startName, final String stopName, final String medianName) {
MedianDateJacobianColumnGenerator medianGenerator = null; MedianDate medianGenerator = null;
// check if we already have set up the provider // check if we already have set up the provider
for (final AdditionalStateProvider provider : getAdditionalStateProviders()) { for (final AdditionalStateProvider provider : getAdditionalStateProviders()) {
if (provider instanceof MedianDateJacobianColumnGenerator && if (provider instanceof MedianDate &&
provider.getName().equals(medianName)) { provider.getName().equals(medianName)) {
// the Jacobian column generator has already been set up in a previous propagation // the Jacobian column generator has already been set up in a previous propagation
medianGenerator = (MedianDateJacobianColumnGenerator) provider; medianGenerator = (MedianDate) provider;
break; break;
} }
} }
if (medianGenerator == null) { if (medianGenerator == null) {
// this is the first time we need the Jacobian column generator, create it // this is the first time we need the Jacobian column generator, create it
medianGenerator = new MedianDateJacobianColumnGenerator(startName, stopName, medianName); medianGenerator = new MedianDate(startName, stopName, medianName);
addAdditionalStateProvider(medianGenerator); addAdditionalStateProvider(medianGenerator);
} }
...@@ -623,23 +624,23 @@ public class NumericalPropagator extends AbstractIntegratedPropagator { ...@@ -623,23 +624,23 @@ public class NumericalPropagator extends AbstractIntegratedPropagator {
* @return generator for the median driver * @return generator for the median driver
* @since 11.1 * @since 11.1
*/ */
private DurationJacobianColumnGenerator manageManeuverDuration(final String startName, final String stopName, final String durationName) { private Duration manageManeuverDuration(final String startName, final String stopName, final String durationName) {
DurationJacobianColumnGenerator durationGenerator = null; Duration durationGenerator = null;
// check if we already have set up the provider // check if we already have set up the provider
for (final AdditionalStateProvider provider : getAdditionalStateProviders()) { for (final AdditionalStateProvider provider : getAdditionalStateProviders()) {
if (provider instanceof DurationJacobianColumnGenerator && if (provider instanceof Duration &&
provider.getName().equals(durationName)) { provider.getName().equals(durationName)) {
// the Jacobian column generator has already been set up in a previous propagation // the Jacobian column generator has already been set up in a previous propagation
durationGenerator = (DurationJacobianColumnGenerator) provider; durationGenerator = (Duration) provider;
break; break;
} }
} }
if (durationGenerator == null) { if (durationGenerator == null) {
// this is the first time we need the Jacobian column generator, create it // this is the first time we need the Jacobian column generator, create it
durationGenerator = new DurationJacobianColumnGenerator(startName, stopName, durationName); durationGenerator = new Duration(startName, stopName, durationName);
addAdditionalStateProvider(durationGenerator); addAdditionalStateProvider(durationGenerator);
} }
......
...@@ -30,8 +30,10 @@ import org.hipparchus.analysis.differentiation.DerivativeStructure; ...@@ -30,8 +30,10 @@ import org.hipparchus.analysis.differentiation.DerivativeStructure;
import org.hipparchus.exception.LocalizedCoreFormats; import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.geometry.euclidean.threed.FieldRotation; import org.hipparchus.geometry.euclidean.threed.FieldRotation;
import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.linear.MatrixUtils; import org.hipparchus.linear.MatrixUtils;
import org.hipparchus.linear.RealMatrix;
import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator; import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
import org.hipparchus.ode.nonstiff.DormandPrince54Integrator; import org.hipparchus.ode.nonstiff.DormandPrince54Integrator;
import org.hipparchus.ode.nonstiff.DormandPrince853Integrator; import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
...@@ -41,14 +43,21 @@ import org.junit.Before; ...@@ -41,14 +43,21 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.orekit.Utils; import org.orekit.Utils;
import org.orekit.attitudes.Attitude; import org.orekit.attitudes.Attitude;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.InertialProvider;
import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitException;
import org.orekit.forces.AbstractForceModel; import org.orekit.forces.AbstractForceModel;
import org.orekit.forces.ForceModel; import org.orekit.forces.ForceModel;
import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel; import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel; <