Skip to content

Flowchart models (YAML, no code)

Many process models are a flowchart: entities arrive, queue for resources, are served, are routed on, and leave. SimulSI can build those from a YAML file, which works everywhere a model is expected - simulsi run, whatif, experiment configs, the dashboard (simulsi ui --model clinic.yaml) and the optimiser.

simulsi run examples/flowcharts/clinic.yaml
simulsi whatif examples/flowcharts/clinic.yaml --presets
simulsi whatif examples/flowcharts/clinic.yaml --vary doctors=2,3,4 --vary arrival_mean=3,5

Example

flow:
  name: clinic
  duration: 600          # run length (time units of your choice)
  warmup: 60
  parameters:            # tunable values; refer to them as $name
    doctors: {default: 3, low: 1, description: doctors on shift}
    arrival_mean: 5.0
    lab_share: {default: 0.3, kind: probability}
  resources:
    nurse: 2
    doctor: $doctors
  sources:
    - name: patient
      interarrival: {distribution: exponential, mean: $arrival_mean}
      next: triage
  stations:
    triage: {resource: nurse, service: {distribution: triangular, low: 2, mode: 4, high: 8},
             next: consult}
    consult:
      resource: doctor
      service: {distribution: lognormal, mu: 2.5, sigma: 0.4}
      patience: {distribution: exponential, mean: 90}   # leaves if not seen in time
      next: {lab: $lab_share, exit: rest}             # random routing
    lab: {delay: 10, next: exit}
  presets:
    extra_doctor: {doctors: 4}

From Python:

from simulsi.flowchart import load_flowchart

model = load_flowchart("""
flow:
  name: shop
  duration: 480
  parameters: {clerks: 2}
  resources: {clerk: $clerks}
  sources: [{name: customer, rate: 0.8, next: till}]
  stations: {till: {resource: clerk, service: {distribution: exponential, mean: 2}, next: exit}}
""")
print(model.simulate(seed=1).metrics["resource.clerk.utilization"])
print(model.evaluate({"clerks": 3}, metric="entity.customer.time_in_system.mean"))

Reference

Top level (under flow:): name, description, version, duration, warmup, parameters, resources, sources, stations, sinks, presets, outputs. Unknown keys are errors, so typos are caught.

parameters: name: value (kind inferred) or name: {default, kind, low, high, unit, description}. Any value elsewhere written as $name is replaced by the parameter's value for each run.

resources: name: capacity or name: {capacity, discipline, schedule, period}. discipline is fifo, lifo or priority; schedule is a list of [time, capacity] rows (shifts), repeating every period.

sources (a list): name, entity (type name, default: the source name), exactly one of interarrival (a distribution or number), rate (Poisson arrivals per time unit) or rate_table ([[time, rate], ...] with an optional period), optional limit, and next.

stations: either resource + service (with optional units - how many units to hold - priority and patience), or delay (time passes with no resource). Durations are numbers or distribution specs.

Two more kinds of station:

  • batch: add batch: 4 (or batch: {size: 4, timeout: 30}) to a station. Entities wait until the group is complete (or the timeout passes since the first one arrived), then the step runs once for the whole group: one oven load, one shuttle trip. Afterwards each entity continues on its own. Metric: station.<name>.batch_size.*.
  • parallel (split/join): parallel: {name: step, ...} plus next. Each branch is a resource + service or delay step; an entity runs all branches at the same time and moves on when the slowest finishes (blood test and X-ray, paperwork and inspection). Metric: station.<name>.<branch>.visits.
  stations:
    tests:
      parallel:
        blood: {resource: lab, service: {distribution: exponential, mean: 20}}
        xray: {resource: radiology, service: 15}
      next: consult
    shuttle: {delay: 25, batch: {size: 12, timeout: 20}, next: exit}

next: a station or sink name, or a mapping {name: probability}; one entry may be rest for whatever probability is left. Sinks are exit plus any names listed in sinks; entities that run out of patience go to the abandoned sink.

Metrics (besides the usual resource metrics): entity.<type>.time_in_system.*, station.<name>.visits, station.<name>.abandoned, sink.<name> and route.<station>.<destination>. Default outputs are each entity type's mean time in system and each resource's utilization and mean wait.

Flowchart files are data: they can only create the building blocks above and registered distributions, never run code. For anything more (state-dependent logic, custom metrics), write a Python model - the YAML keys map one-to-one onto sim.resource, sim.request, Router and arrivals.