MBSE iNsightsMBSE iNsights

Reference

SysML v2 notation, drawn plainly

31 common graphical elements, with the textual syntax beside each one — in SysML v2 you will write the text far more often than you will draw the picture.

Structure

What the system is made of. Definitions and usages share one box; the keyword tells them apart.

Part definition

part def CoolantPump;

A kind of thing — a reusable classifier that usages can be typed by.

Worth knowingUpperCamelCase by convention, and referenced with a colon.

Part usage

part primaryPump : CoolantPump;

A particular occurrence of a part in a context. The type appears in the name compartment after a colon — there is no separate edge for it.

Worth knowinglowerCamelCase by convention. Model usage-first; reach for a definition when a pattern recurs.

Attribute

attribute flowRateLpm : Real;

A value a thing carries. No independent existence — it belongs to whatever declares it.

Item

item def StartCommand;
item received : StartCommand;

Something that flows or is exchanged — a message, a payload, a physical object.

Worth knowingAn accepted payload is an item, never an attribute.

Port

part def PumpController {
  port commandPort : CommandInterface;
}

A named hole in the box, drawn as a small square on the border where something crosses.

Worth knowingPorts are what make a fact observable from outside. Name them and the interface becomes testable.

Compartments

part def PumpController {
  attribute maxFlowLpm : Real;
  port commandPort : CommandInterface;
}

Members shown inside the box, grouped by kind under a dividing rule.

Behavior

What the system does. Every behavioral usage is the same rounded rectangle — accept and send add a marker rather than changing shape.

Action

action 'Check Coolant Level' { out levelOk : Boolean; }

A step. Rounded corners distinguish behavior from structure.

Worth knowingAn action with no declared output still gets a performed flag — but that only tells you the step ran.

Accept action

action 'Await Start'
  accept cmd : StartCommand via controller.commandPort;

A waiting point. The same rounded rectangle as any action, with a filled marker at the top right — notched on its left, for something arriving.

Worth knowingNot the ribbon outline from SysML v1. In v2 every usage is the same rectangle; only the marker changes. Every accept is a place a harness can push.

Send action

action 'Raise Alarm'
  send new LowLevelAlarm() via controller.alarmPort to operator;

Emitting something across the boundary. The mirror of accept — the marker comes to a point on its right instead of being notched on its left.

Use case

use case 'Set Desired Temperature' {
  subject controller : PumpController;
  actor operator : Operator;
}

A goal an actor wants to achieve, described from outside the thing that delivers it. The subject and actors are declared parameters, shown in compartments — not shapes of their own.

Worth knowingName it for the goal, not the system function. "Set Desired Temperature" is something an operator wants; "Maintain Coolant Flow" is something the system does, which is a behavior rather than a use case. There is also no separate actor symbol: an actor is a parameter exactly as the subject is, and each either subsets an existing part usage or is typed by a part def.

Calculation definition

calc def FlowMargin {
  in actual : Real;
  in minimum : Real;
  return margin : Real = actual - minimum;
}

A reusable calculation: named inputs, a returned value, and the expression that produces it.

Worth knowingA definition, so square corners — the same box a calc usage gets, minus the rounding.

Calculation usage

calc flowMargin : FlowMargin {
  in actual = primaryPump.flowRateLpm;
  in minimum = 80.0;
  return margin : Real = actual - minimum;
}

One application of a calculation, with its inputs bound to real values and its return carrying the expression that produces the result.

Worth knowingThe return is not optional, and neither is its expression — a calculation that names a result without saying how it is computed produces nothing. Without a return at all it is just an action.

Succession

first 'Check Coolant Level' then 'Start Pump';

Ordering. B follows A. Drawn with an open arrowhead — two strokes, not a filled triangle.

Worth knowingIt says nothing about which of A's effects are still true while B runs. That is a held state, and it must be declared.

Decision

first 'Check Coolant Level' then levelCheck;
decide levelCheck;
if 'Check Coolant Level'.levelOk then 'Start Pump';
else 'Raise Low Level Alarm';

One branch runs. Guards become assume clauses in the derived requirement.

Worth knowingA branch binds to the member immediately before it, so the if/else must directly follow the decide.

Merge

merge resume;
first 'Raise Low Level Alarm' then resume;
first resume then 'Log Flow Rate';

The same diamond, carrying a filled diamond inside it, bringing alternative paths back together. One edge out instead of several.

Fork and join

fork monitor;
first 'Start Pump' then monitor;
first monitor then 'Log Flow Rate';
first monitor then 'Update Display';
join monitorJoin;

All branches run. A thin filled bar, not a diamond — nothing chooses between the branches.

Worth knowingA state machine is in one state at a time, so a tool has to serialize a fork into an order you never stated.

Terminate

action 'End Generation' terminate;

The behavior stops here rather than this path reaching a normal end. A circled X, drawn as a node.

Worth knowingIt needs no annotation of its own. Whether the ending is a failure or an early stop is read from the routes that reach it — if every one passes through an exception, it is a failure.

State

part def CoolantPump {
  exhibit state pumpStates {
    state off;
    state running {
      entry action send new Started() via statusPort;
    }
  }
}

A condition that persists while something happens. States are exhibited by a part, and carry entry, do and exit actions.

Worth knowingThe use case is in a state; the subject holds other states. The second kind is never inferred.

Transition

transition first start then off;
transition first off accept cmd : StartCommand then running;
transition first running accept when temperature < 40.0 then off;
transition first running accept after 30 [s] then off;

Movement between states, naming what fires it. Four kinds of trigger: an item arriving, a condition becoming true, an absolute time, or an elapsed duration.

Worth knowingThere is no Signal in SysML v2 — that is UML. What is sent and accepted is an item, so a trigger payload is always an item type.

Start and done

first start then 'Check Coolant Level';
first 'Start Pump' then done;

Two different shapes. Start is a filled disc; done is a filled disc inside a ring.

Worth knowingWorth telling apart at a glance — "the flow ended" and "the flow began" should never look alike on a diagram.

Requirements and verification

What must be true, and how anyone would know.

Requirement

requirement <'R-001'> flowRateRequirement {
  subject pump : CoolantPump;
  require constraint { actualFlowLpm >= minimumFlowLpm }
}

An obligation over a subject, carrying assume and require constraints.

Worth knowingThe prose is context. The Boolean expressions are the deliverable.

Constraint

constraint def FlowInRange {
  in f : Real;
  attribute withinLimits : Boolean = f >= 80.0 and f <= 140.0;
}

A Boolean expression with named parameters, declared once and reused.

Worth knowingThis is what turns a bare presence check into something worth checking.

Satisfy

satisfy flowRateRequirement by primaryPump;

A claim that a design element meets a requirement. Dashed, with a keyword on the edge.

Verify

verification def FlowRateTest {
  subject pump : CoolantPump;
  objective flowObjective {
    verify flowRateRequirement;
  }
}

A case that settles whether a requirement was met.

Worth knowingEvery requirement should be verified by at least one case. Mechanical to check once both exist.

Relationships

The edges, and the decorations that distinguish them. Getting these wrong is the most common SysML v2 error.

Feature typing

part def Pump;
part coolantPump : Pump;

A usage is defined by a definition. A hollow triangle with two dots stacked behind it, pointing at the definition.

Worth knowingThe two dots are what distinguish it from plain specialization. Different relationship, different decoration.

Specialization

part def CoolantPump :> Pump;

A kind-of relationship between definitions. A bare hollow triangle points at the more general type.

Worth knowingThis is what makes classification inherit — and what semantic metadata implies behind a keyword.

Subsetting

part backupPump :> ThermalLoop::coolantPump;

A usage that is a subset of another usage — one particular element rather than a shape that recurs.

Worth knowingUse : for a definition and :> for a usage. Swapping them is an error in any validator, not a style choice.

Redefinition

attribute maxFlowLpm redefines
  Pump::maxFlowLpm = 140.0;

Replacing an inherited feature rather than adding one. The triangle, plus a crossbar in front of it.

Worth knowingThe redefines keyword has an operator shorthand, :>> — you will meet it inside flow ends and parameter redeclarations.

Composite membership

part def ThermalLoop {
  part coolantPump : CoolantPump;
}

The owner owns the part outright. A filled diamond at the owning end.

Reference membership

part def ThermalLoop {
  ref part operator : Operator;
}

The owner refers to something it does not own. The same diamond, hollow.

Worth knowingFilled means composite, hollow means reference. It is the difference between having and pointing at.

Dependency

dependency from flowRateRequirement to primaryPump;

A general trace between elements, where nothing stronger applies.

Usage-focused and definition-focused

The same system, modeled two ways. Which you reach for is the biggest structural decision in a SysML v2 model, and it is not a style preference.

Usage-focused
«part»thermalLoop«part»coolantPump«part»impeller
Definition-focused
«part def»ThermalLoopcoolantPump«part def»CoolantPump

Usage-focused

part thermalLoop {
  part coolantPump {
    part impeller;
  }
}

A part has a part has a part. Nothing is declared as a type first — you write the thing you actually have, nested to the depth the system actually goes.

The advantage is speed. You can prototype a structure in minutes and reshape it just as fast, because there is no separate layer of definitions to keep in step. For early architecture, trade studies, and anything you expect to throw away, this is usually the right starting point.

Definition-focused

part def CoolantPump {
  part impeller : Impeller;
}

part def ThermalLoop {
  part coolantPump : CoolantPump;
}

A definition declares a kind of thing, and usages are typed by it. This is the shape a SysML v1 model has, so it is the one most people arrive already fluent in.

It earns its keep when a pattern repeats. If a program has forty pumps that are genuinely the same kind of pump, one definition is worth far more than forty independently nested usages — change it once and every usage follows.

Model usage-first, and introduce a definition when a pattern earns one. The question is not which style is correct, but whether the thing you are pointing at is one particular element or a shape that recurs. Reaching for definitions before you know which is which produces a type hierarchy nobody needed.

Coming from SysML v1

A SysML v1 requirement maps to a SysML v2 requirement usage, not a requirement definition. The instinct to reach forrequirement def is the v1 habit misfiring — a v1 requirement is a particular obligation on a particular subject, which is a usage. Reach for requirement def only when you have a genuine template that several requirements will be typed by.

Missing something you reach for often? It is one entry in a data file — tell me on LinkedIn and it goes in.