Giter Club home page Giter Club logo

spur's Introduction

Spur: Simulation for Planning and Understanding Railways

Spur is an event-based mesoscopic railway network simulation platform, designed to support real-time operations and medium-term planning by capturing the stochastic movement of individual trains and the interactions between trains on the network. The model balances simplification with flexibility, and requires substantially less data and expertise than traditional microscopic simulation models.

Documentation

Documentation is available at Read the Docs

spur's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

spur's Issues

Finish writing initial tests

Need to increase our testing coverage by testing all currently utilized and working components and functions.

Input File Structure Refactoring

Refactoring the structure of the input files to achieve the following:

  • The same route entity representing a specific physical sequence of components can be re-used to avoid unnecessary duplication
  • Each train entity can traverse through the same passenger-facing route multiple times over its lifetime, to mimic the concept of a service block

Summary of proposed changes:

  • Each route entity in the routes.json file would now purely contain the physical sequence of components, without any schedule information
  • Introduction of the new "tour" entity, which would specify multiple routes in the order to be traversed, along with schedule information in args corresponding to each component of each route; stored in a file called tours.json
  • Each train entity in trains.json would be assigned to one tour
  • Within a tour, the last component of each previous route must match the first component of the next route, so the train would seamlessly transition from one route to the next

In the Line 4 example, the routes would become distilled down to just the eastbound and westbound component sequences, and there would only be a few trains, since it is the same few trains operating round-trips along the line repeatedly throughout the day.

GTFS to Component and Train Conversion

Would be good to have an ability to "read" a GTFS feed into a set of useable components based on some specified pre-determined parameters and settings.

The functionality would take one or more GTFS zipfiles and generate components.json, routes.json, and trains.json based on a fairly simple set of criteria. Users could then make modification to components to more easily set up the network.

Agent-oriented traversal times

From @peterlai1: Allow dynamic encoding of traversal times for each track component based on the
desired duration inputted within a specific tour instead of into the component itself.

Multi-Block Parallel Track Component

Proposal and specification for new multi-block parallel track component.

Description

A section of parallel tracks containing one or multiple signal blocks. Each block on each track holds one train, which will progressively traverse to the subsequent blocks if they are unoccupied, in the train's direction of travel. Assumed to have no crossovers between blocks.

Component Parameters

  • Number of tracks
  • Number of blocks
  • Nominal traversal time (for the entire component)

Logic

  • Nominal capacity = Number of tracks x Number of blocks
  • Detecting the travel direction of a train:
    • Look at both the previous and next components for the train, and get their u and v nodes
    • Compare with component's own u and v nodes
    • Two cases:
      • If the previous component has the same v as the current's u, and the next has the same u as the current's v, then the train is going in the direction from u to v
      • If the previous component has the same u as the current's v, and the next has the same v as the current's u, then the train is going in the direction from v to u
  • Assigning tracks:
    • Prioritize putting trains travelling in the same direction onto the same track
    • When a train first enters the component, it occupies the block closest to its entrance (either on the u side or v side)
    • Tracks with the first block occupied at the corresponding entrance side are not available; tracks containing trains travelling in the opposite direction in any block are also not available
    • Among the available tracks, select the track that would minimize the number of gap blocks between the trains on it (i.e., want to maximize the number of trains operating safely on the same track)
    • If no available tracks exist for the current train, reject the train from entering (and SimPy will place it on a wait queue)
  • Hold trains in one block until next block clears
  • Nominal per-block traversal time is the overall nominal traversal time for the entire component divided by the number of blocks; after this time has passed (plus jitter), the train can attempt to switch to the next block in its direction of travel
  • Every time a train leaves a block at the boundaries (either on the u side or v side), re-check if any held trains could enter the component

Yards

A yard component should be a special type of track component (but still a Resource with a capacity) that can handle multiple trains that will stay there for an agent-requested period of time based on a schedule.

Add function to log current state of trains

Add a function to output/log the current location of trains. This is especially useful after a simulation has finished to extend waiting/stopped trains through to the end of the simulation time. It could also be used to check-in at any specific time to add data points where desired.

Proposed function call: model.log_current_state()

Proposed behaviour: Output the location of each vehicle into the agent log file, with a specific key indicating that this is not a check in or out event. I'd suggest something like LOC

Train releases component resource too early

In the train traversal method, the with block at line 87 will release the resource from the train once the train has finished traversing the current segment. However, in the next loop iteration, the train may not be immediately transferred to the next segment (due to an enforced arrival time, or having to wait to use the next segment). While it waits, it should still be using the previous component's resource, but in the current implementation it is not, so the previous component's resource could have a higher number of free usage slots than it should.

A simple fix would be to not use the with statement and explicitly calling resource.release() (passing in the previous req object) when the train is successfully transferred to its next segment (in the next iteration of the loop).

https://github.com/transit-analytics-lab/spur/blob/8b4eb0c45b0b5687077b18cc4024ca9a03a494b2/spur/core/train.py#L69-L121

Block Exclusive Zone

Description

A new class of entities in Spur, with its position in the overall architecture similar to that of the Jitter class, i.e., like a property attached to a component. When there is a "critical" / "exclusive" section of components that can collectively only hold a single train at a time, an instance of the "block exclusive zone" (BEZ) class will be associated with each component (specified in the input file as an extra field in each component, similar to how jitter is specified). The BEZ instance will be identified uniquely by name.

If the critical section is occupied, additional trains attempting to enter it (i.e., the direction of travel is into the section) will be held and placed into a queue in the BEZ instance. Once a train leaves the critical section, the section is free. The next train in the queue is allowed through, which could be entering from either end of the section.

Parameters

  • Name (unique)

Logic

  • BEZ class object:
    • Maintain a Boolean state variable of whether the critical section is occupied
    • Maintain a queue structure of trains waiting to enter the critical section
  • Component with an associated BEZ instance:
    • When a train requests use of the component [this is the function that SpurResource will call to determine if it should accept the train into the component]:
      • Check if the train's previous component has the same BEZ instance as the current one it is trying to enter
        • If yes: train is staying in the same critical section, decide whether to accept the train based on component-specific factors
        • If no: train is entering critical section
          • Check if train is already on the queue in BEZ instance
            • If no: append train to queue in BEZ instance
          • Check if section is unoccupied AND if the current train is at the head of the queue:
            • If yes: dequeue the train, update state to occupied in BEZ instance, accept the train
            • If no: reject the train
  • When a train is being released from the component:
    • Check if the train's next component has the same BEZ instance as the current one it is leaving
      • If yes: train is staying in the same critical section, proceed with the release of the train
      • If no: train is leaving critical section
        • Update state to unoccupied in BEZ instance, proceed with the release of the train
        • Check the head of the queue in BEZ instance - if the train is requesting to enter the critical section from a component other than the current one, proactively call the method to process the request from the resource of that component
          • (if the next train in the queue is requesting to enter from the current component, the request will be processed automatically as the previous train leaves, handled by SimPy)

Unique component and agent ID enforcement

All BaseItem objects that are created should be handled by the Model class. This will allow the Model class to track and enforce requirements for unique component IDs and unique train/agent IDs.

Create a Basic Single-Block Trackway Component

Adapt or extend the TestTrack currently in use to model a simple, single-block piece of track which a train traverses based on a train's attributes (max speed?) and component attributes (length?)

End-of-route handling

Need to decide on what trains do after they finish a route. Do they remain stationary on the track? If so, they shouldn't technically release themselves from that portion of the resource.

This logic should be handled in the train running code.

Loading trains and components by JSON

Implement helper methods to load trains and components from a CSV file. This will require some sort of system to identify the 'Type' of component being added, plus any *args and **kwargs that might be specific to that particular component.

GO Sub model

As an initial test of the core model, we'll simulate the GO subdivision portion of the Metrolinx network. This will require some data setup and will be a good test of how well things got abstracted and parameterized.

Publish documentation to RTD

A documentation structure exists that can be published to readthedocs both as a developer's guide as well as a user guide. This will be useful for our first advertised working version.

SpurResource: custom SimPy Resource class

Proposing to create a new custom class called SpurResource that inherits SimPy's native Resource class. The resource object created as a class attribute in the various Spur component constructors would now use this custom class. In addition to the environment and capacity, the custom class would also take in the component itself as a parameter upon initialization.

The main extension compared to the default Resource class would be an updated _do_put() method, where the conditions for accepting the Request event would depend on more than just the resource capacity. It would also call a new method in its component that could contain logic custom to the specific component type to decide whether to accept a new train. In other words, the train's Request (to use the resource) would only succeed if there are free usage slots within the resource capacity AND if the associated component allows the entry.

The BaseComponent class would also be modified to include this new method that inspects the state of the component and returns True / False representing whether it will allow the entry of / use by a new train. A tentative name for this method could be check_usage_eligibility().

Checklist:

  • Create new SpurResource class
  • Add check_usage_eligibility() to BaseComponent
  • Update the class for the resource attribute in all components

Travel time track component

Create a component that determines traversal time based simply on a travel time component (and can include randomness). This should be a basic extension of the TestTrack that was implemented early on. This travel-time component would be vehicle-agnostic, and would not be useful in situations where different trains have very different dynamics.

Future Milestones for Base GO Model

The goal is to build a base model for the GO rail system, which requires:

  • Converting GTFS and Track Diagram data to Spur's JSON format
  • Adjusting and cleaning up the outputs to be easier to plot
  • Individual component upgrades (station and dwell time modelling; track movement and signally models)
  • Adding better and data-driven stochasticity (disruption modelling and model calibration)
  • Testing and validation

Implement Logging System

Since debugging is going to require a lot of looking at logs, I need to bake-in a logging/output system into the design early on. I suggest doing this after a very basic working model is implemented to get a sense of what logs are useful and how output might look.

Stations

Implement a basic station component that:

  • Accepts a number of trains equal to the number of platforms
  • Holds the train for a specific amount of time based on a set random range of passengers
  • Releases the train after a boarding + fixed dwell time

Scheduling

Need to implement a scheduling system. The schedule should be followed (as much as possible) on the agent level.

Proposed Approach
All trains are placed at the beginning of the simulation, and are given a set route and schedule (which would have to replace the current route list). Trains will timeout until their scheduled starting time, at which point they will move from component to component on their route (as they do now). Places where a scheduled time is enforced (such as a station), the train will have to check the current simulation time against the scheduled departure simulation time from those components.

This can be handled by creating a RouteItem object (or perhaps something with a better name) that holds both the component and the scheduled time. A value of None can indicate that this component is unscheduled; trains should traverse it as fast as they can.

Randomness

As randomness is a core aspect of the system, and an important aspect of modelling, components should have some form of randomness modelling. My suggestion is to build a system that will model "jitter" around a central value (either a mean travel time or a calculated travel time). This effectively creates perturbations in the system cause by whatever might be causing it and allows us to also model directly things like delay logs in the system (add a +400 second jitter or whatever).

Most of this can be accomplished through the use of helper functions, that allow us to add jitter sampled from theoretical distributions.

Formalize component attributes and structure for GUI building

Each component will need to have a GUI-side set of attributes that can set and interface with the SpurCore side of the code. We will need to standardize how those attributes are interfaced with, and how we can construct dialog boxes that allow us to adjust individual component attributes.

It's likely that creating a component will require both adding the code, and then adding a GUI-side dialog or interface that shows the proper components. I'm thinking there will be a widget spot that we can simply point at various custom widgets to update depending on the selected component.

Basic component editor functionality

The goal is to have the ability to do the following basic functions:

  • Drag components onto a map
  • Connect components via nodes
  • Provide component metadata information.

Create conda package installation instructions

Now that I'm (and others are) using conda to set up environments, I suggest we drop the poetry project information and focus on conda installation instructions. I will put together a yaml with required packages to get installation to happen.

Create documentation skeleton

Set up the basic documentation structure and outline to provide both user documentation for the software as well as technical API documentation so that people can access the core software as needed.

Multi-Track Station Component

Proposal and specification for new station component with multiple tracks.

Description

A station with multiple stopping and bypass tracks (i.e. with a capacity greater than 1). A stopping track is assumed to have platform(s) attached, allowing trains to stop at the station and perform passenger boarding / alighting. Trains not stopping at the station could use bypass tracks to bypass the station.

Component Parameters

  • Number of stopping tracks
  • Number of bypass tracks
  • Boarding / alighting duration or volume parameters (Lognormal, Burr distributions)

Logic

  • Overall capacity = Number of stopping tracks + Number of bypass tracks
  • If no departure time specified in the tour, release the train after a small nominal amount of traversal time (bypass the station), plus jitter
  • If # of boarding / alighting trains exceeds # of stopping tracks, do not accept the extra trains and hold them at the previous component
  • For trains stopping at the station, apply dwell time using lognormal or Burr distribution, plus jitter

Future Extensions

  • Trains will be able to specify their preferred track, and be assigned to it if available, and otherwise assigned any free track (depending on whether the train is stopping)
  • Platform-specific boarding / alighting characteristic parameters

Terminus Station Component

Proposal and specification for new terminus station component.

Description

A terminus station with multiple tracks that can also serve as a yard, where trains could spawn and disappear.

Component Parameters

  • Number of tracks with platform
  • Overall capacity
  • Boarding / alighting durations or volume parameters

Logic

  • Essentially a merged version of SimpleYard and Multi-Track Station
  • Number of storage-only tracks = Overall capacity - Number of tracks with platform
  • If a train needs to board / alight, assign a track with platform, and apply dwell time using distribution as in the Multi-Track Station component
  • Trains do not 'bypass' the station; they are immediately made available and it's up to the tour configuration to decide how long they stay there for using departure and arrival time arguments

Future Extensions

  • Assignment of preferred track

Crossovers

Create a basic "crossing" interlocking component that

  • Has a capacity of 1 agent
  • Handles basic two-way crossing of trains

Add initial train parameters to `Train` object.

Trains will need to have some attributes set for them, including:

  • A top speed
  • A "status" tag that can track whether a train is stopped or not
  • (Optional at this point) A basic acceleration attribute that can be used to estimate times based on whether it's stopped or not

May also want to implement some helper methods such as as a get for acceleration/deceleration times (or additional times), with the ability to have things be stochastic if needed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.