-
Notifications
You must be signed in to change notification settings - Fork 29
Conflux
Conflux is a SimMobility agent. The name ‘conflux’ or ‘confluence’ means a junction of two or more rivers (flows). A conflux in SimMobility represents a well-defined subset of the road network elements as explained later in more detail. The entire road-network may be thought of as a set of connected confluxes. Confluxes are managing entities which help in organized storage and movement of person agents across the network. Confluxes constitute the primary control logic for mid-term supply.
DynaMIT supply is the reference model from which SimMobility mid-term supply was built. However, there are subtle differences between the SimMobility framework and DynaMIT in terms of its software implementation. When processing vehicles in the network, DynaMIT iterates through the each node in the network, merges all packets on links which are upstream to the node into one list, sorts them by their distance to the node and processes them one by one. SimMobility goes one step further to group all the immediate upstream links of a node into one logical unit - the conflux. The conflux stores the person agents (vehicles) on those links within it, and processes them in the order they would reach the intersection. DynaMIT supply is a single threaded process. One of the goals of SimMobility is to have parallelism in its simulations. The confluxes are designed to fit the multi-threaded SimMobility framework and thereby instigate parallelism into supply simulations. The confluxes serve as the primary updating agents which can be managed by worker threads.
Each conflux controls the movement of all person agents within the conflux. Theoretically speaking, the running time of the simulation with this mechanism would be marginally worse than DynaMIT supply for small number of drivers but should gradually get better than DynaMIT supply as the number of drivers increase.
A conflux is both a data structure which stores person agents in the simulation and an agent which manages those person agents. Its structure and functionality is explained below.
A conflux is a data structure centered on a node in the road network. All links which flow into the node belong to the conflux of that node.
The diagram above shows an example of a conflux in a simple intersection. The conflux for the SimMobility node shown in the diagram includes only the links highlighted in yellow. These are the links which are immediately upstream to the conflux node.
There are four connected confluxes c1-c4 shown in the diagram above as an example. Each conflux is shaded in a different colour. The diagram shows how two links representing the two directions of the same road belong to different adjacent confluxes.
There are a few sub-structures built into each conflux to help with the storage of agents. Each of them is described in the text below. The following paragraphs are written with the assumption that the reader is familiar with the [road network] (SimMobility-road-network) elements of SimMobility.
For each road segment of a link, there is one or more SegmentStats built. Every road segment has at-least one segment stats associated with it. There can be more than 1 segment stats for a given road segment. Wherever there is a possible queuing point on the road segment it is split into segment stats. For example, if there is a bus-stop in the segment, the buses would queue up there to serve the stop. So we split at the bus-stop location and create multiple segments stats for the same segment. For each link which belongs to a conflux, a list of SegmentStats corresponding to the segments of the link is maintained by the conflux. This list of SegmentStats is stored in increasing order of their respective distances to the conflux node (reverse of the direction of flow of the link). SegmentStats can be thought of as an overlay on a road segment. The SegmentStats data structure stores a reference to the original road segment that it represents, through which it accesses properties of the segment like length, number of lanes, etc.
For each lane of a segment, the SegmentStats structure maintains what is known as the LaneStats. At any given point of time in the simulation, the LaneStats structure maintains the Person entities which are driving in that lane. Each LaneStats also tracks the count of the moving and queuing entities in that lane.
Each SegmentStats structure, in addition to the LaneStats corresponding to the lanes of the parent road segment, has an additional LaneStats called lane infinity. Lane infinity does not represent any real lane on the road network. This augmented LaneStats is used as a loading queue to temporarily hold drivers who are starting their trips in the simulation.
The conflux maintains for each of its links a container representing virtual queue of that link. The virtual queue contains the persons who want to enter the corresponding link from an upstream link. Instead of directly placing the person into the first segment of the next link, we attempt to place a person agent moving out of a link and intending to enter a downstream link is in the virtual of this downstream link in two cases:
- the downstream link has not been processed yet in the current time step or
- the downstream link is not managed by the same thread (it is not running in the same (Worker)[https://github.com/smart-fm/simmobility-prod/wiki/Parallel-Framework] of the upstream link)
The insertion is possible only if there is enough space in the virtual queue (see
Conflux::hasSpaceInVirtualQueue(..)
). To check this, we observe the flow rate of the first segment of the new link, and multiplying it by the frame tick duration we obtain the number of vehicles that can exit that segment in a frame tick. This is the upper bound to the number of vehicles we can insert in the virtual queue. This flow rate is an a-priori attribute of the segment, and it only changes in case of incidents (seeConflux::insertIncident(..)
). If the insertion in the virtual queue is possible, it occurs in the functionpushBackOntoVirtualQueue(..)
. Eventually when all links of the network has been processed, all agents in all virtual queues are allowed to move into the corresponding links of the queue (Conflux::processVirtualQueues(..)
). The number of persons that can be contained in the virtual queue is bounded by the number of persons that can be accepted by the first segment of that link in that tick. Virtual queues are essential to ensure the correctness of supply simulations.
Each conflux has additional lists to hold activity performers and pedestrians who are performing activities or walking in that conflux.
Confluxes are the updating agents in the current mid-term supply simulator. Each conflux updates once in every time-step of the simulation. During its update, the conflux simultaneously scans all its upstream links from the intersection (end of the links) outward to the start of the links and updates all persons who are currently in the conflux.
Person agents in the conflux are moved in non-decreasing order of time they would take to reach the conflux node. The persons who cross the conflux boundary are either moved in the next link (of next conflux) or added to the virtual queue of the next link depending on whether the next conflux has been updated for the current time step or not. The newly starting persons are placed in lane infinity of their starting segment. The persons are removed from the LaneStats and marked for removal when they have completed their trip chain.
After all the confluxes are updated, the persons in the virtual queues of each conflux are moved.
Every person who is active in the simulation has a role (Driver, ActivityPerformer, etc.) associated with him. By design, every role has two facets - the Behavior facet and the Movement facet. The behavior facet is meant for the behavioral or decision making aspects of the role and the movement facet deals with the locomotory aspects.
The Confluxes take control of the persons’ movement during the simulation. Confluxes allow the persons to move across the network in accordance to their trip chains. The conflux monitors and updates some attributes of the person like the time remaining for the person in the current tick, his current trip chain item etc. In every time step of the simulation, the confluxes guide the movement of the person by invoking the frame_tick function of the movement facet of the person's role. The frame_tick function is invoked one or more times until the person has expired time equal to the full size of the time-step.
The frame_tick of the movement facet of driving roles returns the control back to the conflux if any of the following conditions hold.
- If the person has been displaced to the maximum distance that he can move in one time step. The remaining time in this tick for the person becomes 0 in this case. The person's location is updated in the conflux that he now belongs to.
- If the person has reached the end of the current subtrip/activity. The conflux will check the person’s trip chain and initialize the next trip/sub trip or activity for the person. If the person has reached the end of his trip chain, the person is marked for removal.
- If the person has reached the end of a link (conflux boundary). In this case, the person requests for permission to move to the next conflux by setting the requestedNextSegStats to the next segment stats he wants to move into. The conflux immediately grants permission to the person. However, if the next link is already processed for the current time step, the conflux allows the person to move along the next conflux by calling its frame_tick again. On the other hand, if the next conflux is not processed for the current tick, the conflux checks for space in the virtual queue of the next link. If there is no space in the virtual queue (the number of persons in the next Virual Queue (VQ) is equal to the bound set for this tick), the conflux revokes the permission to that person right away and the person starts queuing in that segment. If there is space in the virtual queue, the conflux adds this person to the virtual queue (VQ) of the next link (in the next conflux), removes the person from itself and proceeds to select the next person to move. The person in the VQ will be moved for his remaining time left in the current tick when the virtual queues of the next conflux is processed (after all conflux updates).
One of the primary functions in the agent class is the update()
function. This virtual function is responsible for defining what the agent must do in a time-step. For more details about update()
, refer to the [agents] (SimMobility-Agents) page.
Agents can be classified into simple agents and multi-update agents based on the number of times their update()
function is called in each time step. A multi update agent typically updates more than once in each time step of the simulation. Confluxes are multi-updating agents. They are updated thrice in every time step.
- All person agents directly on the conflux are processed in the first update
- Virtual queue processing takes place in the second update
- Statistics reporting and some value resetting to prepare the conflux for the next time step takes place in the third update
When we assign confluxes to the worker threads, we try to assign adjacent confluxes to the same worker in an attempt to minimize interactions between confluxes from different workers.
In every iteration of its threaded function loop (corresponding to a time-step), the worker adds pending persons at their start times to their respective starting SegmentStats, calls the update()
function of all confluxes it manages thrice to process person agents, processes virtual queues and report the state of all segment stats.
The first conflux's update function scans outward from the conflux node and moves the persons as explained above. After all the confluxes are updated once, the worker asks the confluxes to process the virtual queues by invoking the update()
for the second time. Subsequently, after the virtual queue processing, the third update is called to report from each segmentstats.
The first update of each conflux takes place in frame tick barrier in parallel by different worker threads, but the processing of virtual queues actually takes place in the distribute messages barrier as a single threaded execution. Single threaded execution is needed to prevent persons from crossing the worker boundary and moving into a conflux which is currently processing its own virtual queue.
SegmentStats maintain the statistics required for mesoscopic models to operate at a road segment level.
Following are the main parameters maintained in SegmentStats.
- Supply-side parameters of each road segment needed by the speed-density functions
- Speed, density and flow of the segment for the current time interval
LaneStats within each SegmentStats data structure maintains the statistics needed at a lane level.
- Ordering of agents within the lane
- Number of queuing and moving agents in the lane
- Output Flow Rate of the lane
There is a second type of conflux used in the simulator - the loader conflux. The sole purpose of a loader conflux is to perform necessary initializations for a newly starting person agent and dispatch him to the correct conflux where he must enter into the simulation. The first role of the person as per his trip chain is initialized. The loader conflux determines the starting conflux for the person based on the origin and path of his first sub-trip. The person is then dispatched to the starting conflux through the message bus. On receiving the message, the starting conflux stores the person in its internal lists and allows him to update in every time step. The person is handed over to the next confluxes if he moves out of the current conflux.
There is exactly one loading conflux per worker thread. A loader conflux is identified by an isLoader
boolean flag that is set to true. The loader confluxes help in parallelizing the task of loading person agents into the simulation. New persons are dispatched to a loader conflux of a worker in round robin fashion. The update()
of the loader confluxes are called along with all regular confluxes. During its update, the loader conflux initializes and dispatches the new person agents it had received to their respective starting confluxes. These updates of the loader confluxes take place in parallel along with regular conflux updates in each worker thread.