Modeling Guide for Simulation and Testing#
SysML v2 textual models can be turned into executable C++ code within minutes — no UML tool required. This guide explains how to structure your model so that Sinelabore generates code you can simulate on your PC and use as a basis for testing state-based behavior.
The focus here is on state machines embedded in parts, executable actions (assign, control flow, loops), their interaction via ports, and the execution loop needed to run a model. For element-level syntax details see the sub-pages (Parts, States, Ports, …). For the full traffic-light walkthrough see the GitHub example.
What you can do today#
| Goal | Supported | How |
|---|---|---|
| Simulate state machines on a PC | Yes | Generate C++, call state machine methods in a loop |
| Model interacting parts | Yes | Parts, ports, connections |
| Timed transitions | Yes | accept after … [SI::second] |
| Guarded transitions | Yes | accept when condition or if condition then |
| Executable action behavior | Yes | assign, sequencing (first/then), if/else, decide, loop/while/for — see Actions |
| Hardware / platform hooks | Optional | Empty action def + C++ subclass override when I/O is not modeled in SysML |
| Inject test stimuli via ports | Yes | Send events/data from one part to another |
| Automatic test route generation | UML only (so far) | See Model-Based Testing |
| Trace / live visualization | UML only (so far) | Same as above; SysML v2 trace support may follow |
SysML v2 is ideal for early executable models: validate state logic, timing, and part interaction before committing to target hardware or a full UML toolchain.
Decision Guide#
flowchart TD
Start([New SysML v2 model]) --> Single{Single part<br/>or system of parts?}
Single -->|One part| SM[Part with state machine]
Single -->|Multiple parts| SYS[System part composes sub-parts]
SYS --> Connect[Connect ports between parts]
SM --> Actions{Need behavior<br/>in states or parts?}
Connect --> Actions
Actions -->|Logic and data| ActModel[Model with action syntax<br/>assign, if/else, loops, decide]
Actions -->|Port I/O| Port[Define in/out ports<br/>accept / send in actions]
Actions -->|Hardware I/O| HW[Empty action def<br/>override in C++ subclass]
Actions -->|Timed sequences| Time[Use accept after transitions]
ActModel --> Run[Generate code<br/>run simulation loop]
Port --> Run
HW --> Run
Time --> Run
Run --> Test{Testing goal?}
Test -->|Explore behavior| Sim[Manual simulation<br/>observe state changes]
Test -->|Repeatable checks| Auto[Script stimuli in main<br/>assert on attributes]
1. Model Structure Patterns#
Every executable model follows the same skeleton. Keep this structure in mind before adding details.
Single-file package#
All model elements must reside in one file. Wrap everything in a package (mapped to a C++ namespace):
private import ScalarValues::*;
package MySystem {
// enums, items, ports, parts, connections — all here
}See Packages.
Part with state machine#
State machines can only be attached to parts. Each part with a state machine gets a generated method named after the top-level state def:
part def Controller {
state def controllerSm {
entry; then Idle;
state Idle;
accept after 1[SI::second] then Active;
state Active;
}
}System composition#
To simulate interaction between components, define a system part that owns sub-parts and connects their ports:
part def MySystem {
part master : MasterController;
part slave : DeviceController;
connect master.sendPort to slave.recvPort;
}Sub-parts must be initialized in code after construction — call init() on the system part, then initialize() on each state machine. See Parts.
Event definitions#
Define events as enums. Use comments like //@PartName to associate events with a specific part if needed:
enum def DeviceEvent {
evStart;
evStop;
evError;
}See Enumerations.
2. Action Modeling Patterns#
Actions are first-class executable behavior in SysML v2 — not just placeholders. The code generator translates action bodies into C++ using a context object that gives access to part attributes, parameters, and nested action results. Model your logic here whenever possible; reserve empty action def bodies only for hardware or platform code you intentionally keep in C++.
| Construct | Purpose | Example |
|---|---|---|
assign |
Update attributes, pass data | assign msg := m.msg; |
| Sequencing | Ordered steps | first start; then act1; then act2; then done; |
| Action invocation | Reuse behavior | then action act2:ParentWithPara; |
| Inline action | Local one-off steps | then action { assign x := n; } |
decide / guarded branches |
Conditional flow | then decide; if n==1 then Path1; else done; |
if / else if / else |
Structured conditionals | then if batLevel<4 { … } else { … } |
loop / until |
Repeat until condition | loop action charging { … } until chargeStatus <= 100; |
while |
Pre-checked iteration | while whileGuard <= 5 { assign whileGuard := whileGuard + 1; } |
for … in |
Iterate over collections | for anA in a { assign anA.n := 34; } |
| Parameters | Typed inputs/outputs | in x:Real; out p:Real; assign p := x*x; |
| Port interaction | Receive or send via ports | action accept m:PortData via recvPort { assign msg := m.msg; } |
Actions can be referenced from state machines (entry action …, exit action …, do action …) and from other actions. Nested action usages are mapped to executable C++ code.
Full syntax and generated C++ examples: Actions.
When to use empty action defs#
Use an empty action def only as a hook for hardware or OS services that you do not want to model in SysML — for example setRedLED{} driving a GPIO pin. The simulation can override these in a C++ subclass. All other behavior (calculations, guards, port handling, control flow) belongs in the action body.
/* Modeled in SysML — generated C++ runs directly */
action def computeThreshold {
in level:Integer;
out ok:Boolean;
assign ok := level >= 10 and level <= 90;
}
/* Hook for target hardware — implement in C++ subclass */
action def setRedLED {}3. State Machine Modeling Patterns#
SysML v2 state machines are less expressive than UML state charts but well suited for simulation. These patterns produce clean, readable generated code.
| Pattern | Purpose | Example |
|---|---|---|
| Entry → default state | Define startup state | entry; then Idle; |
| Short-form timed transition | Blinking, timeouts, periodic behavior | accept after 0.5[SI::second] then Off; |
| Long-form transition | Named transition with explicit source | transition t1 first Red accept after 2[SI::second] then Green; |
| Guard on attribute | React to model data, not just time | accept when msg==DeviceEvent::evStart then Running; |
| Entry / exit actions | One-time setup/teardown per state | entry action setRedLED{} or modeled action with body |
| Do activity | Poll ports or run logic each cycle | do action getMsg{} |
| Hierarchical states | Group related states (e.g. OutOfService, Operational) | Nested state Operational { … } |
| History (naming convention) | Return to last substate | Shallow: S1_H, deep: S1_HH |
| Final state | Non-reactive end | state Done; with no outgoing transitions |
Full traffic-light example: States.
Timed transitions#
Time values are specified in seconds only:
accept after 2[SI::second] then Operational;
accept after 0.001[SI::second] then Next; /* 1 ms */The code generator emits timer management code. You must call the state machine method cyclically in your simulation loop (see below).
Reading data from ports in states#
A common pattern for testable models: a do action reads incoming port data into a part attribute; transitions use guards on that attribute:
action def getMsg {
action accept m:PortData via recvPort {
assign msg := m.msg;
}
}
state def deviceSm {
entry; then Idle;
do action getMsg {}
state Idle;
transition t1 first Idle accept when msg==DeviceEvent::evStart then Running;
state Running;
}4. Communication Patterns#
Parts interact through ports and connections. This is the primary mechanism for injecting test stimuli during simulation.
| Pattern | When to use | Modeling |
|---|---|---|
| Unidirectional command | One controller, one or more devices | out port → in port, connect in system part |
| Event + data payload | Send typed messages | Define item or port with attributes |
| Bidirectional | Request/response | Two port pairs in opposite directions |
| Timed stimulus | Auto-start simulation | Controller part with accept after sends via port |
Example:
port def ControlPortData {
in item data : PortData;
}
item def PortData {
attribute msg : DeviceEvent;
}
part def Master {
out port sendPort : ControlPortData;
accept after 2[SI::second] do send DeviceEvent::evStart via sendPort then Done;
}
part def Device {
in port recvPort : ~ControlPortData;
// state machine reacts to msg read from recvPort
}See Ports.
5. Simulation Pattern#
Generated models are intended to run in a simple C++ main function. No RTOS or target hardware is required.
Code generation#
java -cp path_to_bin_folder/* codegen.Main -p Sysml2Text -l cppx your_model.sysmlSet these parameters in codegen.cfg (required for SysML v2 C++ output):
UseEnumBaseTypes=yes
UseStdLibrary=yes
CallInitializeInCtor=no
EnumBaseTypeForEvents=std::int16_tExecution loop#
Each part with a state machine exposes a method named after its state def. Call these cyclically:
using namespace MySystem;
int main() {
MySystem system;
system.init();
system.master->initialize();
system.device->initialize();
for (int i = 0; i < 100; i++) {
system.master->controllerSm();
system.device->deviceSm();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}The sleep interval defines the simulation tick. Choose it smaller than your shortest timeout for reliable timed transitions.
Extending with custom C++ behavior#
Most behavior should live in the SysML model and is generated automatically. Subclass the generated part only when you need platform-specific code that cannot or should not be expressed in SysML — typically hardware I/O, OS calls, or test assertions on external interfaces:
class DeviceSim : public Device {
public:
void setRedLED() override { redOn = true; std::cout << "RED on\n"; }
void resetRedLED() override { redOn = false; }
bool redOn = false;
};Create sub-parts in a custom init() and call the base-class init(). See States — Executing a model.
6. Testing Patterns#
SysML v2 simulation is the foundation for testing state-based models. These approaches work well with the current backend.
Manual exploratory testing#
Run the generated executable and observe attribute changes, port traffic, and state sequences. Because action logic is generated from the model, most behavior is visible without writing C++ — add std::cout in subclass overrides only for hardware hooks.
Scripted stimulus testing#
Drive the model from main with a fixed sequence of port messages or timed runs:
// After N ticks, inject an error event via the master part
if (i == 50) {
system.master->sendError();
}Check part attributes (updated by assign in actions) or subclass overrides for hardware hooks to verify expected behavior.
Incremental modeling pattern#
- Model control logic, calculations, and port handling directly in SysML actions.
- Run the simulation and verify state transitions, guards, and attribute updates.
- Add empty action defs only for hardware boundaries; implement those in a C++ subclass when moving toward target code.
Transition coverage (UML workflow)#
Automatic test route generation, Excel test sheets, and live trace visualization are available for UML state charts today. See Model-Based Testing. If you need these features, model in UML; if you need fast textual iteration, use SysML v2 simulation and port-based scripting.
7. Supported Features (Summary)#
| Category | Supported |
|---|---|
| Package / namespace | Yes |
| Parts, nested parts | Yes |
| Attributes, enums | Yes |
| Items | Yes |
| Ports (in/out), connections | Yes |
| State machines in parts | Yes |
| Entry, exit, do actions | Yes |
Timed transitions (after) |
Yes (seconds) |
Guarded transitions (when, if) |
Yes |
| History states (naming convention) | Yes |
| Final states | Yes |
| Actions — assign, sequencing, parameters | Yes |
Actions — decide, if/else if/else |
Yes |
Actions — loop/until, while, for |
Yes |
| Actions — nested usages, port accept/send | Yes |
at time transitions |
No |
| Regions | No |
| Inner transitions | No |
| Multi-file models | No |
| Imports (code generation) | Ignored — use for editor satisfaction only |
Full limitation list: SysML v2 overview.
8. Anti-Patterns#
| Anti-pattern | Problem | Better approach |
|---|---|---|
| State machine outside a part | Not supported | Always attach state def to a part def |
| Model split across files | Parser reads one file only | Single package, single file |
| Blocking code in actions | Simulation stalls | Keep individual action steps short; use state machines for long-running processes |
| Empty defs for logic that belongs in SysML | Unnecessary C++ hand-coding | Use assign, control flow, and nested actions in the model |
| Tick interval too long | Missed or delayed timeouts | Sleep shorter than smallest after duration |
Forgetting init() / initialize() |
Undefined startup | Call both before the simulation loop |
| Deep hierarchy without purpose | Hard to debug in simulation | Flatten; use hierarchical states only when they clarify behavior |
| Implicit events instead of attributes | SysML v2 uses guards on data, not UML-style event queues | Read ports in do-actions; guard on attributes |
| Expecting UML test tooling | Not available for SysML v2 yet | Use scripted simulation or model in UML for coverage tools |
Quick Checklist#
Before generating and running your model:
- All elements in one file, one package
- Every state machine belongs to a part
- System part composes and connects sub-parts
- Events defined as enums; port payloads typed
- Default state set (
entry; then …) - Behavior modeled in action bodies; hardware hooks only where needed
-
codegen.cfgparameters set for SysML v2 - Simulation loop calls all state machine methods cyclically
- Tick interval suitable for shortest timeout
Next Steps#
- Clone the traffic-light example and run it locally.
- Adapt the model: change timeouts, add states, inject port events.
- Explore element details in the SysML v2 documentation.
- When the model stabilizes, consider a UML tool workflow for formal test-case generation and target code export.
This guide will evolve as the SysML v2 backend gains features. Feedback and example models are welcome.