Skip to content

Architecture

Christian R edited this page Jul 18, 2023 · 77 revisions

You can find the diagrams in the repository visual-paradigm-diagrams.

Abstract architecture

Abstract Architecture

The diagram shows the abstract architecture as a component diagram. The abstract architecture contains the components and which component uses other ones.

Some notes regarding the REST API and SUMO components: The REST API component handles and validates incoming requests from users or the dashboard. SUMO is our framework for traffic simulation.

Interaction of components

The interaction between components will be modeled as sequence diagrams.

Start run

The following sequence diagram shows the setup of the simulation. The setup contains loading the configurations and initializing the components. Afterward, it starts the simulation in a new process inside of the celery worker. This process is shown in the second diagram.

PUT _run

Celery Worker Process

Stop run

DELETE _run__id

Get progress of run

GET _run__id

Component interfaces

The component interfaces will be modeled as component diagram. An Interface is a well-defined class to use.

Interfaces

Concrete architecture

The concrete architecture will be modeled as class diagram. Everybody is responsible to update their interface-classes with mermaid.

Implementor

The Implementor component contains the functions to execute the requested action. It initializes the Components for the Simulation and works with the Communicator to start the simulation. This will only be used internally by the same developer and that's why not be documented.

Communicator

It calls the DataScience module after the completion of the simulation.

classDiagram
  class ICommunicator {
    +progress: float
    +sumo_running: bool
    -configuration: String
    -components
    -current_tick: int
    -max_tick: int

    +ICommunictor(components: List[IComponent], max_tick: int, sumo_port: int, sumo_configuration: String)
    +add_component(IComponent)
    +run()
  }
Loading

To show the progress of a run, the state or to stop a run, please use the following class methods:

  • Communicator.progress(process_id: str)
  • Communicator.stateprocess_id: str)
  • Communicator.stop(process_id: str)

DataScience

Evaluates the logged data and calculates data. This will only be used internally by the same developer and that's why not be documented.

Logger

Writes logs to the database.

classDiagram
  class ILogCreator {
    +run_id: UUID

    +spawn_train(tick: int, train_id: str)
    +remove_train(tick: int, train_id: str)
    +arrival_train(tick: int, train_id: str, station_id: str)
    +departure_train(tick: int , train_id: str, station_id: str)
    +create_fahrstrasse(tick: int, fahrstrasse: str)
    +remove_fahrstrasse(tick: int, fahrstrasse: str)
    +set_signal(tick: int, signal_id: UUID, state_before: int, state_after: int)
    +train_enter_block_section(tick: int, train_id: str, block_section_id: str, block_section_length: str)
    +train_leave_block_section(tick: int, train_id: str, block_section_id: str, block_section_length: str)
    +inject_platform_blocked_fault(tick: int, platform_blocked_fault_configuration: UUID, affected_element: str)
    +inject_track_blocked_fault(tick: int, track_blocked_fault_configuration: UUID, affected_element: str) 
    +inject_track_speed_limit_fault(tick: int, track_speed_limit_fault_configuration: UUID, affected_element: str, value_before: str, value_after: str)
    +inject_schedule_blocked_fault(tick: int, train_cancelled_fault_configuration: UUID, affected_element: str)
    +inject_train_prio_fault(tick: int, train_prio_fault_configuration: UUID, affected_element: str, value_before: str, value_after: str) 
    +inject_train_speed_fault(tick: int, train_speed_fault_configuration: UUID, affected_element: str, value_before: str, value_after: str)
    +resolve_platform_blocked_fault(tick: int, platform_blocked_fault_configuration: UUID)
    +resolve_track_blocked_fault(tick: int, track_blocked_fault_configuration: UUID)
    +resolve_track_speed_limit_fault(tick: int, track_speed_limit_fault_configuration: UUID)
    +resolve_train_cancelled_fault(tick: int, train_cancelled_fault_configuration: UUID)
    +resolve_train_prio_fault(tick: int, train_prio_fault_configuration: UUID)
    +resolve_train_speed_fault(tick: int, train_speed_fault_configuration: UUID)
    +remove_fault(tick: int, injection_id: int)
  }

  class ILogCollector {
    -get_trains_departure_arrivals(run_id)
    -get_departures_of_train(run_id, train_id)
    -get_arrivals_of_train(run_id, train_id)
    +get_departures_arrivals_of_train(run_id, train_id)
    +get_departures_arrivals_all_trains(run_id)
    -get_trains_block_section(run_id)
    +get_block_section_times_of_train(run_id, train_id)
    +get_block_section_times_all_trains(run_id)
  }
Loading

FaultInjector

Inject faults into the Spawner or Interlocking to test the robustness of the simulation.

classDiagram

  class FaultInjector {
    +faults: list[Fault]
    +add_fault(Fault)
    +next_tick(tick)
  }

Loading

Spawner

Spawns trains and people defined by a schedule, parameters or data from outside.

classDiagram
  class Spawner {
    +configuration: SpawnerConfiguration
    +train_spawner: TrainBuilder
    +next_tick(tick: int)
    +get_schedule(schedule_id: str): Schedule
  }
  class ISpawnerDisruptor {
    <<interface>>
    +block_schedule(schedule_id: int)
    +unblock_schedule(schedule_id: int)
  }
  Spawner ..> ISpawnerDisruptor: implements
Loading

RouteController

classDiagram
    IInterlockingDisruptor --> Route_Controller
    class IInterlockingDisruptor {
        + insert_track_blocked(track: Track)
        + insert_track_unblocked(track: Track)
        + insert_platform_blocked(platform: Platform)
        + insert_platform_unblocked(platform: Platform)
        + insert_track_speed_limit_changed(track: Track)
        + insert_train_max_speed_changed(train: Train)
        + insert_train_priority_changed(train: Train)
    }
    class Route_Controller{
        + set_spawn_route(start_track: Track, end_track: Track) -> str
        + update_fahrstrasse(train: Train, track: Track)
        + maybe_update_fahrstrasse(train: Train, track: Track)
    }
Loading

SimulationObjects

Provides utility-functions to update objects in the simulation.

classDiagram
    ISimulationObject <|-- ISimulationTrain
    ISimulationObject <|-- ISimulationNode
    ISimulationNode <|-- ISimulationSignal
    ISimulationNode <|-- ISimulationSwitch
    ISimulationObject <|-- ISimulationTrack
    ISimulationObject <|-- ISimulationPlatform

    class ISimulationObject {
        +identifier: str
        +updater: ISimulationObjectUpdater
        +update(updates: dict)
        +add_subscription() -> int
        +from_simulation(simulation_object, updater: ISimulationObjectUpdater) -> ISimulationObject
        +add_simulation_connections()
    }

    class ISimulationTrain {
        +current_track: ISimulationTrack
        +priority: int
        +position: tuple[float, float]
        +speed: float
        +max_speed: float
        +route: String
        +timetable: ITimetable
        +current_platform: IPlatform
        +new(train_type: String, platform: ISimulationPlatform, timetable: ITimetable)
    }

    class ISimulationSignal {
        +state: Enum[Halt, Go]
    }

    class ISimulationNode {
        +position: tuple[float, float]
    }

    class ISimulationSwitch {
        +state: Enum[Left, Right]
    }

    class ISimulationTrack {
        +blocked: bool
        +speed_limit: float
    }

    class ISimulationPlatform {
        +edge: ISimulationEdge
        +platform_id: String
        +blocked: bool
    }

    class IInfrastructureProvider {
        -simulation: SimulationComponent
        +turn_point(yaramo_point: String, target_orientation: String)
        +set_signal_state(yaramo_signal: String, target_state: String)
        +tds_count_in_callback(callback: Callable)
        +tds_count_out_callback(callback: Callable)

    }

    class ISimulationObjectsUpdater {
        objects: List[ISimulationObject]
        trains: List[ISimulationTrain]
        signals: List[ISimulationSignal]
        switches: List[ISimulationSwitch]
        tracks: List[ISimulationTrack]
        platforms: List[ISimulationPlatform]
        +nextTick(tick: int)
    }
Loading

TrainBuilder

It provides functionality to spawn trains in the simulation.

classDiagram
    class ITrainBuilder {
        +spawn_train(identifier: str, timetable: List[str], train_type: str) -> bool
    }
Loading

Database Class Diagram

The following diagram show the database schema.

The classes Track and Platform are not part of the database. You can find the corresponding ids of the platform in an app configuration file and ids of the tracks in the SUMO-XML.

Please keep in mind that m:n relations are implemented as reference table.

classDiagram
    FaultConfiguration <|-- PlatformBlockedFaultConfiguration
    FaultConfiguration <|-- ScheduleBlockedFaultConfiguration
    FaultConfiguration <|-- TrainSpeedFaultConfiguration
    FaultConfiguration <|-- TrackSpeedLimitFaultConfiguration
    FaultConfiguration <|-- TrackBlockedFaultConfiguration
    FaultConfiguration <|-- TrainPrioFaultConfiguration

    LogEntry <|-- TrainSpawnLogEntry
    LogEntry <|-- TrainRemoveLogEntry
    LogEntry <|-- TrainArrivalLogEntry
    LogEntry <|-- TrainDepartureLogEntry
    LogEntry <|-- CreateFahrstrasseLogEntry
    LogEntry <|-- RemoveFahrstrasseLogEntry
    LogEntry <|-- SetSignalLogEntry
    LogEntry <|-- TrainEnterBlockSectionLogEntry
    LogEntry <|-- TrainLeaveBlockSectionLogEntry
    LogEntry <|-- InjectFaultLogEntry
    LogEntry <|-- ResolveFaultLogEntry

    Token "1" -- "0..*" SimulationConfiguration
    SimulationConfiguration "0..*" *-- "0..*" FaultConfiguration
    SimulationConfiguration "0..*" *-- "1" InterlockingConfiguration
    SimulationConfiguration "0..*" *-- "1" SpawnerConfiguration

    SimulationConfiguration "1" -- "0..*" Run
    Run "1" o-- "0..*" LogEntry

    SpawnerConfiguration "0..*" -- "0..*" Schedule
    ScheduleBlockedFaultConfiguration "0..*" -- "1" Schedule

    TrackBlockedFaultConfiguration "0..*" -- "1" Track
    TrackSpeedLimitFaultConfiguration "0..*" -- "1" Track
    PlatformBlockedFaultConfiguration "0..*" -- "1" Platform

    InjectFaultLogEntry "0..*" o-- "0..1" PlatformBlockedFaultConfiguration
    InjectFaultLogEntry "0..*" o-- "0..1" TrackBlockedFaultConfiguration
    InjectFaultLogEntry "0..*" o-- "0..1" TrackSpeedLimitFaultConfiguration
    InjectFaultLogEntry "0..*" o-- "0..1" ScheduleBlockedFaultConfiguration
    InjectFaultLogEntry "0..*" o-- "0..1" TrainPrioFaultConfiguration
    InjectFaultLogEntry "0..*" o-- "0..1" TrainSpeedFaultConfiguration

    class SimulationConfiguration {
        + id: UUID
        + description: String
    }

    class Token {
        + id: UUID
        + permission: String
        + name: String
        + hashedToken: String
    }

    class Run {
       + id: UUID
    }

    class LogEntry {
        + timestamp: DateTime
        + tick: int
        + message: str
    }

    class TrainSpawnLogEntry {
        + train_id: str
    }

    class TrainRemoveLogEntry {
        + train_id: str
    }

    class TrainArrivalLogEntry {
        + train_id: str
        + station_id: str
    }

    class TrainDepartureLogEntry {
        + train_id: str
        + station_id: str
    }

    class CreateFahrstrasseLogEntry {
        + fahrstrasse: str
    }

    class RemoveFahrstrasseLogEntry {
        + fahrstrasse: str
    }

    class SetSignalLogEntry {
        + signal_id: str
        + state_before: int
        + state_after: int
    }

    class TrainEnterBlockSectionLogEntry {
        + train_id: str
        + block_section_id: str
        + block_section_length: float
    }

    class TrainLeaveBlockSectionLogEntry {
        + train_id: str
        + block_section_id: str
        + block_section_length: float
    }

    class InjectFaultLogEntry {
        + affected_element: str
        + value_before: str
        + value_after: str
    }

    class ResolveFaultLogEntry {

    }

    class FaultConfiguration {
        +start_tick: int
        +end_tick: int
        +description: str

    }

    class PlatformBlockedFaultConfiguration {
        +affected_element_id: str
    }

    class ScheduleBlockedFaultConfiguration {
        +affected_element_id: str
    }

    class TrainSpeedFaultConfiguration {
        +affected_element_id: str
    }

    class TrackSpeedLimitFaultConfiguration {
        +affected_element_id: str
    }

    class TrackBlockedFaultConfiguration {
        +affected_element_id: str
    }

    class TrainPrioFaultConfiguration {
        +affected_element_id: str
        +new_prio: int
    }

    class ScheduleConfiguration {
        +schedule_type: str
        +strategy_type: str
        +strategy_start_tick: int
        +startegy_end_tick
        +train_schedule_train_type: str
        +regular_strategy_frequency: int
        +random_strategy_trains_per_1000_ticks: float
        +random_strategy_seed: int
        +demand_strategy_power_station: str
        +demand_strategy_scaling_factor: float
        +demand_strategy_start_datetime: datetime
    }

    ScheduleConfigurationXSimulationPlatform "1" o-- "1" ScheduleConfiguration

    class ScheduleConfigurationXSimulationPlatform {
        +index: int
        +simulation_platform_id: str
    }

    SpawnerConfiguration "m" o-- "n" ScheduleConfiguration

    class SpawnerConfiguration {

    }

    class SmardApiIndex {
        timestamp: datetime
    }

    class SmardApiEntry {
        timestamp: datetime
        value: float
    }

    SmardApiEntry "" *-- "1" SmardApiIndex : index

    class InterlockingConfiguration {
        + dynamicRouting: Boolean
    }

    class Track {

    }

    class Platform {

    }
    
Loading

Here a more accurate version:

test

I recommend installing pgadmin and using their ERD-Tool.

Class types

Configuration class

A configuration class contains information to initialize the functionality class. It inherits from the BaseModel in order to be saved to the database.

Pass an object of the configuration class the the according functionality class during the initialization.

Please keep the OpenAPI3 definition, postman collections and the database class diagram in sync with the configuration class. Ask Antony, if you need help.

Functionality class

Interface to interact with a Communicator. Pass an object of the configuration class the the according functionality class during the initialization.

Interaction between classes

The following diagram shows a rough overview over the interaction between configuration classes (in this example SpawnerConfiguration and functionality classes (in this case the component Spawner contains the class).

Initializing component