Click or drag to resize

Segments

SegmentDefinitions are the fundamental type in the Segment Propagation Library. This topic explains what segments are, how they work, and other basic related concepts, and also includes descriptions and examples for each type of segment provided by the library.

Note Note

The functionality described in this topic requires a license for the Segment Propagation Library.

Segments

Traditionally, propagation in STK usually involved setting up an object's initial conditions, and then propagating until some time limit is hit. Although such tools and libraries are very useful, they may be too simple to model a vehicles whole trajectory. There was no way to handle the case when the way the object is propagated changes short of keeping track of it yourself.

For example, consider what it would take to propagate a satellite through an impulsive maneuver. There is a lot of plumbing and busy work you would need to do. First, you would propagate starting from your initial conditions, then determine the time of maneuver, which is the time at which you stop your initial propagation. Then you would take that final state, apply the maneuver, then propagate forward from that new state. Finally, you would have to manually stitch together the ephemeris, being careful about the discontinuity at the time of the maneuver.

Automating that kind of trajectory design is exactly what the Segment Propagation Library is for. You would first define a NumericalPropagatorSegment with a NumericalPropagatorDefinition and a StoppingCondition, then an ImpulsiveManeuverSegment with your delta-v and other maneuver information, and finally a second NumericalPropagatorSegment stopping at your desired event. Finally, you put them all into a SegmentList, propagate, and get your ephemeris out.

Note Note

Although the examples given in the documentation are for spacecraft, most of the segments can be used for any kind of propagation. See the Aircraft Propagation topic for information on propagating aircraft using the same concepts.

Types of Segments

The segment types included range from general base types to controlling the flow of segments to ones specific for satellite propagation forward or backward in time. If some part of your trajectory cannot be represented as one of these segments then you can extend the library to add to the capability yourself, or contact AGI to request the additional capability.

Each of these segment types are described in more detail in the Individual Segments section below.

The Segment Life Cycle

Segments follow the Create-Set-Call pattern like most of the rest of Components. After determining how to split your desired trajectory into segments, instantiate and configure each segment. Generally you will construct an overall SegmentList by adding each segment to the Segments (get) list. Then, call getSegmentListPropagator on the overall SegmentList, which returns a SegmentPropagator. When you call propagate, all individual segments added to the list will be propagated in order. With a few exceptions, the final state of each segment will be used as the initial state of the next segment (except for the NumericalInitialStateSegment which defines its own initial state. FollowSegment can also be configured to ignore the previous segment's final state). Once propagation is finished, a SegmentResults is returned. When propagating a SegmentList, a SegmentListResults will be returned. The ephemeris for each segment can be accessed by calling getDateMotionCollectionOfOverallTrajectory, and other information can be interrogated as well. In addition, the SegmentResults created by some segments (SegmentList, TargetedSegmentList, and NumericalPropagatorSegment) can be cast to a more specific type deriving from SegmentResults, as shown in later examples.

In order to change the configuration of your segments during propagation, such as to solve for a constrained trajectory or to enable or disable some elements, use a TargetedSegmentList instead of a SegmentList. TargetedSegmentLists, in addition to a list of segments, have a list of TargetedSegmentListOperators that will alter the configuration of the segments in a defined way.

One of the most common TargetedSegmentListOperators is the TargetedSegmentListDifferentialCorrector. This operator works by treating the computed trajectory as a multivariable function. Each segment that can be varied by the function solver has methods to aid in the creation of a SegmentPropagatorVariable to feed to the targeted segment list's differential corrector. Or, you can use a ParameterizedScalarVariable to control wrapped geometry types in the nested segments. Once the corrector is added to the TargetedSegmentList and everything is configured, propagation can commence just like the normal SegmentList. Function solvers will compute the trajectory, vary the variables, and re-compute, iterating over and over again towards a goal.

Segment Adapters

Most segments require that you specify the identifications of the elements getting propagated and what ReferenceFrame, Axes, or object that the propagated values will be defined in, and a StateElementAdapterDefinition. When the SegmentPropagators are configured, the segment will take the previous segment's defined-in object (ReferenceFrame, Axes...) for each of that segment's elements. Having retrieved those values, the current segment will create an adapter that will perform the transformation of the final value of the previous segment at propagation time. These adapters are preserved in the SegmentResults as well.

All in all, this means that your segments do not all need to propagate in the same frame. If you are modeling a trajectory from the Earth to the Moon, you can break it up into two segments; the first in the Earth's inertial frame, and the second in the Moon's inertial frame. When you get the results for these two segments, the ephemeris for each individual segment will be in whatever frame you defined it in, but when you call getDateMotionCollectionOfOverallTrajectory, you can specify the defined-in object to get the entire ephemeris in the desired frame or axes.

Note that many segments will handle the adapter configuration automatically. NumericalPropagatorSegment, for example, knows how to create adapters for all built in PropagationStateElements and AuxiliaryStateElements. SegmentList leverages its nested segments to create the adapters. Also, some segments that are used for control flow (such as ReturnSegment and StopSegment) are designed to use the previous segment's defined-in objects, since they themselves do not modify or propagate a state.

Individual Segments

InitialStateSegment

InitialStateSegment<T> is a segment that will have in its results a single state initialized from the InitialState (get / set) property. You will need to configure the adapters on this segment by calling setElementAndAdapter. It should only be used as the first segment to get propagated that isn't a SegmentList. Otherwise there will be a discontinuity, as the final state of the previous segment will be ignored by this segment.

Any InitialStateSegment<T> should be the first segment to get propagated (that is not a SegmentList or TargetedSegmentList). However, this segment is not required as long as one of the following is true:

This segment is the only segment that allows for the values in the initial state to be modified by a TargetedSegmentListOperator. See the Multivariable Function Solvers topic for more information.

The following code sample demonstrates how to configure a simple InitialStateSegment<T>:

Java
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();

SegmentList overallList = new SegmentList();

// create our initial state segment
InitialStateSegment<BasicState> initialStateSegment = new InitialStateSegment<BasicState>();

// define the state
BasicState initialState = new BasicState();
initialState.addStateElementMotion(SatelliteMotionIdentification,
                                   new Motion1<Cartesian>(new Cartesian(8000000.0, 0.0, 0.0), 
                                                          new Cartesian(0.0, 5500.0, 5500.0)));
initialState.setCurrentDate(TimeConstants.J2000);

initialStateSegment.setInitialState(initialState);

// set the adapter and ReferenceFrame for this segment
initialStateSegment.setElementAndAdapter(new ReferenceFrameAdapter(SatelliteMotionIdentification, earth.getInertialFrame()));

// create some propagate segment
PropagateSegment propagateSegment = createAndConfigurePropagateSegment();

// compose the segments together
overallList.getSegments().add(initialStateSegment);
overallList.getSegments().add(propagateSegment);

// propagate
SegmentListPropagator propagator = overallList.getSegmentListPropagator(new EvaluatorGroup(), null);

SegmentListResults results = propagator.propagateSegmentList();
BasicState firstPropagatedState = (BasicState) results.getEntireComputedEphemeris().get(0);
// firstPropagateState will be the same as initialState

BasicLaunchSegment

BasicLaunchSegment is a segment that produces ephemeris in the configured CentralBody (get / set)'s fixed frame. The underlying physical model of this segment uses an ellipse approximating the trajectory in the central body's fixed frame from the launch position to the burnout position. This trajectory is then sampled for output via simple interpolation. The segment begins at the configured launch position and epoch. The launch position may be augmented with an optional initial acceleration. The segment ends at a configured burnout epoch (launch epoch plus time of flight) with the burnout position specified in the same frame as the launch position. The burnout velocity may be specified in either the fixed frame with a specified velocity magnitude, or in the inertial frame with a specified velocity magnitude, flight path angle, and azimuthal angle. In the fixed frame mode the flight path angle is zero and the inclination of the final state is determined by the arc between the launch and burnout states.

The complete set of options one may set on BasicLaunchSegment may be found on the class's documentation page.

Some important remarks regarding this segment:

  • The state element adapter must be set.

  • The positions for both launch and burnout by default assume the CentralBody (get / set) fixed frame. Both positions must be set in the same frame.

  • It is important to note that the burnout velocity can be specified in either fixed or inertial frames, irrespective of the frame used for the positions.

  • If the input states have information for orders greater than 0, this information is ignored.

  • This segment may produce warnings indicating potential issues when attempting to create an ellipse for interpolation. See the documentation for BasicLaunchSegmentResults for the types of warnings and their meanings.

The following code sample demonstrates how to configure a BasicLaunchSegment:

Java
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();

// Launch and burnout points. Higher order terms in the motion are ignored, and may be optionally computed by the propagator.
Cartesian launchLocation = earth.getShape().cartographicToCartesian(new Cartographic(Trig.degreesToRadians(1.5), Trig.degreesToRadians(7.0), 0));
Motion1<Cartesian> launchMotion = new Motion1<Cartesian>(launchLocation);
Cartesian burnoutLocation = earth.getShape().cartographicToCartesian(new Cartographic(Trig.degreesToRadians(89), Trig.degreesToRadians(47.0), 3000000));
Motion1<Cartesian> burnoutMotion = new Motion1<Cartesian>(burnoutLocation);
// Motion ID
String motionElementID = "LaunchMotion";

// Segment definition.
BasicLaunchSegment basicLaunchSegment = new BasicLaunchSegment(new Duration(0, 60.0)); // 60 second step size.
basicLaunchSegment.setElementAndAdapter(new ReferenceFrameAdapter(motionElementID, earth.getFixedFrame()));  // The input positions are in the Earth fixed frame.
basicLaunchSegment.setCentralBody(earth);

// Launch state.
BasicState launchState = new BasicState();
launchState.addStateElementMotion(motionElementID, launchMotion);
launchState.setCurrentDate(new JulianDate(new GregorianDate(2017, 10, 3, 0, 0)));
basicLaunchSegment.setLaunchState(launchState);
basicLaunchSegment.setMotionID(motionElementID);

// Burnout state.
BasicState burnoutState = new BasicState();
burnoutState.addStateElementMotion(motionElementID, burnoutMotion);
burnoutState.setCurrentDate(launchState.getCurrentDate().add(new Duration(0, 600.0))); // 600 seconds is the time of flight.
basicLaunchSegment.setBurnoutState(burnoutState);
basicLaunchSegment.setBurnoutVelocityFrame(SimpleAscentPropagatorBurnoutVelocityFrame.FIXED_FRAME);
basicLaunchSegment.setBurnoutVelocityMagnitude(ValueDefinition.toValueDefinition(7299.76)); // In SI units in the Earth's fixed frame.

SegmentPropagator launchPropagator = basicLaunchSegment.getSegmentPropagator();
SegmentResults results = launchPropagator.propagate();

// Cast the results to check the warnings property.
BasicLaunchSegmentResults resultsWithWarningsProperty = (results instanceof BasicLaunchSegmentResults) ? (BasicLaunchSegmentResults) results : null;

NumericalInitialStateSegment

NumericalInitialStateSegment is an InitialStateSegment<T>: that will initialize its InitialState (get / set) property from a NumericalPropagatorDefinition. Its adapters will be configured automatically for this segment.

The following code sample demonstrates how to configure a simple NumericalInitialStateSegment:

Java
SegmentList overallList = new SegmentList();

// create the segment
NumericalInitialStateSegment initialStateSegment = new NumericalInitialStateSegment();
initialStateSegment.setName("Initial_State_Segment");

// for the NumericalInitialStateSegment, the initial state will be configured 
// with the initial values stored in a NumericalPropagatorDefinition
PropagationNewtonianPoint propagationPoint = createPropagatedNewtonianPoint(SatelliteMotionIdentification);
NumericalPropagatorDefinition numericalPropagator = createNumericalPropagator(propagationPoint);
initialStateSegment.setPropagatorDefinition(numericalPropagator);
// adapters are configured automatically

// use the same NumericalPropagatorDefinition when configuring the propagate segment
NumericalPropagatorSegment propagationSegment = configureNumericalPropagatorSegment(numericalPropagator, propagationPoint);

overallList.getSegments().add(initialStateSegment);
overallList.getSegments().add(propagationSegment);

// get the propagator and propagate
EvaluatorGroup group = new EvaluatorGroup();
SegmentPropagator segmentPropagator = overallList.getSegmentPropagator(group);

SegmentResults propagationResults = segmentPropagator.propagate();

PropagateSegment

This segment will take a StoppablePropagator, and propagate it forward or backward in time, stopping when one of its StoppingConditions (get) is satisfied. The SegmentResults returned will be an instance of PropagateSegmentResults, and will include information regarding how propagation was stopped. You will need to configure the adapters on this segment by calling setElementAndAdapter, however, some derived types will configure the elements and adapters automatically.

Normally this segment will propagate from the previous segment's final state. However, when there is no such segment before this one providing a final state, it will start from the initial state returned from getInitialState. However, if that initial state is null, and no initial state passed into the propagate method, an exception will be thrown.

The thresholds of the StoppingConditions can be modified by a TargetedSegmentListOperator.

The following code sample demonstrates how to create a PropagateSegment with a StoppingCondition:

Java
// general settings
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
Motion1<Cartesian> initialConditions = new Motion1<Cartesian>(new Cartesian(8000000.0, 0.0, 0.0), 
                                                              new Cartesian(1500.0, 8500.0, 0.0));
JulianDate initialDate = TimeConstants.J2000;

// configure the wrapped stoppable propagator
TwoBodyStoppablePropagator twoBodyPropagator = new TwoBodyStoppablePropagator();
twoBodyPropagator.setGravitationalParameter(WorldGeodeticSystem1984.GravitationalParameter);
twoBodyPropagator.setPropagationFrame(earth.getInertialFrame());
twoBodyPropagator.setStep(Duration.fromMinutes(5.0));
twoBodyPropagator.setPropagationPointIdentification(SatelliteMotionIdentification);
twoBodyPropagator.setInitialDate(initialDate);
twoBodyPropagator.setInitialMotion(initialConditions);

// make the segment
PropagateSegment propSegment = new PropagateSegment(twoBodyPropagator);

// add a stopping condition
propSegment.getStoppingConditions().add(new DurationStoppingCondition(new Duration(0, 120.0)));

// configure the element and adapter on the propagator
propSegment.setElementAndAdapter(new ReferenceFrameAdapter(SatelliteMotionIdentification, 
                                                           earth.getInertialFrame()));

// get our propagator and propagate
SegmentPropagator propagator = propSegment.getSegmentPropagator();
PropagateSegmentResults results = (PropagateSegmentResults) propagator.propagate();

NumericalPropagatorSegment

This segment will take a NumericalPropagatorDefinition, and propagate it forward or backward in time, stopping when one of its StoppingConditions (get) is satisfied. The adapters on this segment will be configured automatically.

Normally this segment will propagate from the previous segment's final state. However, when there is no such segment before this one providing a final state, it will start from the initial condition of its configured PropagatorDefinition (get / set).

The following code sample demonstrates how to create a NumericalPropagatorSegment with two StoppingConditions:

Java
// create the segment
NumericalPropagatorSegment propagatorSegment = new NumericalPropagatorSegment();
propagatorSegment.setName("Propagator_Segment");

// create and add the NumericalPropagatorDefinition
PropagationNewtonianPoint propagationPoint = createPropagatedNewtonianPoint(SatelliteMotionIdentification);
NumericalPropagatorDefinition numericalPropagator = createNumericalPropagator(propagationPoint);
propagatorSegment.setPropagatorDefinition(numericalPropagator);

// create and add a stopping condition
DurationStoppingCondition durationStop = new DurationStoppingCondition(Duration.fromDays(10D));
durationStop.setName("Duration_of_10days_Stopping_Condition");
propagatorSegment.getStoppingConditions().add(durationStop);

// create and add a second stopping condition
ScalarStoppingCondition altitudeStoppingCondition = 
        new ScalarStoppingCondition(new ScalarCartographicElement(earth,
                                                                  propagationPoint.getIntegrationPoint(), 
                                                                  CartographicElement.HEIGHT),
                                    500000.0, // 500 km desired value
                                    0.01, // 1 cm tolerance 
                                    StopType.ANY_THRESHOLD);
altitudeStoppingCondition.setName("Altitude_Of_500km_Stopping_Condition");
propagatorSegment.getStoppingConditions().add(altitudeStoppingCondition);

// get the propagator and propagate
SegmentPropagator numericalSegmentPropagator = propagatorSegment.getSegmentPropagator();
PropagateSegmentResults propagationResults = (PropagateSegmentResults) numericalSegmentPropagator.propagate();

HoldSegment

This segment will create a ConstantStateStoppablePropagator, and propagate it forward or backward in time, stopping when one of its StoppingConditions (get) is satisfied. You can configure the adapters on this segment by calling setElementAndAdapter, to change the ReferenceFrame, Axes, or defined-in object of an element from what it was in the previous segment. However, if the state elements from the previous segment are already in the desired frame or axes, no adapter is needed.

This segment does not provide an initial state. It will throw an exception if no state is passed to the propagate method.

The following code sample demonstrates how to create a HoldSegment:

Java
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
PropagateSegment firstSegment = createAndConfigurePropagateSegment();

// initially propagating in the inertial frame
firstSegment.setElementAndAdapter(new ReferenceFrameAdapter(SatelliteMotionIdentification, earth.getInertialFrame()));

// stop when our range to our target is 0
ScalarStoppingCondition rangeOfZeroStoppingCondition = createRangeOfZeroStoppingCondition();
firstSegment.getStoppingConditions().add(rangeOfZeroStoppingCondition);

// hold our fixed position for 2 days
HoldSegment holdSegment = new HoldSegment();
holdSegment.setStep(Duration.fromMinutes(3.0));
holdSegment.getStoppingConditions().add(new DurationStoppingCondition(Duration.fromDays(2.0)));
holdSegment.setElementAndAdapter(new ReferenceFrameAdapter(SatelliteMotionIdentification, earth.getFixedFrame()));

// configure the list and propagate
SegmentList list = new SegmentList();
list.getSegments().add(firstSegment);
list.getSegments().add(holdSegment);

SegmentListPropagator propagator = list.getSegmentListPropagator();

FollowSegment

With this segment, the initial and final state of propagation can be configured beyond the default behavior of the segments. This segment will take a StoppablePropagator, and then evaluate the segment's StartOfFollowSegment (get / set) and EndOfFollowSegment (get / set), returning the propagated results in between. You will need to configure the adapters on this segment by calling setElementAndAdapter. This segment can be useful if you have an ephemeris extended into the future and you want to perform a maneuver, but you don't know when.

Since the initial state of the segment may not use the final state of the previous segment, there can be a discontinuity in the results if this is not the first ephemeris producing segment.

The following code sample demonstrates how to create a FollowSegment:

Java
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
String covarianceIdentification = "Covariance";

StkEphemerisFile ephemerisFile = getEphemerisFile(); // get our ephemeris file

// configure our state with the ephemeris file data
GeometryDynamicState dynamicState = new GeometryDynamicState();
Point ephemerisLocationPoint = ephemerisFile.createPoint();
Covariance3By3DynamicMatrix covariance = new Covariance3By3DynamicMatrix(ephemerisFile.createCovarianceInterpolator());

dynamicState.setElement(SatelliteMotionIdentification, ephemerisLocationPoint);
dynamicState.setElement(covarianceIdentification, covariance);

// create the wrapped stoppable propagator
DynamicStateStoppablePropagator stoppablePropagator = new DynamicStateStoppablePropagator();
stoppablePropagator.setDynamicState(dynamicState);

// create our segment
FollowSegment follow = new FollowSegment(stoppablePropagator);
// set our adapters
follow.setElementAndAdapter(new ReferenceFrameAdapter(SatelliteMotionIdentification, earth.getInertialFrame()));
follow.setElementAndAdapter(new SimpleAdapter<Matrix>(covarianceIdentification));

// create our stopping condition
DurationStoppingCondition stoppingCondition = new DurationStoppingCondition();
// we are going to run in a differential corrector where we control our stopping condition threshold
ParameterizedDurationVariable durationTripVariable = 
        new ParameterizedDurationVariable(Duration.fromMinutes(30), 60.0, 1.0, follow);
stoppingCondition.setThreshold(durationTripVariable.getValue());
follow.getStoppingConditions().add(stoppingCondition);

// we know that we need to spend at least an hour in the parking orbit
follow.setStartOfFollowSegment(
        new FollowSegmentStartsWithStoppingConditions(new DurationStoppingCondition(Duration.fromHours(1.0))));

// let the configured conditions end the propagation
follow.setEndOfFollowSegment(new FollowSegmentEndsAsWithDefaultConditions());

// and after we stop the previous segment, perform a maneuver
ImpulsiveManeuverSegment impulsiveManeuver = new ImpulsiveManeuverSegment();
ImpulsiveManeuverInformation leaveParkingOrbit = 
        new ImpulsiveManeuverInformation(SatelliteMotionIdentification, 
                                         new Cartesian(1000.0, 0.0, 0.0), 
                                         earth.getInertialFrame().getAxes());
impulsiveManeuver.getManeuvers().add(leaveParkingOrbit);

// configure our overall list
TargetedSegmentList segmentList = new TargetedSegmentList();
segmentList.getSegments().add(follow);
segmentList.getSegments().add(impulsiveManeuver);
// add more segments

// configure our differential corrector
TargetedSegmentListDifferentialCorrector differentialCorrector = new TargetedSegmentListDifferentialCorrector();

// the constraint
ScalarAtEndOfSegmentConstraint trueAnomalyConstraint = new ScalarAtEndOfSegmentConstraint();

// we need to use the parameter in the constraint to create our point
ParameterizedOnStatePoint constraintPoint = 
        new ParameterizedOnStatePoint(trueAnomalyConstraint.getParameter(), 
                                      earth.getInertialFrame(), 
                                      SatelliteMotionIdentification);

// with the point, we can create our true anomaly
Scalar trueAnomalyScalarForConstraint = 
        new ScalarModifiedKeplerianElement(WorldGeodeticSystem1984.GravitationalParameter, 
                                           constraintPoint, 
                                           KeplerianElement.TRUE_ANOMALY, 
                                           earth.getInertialFrame());
trueAnomalyConstraint.setScalar(trueAnomalyScalarForConstraint);
trueAnomalyConstraint.setDesiredValue(ValueDefinition.toValueDefinition(Trig.degreesToRadians(180.0)));
trueAnomalyConstraint.setSegment(follow);
trueAnomalyConstraint.setTolerance(0.0001);

// finish configuring our differential corrector
differentialCorrector.getConstraints().add(trueAnomalyConstraint);
differentialCorrector.getVariables().add(durationTripVariable);

// add the corrector to our targeted segment list
segmentList.getOperators().add(differentialCorrector);

// propagate
SegmentListPropagator propagator = segmentList.getSegmentListPropagator();
SegmentListResults results = propagator.propagateSegmentList();

ImpulsiveManeuverSegment

ImpulsiveManeuverSegment applies a change to the velocity of one or more Cartesian propagation elements in the state. This will result in a discontinuity in the velocity. Two ephemeris points are returned in its SegmentResults, one before the maneuver and one after the maneuver. The adapters on this segment will be configured automatically.

One concern about satellites performing maneuvers is that they may run out of fuel. By changing the InvalidFuelUseBehavior (get / set) property on the particular maneuver information, you can control what will happen if the vehicle would run out of fuel during the maneuver. You can set it to throw an exception, to stop propagating, to perform only the amount of the maneuver possible, or to do the entire requested maneuver regardless of the fuel state. Regardless of which option is selected, the RanOutOfFuel (get) property in the returned results will be set to true.

ImpulsiveManeuverInformation takes in the rocket's exhaust velocity in order to perform the fuel usage calculation. If instead you have the specific impulse of your rocket engine, you can generally calculate the exhaust velocity by multiplying the specific impulse by EarthSurfaceGravity

Every property except for the Orientation (get / set) can be directly modified by a TargetedSegmentListOperator. Note that the Orientation (get / set) can depend on the position and velocity of the spacecraft, but to do so you have to use the PropagationPoint (get) included in the ImpulsiveManeuverInformation.

The following code sample demonstrates how to configure an ImpulsiveManeuverSegment by adding an ImpulsiveManeuverInformation:

Java
// create the segment
ImpulsiveManeuverSegment impulsiveManeuverSegment = new ImpulsiveManeuverSegment();
impulsiveManeuverSegment.setName("Impulsive_Maneuver");

// create the maneuver information for the particular point element getting propagated
ImpulsiveManeuverInformation maneuverInformation = 
        new ImpulsiveManeuverInformation(SatelliteMotionIdentification, 
                                         new Cartesian(103.2, 0.002, 1.02), // delta-v, meters/second
                                         null);
maneuverInformation.setOrientation(new AxesVelocityOrbitNormal(maneuverInformation.getPropagationPoint(), earth));
impulsiveManeuverSegment.getManeuvers().add(maneuverInformation);

// add the impulsive maneuver segment to a segment list (since the ImpulsiveManeuverSegment 
// can't be the first or only segment propagated)
someSegmentList.getSegments().add(impulsiveManeuverSegment);

// get the propagator and propagate
SegmentListPropagator propagator = someSegmentList.getSegmentListPropagator();
SegmentListResults overallResults = propagator.propagateSegmentList();

// get the specific results
SegmentResults temporaryResults = overallResults.getResultsOfSegment(impulsiveManeuverSegment);
ImpulsiveManeuverSegmentResults impulsiveManeuverResults = (ImpulsiveManeuverSegmentResults) temporaryResults;

SegmentList

SegmentList is a container of multiple segments. It is a segment itself, so one SegmentList can contain another SegmentList. When propagated, it returns a SegmentResults that you may cast to a SegmentListResults in order to get additional information, such as the time interval of each segment and results of each individual segment. The adapters do not need to be set; they will be initialized from the nested segments. Remember that the order of the segments in Segments (get) is important.

The following code sample demonstrates how to populate the Segments (get) list and propagate the overall SegmentList:

Java
// make up a bunch of segments
NumericalInitialStateSegment initialSegment = configureNumericalInitialStateSegment();
NumericalPropagatorSegment propagateSegment = configureNumericalPropagatorSegment();
ImpulsiveManeuverSegment maneuverSegment = configureImpulsiveManeuver();
NumericalPropagatorSegment finalPropagateSegment = configureNumericalPropagatorSegment();
SegmentList someOtherSegmentList = new SegmentList();
someOtherSegmentList.setName("Some_Other_Segment_List");

// create the SegmentList you will propagate
SegmentList masterSegmentList = new SegmentList();
masterSegmentList.setName("MasterSegmentList");

// add the segments in order
masterSegmentList.getSegments().add(initialSegment);
masterSegmentList.getSegments().add(propagateSegment);
someOtherSegmentList.getSegments().add(maneuverSegment);

// nest the maneuver in an inner SegmentList
masterSegmentList.getSegments().add(someOtherSegmentList);

// go ahead and put one SegmentList in another
masterSegmentList.getSegments().add(finalPropagateSegment);

// get the propagator and propagate
SegmentListPropagator segmentListProapgator = masterSegmentList.getSegmentListPropagator();
SegmentListResults segmentListResults = segmentListProapgator.propagateSegmentList();

// SegmentListResults will recursively search for a specific segments results
SegmentResults maneuverResults = segmentListResults.getResultsOfSegment(maneuverSegment);

TargetedSegmentList

TargetedSegmentList is a SegmentList that also has one or more TargetedSegmentListOperators. The segments included in the TargetedSegmentList will have some part of its segments modified by the operators. These modifications can change values of settings in the segments to solve for a particular trajectory, or turn some option on or off. See the Targeted Segment List Operators topic for more information.

Configuring a TargetedSegmentList is the same as configuring a normal SegmentList, but also requires that you configure at least one TargetedSegmentListOperator. See the Targeted Segment List Operators topic for examples to how to configure and use TargetedSegmentListOperators and TargetedSegmentList.

UpdateSegment

UpdateSegment allows you to directly edit the state from the previous segment. The adapters do not need to be set. Often editing the state is done with a callback that will modify a value in the state. For example, if you wanted to decrease the fuel mass, the following code sample demonstrates how to do so:

Java
UpdateSegment updateSegment = new UpdateSegment();

// we will vary the fuel mass to target a final overall mass
ParameterizedScalarVariable variable = new ParameterizedScalarVariable(100.0, 1.0, 0.1, updateSegment);

// configure the updater
SingleValueStateUpdater fuelMassUpdater = 
        new SingleValueStateUpdater(
                variable.getValue(), 
                SingleValueUpdaterCallback.of((state, updateValue) -> {
                    // update the state by subtracting the value of the update value from the fuel mass
                    state.modifyValue(fuelMassID, state.<Double> getValue(fuelMassID) - updateValue);
                    return state;
                }));

// you can have as many updaters as you would like
updateSegment.getUpdates().add(fuelMassUpdater);

// configure our overall segment list
TargetedSegmentList targetedSegmentList = new TargetedSegmentList();
targetedSegmentList.getSegments().add(initialStateSegment); // made earlier
targetedSegmentList.getSegments().add(updateSegment);
TargetedSegmentListDifferentialCorrector differentialCorrector = new TargetedSegmentListDifferentialCorrector();

// we want our overall mass to be 850 kg
DelegateBasedConstraint overallMassConstraint = 
        new DelegateBasedConstraint(
                DelegateBasedConstraintCallback.of(s -> 
                        s.getStateForNextSegment().<Double> getValue(fuelMassID) +
                        s.getStateForNextSegment().<Double> getValue(dryMassID)), 
                updateSegment, 
                850.0, 
                0.1);

// finish configuring our differential corrector
differentialCorrector.getConstraints().add(overallMassConstraint);
differentialCorrector.getVariables().add(variable);

// add the operator
targetedSegmentList.getOperators().add(differentialCorrector);

// propagate
SegmentListPropagator propagator = targetedSegmentList.getSegmentListPropagator();
SegmentListResults results = propagator.propagateSegmentList();
SegmentResults updateSegmentResults = results.getSegmentResults().get(1);
double finalMass = updateSegmentResults.getStateForNextSegment().<Double> getValue(fuelMassID) + 
                   updateSegmentResults.getStateForNextSegment().<Double> getValue(dryMassID);
// will be 850

ReturnSegment

ReturnSegment is a segment that will end propagation of a specified SegmentList if enabled. This segment can also distinguish between running as part of normal propagation, or if it is being run as part of a TargetedSegmentListOperator and be enabled or disabled depending on which content it is being propagated.

The related ChangeReturnSegmentOperator type is a TargetedSegmentListOperator that can change the Behavior (get / set) property of a ReturnSegment.

Generally, a ReturnSegment can end any SegmentList that it is in, however, there is one notable exception. If a ReturnSegment is in a TargetedSegmentList, it can not return out to a SegmentList that is outside of the TargetedSegmentList while the TargetedSegmentList is running a ChangeReturnSegmentOperator.

The following code sample demonstrates using a ReturnSegment:

Java
// define constants
String satelliteName = "Satellite";
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();

// make the segment list (create the differential corrector too)
TargetedSegmentList segmentList = createTargetedSegmentList();

// initial state
NumericalInitialStateSegment initialStateSegment = configureNumericalInitialStateSegment();
ImpulsiveManeuverSegment firstManeuver = createFirstManeuver();

// make the propagation segment
// we will need the integration point to make the altitude stopping condition
PropagationNewtonianPoint propagationPoint = createPropagatedNewtonianPoint(satelliteName);
NumericalPropagatorSegment propagationSegment = new NumericalPropagatorSegment();
propagationSegment.setPropagatorDefinition(createNumericalPropagator(propagationPoint));

// make a stopping condition
ScalarStoppingCondition altitudeStoppingCondition = new ScalarStoppingCondition(
        new ScalarCartographicElement(
                earth,
                propagationPoint.getIntegrationPoint(),
                CartographicElement.HEIGHT),
        420000000.0, // 42,000 kilometers
        1.0,         // stop within a meter
        StopType.ANY_THRESHOLD);
propagationSegment.getStoppingConditions().add(altitudeStoppingCondition);

// if the satellite goes above 42 000 km, then we don't want to do the second maneuver
ReturnSegment stopIfAltitudeIsTooLow = new ReturnSegment(segmentList, ReturnSegmentBehavior.ENABLED);
propagationSegment.setStoppingConditionAutoSegment(altitudeStoppingCondition, stopIfAltitudeIsTooLow, 1);

// or our orbit might still be too low in which case we want to do another maneuver
StoppingCondition anotherStoppingCondition = createSomeOtherStoppingCondition();
propagationSegment.getStoppingConditions().add(anotherStoppingCondition);
ImpulsiveManeuverSegment impulsiveManeuver = createSecondManeuver();

// configure the segment list
segmentList.getSegments().add(initialStateSegment);
segmentList.getSegments().add(firstManeuver);
segmentList.getSegments().add(propagationSegment);
segmentList.getSegments().add(impulsiveManeuver);

StopSegment

StopSegment is a segment that will stop all propagation, if enabled. This can be very useful to use with an auto-sequence, configured by calling setStoppingConditionAutoSegment, where you know that propagation should not continue if a particular StoppingCondition is satisfied.

If the StopSegment is enabled, propagation will stop the very first time the segment is propagated. This includes when being run as part of a TargetedSegmentListOperator.

The related ChangeStopSegmentOperator type is a TargetedSegmentListOperator that can change the StopEnabled (get / set) property of a StopSegment.

The following code sample demonstrates using a StopSegment:

Java
// define constants
String satelliteName = "Satellite";
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();

// make the segment list
SegmentList segmentList = new SegmentList();

// initial state
NumericalInitialStateSegment initialStateSegment = configureNumericalInitialStateSegment();

// make the propagation segment
// we will need the integration point to make the altitude stopping condition
PropagationNewtonianPoint propagationPoint = createPropagatedNewtonianPoint(satelliteName);
NumericalPropagatorSegment propagationSegment = new NumericalPropagatorSegment();
propagationSegment.setPropagatorDefinition(createNumericalPropagator(propagationPoint));

// make a stopping condition
ScalarStoppingCondition altitudeStoppingCondition = new ScalarStoppingCondition(
        new ScalarCartographicElement(
                earth,
                propagationPoint.getIntegrationPoint(),
                CartographicElement.HEIGHT),
        100000.0, // 100 kilometers
        1.0,      // stop within a meter
        StopType.THRESHOLD_DECREASING); // the satellite won't come back up

// the satellite won't come back up
propagationSegment.getStoppingConditions().add(altitudeStoppingCondition);

// if the satellite goes below 100 km, then stop propagation
StopSegment stopIfAltitudeIsTooLow = new StopSegment(true);
propagationSegment.setStoppingConditionAutoSegment(altitudeStoppingCondition, stopIfAltitudeIsTooLow, 1);

// or our orbit might not reenter in which case we want to continue propagating another segment.
StoppingCondition anotherStoppingCondition = createSomeOtherStoppingCondition();
propagationSegment.getStoppingConditions().add(anotherStoppingCondition);

// if we don't stop, this segment will propagate after the previous propagation segment finishes
NumericalPropagatorSegment someOtherPropagationSegment = configureNumericalPropagatorSegment();

// configure the segment list
segmentList.getSegments().add(initialStateSegment);
segmentList.getSegments().add(propagationSegment);
segmentList.getSegments().add(someOtherPropagationSegment);