Skip to content

5a. Level 3 Implementation Details

Overview

This document provides Level 3 architectural details for the actual MVP implementation with 4 bounded contexts: Configuration, Retrofit Workflow, Railway Infrastructure, and External Trains.

5a.1 Configuration Context - Level 3

Component Diagram

graph TB
    subgraph "Configuration Context - Level 3"
        Builder["ConfigurationBuilder<br/>Load from files"]
        Loader["FileLoader<br/>Parse JSON/CSV"]

        subgraph "Domain Models (Pydantic)"
            Scenario[Scenario]
            Train[Train]
            Wagon[Wagon]
            Track[Track]
            Workshop[Workshop]
            Locomotive[Locomotive]
            Routes[Routes]
            ProcessTimes[ProcessTimes]
        end
    end

    Files[JSON/CSV Files] --> Builder
    Builder --> Loader
    Loader --> Scenario
    Loader --> Train
    Loader --> Wagon
    Loader --> Track
    Loader --> Workshop
    Loader --> Locomotive
    Loader --> Routes
    Loader --> ProcessTimes

    classDef builder fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    classDef model fill:#c5e1a5,stroke:#558b2f,stroke-width:2px

    class Builder,Loader builder
    class Scenario,Train,Wagon,Track,Workshop,Locomotive,Routes,ProcessTimes model

Components

Component File Responsibility
ConfigurationBuilder configuration_builder.py Load scenario from file path
FileLoader file_loader.py Parse JSON/CSV files, handle references
Scenario scenario.py Root configuration model with validation
ProcessTimes process_times.py Timing configuration for operations
DTOs dtos/ Input data transfer objects

Code Example

from pathlib import Path
from contexts.configuration.domain.configuration_builder import ConfigurationBuilder

# Load scenario
scenario = ConfigurationBuilder(Path("scenario_dir")).build()

# Access configuration
print(f"Scenario: {scenario.id}")
print(f"Workshops: {len(scenario.workshops)}")
print(f"Trains: {len(scenario.trains)}")

5a.2 Retrofit Workflow Context - Level 3

Component Diagram

graph TB
    subgraph "Retrofit Workflow Context - Level 3"
        Context["RetrofitWorkflowContext<br/>Initialization & orchestration"]

        subgraph "Coordinators (Application Layer)"
            Arrival["ArrivalCoordinator<br/>Process train arrivals"]
            Collection["CollectionCoordinator<br/>Move to retrofit track"]
            Workshop["WorkshopCoordinator<br/>Retrofit operations"]
            Parking["ParkingCoordinator<br/>Move to parking"]
        end

        subgraph "Domain Services (No SimPy)"
            Batch["BatchFormationService"]
            Rake["RakeFormationService"]
            TrainForm["TrainFormationService"]
            Schedule["WorkshopSchedulingService"]
            Coupling["CouplingService"]
            Route["RouteService"]
        end

        subgraph "Resource Managers (Infrastructure)"
            LocoMgr["LocomotiveResourceManager"]
            TrackMgr["TrackCapacityManager"]
            WorkshopMgr["WorkshopResourceManager"]
        end

        subgraph "Metrics Collection"
            Metrics["SimulationMetrics"]
            WagonCol["WagonCollector"]
            LocoCol["LocomotiveCollector"]
            WorkshopCol["WorkshopCollector"]
        end
    end

    Context --> Arrival
    Context --> Collection
    Context --> Workshop
    Context --> Parking

    Arrival --> Batch
    Collection --> Rake
    Workshop --> Schedule
    Parking --> TrainForm

    Arrival --> LocoMgr
    Collection --> TrackMgr
    Workshop --> WorkshopMgr

    Context --> Metrics
    Metrics --> WagonCol
    Metrics --> LocoCol
    Metrics --> WorkshopCol

    classDef coord fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    classDef domain fill:#c5e1a5,stroke:#558b2f,stroke-width:2px
    classDef resource fill:#fff9c4,stroke:#f57f17,stroke-width:2px
    classDef metrics fill:#ffccbc,stroke:#bf360c,stroke-width:2px

    class Context,Arrival,Collection,Workshop,Parking coord
    class Batch,Rake,TrainForm,Schedule,Coupling,Route domain
    class LocoMgr,TrackMgr,WorkshopMgr resource
    class Metrics,WagonCol,LocoCol,WorkshopCol metrics

Coordinators (Application Layer)

Coordinator Responsibility SimPy Process
ArrivalCoordinator Receive trains, classify wagons, distribute to collection tracks Yes
CollectionCoordinator Form batches, allocate locomotive, transport to retrofit track Yes
WorkshopCoordinator Assign wagons to workshops, execute retrofit, return to retrofitted track Yes
ParkingCoordinator Transport completed wagons to parking tracks Yes

Domain Services (No SimPy Dependencies)

Service Responsibility
BatchFormationService Create wagon batches based on capacity constraints
RakeFormationService Form and dissolve wagon rakes with coupling logic
TrainFormationService Assemble trains (locomotive + rake) with preparation times
WorkshopSchedulingService Schedule wagon batches to available workshops
CouplingService Calculate coupling/decoupling times
RouteService Provide route durations between tracks

Resource Managers (Infrastructure Layer)

Manager Responsibility
LocomotiveResourceManager Allocate and release locomotives (SimPy Resource)
TrackCapacityManager Manage track capacity and wagon placement
WorkshopResourceManager Manage workshop station availability (SimPy Resource)

Workflow Sequence

sequenceDiagram
    participant Train
    participant Arrival
    participant Collection
    participant Workshop
    participant Parking

    Train->>Arrival: TrainArrivedEvent
    Arrival->>Arrival: Classify wagons
    Arrival->>Collection: Add to collection queue
    Collection->>Collection: Form batch
    Collection->>Collection: Allocate locomotive
    Collection->>Workshop: Transport to retrofit track
    Workshop->>Workshop: Select workshop
    Workshop->>Workshop: Allocate stations
    Workshop->>Workshop: Execute retrofit
    Workshop->>Parking: Move to retrofitted track
    Parking->>Parking: Form batch
    Parking->>Parking: Transport to parking

5a.3 Railway Infrastructure Context - Level 3

Component Diagram

graph TB
    subgraph "Railway Infrastructure Context - Level 3"
        Context["RailwayContext<br/>Track building & services"]

        subgraph "Aggregates"
            TrackGroup["TrackGroup<br/>Group tracks by type"]
            Track["Track<br/>Individual track entity"]
            Occupancy["TrackOccupancy<br/>Wagon placement logic"]
        end

        subgraph "Services"
            Selector["TrackSelector<br/>Selection strategies"]
            Capacity["CapacityService<br/>Capacity queries"]
        end
    end

    Context --> TrackGroup
    TrackGroup --> Track
    Track --> Occupancy
    Context --> Selector
    Context --> Capacity
    Selector --> TrackGroup
    Capacity --> Track

    classDef component fill:#e1f5fe,stroke:#01579b,stroke-width:2px

    class Context,TrackGroup,Track,Occupancy,Selector,Capacity component

Components

Component Responsibility Pattern
RailwayContext Build tracks from scenario, provide services Context
TrackGroup Group tracks by type (collection, retrofit, parking, workshop) Aggregate
Track Individual track with capacity and fill factor Entity
TrackOccupancy Manage wagon placement and capacity Aggregate
TrackSelector Select tracks based on strategies Service
CapacityService Query track capacity and availability Service

Track Selection Strategies

  • LEAST_OCCUPIED: Select track with lowest occupancy ratio
  • ROUND_ROBIN: Cycle through available tracks
  • FIRST_AVAILABLE: Select first track with capacity
  • RANDOM: Random selection from available tracks

5a.4 External Trains Context - Level 3

Component Diagram

graph TB
    subgraph "External Trains Context - Level 3"
        Context["ExternalTrainsContext<br/>Train arrival management"]

        subgraph "Components"
            Publisher["EventPublisher<br/>Publish train arrivals"]
            Factory["WagonFactory<br/>Create wagon entities"]
        end

        subgraph "Events"
            TrainEvent["TrainArrivedEvent<br/>Train + wagons"]
        end
    end

    Context --> Publisher
    Context --> Factory
    Publisher --> TrainEvent
    Factory --> TrainEvent

    classDef component fill:#e1f5fe,stroke:#01579b,stroke-width:2px

    class Context,Publisher,Factory,TrainEvent component

Components

Component Responsibility
ExternalTrainsContext Initialize train arrivals from scenario
EventPublisher Publish TrainArrivedEvent to event bus
WagonFactory Create wagon entities from train data

Train Arrival Flow

sequenceDiagram
    participant Scenario
    participant ExternalTrains
    participant EventBus
    participant RetrofitWorkflow

    Scenario->>ExternalTrains: Initialize with trains
    ExternalTrains->>ExternalTrains: Schedule arrivals
    loop For each train
        ExternalTrains->>EventBus: Publish TrainArrivedEvent
        EventBus->>RetrofitWorkflow: Deliver event
        RetrofitWorkflow->>RetrofitWorkflow: Process wagons
    end

5a.5 Integration Patterns

Event Bus Communication

from contexts.shared.domain.events import EventBus, TrainArrivedEvent

# External Trains publishes event
event_bus.publish(TrainArrivedEvent(
    train_id="T001",
    wagons=[wagon1, wagon2, wagon3],
    arrival_time=100.0
))

# Retrofit Workflow subscribes
event_bus.subscribe(TrainArrivedEvent, arrival_coordinator.handle_train_arrival)

Track Capacity Queries

from contexts.railway_infrastructure.application.railway_context import RailwayContext

# Query track capacity
railway = RailwayContext(scenario)
track = railway.track_selector.select_track_with_capacity('collection', required_length=50.0)

# Place wagons on track
railway.place_wagons_on_track(track.id, wagons)

Resource Allocation

from contexts.retrofit_workflow.infrastructure.resource_managers import LocomotiveResourceManager

# Allocate locomotive
loco_manager = LocomotiveResourceManager(env, locomotives)
locomotive = yield loco_manager.allocate()

# Use locomotive
yield from transport_wagons(locomotive, wagons, destination)

# Release locomotive
loco_manager.release(locomotive)

5a.6 File Organization

popupsim/backend/src/
├── main.py                                    # CLI entry point
├── application/
│   └── simulation_service.py                  # Orchestrates all contexts
├── contexts/
│   ├── configuration/                         # Configuration Context
│   │   ├── domain/
│   │   │   ├── configuration_builder.py       # Load from files
│   │   │   └── models/
│   │   │       ├── scenario.py
│   │   │       ├── process_times.py
│   │   │       └── ...
│   │   └── infrastructure/
│   │       └── file_loader.py                 # Parse JSON/CSV
│   ├── retrofit_workflow/                     # Retrofit Workflow Context
│   │   ├── application/
│   │   │   ├── retrofit_workflow_context.py   # Main context
│   │   │   └── coordinators/
│   │   │       ├── arrival_coordinator.py
│   │   │       ├── collection_coordinator.py
│   │   │       ├── workshop_coordinator.py
│   │   │       └── parking_coordinator.py
│   │   ├── domain/
│   │   │   └── services/
│   │   │       ├── batch_formation_service.py
│   │   │       ├── rake_formation_service.py
│   │   │       ├── train_formation_service.py
│   │   │       ├── workshop_scheduling_service.py
│   │   │       ├── coupling_service.py
│   │   │       └── route_service.py
│   │   └── infrastructure/
│   │       ├── resource_managers/
│   │       │   ├── locomotive_resource_manager.py
│   │       │   ├── track_capacity_manager.py
│   │       │   └── workshop_resource_manager.py
│   │       └── metrics/
│   │           ├── simulation_metrics.py
│   │           ├── wagon_collector.py
│   │           ├── locomotive_collector.py
│   │           └── workshop_collector.py
│   ├── railway_infrastructure/                # Railway Infrastructure Context
│   │   ├── application/
│   │   │   └── railway_context.py             # Track building & services
│   │   ├── domain/
│   │   │   ├── aggregates/
│   │   │   │   ├── track_group.py
│   │   │   │   ├── track.py
│   │   │   │   └── track_occupancy.py
│   │   │   └── services/
│   │   │       ├── track_selector.py
│   │   │       └── capacity_service.py
│   │   └── infrastructure/
│   │       └── track_repository.py
│   ├── external_trains/                       # External Trains Context
│   │   ├── application/
│   │   │   └── external_trains_context.py     # Train arrival management
│   │   ├── domain/
│   │   │   ├── wagon_factory.py
│   │   │   └── events/
│   │   │       └── train_arrived_event.py
│   │   └── infrastructure/
│   │       └── event_publisher.py
│   └── shared/                                # Shared Kernel
│       ├── domain/
│       │   ├── events/
│       │   │   └── event_bus.py
│       │   └── value_objects/
│       └── infrastructure/
│           └── simpy_adapter.py
└── tests/
    └── unit/
        ├── configuration/
        ├── retrofit_workflow/
        ├── railway_infrastructure/
        └── external_trains/

5a.7 Wagon State Machine

stateDiagram-v2
    [*] --> ARRIVING: Train arrives
    ARRIVING --> SELECTING: At hump
    SELECTING --> SELECTED: Needs retrofit + capacity available
    SELECTING --> REJECTED: No capacity
    SELECTED --> MOVING_TO_COLLECTION: Locomotive pickup
    MOVING_TO_COLLECTION --> ON_COLLECTION_TRACK: Delivered
    ON_COLLECTION_TRACK --> MOVING_TO_RETROFIT: Batch formed
    MOVING_TO_RETROFIT --> ON_RETROFIT_TRACK: At retrofit track
    ON_RETROFIT_TRACK --> MOVING_TO_WORKSHOP: Workshop ready
    MOVING_TO_WORKSHOP --> RETROFITTING: At station
    RETROFITTING --> RETROFITTED: Retrofit complete
    RETROFITTED --> MOVING_TO_RETROFITTED: Pickup batch
    MOVING_TO_RETROFITTED --> ON_RETROFITTED_TRACK: At retrofitted track
    ON_RETROFITTED_TRACK --> MOVING_TO_PARKING: To parking
    MOVING_TO_PARKING --> PARKING: At parking track
    REJECTED --> [*]
    PARKING --> [*]

5a.8 Technology Integration

SimPy Integration

SimPyAdapter provides abstraction:

class SimPyAdapter:
    def delay(self, duration: float) -> Generator
    def run_process(self, process: Callable, *args) -> None
    def create_store(self, capacity: int) -> Any
    def create_event(self) -> Any
    def current_time(self) -> float
    def run(self, until: float) -> None

Pydantic Integration

All domain models use Pydantic for: - Type safety - Automatic validation - JSON serialization - Field constraints - Custom validators

Event Bus Integration

from contexts.shared.domain.events import EventBus

# Initialize event bus
event_bus = EventBus()

# Subscribe to events
event_bus.subscribe(TrainArrivedEvent, handler)

# Publish events
event_bus.publish(TrainArrivedEvent(...))