Chapter 2. Tutorial: Modeling the State Structure of a Home with SysML v2
This tutorial introduces the most important state structure modelling concepts of SysML v2:
- data types and attributes (or data properties), including predefined data types, such as String and Integer, as well as predefined quantity value types from the International System of Quantities (ISQ), such as ISQ::AreaValue or ISQ::ElectricCurrentValue,
- part types and part properties,
- connection types and connection properties,
- item types and item properties,
- port types and port properties,
- interface types and interface properties.
The running example of the tutorial (inspired by an example presented by Michael Jastram) describes a home as a system consisting of
- rooms, which are connected with each other by doors, and
- devices, which are connected to power outlets of the home's electric grid via interfaces connecting their ports.
We are going to model a simple type of home consisting of a bed room, a living room equipped with a television, a kitchen equipped with a dishwasher, and a bath room.
1 Making a Sketch of a Model
We can make a quick model sketch by not considering the ranges (or the typing) of properties.
1.1 Modeling Rooms and Devices as Parts of a Home
In a first step we just define the attribute size and the type of rooms as well as the type of devices a home consists of. We can model both the rooms and devices of a home as parts or components by defining corresponding part properties for the part type Home:
part def Home { attribute size; part bedRoom; part livingRoom; part kitchen; part bathRoom; part tv; part dishwasher; }
This declaration defines a part type Home with the six part properties bedRoom, livingRoom, kitchen, bathRoom, tv and dishwasher, such that for a home h, the expressions h.bedRoom, h.livingRoom, h.kitchen, and h.bathRoom denote the four rooms, while h.tv and h.dishwasher denote two devices, h consists of.
Notice that any system may be a subsystem (or part) of a larger system. For instance, a home may be a part of a city. Therefore, in SysML v2, systems are defined as part types.
1.2 Modeling Connections between Rooms
We may also want to describe in our model, which rooms are connected to each other. The simplest way of expressing this in SysML v2 is by simply stating which room is connected to which other room in the following way:
part def Home { attribute size; part bedRoom; part livingRoom; part kitchen; part bathRoom; part tv; part dishwasher; connect livingRoom to bedRoom; connect livingRoom to kitchen; connect livingRoom to bathRoom; }
The above connection statements are actually shorthand forms of the full connection property definitions shown below.
1.3 Modeling Power Outlets and Device Sockets as Ports
After describing how a home is composed of rooms and devices and how its rooms are connected to each other in a SysML v2 state structure model, we extend this model by adding power outlets in rooms and a number of electrical devices connected to power outlets. Both the power outlets and the device sockets are modeled in the form of ports, which are special objects that represent connection points and can be interconnected by interfaces. Likewise, we model both a water spigot bank in the kitchen and the water inlet of the dishwasher as ports.
Ports have directed (output or input) properties and can be connected via an interface for enabling transfers of physical quantities or signals, if their types match in the sense that they have the same directed properties, but with inverse direction.
The resulting model defines port properties (of part properties) as well as interface properties, as shown in the following sketch:
part def Home { attribute size; part bedRoom; part livingRoom { port outlet { out power;} } part kitchen { port outlet { out power;} port spigotBank { out water;} } part bathRoom; part tv { port socket { in power;} } part dishwasher { port socket { in power;} port waterInlet { in water;} } connect livingRoom to bedRoom; connect livingRoom to kitchen; connect livingRoom to bathRoom; interface tv.socket to livingRoom.outlet; interface dishwasher.socket to kitchen.outlet; interface dishwasher.waterInlet to kitchen.spigotBank; }
Notice that the interface connection statements in this model sketch are actually shorthand forms of the full interface property definitions shown in the full model below.
1.4 Adding an Electric Grid as a Component of the Home
We can define a home's electric grid (with 120 V and a maximum current of 32 A) in the form of a part property electricGrid that has two attributes voltage and maxCurrent as well as a many-valued port property outlets. For being able to define a grid with specific voltage and current values, we first need to import the predefined quantity units V and A from the SI library:
public import SI::V; public import SI::A; part def Home { attribute size; part electricGrid { attribute voltage = 120 [V]; attribute maxCurrent = 32 [A]; port outlets[*] { attribute voltage = electricGrid.voltage; attribute maxCurrent; out power; } } part bedRoom; part livingRoom { port outlet :> electricGrid.outlets { redefine maxCurrent = 10 [A]; } } part kitchen { port outlet :> electricGrid.outlets { redefine maxCurrent = 16 [A]; } } part bathRoom; ... }
Notice that the attributes voltage and maxCurrent of electricGrid are bound to the quantity values 120 [V] and 32 [A], and the attributes livingRoom.outlet.voltage as well as kitchen.outlet.voltage are bound to electricGrid.voltage.
Also, in this extended model, the port property outlet defined for the livingRoom and the kitchen now specializes the outlets property of electricGrid as expressed by the symbol :>. This makes sure that both livingRoom.outlet and kitchen.outlet are included in electricGrid.outlets.
The multiplicity * shown enclosed in brackets [*] as a suffix of the port property name electricGrid.outlets indicates that the electricGrid can have zero, one or many outlets. The symbol * is a short form of the multiplicity expression 0..* standing for zero-or-more.
For making sure that the maximum current of power outlets cannot be greater than the maximum current of the electric grid, we add a corresponding constraint in the full model below.
2 Adding the Ranges of Attributes and Part Properties
Since we didn't define a range for the attribute size in the model sketch above, it may have values representing other things than area quantities. In order to prevent this, we have to define the attribute size typed by a suitable data type as its range:
part def Home { attribute size : ISQ::AreaValue; part bedRoom; part livingRoom; part kitchen; part bathRoom; part tv; part dishwasher; }
Notice that the data type AreaValue chosen for typing the attribute size comes from the SysML v2 library ISQ, where it is predefined along with other basic quantity value types and quantity units according to the International System of Quantities. It allows area values such as "92.5 [m^2]".
Since we didn't define a range for the part properties in the model above, they may have values representing neither rooms nor devices. In order to prevent this, we define the part types Room and Device, as well as their subtypes Kitchen and Dishwasher, for typing the part properties of Home:
part def Room { attribute name : String; attribute size : ISQ::AreaValue; port outlet { out power :> ISQ::electricPower;} } part def Kitchen :> Room { port spigotBank { out water : Water;} } part def Device { attribute name : String; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; port socket { in power :> ISQ::electricPower;} } part def Dishwasher :> Device { port waterInlet { in water : Water;} } part def Home { attribute size : ISQ::AreaValue; part bedRoom : Room; part livingRoom : Room; part kitchen : Kitchen; part bathRoom : Room; part tv: Device; part dishwasher: Dishwasher; }
Notice that for some quantity types, such as for voltage and electric power, the ISQ library only defines quantity properties such as ISQ::voltage and ISQ::electricPower, but no corresponding quantity value types (e.g., there is no VoltageValue element in the ISQ library).
3 Defining an Attribute with a Computed Value
We can have the value of the Home::size attribute being computed by adding up the size of all four rooms:
part def Room {...} part def Home { attribute size : ISQ::AreaValue = bedRoom.size + livingRoom.size + kitchen.size + bathRoom.size; part bedRoom : Room; ... }
4 Modeling Involved Objects That Are Not Parts
In SysML v2, objects are called items. Therefore, objects that are not parts in the sense of SysML v2 can be modelled as plain items.
In addition to describing the rooms of a home as its parts, we can also describe other involved objects that are not parts of the home, such as the people that are currently present in the home or the city, in which the home is located, by classifying them as items like so:
part def Room {...} item def Person { attribute name : String; } item def City { attribute name : String; } part def Home { item peoplePresentInHome[*]: Person; item city: City; part bedRoom : Room; ... }
Notice the multiplicity * shown enclosed in brackets [*] as a suffix of the item property name peoplePresentInHome. It indicates that there can be zero, one or many people present in the home. The symbol * is a short form of the multiplicity expression 0..* standing for zero-or-more.
5 Distinguishing between "Composite" and "Referential" Properties
In KerML and SysML v2, properties (or features) are either composite or referential. By default, attributes are referential, while part and item properties are composite. When a part has a value for a composite property, this value represents an occurrence, the life of which ends when the life of the part ends. In other words, the value is destroyed together with the part. Such a life cycle dependency does not hold for referential properties.
For the model fragment in the previous section, this means that the item property city should be declared to be referential because it does not make sense to state that destroying a home implies destroying the city it is located in. On the other hand, the item property peoplePresentInHome may be left as composite (by default), if we want to make the assumption that the people present in a home when it is destroyed are destroyed together with the home resulting in the following corrected model fragment:
part def Room {...} item def Person {...} item def City {...} part def Home { item peoplePresentInHome[*]: Person; ref item city: City; part bedRoom : Room; ... }
6 Adding the Ranges and Multiplicities of Connection Properties
The shorthand syntax for defining connections used in the model sketch above leaves them kind of abstract by not describing their concrete type. We may want to state that rooms are connected via doors. Notice that a door, which is mounted between two rooms of a home, is not just an object, but also a connection between the two rooms (such a connection is called a binary link and its connection type is called an association in UML and KerML/SysML2).
So, we first need to define the binary connection type Door with the two attributes width and height before we can define the (types of) connections between rooms in the form of connection properties typed by Door. Since a room has at least one door to another room, but may also have more than one door connecting it to other rooms, the multiplicity that constrains its number of doors is 1..*. Consequently, the cross multiplicity for both ends of the connection type Door is 1..*, as expressed in the definition of Door in the following model fragment:
part def Room {...} connection def Door { end [1..*] part room1 : Room; end [1..*] part room2 : Room; attribute width : ISQ::LengthValue; attribute height : ISQ::LengthValue; } part def Home { ... connection livingRoom2bedRoom[1] : Door
connect livingRoom to bedRoom; connection livingRoom2kitchen[1] : Door connect livingRoom to kitchen; connection livingRoom2bathRoom[1] : Door
connect livingRoom to bathRoom; }
Notice that the multiplicity 1 defined for the three connection properties livingRoom2bedRoom, livingRoom2kitchen and livingRoom2bathRoom implies that these properties hold exactly one value representing the door that connects the two rooms concerned. This implies that there is exactly one door between the two rooms connected. We could also allow having a second door between two rooms by changing these multiplicities from 1 to 1..2.
7 Adding Port Types and Interface Types
We finally complete the typing of all properties by adding the port and interface types that provide the ranges for port and interface properties.
port def PowerOutletPort { out attribute power :> ISQ::electricPower; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; } part def Room { attribute name : String; attribute size : ISQ::AreaValue; port outlet : PowerOutletPort; } item def Water; port def WaterSpigotBankPort { out item water : Water; } part def Kitchen :> Room { port spigotBank : WaterSpigotBankPort; } part def ElectricGrid { attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; port outlets[1..*] : PowerOutletPort; } port def DeviceSocketPort { in attribute power :> ISQ::electricPower; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; } part def Device { attribute name : String; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; port socket : DeviceSocketPort { redefines maxCurrent = Device::maxCurrent; } } port def DeviceWaterInletPort { in item water : Water; } part def Dishwasher :> Device { port waterInlet : DeviceWaterInletPort; } interface def Socket2OutletInterface { end port socket : DeviceSocketPort; end port outlet : PowerOutletPort; } interface def WaterInlet2SpigotBankInterface { end port waterInlet : DeviceWaterInletPort; end port spigotBank : WaterSpigotBankPort; } part def Home { ... interface tv2PowerOutlet : Socket2OutletInterface connect tv.socket to livingRoom.outlet; interface dishwasher2PowerOutlet : Socket2OutletInterface connect dishwasher.socket to kitchen.outlet; interface dishwasher2SpigotBank : WaterInlet2SpigotBankInterface connect dishwasher.waterInlet to kitchen.spigotBank; }
8 Adding Constraints
For making sure that the voltage of power outlets cannot be different from the voltage of the electric grid and that their maximum current cannot be greater than the maximum current of the electric grid, we can add corresponding constraints in the model element concerned, which is the port property ElectricGrid::outlets:
part def ElectricGrid { attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; port outlets[1..*] : PowerOutletPort { assert constraint { (that as PowerOutletPort).voltage == voltage } assert constraint { (that as PowerOutletPort).maxCurrent <= maxCurrent } } }
Notice that in the constraint definition we use the predefined indexical variable that for referencing the values of the outlets property. Since that has to be casted to the type of the values it references (here, the port type PowerOutletPort), we need to use the cast expression (that as PowerOutletPort)
for being able to access the type's properties (such as the attributes voltage and maxCurrent).
9 The Complete Model
We can finally show the complete model:
public import ScalarValues::String; public import SI::V; public import SI::A; port def PowerOutletPort { out attribute power :> ISQ::electricPower; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; } part def Room { attribute name : String; attribute size : ISQ::AreaValue; port outlet : PowerOutletPort; } item def Water; port def WaterSpigotBankPort { out item water : Water; } part def Kitchen :> Room { port spigotBank : WaterSpigotBankPort; } connection def Door { end [1] part room1 : Room; end [1] part room2 : Room; attribute width : ISQ::LengthValue; attribute height : ISQ::LengthValue; } part def ElectricGrid { attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; port outlets[1..*] : PowerOutletPort { assert constraint { (that as PowerOutletPort).voltage == voltage } assert constraint { (that as PowerOutletPort).maxCurrent <= maxCurrent } } } part def ElectricGrid120V :> ElectricGrid { redefines voltage :> ISQ::voltage = 120 [V]; redefines maxCurrent : ISQ::ElectricCurrentValue = 32 [A]; } port def DeviceSocketPort { in attribute power :> ISQ::electricPower; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; } part def Device { attribute name : String; attribute voltage :> ISQ::voltage; attribute maxCurrent : ISQ::ElectricCurrentValue; port socket : DeviceSocketPort { redefines maxCurrent = Device::maxCurrent; } } port def DeviceWaterInletPort { in item water : Water; } part def Dishwasher :> Device { port waterInlet : DeviceWaterInletPort; } interface def Socket2OutletInterface { end port socket : DeviceSocketPort; end port outlet : PowerOutletPort; } interface def WaterInlet2SpigotBankInterface { end port waterInlet : DeviceWaterInletPort; end port spigotBank : WaterSpigotBankPort; } item def Person { attribute name : String; } part def Home { item peoplePresentInHome[*]: Person; part electricGrid : ElectricGrid120V; part bedRoom : Room {redefines outlet :> electricGrid.outlets;} part livingRoom : Room {redefines outlet :> electricGrid.outlets;} part kitchen : Kitchen {redefines outlet :> electricGrid.outlets;} part bathRoom : Room {redefines outlet :> electricGrid.outlets;} part tv : Device {redefines maxCurrent = 2 [A];} part dishwasher : Dishwasher {redefines maxCurrent = 12 [A];} connection livingRoom2bedRoom[1] : Door
connect livingRoom to bedRoom; connection livingRoom2kitchen[1] : Door connect livingRoom to kitchen; connection livingRoom2bathRoom[1] : Door
connect livingRoom to bathRoom; interface dishwasher2PowerOutlet : Socket2OutletInterface connect dishwasher.socket to kitchen.outlet; interface tv2PowerOutlet : Socket2OutletInterface connect tv.socket to livingRoom.outlet; interface dishwasher2SpigotBank : WaterInlet2SpigotBankInterface connect dishwasher.waterInlet to kitchen.spigotBank; }
Notice that due to a semantic constraint in the SysML v2 spec, port properties are allowed to have only referential (non-composite) properties, therefore the two assert constraint declarations for the property ElectricGrid.outlets must be prefixed with the keyword "ref" for being able to parse this model.