Skip to content

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:

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
2.5

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)
ideal_capacity MaxFlow
supported_load MaximumSupportedDemand
under_failures TrafficMatrixPlacement

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.