Tutorial¶
A scenario describes a network, its traffic, failure policies and an ordered workflow. Preparation turns it into one read-only graph with one bandwidth unit q, and a run returns typed results (Scenario, preparation and run).
Write a scenario¶
Save this as example.yaml:
seed: 42
network:
nodes: {A: {}, B: {}, C: {}}
links:
- {source: A, target: B, capacity: 10, cost: 1}
- {source: B, target: C, capacity: 10, cost: 2}
failures:
random_link:
modes:
- weight: 1
rules:
- {scope: link, mode: choice, count: 1}
demands:
traffic:
- {source: ^A$, target: ^C$, volume: 4, preset: SHORTEST_PATHS_ECMP}
workflow:
- type: MaxFlow
name: ideal_capacity
source: ^A$
target: ^C$
preset: TE_MAXFLOW_UNLIM
outputs: {min_cut: true, cost_distribution: true}
- type: MaximumSupportedDemand
name: supported_load
demand_set: traffic
- type: TrafficMatrixPlacement
name: under_failures
demand_set: traffic
alpha_from_step: supported_load
failure_policy: random_link
iterations: 20
Each physical link carries traffic in both directions, each with its full capacity (Links, directions and what is enabled). Costs are positive integers (link keys). Volumes and capacities are physical amounts; native bandwidth results are whole units of q, which preparation chooses (Units and the resolution q).
seed makes the random failure draws repeatable (Seeds).
What the other keys mean:
failuresdeclares a failure policy: here, one random link fails per draw (Failures: patterns, cases and states;failures).- A
presetnames a model:SHORTEST_PATHS_ECMPsplits whole units equally among equal-cost next hops at each router;TE_MAXFLOW_UNLIMasks for the largest flow (Routing models and admission). outputsasks for optional results: here the minimum cut and the cost report (Output selection).MaximumSupportedDemandsearches for the largest multiplier alpha of the demand volumes that the network carries in full, until the gap between a feasible and an infeasible alpha is at mostalpha_tolerance, 0.01 by default (Maximum supported demand; MaximumSupportedDemand).alpha_from_stepplaces the demands at the multiplier an earlier MSD step found (Demands: how traffic enters; TrafficMatrixPlacement).failure_policyanditerationsrun that placement over 20 failure draws (Keys common to analysis steps).
Run and inspect¶
ngraph inspect example.yaml
ngraph run example.yaml --output results/
ngraph run example.yaml --stdout --no-results
ngraph run example.yaml --profile --output results/
run writes results/example.results.json. --stdout emits pure JSON, and --profile reports where the run spends its time; diagnostic and step-profile reports go to stderr. The output file is replaced after complete encoding succeeds (Command Line).
Read results¶
The document has metadata, units_report and an ordered steps array. Each step records its normalized question (what it asked) and typed result. The units_report holds q and the run's precision (Results and their units); each failure case's states.converged.totals holds the placement's totals in the converged state (Failures: patterns, cases and states, Demands: how traffic enters).
jq '.steps[] | select(.name == "supported_load") | .result.alpha_feasible.value' results/example.results.json
MSD reports its largest tested feasible alpha and every probe it made; the placement step records that it used that alpha (Maximum supported demand). alpha_feasible is an exact fraction with its value, numerator and denominator; .value prints the number.
jq -c '.units_report.q as $q | .steps[] | select(.name == "under_failures") | .result.cases[]
| {case: .case.id, occurrences: .case.occurrences,
requested: (.states.converged.totals.reference_request_units * $q),
delivered: (.states.converged.totals.delivered_units * $q)}' results/example.results.json
{"case":"baseline","occurrences":0,"requested":10,"delivered":10}
{"case":"failure-000001","occurrences":11,"requested":10,"delivered":0}
{"case":"failure-000002","occurrences":9,"requested":10,"delivered":0}
Totals are in units of q, so the command multiplies them by q for physical bandwidth (Units and the resolution q). The intact chain has physical capacity 10, cut at A→B, and route cost 3. Either single-link failure disconnects A from C. The 20 draws therefore collapse into at most two failure patterns, plus the baseline. occurrences sum to 20; the baseline is not an extra trial (Failures: patterns, cases and states).
Every case asks the same request, so the worst case is the one that delivers least, here either failure (Failures: patterns, cases and states); what a case does not deliver was not admitted or was dropped (Demands: how traffic enters).
To export one step, add --keys under_failures: the whole workflow still runs, and the step keeps its execution order 2 (Filtering Results by Step Names).
Use Python¶
from pathlib import Path
from ngraph import Scenario, prepare, run, write_json
scenario = Scenario.from_yaml(Path("example.yaml").read_text())
prepared = prepare(scenario)
result = run(prepared)
for step in result.steps:
print(step.name, step.step_type)
with open("python-results.json", "w") as destination:
write_json(result, destination)
Results belong to the returned run; topology edits after prepare need a new preparation (Scenario, preparation and run). Library users can prepare selected demand sets and call capacity, place, paths, edge_sensitivity or maximum_supported_demand directly with typed queries (Python API).
Continue with How NetGraph computes, then the examples: Basic Example, Clos Fabric and Bundled Scenarios.