Sinelabore Homepage

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; }
forin 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 portin 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.sysml

Set these parameters in codegen.cfg (required for SysML v2 C++ output):

UseEnumBaseTypes=yes
UseStdLibrary=yes
CallInitializeInCtor=no
EnumBaseTypeForEvents=std::int16_t

Execution 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#

  1. Model control logic, calculations, and port handling directly in SysML actions.
  2. Run the simulation and verify state transitions, guards, and attribute updates.
  3. 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.cfg parameters set for SysML v2
  • Simulation loop calls all state machine methods cyclically
  • Tick interval suitable for shortest timeout

Next Steps#

  1. Clone the traffic-light example and run it locally.
  2. Adapt the model: change timeouts, add states, inject port events.
  3. Explore element details in the SysML v2 documentation.
  4. 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.