Skip to content

7. MVP File Formats

Overview

A scenario is a directory of JSON files plus one CSV train schedule. The root scenario.json points to the other files through a references map. The authoritative, runnable examples live under Data/examples/ (e.g. ten_trains_two_days_baseline/); the snippets below are taken from there.

Field names are defined by the Pydantic input DTOs in contexts/configuration/application/dtos/ and the domain models in contexts/configuration/domain/models/.

JSON Format

scenario.json

The root file. It carries the id/dates and selection strategies, and references the other files by relative name via references:

{
  "id": "test_scenario_01",
  "description": "DAC retrofit simulation with 2 locos, 2 collection tracks, 2 workshops with 2 bays",
  "version": "1.0.0",
  "start_date": "2025-12-01T00:00:00+00:00",
  "end_date": "2025-12-11T00:00:00+00:00",
  "collection_track_strategy": "first_available",
  "retrofit_selection_strategy": "least_occupied",
  "retrofitted_selection_strategy": "least_occupied",
  "workshop_selection_strategy": "least_occupied",
  "parking_selection_strategy": "least_occupied",
  "references": {
    "locomotives": "locomotive.json",
    "process_times": "process_times.json",
    "routes": "routes.json",
    "trains": "train_schedule.csv",
    "topology": "topology.json",
    "tracks": "tracks.json",
    "workshops": "workshops.json"
  }
}

Strategy fields accept SelectionStrategy values: first_available, least_occupied, round_robin, best_fit, random. The scenario also supports additional optional fields (parking thresholds, locomotive strategies, and a task_priorities map) — see scenario.py.

topology.json

Defines the physical network: nodes and edges, where each edge has a length in meters:

{
  "nodes": [1, 2],
  "edges": {
    "collection1": {"nodes": [1, 2], "length": 500.0},
    "track_19": {"nodes": [1, 2], "length": 169.0}
  }
}

tracks.json

A tracks array. Each track has an id, optional name, the edges it occupies, and a type (collection, retrofit, retrofitted, parking, workshop, mainline, rescource_parking):

{
  "tracks": [
    {"id": "collection1", "name": "Collection track", "edges": ["collection1"], "type": "collection"},
    {"id": "retrofit", "edges": ["retrofit"], "type": "retrofit"},
    {"id": "parking1", "name": "Parking track", "edges": ["parking1"], "type": "parking"}
  ]
}

workshops.json

Optional metadata plus a workshops array. Each workshop has id, name, retrofit_stations (number of bays), and the track it sits on:

{
  "metadata": {"description": "Workshop configurations", "version": "1.0.0"},
  "workshops": [
    {"id": "WS_01", "name": "First workshop", "retrofit_stations": 2, "track": "track_WS1"}
  ]
}

locomotive.json

Optional metadata plus a locomotives array. Each locomotive has id, name, and a home track:

{
  "metadata": {"description": "Locomotive configurations", "version": "1.0.0"},
  "locomotives": [
    {"id": "LOCO_01", "name": "Shunting loco", "home track": "track_19"}
  ]
}

routes.json

A routes array. Each route has an id, a duration in minutes, and a path (ordered list of edge/track ids the route traverses):

{
  "routes": [
    {"id": "track_19_collection1", "duration": 60.0, "path": ["track_19", "Mainline", "collection1"]},
    {"id": "track_19_retrofit", "duration": 5.0, "path": ["track_19", "retrofit"]}
  ]
}

process_times.json

Timing configuration (minutes) for operations, keyed by coupler type where relevant:

{
  "wagon_retrofit_time": 60.0,
  "train_to_hump_delay": 0.0,
  "wagon_hump_interval": 0.0,
  "screw_coupling_time": 2.0,
  "screw_decoupling_time": 3.0,
  "dac_coupling_time": 0.5,
  "dac_decoupling_time": 0.5
}

CSV Format

train_schedule.csv

The train schedule has one row per wagon. The delimiter is auto-detected: if the header line contains a semicolon the file is read as semicolon-delimited (as in the bundled examples), otherwise comma-delimited. Arrival times are ISO 8601 timestamps (timezone-aware). Columns:

train_id;wagon_id;arrival_time;length;is_loaded;needs_retrofit;Track
T1;W0001;2025-12-01T06:00:00+00:00;15.9;False;True;collection
T1;W0002;2025-12-01T06:00:00+00:00;16.1;False;True;collection
T2;W0003;2025-12-01T08:00:00+00:00;20.4;False;True;collection
Column Description
train_id Identifier of the arriving train
wagon_id Unique wagon identifier
arrival_time ISO 8601 timestamp of arrival (timezone-aware)
length Wagon length in meters
is_loaded Whether the wagon is loaded (loaded wagons are rejected)
needs_retrofit Whether the wagon needs DAC retrofit
Track Arrival track type (e.g. collection)

Validation

All input files are parsed into Pydantic DTOs/models in the Configuration context and run through the validation pipeline (see ADR-002).

Examples

Runnable examples are in the Data/examples/ directory of the repository. The tutorial walks through each file using the ten_trains_two_days_baseline scenario.