Concept: Requirements¶
Requirements in tg_model are executable packages — not just text. Each Requirement
subclass owns parameters, attributes, and constraints using the same surface as a Part.
The difference is that a Requirement also carries a model.doc(...) “shall” statement
and participates in allocation wiring.
Composing requirement packages¶
Use model.composed_of(name, ChildType) to build a hierarchy:
from unitflow.catalogs.si import kg, m
from tg_model import Requirement
class PayloadReq(Requirement):
@classmethod
def define(cls, model):
model.name("payload_req")
model.doc("Design payload mass shall not exceed structural envelope.")
scenario = model.parameter("scenario_payload_kg", unit=kg)
envelope = model.parameter("envelope_payload_kg", unit=kg)
margin = model.attribute("payload_margin_kg", unit=kg, expr=envelope - scenario)
model.constraint("payload_margin_non_negative", expr=margin >= 0 * kg)
class RangeReq(Requirement):
@classmethod
def define(cls, model):
model.name("range_req")
model.doc("Design mission range shall not exceed modeled envelope.")
scenario = model.parameter("scenario_range_m", unit=m)
envelope = model.parameter("envelope_range_m", unit=m)
margin = model.attribute("range_margin_m", unit=m, expr=envelope - scenario)
model.constraint("range_margin_non_negative", expr=margin >= 0 * m)
class L1MissionReqs(Requirement):
@classmethod
def define(cls, model):
model.name("l1_mission_reqs")
model.doc("Level-1 mission closure requirements.")
model.composed_of("payload", PayloadReq)
model.composed_of("range", RangeReq)
L1MissionReqs owns both children. After instantiate, slots are accessible at
cm.root.reqs.payload.scenario_payload_kg etc.
Mounting requirements on a System¶
Use model.composed_of(name, RequirementType) on a System to mount the requirement tree,
then model.allocate(req_ref, part_ref, inputs={...}) to wire values in:
from unitflow.catalogs.si import kg, m
from tg_model import Part, System
class Aircraft(Part):
@classmethod
def define(cls, model):
model.name("aircraft")
model.parameter("max_payload_kg", unit=kg)
model.parameter("max_range_m", unit=m)
class MissionProgram(System):
@classmethod
def define(cls, model):
model.name("mission_program")
scenario_payload = model.parameter("scenario_payload_kg", unit=kg)
scenario_range = model.parameter("scenario_range_m", unit=m)
aircraft = model.composed_of("aircraft", Aircraft)
reqs = model.composed_of("reqs", L1MissionReqs)
model.allocate(reqs.payload, aircraft, inputs={
"scenario_payload_kg": scenario_payload,
"envelope_payload_kg": aircraft.max_payload_kg,
})
model.allocate(reqs.range, aircraft, inputs={
"scenario_range_m": scenario_range,
"envelope_range_m": aircraft.max_range_m,
})
model.allocate(req_ref, target_ref, inputs={...}) takes:
req_ref— aRequirementRefpointing to the package to satisfy (obtained frommodel.composed_ofor dot-navigation into a composed tree)target_ref— aPartRefor similar ref to the design element being allocated toinputs— adict[str, AttributeRef]mapping eachparametername declared in the requirement class to the Part slot that provides the value
Reading constraint results¶
After evaluate, requirement constraints appear in RunResult.constraint_results
tagged with requirement_path and allocation_target_path:
cm = instantiate(MissionProgram)
result = cm.evaluate(inputs={
cm.root.scenario_payload_kg: 45_000 * kg,
cm.root.aircraft.max_payload_kg: 50_000 * kg,
cm.root.scenario_range_m: 8_000_000 * m,
cm.root.aircraft.max_range_m: 9_000_000 * m,
})
print("Overall passed:", result.passed)
for cr in result.constraint_results:
print(
f"{cr.name}: {'PASS' if cr.passed else 'FAIL'}"
f" requirement={cr.requirement_path}"
f" target={cr.allocation_target_path}"
)
Filter by requirement path to get per-package results:
payload_results = [
cr for cr in result.constraint_results
if cr.requirement_path and "payload" in cr.requirement_path
]
Available methods inside Requirement.define()¶
Method |
Description |
|---|---|
|
Human-readable identifier. Required once. |
|
“Shall” statement. Required once. Requirement-only. |
|
Bindable input slot. Wired via |
|
Derived value. |
|
Pass/fail check. |
|
Nested child requirement package. |
|
External provenance (standard, clause, URI). |
|
Traceability edge from a node to a citation. |