Event Detection

Behavior Execution Engine uses specific types to produce the data required for event detection. BooleanValue, TimeDuration, and TimeInstant correspond to change events, relative time events, and absolute time events, respectively.

SysML Type Description
Moxie-Base::Structure::BooleanValue Used in change events and guards
Moxie-Base::Structure::TimeDuration Used in relative time events
Moxie-Base::Structure::TimeInstant Used in absolute time events

Times

When modeling physics, time precision is extremely important. Internally, Behavior Execution Engine uses the MoxieTime class for handling time calculations. The MoxieTime class contains a representation of the time based on input and exposes arithmetic enabling you to add and subtract durations of time accurately and precisely. Whether you provide time data as an ISO8601 string, a Gregorian calendar date and time, or a Julian date, MoxieTime will accept and process that information effectively, including handling any historical leap seconds that may occur during the time spans of the simulation. For more information on configuring leap seconds, see the com.agi.moxie.api.time.LeapSecondsProvider API documentation.

The instance of StkTimeHelper on StkToolbox provides methods such as stkAgVariantToMoxieTime and moxieTimeToStkEpochSeconds for converting the AgVariant and EpochSeconds values used in STK to the MoxieTime type used inside Behavior Execution Engine.

Because the Epoch used inside STK may be different from the start time of the simulation, the measure of EpochSeconds in STK may or may not correspond to the elapsed seconds from the start of the simulation. When using STK Object Model, take care to use the correct values, depending on which units you are using for time in STK.

STK-related features are only available if you acquired Behavior Execution Engine as part of STK Enterprise or otherwise have a valid license for STK. If you acquired Behavior Execution Engine as part of ModelCenter Enterprise but have access to a valid STK license, contact us for access to the STK-related features.

Changes

For handling time-varying boolean expressions for change events (or for guards), the expression must result in a BooleanValue or a boolean primitive (SysML::Libraries::PrimitiveValueTypes::Boolean). Behavior Execution Engine reevaluates boolean primitives after every state update to determine whether or not to fire an event. There are several different ways to handle these boolean types:

  • For values that are constant, and therefore do not fire change events, you should use BooleanValue.constant(boolean).
  • For a property that is just a toggle set by other operations, you can use either a boolean primitive or a BooleanValue. These would be backed by a BasicProperty<Boolean>(timeProvider, boolean) or a BasicProperty<BooleanValue>(timeProvider, BooleanValue.constant(boolean)), respectively, in the delegate code.
  • For time-varying analysis, you can perform the event detection yourself and create a new instance using BooleanValue.fromTrueIntervals(Collection<Interval<MoxieTime>>).
  • For STK or STK Engine, you can use the StkToolbox to convert an instance of IAgStkAccess directly to a BooleanValue.
  • For STK Components, you can use any AccessQuery to compute the true intervals, and then you can convert those into a BooleanValue. For example:
    TimeIntervalCollection accessResult = accessQuery.getEvaluator().evaluate(analysisStartJulianDate, analysisStopJulianDate).getSatisfactionIntervals();
    List<Interval<MoxieTime>> moxieIntervals = accessResult.getSatisfactionIntervals().stream().map(x-> {
        JulianDate intervalStart = x.getStart().toTimeStandard(TimeStandard.getInternationalAtomicTime());
        JulianDate intervalStop = x.getStop().toTimeStandard(TimeStandard.getInternationalAtomicTime());
        return new Interval<>(
            MoxieTime.fromJulianTimeTai(intervalStart.getDay(), intervalStart.getSecondsOfDay()),
            MoxieTime.fromJulianTimeTai(intervalStop.getDay(), intervalStop.getSecondsOfDay()),
            true,
            false);
    }).collect(Collectors.toList());
    BooleanValue whenTrue = BooleanValue.fromTrueIntervals(moxieIntervals);

    Figure 1: Example code to extract a BooleanValue using STK Components

    When converting STK Components' representations of JulianDate into the Behavior Execution Engine equivalent JulianTime, make sure to specify a consistent time standard across STK Components and Behavior Execution Engine. To avoid any confusion over leap seconds between the two systems, International Atomic Time (TAI) is a good choice, as shown in Figure 1.

STK-related features are only available if you acquired Behavior Execution Engine as part of STK Enterprise or otherwise have a valid license for STK. If you acquired Behavior Execution Engine as part of ModelCenter Enterprise but have access to a valid STK license, contact us for access to the STK-related features.

The instances of a Property type returned from an xyzProperty() method are intended to be unique to each object and should not be held or returned from any other object than the one that created them. xyzProperty().getValue() may return different values at different times. As the simulation progresses, the instances returned from the Property<T> methods may have been reconfigured with new instances and new values. So, be careful when caching or holding on to values from other objects. In general, the values returned from object properties are only valid at the current simulation time, even though they may represent dynamics that model values from the past and into the future. Unless explicitly documented otherwise, assume that the object references from calling getValue() or the return values from operations will change between calls to your code.

The Behavior Execution Engine API contains the infrastructure required to implement or extend delegates for use with Behavior Execution Engine.

You can use operations in state machines to trigger call events. Any time Behavior Execution Engine executes an operation from an effect in a state machine, it calls the corresponding Java method. If there is a trigger expecting a call event for that operation, the Java method must send the call event back to itself to alert the state machine that the operation has been called. Otherwise, unless the @AutoDelegateImplementation annotation is applied on the class, the call events will not fire. You can see an example of this in Figure 2, which uses call events from the hot air balloon ride example.

@Override
public void launch() {
    mStateMachineRemoteControl.sendCallEventToSelf("Structure::BalloonOperator::launch");
}

@Override
public void land() {
    mStateMachineRemoteControl.sendCallEventToSelf("Structure::BalloonOperator::land");
}

Figure 2: The balloon operator call events for launching and landing the balloon

Manually implementing a delegate class requires explicit implementation of all call events. However, when using the @AutoDelegateImplementation annotation, sending call events is handled automatically. See Auto Implementation for more details.