Chapter 2: Scenario Configuration¶
File: scenario.json¶
The scenario.json file is the entry point for your simulation. It defines metadata, simulation timeframe, selection strategies, and references to all other configuration files.
Example Configuration¶
{
"id": "test_scenario_01",
"description": "DAC retrofit simulation",
"version": "1.0.0",
"start_date": "2025-12-01T00:00:00+00:00",
"end_date": "2025-12-20T00:00:00+00:00",
"collection_track_strategy": "first_available",
"retrofit_selection_strategy": "best_fit",
"retrofitted_selection_strategy": "first_available",
"workshop_selection_strategy": "least_occupied",
"parking_selection_strategy": "first_available",
"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"
}
}
Parameters¶
Metadata¶
| Parameter | Type | Description | Example |
|---|---|---|---|
id |
string | Unique scenario identifier | "test_scenario_01" |
description |
string | Human-readable description | "DAC retrofit simulation" |
version |
string | Scenario version (semantic versioning) | "1.0.0" |
Simulation Timeframe¶
| Parameter | Type | Description | Example |
|---|---|---|---|
start_date |
ISO 8601 datetime | Simulation start time (UTC) | "2025-12-01T00:00:00+00:00" |
end_date |
ISO 8601 datetime | Simulation end time (UTC) | "2025-12-20T00:00:00+00:00" |
Important:
- Use ISO 8601 format with timezone (+00:00 for UTC)
- End date must be after start date
- All train arrivals in train_schedule.csv must fall within this timeframe
Selection Strategies¶
These strategies determine how the simulation selects resources when multiple options are available. Each track type and resource can have its own strategy.
| Parameter | Type | Available Values | Description |
|---|---|---|---|
collection_track_strategy |
string | See strategies below | How to select collection tracks for arriving trains |
retrofit_selection_strategy |
string | See strategies below | How to select retrofit tracks for wagon staging |
retrofitted_selection_strategy |
string | See strategies below | How to select retrofitted tracks for completed wagons |
workshop_selection_strategy |
string | See strategies below | How to select workshops for retrofit operations |
parking_selection_strategy |
string | See strategies below | How to select parking tracks for final storage |
Available Strategies:
| Strategy | Description | Best For |
|---|---|---|
least_occupied |
Selects resource with most available capacity | Load balancing, even utilization |
most_available |
Same as least_occupied (alias) |
Load balancing |
first_available |
Selects first resource with any capacity | Simple scenarios, predictable behavior |
best_fit |
Selects resource with least available capacity that fits | Space optimization, filling tracks completely |
round_robin |
Cycles through resources in order | Fair distribution |
shortest_queue |
Selects resource with shortest waiting queue | Minimizing wait times |
random |
Random selection from available resources | Testing, load distribution |
Recommended Configurations:
- Collection tracks:
first_available- Simple, predictable train arrival handling - Retrofit tracks:
best_fit- Optimizes space usage, fills tracks efficiently - Retrofitted tracks:
first_available- Simple staging before parking - Workshops:
least_occupied- Balances workload across workshops - Parking tracks:
first_available- Simple final storage allocation
References¶
The references object maps logical names to configuration filenames. All paths are relative to the scenario directory.
| Key | Required | Description | Typical Filename |
|---|---|---|---|
locomotives |
Yes | Locomotive configuration | locomotive.json |
process_times |
Yes | Operation timing parameters | process_times.json |
routes |
Yes | Movement paths between tracks | routes.json |
trains |
Yes | Train schedule and wagon data | train_schedule.csv |
topology |
Yes | Network structure | topology.json |
tracks |
Yes | Track definitions | tracks.json |
workshops |
Yes | Workshop configurations | workshops.json |
Note: All referenced files must exist in the scenario directory, or PopUpSim will fail validation.
Common Modifications¶
Extending Simulation Duration¶
To simulate a longer period:
{
"start_date": "2025-12-01T00:00:00+00:00",
"end_date": "2025-12-31T23:59:59+00:00"
}
Changing Selection Strategies¶
To test different resource allocation approaches:
{
"collection_track_strategy": "round_robin",
"retrofit_selection_strategy": "least_occupied",
"retrofitted_selection_strategy": "first_available",
"workshop_selection_strategy": "shortest_queue",
"parking_selection_strategy": "best_fit"
}
Strategy Impact Examples:
- Using
best_fitfor retrofit tracks fills each track completely before using the next, maximizing space efficiency - Using
least_occupiedfor workshops distributes work evenly, preventing bottlenecks - Using
shortest_queuefor workshops minimizes wagon waiting times
Setting Maximum Fill Levels Per Track Type¶
To define how much of each track type's physical length should be usable, use track_type_fill_factors. This sets a default fill factor for all tracks of a given type:
{
"track_type_fill_factors": {
"parking": 0.6,
"collection": 0.8,
"retrofit": 0.9,
"retrofitted": 0.85,
"workshop": 1.0
}
}
| Parameter | Type | Description |
|---|---|---|
track_type_fill_factors |
object | Maps track type names to fill factor values (0.0 – 1.0) |
Fill Factor Values:
- 1.0 = 100% of physical track length is usable
- 0.75 = 75% of physical track length is usable (default when not specified)
- 0.5 = 50% of physical track length is usable
Precedence: If an individual track in tracks.json specifies its own fillfactor, that value takes priority over the type-level default defined here.
Use Cases: - Set parking tracks to 60% to leave safety margins for shunting operations - Set collection tracks to 80% to account for coupling distances - Set workshop tracks to 100% since wagons are precisely positioned
Locomotive Task Priorities¶
To control which operations a locomotive serves first, configure task_priorities. Priorities are dynamic — they change based on track fill levels, so the system reacts to pressure automatically.
{
"task_priorities": {
"collection_to_retrofit": {
"base_priority": 2,
"hold_until": {"condition": "target_fill_below", "threshold": 0.6},
"rules": [
{"condition": "source_fill_above", "threshold": 0.7, "priority": 1},
{"condition": "source_fill_above", "threshold": 0.9, "priority": 0}
]
},
"retrofit_to_workshop": {
"base_priority": 3,
"rules": [
{"condition": "target_idle", "threshold": 0.0, "priority": 1},
{"condition": "source_fill_below", "threshold": 0.2, "priority": 5}
]
},
"workshop_to_retrofitted": {
"base_priority": 2,
"rules": []
},
"retrofitted_to_parking": {
"base_priority": 3,
"hold_until": {"condition": "source_fill_above", "threshold": 0.3},
"rules": [
{"condition": "source_fill_above", "threshold": 0.8, "priority": 1},
{"condition": "source_fill_above", "threshold": 0.95, "priority": 0}
]
}
}
}
Task Types:
| Task Type | Movement |
|---|---|
collection_to_retrofit |
Collection track → Retrofit staging |
retrofit_to_workshop |
Retrofit staging → Workshop |
workshop_to_retrofitted |
Workshop → Retrofitted staging |
retrofitted_to_parking |
Retrofitted staging → Parking |
Priority Values:
- Lower number = higher priority (0 is most urgent)
- base_priority applies when no rules match
- Rules are evaluated top-to-bottom, last matching rule wins
Hold Until (Task Eligibility Gate):
The hold_until field prevents a task from being submitted until a condition is met. This avoids wasteful small-batch trips — wagons accumulate until there's enough room at the target for a meaningful batch.
| Parameter | Type | Description |
|---|---|---|
condition |
string | Condition that must be TRUE for the task to proceed |
threshold |
float | Threshold value (0.0–1.0) |
Example: "hold_until": {"condition": "target_fill_below", "threshold": 0.6} means "don't move wagons until the target track is below 60% full." While held, wagons accumulate at the source, naturally forming larger batches.
Max Hold Time (Escape Hatch):
The max_hold_time field (in minutes) prevents operational stalls when hold conditions are too aggressive or fill levels don't change. If a task has been waiting longer than this, the hold condition is overridden and the task becomes eligible.
"collection_to_retrofit": {
"hold_until": {"condition": "target_fill_below", "threshold": 0.7},
"max_hold_time": 30.0
}
This means: "Hold until retrofit is below 70% full, but if we've been waiting 30+ minutes, do it anyway." Without max_hold_time, tasks are held indefinitely until the condition is met.
Available Conditions (for both rules and hold_until):
| Condition | Description |
|---|---|
source_fill_above |
Source track type fill level exceeds threshold |
source_fill_below |
Source track type fill level is below threshold |
target_fill_above |
Target track type fill level exceeds threshold |
target_fill_below |
Target track type fill level is below threshold |
target_idle |
Target resource (workshop) is idle |
How It Works:
1. Coordinator detects wagons ready to move
2. If hold_until condition is NOT met → task is held (not submitted)
3. Once condition is met → task is submitted to the dispatcher
4. Dispatcher evaluates priority of all eligible pending tasks
5. Highest-priority task (lowest number) gets the next free locomotive
6. Ties are broken by submission time (first-come-first-served)
Optimization Use Cases: - Hold collection→retrofit until retrofit is below 60% (accumulate proper batches) - Hold parking until retrofitted track is above 30% (don't waste trips for 1-2 wagons) - Clear collection tracks urgently when trains are arriving (prevent blocking) - Feed idle workshops immediately (maximize throughput) - Escalate parking when retrofitted track fills up (prevent workshop stalling)
Validation Rules¶
idmust be unique across scenariosstart_datemust be beforeend_date- All referenced files must exist
- Selection strategies must use valid values
- Dates must be in ISO 8601 format with timezone
Next Steps¶
Continue to Chapter 3: Topology Configuration to learn about network structure.