Calculations#
Role in SysML v2#
A calculation definition (calc def) is a kind of action definition that produces a single
value, its result. It takes in parameters, and its return parameter declares the result’s
type and the expression that computes it. An action describes steps that happen over time; a
calculation describes a formula. That makes it the place for a formula that several parts,
actions or transitions share.
calc def Acceleration {
in p : PowerValue;
in m : MassValue;
in v : SpeedValue;
return : Real = p / (m * v);
}The result may also be given a name: return a : Real = p / (m * v);. It may equally be written
as the last expression of the body, which is the spec’s other spelling for the same thing:
calc def Acceleration {
in p : PowerValue;
in m : MassValue;
in v : SpeedValue;
return : Real;
p / (m * v)
}A calculation may name intermediate values, and call another calculation:
calc def Area {
in w : Real;
in h : Real;
attribute scale : Real = 2.0; // a local of the generated function
return : Real = w * h * scale;
}Mapping to code#
A calc def becomes a free function in the namespace of its package: an inline function in C++
(-l cppx), a module-level def in Python (-l python). The in parameters become the
function’s parameters, in the order written, and the return expression becomes its body.
Parameter and result types map as they do for attributes: Integer
becomes int, Real becomes double in C++ and float in Python, and Boolean becomes bool.
Because the result is an ordinary function, you call a calculation by name, with its arguments
in parentheses and in parameter order: Twice(steps). No instance is needed, and the order the
calculations are written in does not matter — one may call another that comes later in the file.
A calc def written inside a part def belongs to that part: it becomes a static member
function in C++ and a @staticmethod in Python. Everything the part owns can call it — its
attribute values, its actions and its state machine.
A calculation usage applies a calculation to values bound at the usage, and computes its result when it is performed:
action run {
calc twice : Scale {
in x = 21;
}
first start;
then twice; // performing it computes the result
then assign scaled := twice.result;
then done;
}A usage that names no definition states its own result instead — calc thrice { in v = 14; return : Integer; v * 3 }.
A part may declare a usage too, beside its attributes and actions. Performing it computes the result the part then holds:
part def Runner {
calc onPart : Scale {
in x = 10;
}
}Example#
SysML v2 source code:
package HeaterControl {
private import ScalarValues::*;
calc def Twice {
in x : Integer;
return : Integer = x * 2;
}
calc def InRange {
in v : Real;
in lo : Real;
in hi : Real;
return inside : Boolean = v >= lo and v <= hi;
}
part def Heater {
attribute temp : Real default 21.5;
attribute steps : Integer default 3;
attribute comfortable : Boolean := InRange(temp, 19.0, 23.0);
action boost {
first start;
then assign steps := Twice(steps);
then done;
}
}
}C++ source code (excerpt):
inline bool InRange(double v, double lo, double hi) { return v >= lo and v <= hi; }
inline int Twice(int x) { return x * 2; }
// in Heater::init()
comfortable = InRange(temp, 19.0, 23.0);
// in the boost action
steps = Twice(steps);Python source code (excerpt):
def Twice(x: int) -> int:
return x * 2
def InRange(v: float, lo: float, hi: float) -> bool:
return v >= lo and v <= hi
# in Heater.init()
self.comfortable = InRange(self.temp, 19.0, 23.0)
# in the boost action
self._part.steps = Twice(self._part.steps)An attribute whose value calls a calculation (
:=or=) is computed once, in the generatedinit(). It is not re-evaluated whentempchanges later. To recompute it,assignit in an action or on a transition.
Where a calculation can be called#
| Called from | C++ | Python |
|---|---|---|
The value of an attribute (=, :=) |
Yes | Yes |
assign in an action |
Yes | Yes |
| A state machine: guard, entry action, transition effect | Yes | Yes |
| Another calculation | Yes | Yes |
In a state machine a calculation reads like any other expression:
state Cold { entry assign steps := Twice(steps); }
transition first Cold if Twice(steps) > 30 then Hot;Not supported yet#
-
A result type that is not declared. SysML lets the result type be inferred from the expression; the generator does not infer it, because C++ needs the type at the declaration. Say what the calculation computes:
calc def Sum { in a : Real; in b : Real; a + b } // W3171 calc def Sum { in a : Real; in b : Real; return : Real; a + b } // write this instead -
A visibility keyword before the result expression.
MemberPrefixon aResultExpressionMember(private x * x) is not accepted.
See also Actions and the Missing Features list.