Concept: External Compute (Concrete Binding)¶
Use external compute when a value comes from another tool or model.
Example¶
from unitflow import Quantity, kg
from tg_model import Part, System
from tg_model.execution import Evaluator, RunContext, compile_graph, instantiate
from tg_model.integrations import ExternalComputeBinding, ExternalComputeResult
class MassTool:
@property
def name(self):
return "mass_tool"
def compute(self, inputs):
# inputs values are unitflow Quantity objects
dry = inputs["dry"]
payload = inputs["payload"]
return ExternalComputeResult(value=dry + payload, provenance={"tool": self.name})
class VehicleMassAnalysis(Part):
@classmethod
def define(cls, model):
dry = model.parameter_ref(Vehicle, "dry_kg")
payload = model.parameter_ref(Vehicle, "payload_kg")
total = model.attribute(
"total_kg",
unit=kg,
computed_by=ExternalComputeBinding(
external=MassTool(),
inputs={"dry": dry, "payload": payload},
),
)
model.constraint("non_negative", expr=(total >= Quantity(0, kg)))
class Vehicle(System):
@classmethod
def define(cls, model):
model.parameter("dry_kg", unit=kg, required=True)
model.parameter("payload_kg", unit=kg, required=True)
model.part("mass_analysis", VehicleMassAnalysis)
cm = instantiate(Vehicle)
graph, handlers = compile_graph(cm)
ctx = RunContext()
result = Evaluator(graph, compute_handlers=handlers).evaluate(
ctx,
inputs={
cm.root.dry_kg.stable_id: Quantity(10000, kg),
cm.root.payload_kg.stable_id: Quantity(5000, kg),
},
)
print(result.passed)
print(ctx.get_value(cm.root.mass_analysis.total_kg.stable_id))
Same run with evaluate (recommended)¶
After instantiate, you can skip manual compile_graph / Evaluator and pass slot handles:
result = cm.evaluate(
inputs={
cm.root.dry_kg: Quantity(10000, kg),
cm.root.payload_kg: Quantity(5000, kg),
},
)
print(result.passed)
See Quickstart (Concrete Example) and FAQ.
Input and output contract¶
Binding keys: The string keys in
ExternalComputeBinding(..., inputs={"dry": ..., "payload": ...})are the names yourcompute(self, inputs)receives. Values areunitflow.Quantityinstances with compatible units for the linked slots.Single output: Return
ExternalComputeResult(value=...)with one quantity; the compiler wires it to the attribute that usescomputed_by=.Multiple outputs: Return
ExternalComputeResult(value={"route_a": q1, "route_b": q2})and supply matchingoutput_routeson the binding so each name maps to an attribute ref (see API docs forlink_external_routes).Static checks: If the external object implements
validate_binding, passconfigured_model=intovalidate_graphso units and routes can be checked beforeevaluate.Ownership rule: keep root
Systemtypes structural and putcomputed_by=attributes and related constraints on the owningPartor requirement package.
Rule of thumb¶
If logic is simple and local, keep it as expression math.
If logic depends on external tools/data, bind external compute explicitly.