In modeling a behavior, we often need to represent a selection logic controlled by a set of stimuli. How we do it correctly and sufficiently lies within how well we understand the Executable Constructs.
Let us take a look at the behavior of automobile traffic at an intersection controlled by traffic lights:
- An automobile approaches the interaction.
- The automobile maintains its speed if the traffic signal is green.
- The automobile slows down to a full stop if the traffic signal is red.
- The automobile speeds up to clear the intersection if the traffic signal is amber and it is not safe to attempt a full stop. (This behavior seems to be more common than we care to believe)
In GENESYS and other model-based systems engineering (MBSE) tools, there are two basic executable constructs we can consider: Concurrency (or Parallel) and Select. (There is also a Multiple-Exit construct in GENESYS, which we will revisit later on.) If we express the behavior of the automobile approaching the intersection the same way our colloquialisms work, it would look like this in a model:
The automobile approaches the intersection. It can do one of three things. It slows down to stop, OR it speeds up, OR it maintains speed. It must select one of the three paths; it must not execute more than one option.
That seems logical. And therefore, a Select construct (OR construct) must be the correct choice for this behavior. But did we miss something here?
The problem with using Select in this case is that we are ignoring the controlling stimuli: the red, amber, and green traffic signals. What controls the execution of a Select construct is pure probability. If no value of probability is specified for each of the paths, the “randomness” of flow execution is evenly distributed among the available paths. The behavior in the enhanced functional block diagram (EFFBD) above really reads:
The automobile approaches the intersection. In 33.33% of the time, it slows down to stop. OR in 33.33% of the time, it speeds up. OR in 33.33% of the time, it maintains speed. The traffic signals do not mean anything to the automobile. And that is a huge problem!
Let us look at the same scenario, but with the traffic signal stimuli in mind. The colloquialisms should now express:
The automobile approaches the intersection. It has three available options of behavior: “slow down to stop” option, AND “speed up” option, AND “maintain speed” option. The option it takes depends on which stimulus it receives in the form of the traffic signal. It still only executes one of the three available paths, but before a stimulus gets to it, it has ALL three available options waiting for a stimulus.
With that narrative, our EFFBD looks like this:
The top half of the overall construct expresses the behavior of the traffic light. From the lens of the driver (or the “automobile” system) this behavior is random: sometimes the light is red, sometimes it is amber, and sometimes it is green when she approaches the intersection. Therefore, a Select (OR) construct is employed for the traffic light to output either a red light, or an amber light, or a green light. Never can more than one stimulus be available at any given time. This matches with reality.
The bottom half of the overall construct expresses the behavior of the automobile. Instead of a Select construct, a Concurrency construct is used to express there are three concurrently available paths, all enabled right after the activity “Approach Intersection”. Which one is to be executed depends on which stimulus is to be provided by the external system “Traffic Light”. If “Amber Light” becomes available because the activity “Signal Amber” has executed, then “Amber Light” will act as a trigger to execute “t2 Speed Up” activity. Once “t2 Speed Up” has finished, the kill switch on its branch will terminate the whole Concurrency construct:
In theory, all paths (branches) of a Concurrency construct must finish their own execution before the whole construct can finish its execution. But because we are employing a triggering stimulus to “select” which path to execute, only one path can ever finish. (Because only one traffic signal color can be available at any given time.) As a result, the kill switch placed on each of the three paths is necessary to complete the execution of the entire Concurrency construct. In other words, whichever path is selected by the stimulus, also becomes the execution controller of its whole Concurrency construct.
If you think about the application of the kill switch concept in reality, it makes sense too:
Once the automobile driver has chosen to “speed up” because of the amber traffic signal, that decision overrides the need to execute the other two activities (“slow down to stop” and “maintain speed”). The execution to “speed up” now controls the overall executable options the driver is presented with at the intersection. Once it has finished, it can kill the whole Concurrency construct.
A quick simulation run provides me with:
In this simulation run, the traffic light is signaling amber as the automobile approaches the intersection. As a result, the automobile speeds up to clear the intersection. “t2 Slow Down to Stop” and “t2 Maintain Speed” are not executed, and are subsequently “killed”. As discussed earlier, since the external stimulus is randomized, I would have to run the simulation a few times to observe all three paths being executed.
In my experience, the application of the Concurrency construct and kill switches to select an execution path works very well with high-level functional behaviors. It works exceptionally well with operational behaviors, in the Capability Architecture Development schema. However, when dealing with low-level functional behavior, the kill-switch mechanism makes the logic expression less “elegant”. Killing unexecuted branches of a Concurrency construct is quite crude, and software logic rarely works this way. Instead, we should use the Multiple-Exit construct in low-level functional behavior. Without introducing a separate functional model for this example, let us look at our automobile and traffic light example again. The behavior looks something like this when we employ a Multiple-Exit construct:
In this structure, the activity “t3 Approach Intersection” takes in the traffic signal input (not a trigger) whichever color it might be, then decides which exit to take: Red, Amber, or Green. The logic flow is more elegant because the decision-making lies within an activity (or function if we work on a functional behavior). No stimulus triggering and branch killing are necessary. Software logic works this way too. Decision-making requires an active function to perform. The only drawback of the Multiple-Exit construct is the readiness of its simulation execution. At the time when this article is written, a custom GENESYS script is necessary to make the Multiple-Exit construct executable in a simulation. On the contrary, using the Concurrency construct and kill switches does not require any scripting.
There are other posted articles on Multiple-Exit and Exit Conditions which further expand the topic. You can find these well-written articles here:
With a simple model of an automobile’s behavior at a signal-controlled intersection, we have demonstrated a method to select a flow path when external stimuli play a role in decision-making. Unlike the colloquial use of the word “or”, the Select (OR) construct is not a viable option, given its probabilistic nature. The combination of a Concurrency construct, triggers, and kill switches can provide a simple but effective expression of the behavior. We have also touched on the option of the Multiple-Exit construct, with its advantage and disadvantage over the Concurrency method. The GENESYS system definition language (SDL) is rich. The Structure concept, including the executable constructs as a part of the SDL, can aid and enhance your experience in building a successful system behavior.