Execution Pipeline (Compile -> Instantiate -> Graph -> Evaluate)¶
This is the canonical flow for ThunderGraph Model.
1) Compile types¶
Call SomeSystem.compile() (or let helper APIs call compile implicitly).
What happens:
define(cls, model)records nodes/edges intoModelDefinitionContextdeclarations are validated
child part types and requirement block types are compiled recursively
a cached compiled artifact is stored on the class
Output: class-level compiled artifact (definition data), not an instance topology.
2) Instantiate a configured topology¶
Call instantiate(SomeSystem) to get ConfiguredModel. Equivalent: SomeSystem.instantiate() when the root type is a System subclass.
What happens:
builds concrete
PartInstance,PortInstance, andValueSlotobjectsresolves structural connections
resolves allocations and references
creates registries by path and stable id
freezes topology (no structural mutation afterward)
Output: one immutable configuration-scoped topology.
2a) Default run path: ConfiguredModel.evaluate (recommended)¶
Call configured_model.evaluate(inputs={slot: Quantity, ...}) with handles (ValueSlot) on that model. The first call compiles the dependency graph (cached on the instance), optionally runs validate_graph, then runs the synchronous evaluator. Subsequent calls reuse the same graph. This is the low-ceremony path documented in the user Quickstart and FAQ.
3) Compile dependency graph¶
Call compile_graph(configured_model).
What happens:
creates bipartite value/compute graph
adds handlers for expressions, rollups, external compute, solve groups, constraints
encodes dependency edges in evaluation order direction
Output: DependencyGraph + compute_handlers.
4) Validate graph (optional but recommended)¶
Call validate_graph(graph, configured_model=cm).
What happens:
checks cycles and orphaned compute
checks rollups and solve-group integrity
runs optional external binding validation hooks
Output: ValidationResult (pass/fail + failures list).
5) Evaluate one run (explicit pipeline)¶
Create fresh RunContext, then run Evaluator(graph, compute_handlers).evaluate(...)
(or .evaluate_async(...) for async external backends). If you already used ConfiguredModel.evaluate (step 2a), you are not required to do steps 3–5 separately unless you need the explicit objects.
What happens:
input parameters are bound into context
nodes execute in topological order when dependencies are ready
realized values and failures are stored in
RunContextconstraint results are collected into
RunResult
Output: RunResult + per-slot state in RunContext.
Requirement acceptance path¶
Requirements become executable checks when:
requirement has acceptance expression (
expr=orrequirement_accept_expr)requirement is allocated (
allocate(...))required inputs are bound (
allocate(..., inputs=...)for requirement-input patterns)
Then acceptance checks are compiled into the same graph/evaluation pass.
Behavioral path¶
Behavior dispatch APIs (dispatch_event, dispatch_decision, etc.) operate on RunContext
and optional BehaviorTrace. They do not mutate ConfiguredModel topology.
One sentence summary¶
Compile declarations once, instantiate topology once per configuration, evaluate many times with fresh run contexts.