Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

allocate

This notebook introduces allocate, the SysML v2 relationship that assigns a behavioral element to a logical component; after running it you can express which component performs which function.

Chapter 4 nested ApplyHeat inside ToastBread as the usage applyHeat, reachable from Toaster’s own inherited toastBread action (Chapter 1’s perform action toastBread : ToastBread on ToastingSystem). Chapter 1 also gave Toaster a heating part typed by HeatingSystem. allocate connects these two: the component that performs the function, named and pointed at directly, rather than left as an unstated intent.

abstract part def HeatingSystem {
    perform action applyHeat : ApplyHeat;
}

HeatingSystem becomes an abstract logical component that performs ApplyHeat: the perform relationship states, in the model, which component carries the function. This is the logical-component idiom this tutorial uses: an abstract part def that performs an action, not yet realized by any concrete part.

part def Toaster :> ToastingSystem {
    attribute cycleTime : ISQ::DurationValue;
    part heating : HeatingSystem;
    part control : ControlSystem;
    allocation heatAllocation allocate toastBread.applyHeat to heating;
}

The allocation is named (heatAllocation) so model.query() can find it directly, and it is written as a member of Toaster itself, alongside heating: both ends are features the allocation can reach because it lives in the same body — toastBread, the action Toaster inherits from ToastingSystem, and heating, the part declared right beside it.

Both ends of an allocation must resolve to an existing usage. The negative control below allocates from a step that was never declared.

Neg control diagnostics: 'unresolved reference: ToastBread::undefinedStep'

The diagnostic reports an unresolved reference: ToastBread::undefinedStep was never declared, so the allocation’s source usage does not exist.

Allocations: [{'id': 'ToasterDemo::Toaster::heatAllocation', 'type': 'AllocationUsage', 'ends': [['ToasterDemo::ToastingSystem::toastBread', 'ToasterDemo::ToastBread::applyHeat'], ['ToasterDemo::Toaster::heating']]}]
Perform relationships: [{'performer': 'ToasterDemo::ToastingSystem', 'action': 'ToasterDemo::ToastBread'}, {'performer': 'ToasterDemo::HeatingSystem', 'action': 'ToasterDemo::ApplyHeat'}]

find_allocations shows heatAllocation’s real ends: the first is the feature chain toastBread.applyHeat — toastBread, declared on ToastingSystem and inherited by Toaster, then applyHeat, nested inside the ToastBread action — and the second is Toaster::heating, a usage, not HeatingSystem the definition. perform_relationships shows HeatingSystem (the definition Toaster::heating is typed by) performing ApplyHeat: the allocation targets the usage; the performer relationship is stated on its type. Usage-level allocation is exactly this distinction, not a detail to blur past.

The assembled definitions loaded without error, and the query results confirm the allocation’s own ends, not just that a component of the right type performs the function.

Try the chapter exercise in exercises/ch05/exercise.ipynb: allocate your coffee maker’s applyWater step (Brew’s own nested action usage, from Chapter 4) to brewUnit (a usage, not BrewUnit the definition), following the pattern this notebook builds.