Chapter 9. Modeling the Dynamics of a System

In general, the dynamics of a system can be captured by modeling the types of events and processes (including actions and activities), occurring in the system. However, SysrML2 does neither include an explicit concept of events (and event types), nor of processes (and process types). Rather, it sticks to the UML behavior modeling concepts of "actions" and "states".

Regarding the ontological semantics of SysML2's concept of "actions", it seems that it is supposed to subsume also event types and process types. This interpretation is based on the fact that the SysML spec (in Section 7.9.1) is using the term "event" for special occurrences involving performer objects, such as sending or receiving messages.

Ontologically, events may be (1) instantaneous or have a duration, (2) atomic or composite, while activities are special processes, and we have to distinguish between ongoing and completed processes. In the approach of (Guarino and Guizzardi 2024), only completed activities and processes correspond to events, since events are always in the past. However, while this ontological distinction is important for ontology-driven conceptual domain modeling, we may, for simplicity, choose using overloaded concepts of activity/process types as event types, possibly subsuming both completed and ongoing processes, for systems modeling.

9.1. Action Types ("Behaviors"), Steps and Successions

In KerML, the actions of a system are considered as performances of the system's behavior and their types are called "Behaviors":

Behaviors are classes that classify performances, which are kinds of occurrences that can be spread out in disconnected portions of space and time. The performance of behaviors can cause effects on other things, including their existence and relations, some of which might be accepted as input to or provided as output from the behavior.

Behaviors can have steps, which are features typed by behaviors, allowing the containing behavior to coordinate the performance of other behaviors. Steps can be ordered in time using succession connectors. They can also be connected by item flows to model things flowing between the output of one step and the input of another. Steps can also nest other steps to augment or redefine steps inherited from their behavior types.

Features declared in the body of a behavior with a direction are considered to be the owned parameters of the behavior. Features with direction in are input parameters, those with direction out are output parameters, and those with direction inout are both input and output parameters.

The following example models a "behavior", or action type, TakePicture with two action steps:

behavior Focus;
behavior Shoot;
behavior TakePicture {
  step focus[1] : Focus;
  step shoot[1] : Shoot;
}

Notice that since an action step is a 'composite feature', for each performance of its owning behavior, any action step performance must happen during that performance, so it must end before, or at the same time when, the performance of their owning behavior ends.

The KerML library Performances includes the predefined Behavior Performance, which is the most general action type (or Behavior) in the sense that every other action type is a subtype of it. A Kernel-layer Behavior declaration made with the keyword "behavior" like the following one:

behavior Drive;

is equivalent to the following Core-layer classifier declaration made with the help of the predefined classifier Performance:

classifier Drive specializes Performance;

Successions of Action Steps

Successions are binary KerML connectors (link-valued properties) that allow describing the temporal precedence between two suboccurrences.

While a connector value may be a link object representing a physical connection (between system components) as an occurrence in space and time, a succession value is rather a kind of abstract binary link that does not inherit the features of Occurrence, so it does, for instance, not have any time slices or snapshots. In other words, while connector values may represent material relationships, succession values represent formal temporal relationships.

Typically, successions are used for connecting successive action steps. They are declared by using the keyword succession together with the keywords first and then, as in the following example:

behavior TakePicture {
  step focus[1] : Focus;
  step shoot[1] : Shoot;
  succession controlFlow first focus then shoot;
}

A succession must directly or indirectly specialize the predefined feature happensBeforeLinks (from the Occurrences library) that is typed by the predefined association HappensBefore. Normally, a succession is not explicitly typed by an association, in which case it is semantically implied that it is typed by HappensBefore. Consequently, any occurrence o1 as a value of the first step must happen before the then step occurrence o2 in the sense that o1 ends before o2 starts.

HappensBefore is a predefined association whose links relate "an earlierOccurrence to a laterOccurrence, indicating that the Occurrences do not overlap in time (... none of their snapshots happen at the same time), and the earlierOccurrence happens first. This means no Occurrence HappensBefore itself."
[Section 9.2.4.2.1 of KerML v1.0 Beta 4]

Consequently, HappensBefore represents a strict partial order, that is, an irreflexive, asymmetric and transitive relation.

The declaration of a succession can be simplified by omitting its name, like so:

  first focus then shoot;

As for connector ends on regular connectors, constraining multiplicities can also be defined for the connector ends of successions, as shown in the following example.

behavior TakePictureWithMultiFocusing {
  step focus[1..*] : Focus;
  step shoot[1] : Shoot;
  // a shoot action must be preceded by at least one focus action, and
  // a focus action must be succeeded by exactly one shoot action
  succession multiFocusing
    first [1..*] focus then [1] shoot;
  // a shoot action must not be succeeded by a focus action
  first [0] shoot then [0] focus;
}

Declaring an Immediate Succession

Declaring Dynamic Constraints in the Form of Succession Multiplicities

Declaring successions with suitable multiplicities allows defining behaviors based on dynamic (temporal logic) constraints like in declarative business process modeling approaches such as DECLARE. For instance, the three most important types of DECLARE constraints, Response, Precedence and Neg-Succession, can be expressed by corresponding succession declarations, as shown in the following table.

Name of constraint typeDECLARE template nameKerML declaration patternLTL formulaExplanation of the constraint's meaning
Follow-UpResponsefirst [*] focus then [1..*] shoot□( focus ⇒ ◇shoot)A focus action must be succeeded by a shoot action.
PrecedencePrecedencefirst [1..*] focus then [*] shoot(¬shoot U focus) v □(¬shoot)A shoot action must be preceded by a focus action.
ExclusionNeg-Successionfirst [0] cancel then [0] pay□( cancel ⇒ ¬◇pay)A cancel (order) action must not be succeeded by a pay action, implying that a pay action must not be preceded by a cancel action.

In DECLARE, the meaning of constraint templates is provided by a translation to formulas of Linear Temporal Logic (LTL), which includes the temporal operators ◇ standing for "eventually", □ standing for "always", and U standing for "until". For instance, the formula (F U G) stands for "F until G" meaning that at some point in time G holds and all the time before that F holds. While the variables in the propositional temporal logic LTL, like F and G, normally represent sentences, in the context of providing a logical semantics for business processes, they are taken to represent actions or activities. For more about using LTL as a logical semantics for constraint-based business process models see Declarative Process Specifications by Ciccio and Montali, 2022.

An Example of a Business Process Model

We consider a simple process type of renting hotel rooms adopted from (Pesic et al 2007) for illustrating business process modeling with KerML. Renting hotel rooms processes consist of seven types of activities: (1) "book room": enter client name, payment data, etc; (2) “check-in”: record client arrival, provide key card, etc; (3) “bill”: for billing the number of nights, room services, laundry services, etc; (4) “provide room service”: provide a room service for the client; (5) “provide laundry service”: provide a laundry service for the client; (6) “charge”: the client is charged the total price of the stay; and (7) “check-out”: client checks out at the reception.

Following the terminology of SysML2, we say "action" instead of "activity".

This hotel room renting process type is only weakly structured since it does not properly sequence all types of actions. But it has a few (dynamic) constraints:

  1. Every process has to start with a "book room" action followed by a “check-in” action.
  2. Every process must include at least one action of type “bill”, i.e., at least the number of nights will be billed. However, it might be the case that the bill is extended multiple times during a process (due to room services and laundry services provided during the stay).
  3. Every action of type “provide room service” or “provide laundry service” must be billed. However, it is possible that several services are billed at once, instead of billing each service separately.
  4. When the client “checks-out”, the bill must either have been charged already or will be charged at, or after, check-out.

We start by capturing the seven action types of this process type in the form of KerML Behavior definitions:

behavior BookRoom {
  feature clientName : String;
  feature preferredWayOfPayment: String;
  ...
}
behavior CheckIn {...}
behavior ProvideRoomService {...}
behavior ProvideLaundryService {...}
behavior Bill {...}
behavior Charge {...}
behavior CheckOut {...}

Then we use these action type definitions for defining corresponding action steps in a RentHotelRoom action type definition:

behavior RentHotelRoom {
  step bookRoom[1] : BookRoom;
  step checkIn[0..1] : CheckIn;
  step provideRoomService[*] : ProvideRoomService;
  step provideLaundryService[*] : ProvideLaundryService;
  step bill[1..*] : Bill;
  step charge[1] : Charge;
  step checkOut[0..1] : CheckOut;
  // Follow-Up: A room service must be succeeded by a bill action
  first [*] provideRoomService then [1..*] bill;
  // Follow-Up: A laundry service must be succeeded by a bill action
  first [*] provideLaundryService then [1..*] bill;
}

Notice that this action type definition includes three step cardinality constraints:

  1. The steps bookRoom and charge are executed exactly once.
  2. The steps checkIn and checkOut are executed at most once.
  3. The step bill is executed at least once.

and two follow-up constraints:

  1. A provideRoomService action must be succeeded by a bill action.
  2. A provideLaundryService action must be succeeded by a bill action.

We need to define three more precedence constraints and two more combined follow-up/precedence constraints:

behavior RentHotelRoom {
  ...
  // A check-in must be preceded by a book room action
  first [1..*] bookRoom then [*] checkIn;
  // A room service must be preceded by a check-in.
  first [1..*] checkIn then [*] provideRoomService;
  // A laundry service must be preceded by a check-in.
  first [1..*] checkIn then [*] provideLaundryService;
  // A book room action must be succeeded by a charge, and
  // a charge must be preceded by a book room action.
  first [1..*] bookRoom then [1..*] charge;
  // A check-in must be succeeded by a check-out, and
  // a check-out must be preceded by a check-in.
  first [1..*] checkIn then [1..*] checkOut;
}

Given the above step cardinality constraints for bookRoom, checkIn, charge and checkOut, these constraints could be rewritten in the following way, which is equivalent, but more informative:

behavior RentHotelRoom {
  ...
  // A check-in must be preceded by exactly one book room action.
  first [1] bookRoom then [0..1] checkIn;
  // A room service must be preceded by exactly one check-in.
  first [1] checkIn then [*] provideRoomService;
  // A laundry service must be preceded by exactly one check-in.
  first [1] checkIn then [*] provideLaundryService;
  // A book room action must be succeeded by exactly one charge, and
  // a charge must be preceded by exactly one book room action.
  first [1] bookRoom then [1] charge;
  // A check-in must be succeeded by exactly one check-out, and
  // a check-out must be preceded by exactly one check-in.
  first [1] checkIn then [1] checkOut;
}

Modeling "Control Nodes" as Special Steps

In classical process modeling languages, such as UML Activity Diagrams or BPMN Process Diagrams, control nodes have been used for branching and merging the "control flow" of a process, that is, the flow of process events. In KerML, branching and merging within a Behavior is specified with the help of steps that are typed by the following special control behaviors predefined in the ControlPerformances library:

DecisionPerformance
A step that is typed by the predefined behavior DecisionPerformance is called a decision step. A decision step has values (performances) representing the earlierOccurrence of exactly one HappensBefore link of the successions going out of the step. Successions going out of such steps must have cross multiplicities of 1 towards the step, and 0..1 away from it. A decision performance has a HappensBefore link as the value of its outgoingHBLink feature, instantiating the succession that has been selected from those, which have the decision performance behavior as their source.
MergePerformance
A step that is typed by the predefined behavior MergePerformance is called a merge step. A merge performance (value) of a merge step is the laterOccurrence of exactly one HappensBefore link of the successions coming into the step. Successions coming into merge steps must have cross multiplicities of 1 towards the step, and 0..1 away from it.
IfPerformance
A step that is typed by the predefined behavior IfPerformance is called a conditional step. IfPerformances determine whether a performance occurs based on the result of a BooleanEvaluation. Two specializations IfThenPerformance and IfElsePerformance have one clause each, thenClause and elseClause, respectively, that occur when the BooleanEvaluation is true or false, respectively. IfThenElsePerformance is an IfPerformance that has both a thenClause and an elseClause.
LoopPerformance
A step that is typed by the predefined behavior LoopPerformance is called a loop step. Loop performances have a body that occurs iteratively as determined by the Boolean evaluations whileTest and untilTest. The body occurs iteratively as long as the result of whileTest is true before each iteration (and after the previous one, if any), and the result of untilTest is false after each iteration and before the next one (except after the last one, when it is false).

The following example illustrates the use of decision and merge control node steps in KerML:

behavior Admit;
behavior Touchup;
behavior MarkForRecycling;
behavior Ship;
behavior Manufacture {
  step admit[1] : Admit;
  first [1] admit then [1] inspect;
  // Decision
  step inspect : DecisionPerformance [*];
    // Two decision branches
    first [1] inspect then [0..1] finish;
    first [1] inspect then [0..1] recycle;
  step finish[*] : Touchup;
  step recycle[*] : MarkForRecycling;
  // Two merge branches
  first [0..1] finish then [1] mergeBeforeShip;
  first [0..1] recycle then [1] mergeBeforeShip;
  // Merge
  step mergeBeforeShip[*] : MergePerformance;
  // After merge
  first [1] mergeBeforeShip then [1] ship;
  step ship[*] : Ship;
}

9.2. Functions and Expressions

Functions are Behaviors with one out parameter designated as the result parameter. Functions classify evaluations, which are kinds of performances that produce results as values of the result parameter. Like all Behaviors, Functions can change things, often referred to as "side effects". A pure Function is one that has no side effects and always produces the same results given the same input values, similarly to a function in the mathematical sense.

Expressions are steps typed by only a single Function, which means that their values are evaluations. An expression whose value is an evaluation with results is said to evaluate to those results. They can be steps in any behavior, but a Function, in particular, can designate one of its expression steps as the result expression that gives the value of its result parameter. Expressions can have their own nested parameters, to augment or redefine those of their Functions, including the result parameter. They can also own other expressions and designate a result expression, similarly to a Function.

The body of a Function may contain the declaration of a result expression at the end, as in the following example:

function Average {
  in scores[1..*] : Rational;
  return : Rational;
  // result expression
  sum(scores) / size(scores)
}

The result of the result expression is implicitly bound to the result parameter of the containing Function. Alternatively, a result expression can be explicitly bound to the result parameter like so:

function Average { 
  in scores[1..*] : Rational;
  return : Rational = sum(scores) / size(scores);
}

The KerML library Performances includes the predefined Function Evaluation, which is the most general Function in the sense that every other Function is a subtype of it. A Kernel-layer Function declaration made with the keyword "function" like the following one:

function MyFun;

is equivalent to the following Core-layer classifier declaration made with the help of the predefined Function Evaluation:

classifier MyFun specializes Evaluation;

Expressions

An expression can be declared as a step using the keyword expr. As for a step, directed features declared in the body of an expression are considered to be parameters of the expression.

Example 1:

function UnaryFunction {in x : Anything; return: Anything;}
function apply {
  in expr fn : UnaryFunction;
  in value : Anything;
  return : Anything = fn( value);
}

Example 2 (shows how an expression can be invoked using a feature chain):

class Stats {
  feature vales[1..*] : Real;
  expr avg { sum(values)/size(values) }
}
feature myStats : Stats {
  redefines feature values = (1.0, 2.0, 3.0);
}
feature myAvg = myStats.avg();

9.3. Interactions

Interactions are behaviors that are also associations, classifying performances that are also links between occurrences. They specify how the linked participants affect each other and collaborate.

Transfers are interactions between two participants that carry items from one occurrence to another, with items optionally identified by output and input features of the source and target occurrence, respectively.

Item flows are steps that are also binary connectors, with values that are transfers. An item flow optionally ensures that items are transferred from an output feature of the connected source feature to an input feature of the target feature. Succession item flows are item flows that are also successions. They identify transfers that happen after their source (that is, after the end of the occurrence where the items come from) and before their target (that is, before the start of the occurrence where the items go to).

Example:

interaction Authorization {
  end feature client[*] : Computer;
  end feature server[*] : Computer;
  composite step login;
  composite step authorize;
  composite succession login then authorize;
}

The KerML library Transfers includes the predefined binary Interaction Transfer, which is the most general binary Interaction in the sense that every other binary Interaction is a subtype of it. A Kernel-layer binary Interaction declaration made with the keyword "interaction" like the following one:

interaction Authorization;

is equivalent to the following Core-layer classifier declaration made with the help of the predefined binary Interaction Transfer:

classifier Authorization specializes Transfer;

Item Flows

An item flow is similar to a binary connector. Unlike a regular binary connector declaration, though, an item flow declaration does not directly specify the related features for the item flow. Instead, the declaration gives the source output feature for the transfer after the keyword from and the target input feature for the transfer after the keyword to. The related features are then determined as the owning features of the features given in the item flow declaration.

In the following example, an item flow connects the out-parameter of an action step focus to the in-parameter of an action step shoot, allowing to transfer images obtained from focus actions as inputs to shoot actions.

behavior Focus { in scene: Scene; out image: Image; }
behavior Shoot { in image: Image; out picture: Picture; }
behavior TakePicture {
  in scene : Scene;
  out picture : Picture;
  binding focus.scene = scene;
  binding picture = shoot.picture;
  step focus : Focus;
  step shoot : Shoot;
  succession focus then shoot;
  flow focus.image to shoot.image;
}

9.4. Open Questions

1 Missing Control Behaviors

KerML predefines control behaviors in the ControlPerformances library. However, there is neither an element for fork nodes, nor for join nodes.

And why is LoopPerformance defined as a control behavior?