Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSRailSignalControl.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// Centralized services for rail signal control (Singleton)
19/****************************************************************************/
20#include <config.h>
21
22#include <cassert>
23#include <utility>
24#include <vector>
25#include <bitset>
26#include <microsim/MSNet.h>
27#include <microsim/MSRoute.h>
28#include <microsim/MSEdge.h>
29#include <microsim/MSLane.h>
30#include "MSRailSignal.h"
32#include "MSDriveWay.h"
33#include "MSRailSignalControl.h"
34
35
36//#define DEBUG_BUILD_DEADLOCK_CHECK
37
38// ===========================================================================
39// static value definitions
40// ===========================================================================
44
45// ===========================================================================
46// method definitions
47// ===========================================================================
50
59
60void
62 delete myInstance;
63 myInstance = nullptr;
64}
65
66void
68 if (myInstance != nullptr) {
74 //myInstance->myActiveSignals.clear();
75 }
76}
77
78
81
82void
83MSRailSignalControl::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
84 if (vehicle->isRail()) {
85 std::string dummyMsg;
86 if ((to == MSNet::VehicleState::BUILT && (!vehicle->getParameter().wasSet(VEHPARS_FORCE_REROUTE) || vehicle->hasValidRoute(dummyMsg)))
88 // @note we could delay initialization until the departure time
91 }
92 }
93 }
94}
95
96
97void
99 mySignals.push_back(signal);
100 for (const auto& links : signal->getLinks()) {
101 for (const MSLink* link : links) {
102 mySignalizedClasses |= link->getPermissions();
103 }
104 }
105}
106
107
108void
110 //std::cout << time2string(SIMSTEP) << " addWaitRelation waits=" << waits->getID() << " foe=" << reason->getID() << "\n";
111 myWaitRelations[waits] = WaitRelation(rs, reason, constraint);
112}
113
114
115bool
117 std::set<const SUMOVehicle*> seen;
118 std::vector<WaitRelation> list;
119 const SUMOVehicle* cur = veh;
120 std::vector<MSRailSignalConstraint*> constraints;
121 std::vector<const SUMOVehicle*> constraintBlocked;
122 std::vector<const MSRailSignal*> constraintSignals;
123 //std::cout << time2string(SIMSTEP) << " haveDeadlock veh=" << veh->getID() << "\n";
124 while (seen.count(cur) == 0) {
125 auto it = myWaitRelations.find(cur);
126 if (it != myWaitRelations.end()) {
127 if (it->second.constraint != nullptr) {
128 constraints.push_back(it->second.constraint);
129 constraintBlocked.push_back(cur);
130 constraintSignals.push_back(it->second.railSignal);
131 }
132 seen.insert(cur);
133 list.push_back(it->second);
134 cur = it->second.foe;
135 } else {
136 return false;
137 }
138 }
139 if (cur == veh) {
140 const bool newDeadlock = myWrittenDeadlocks.count(seen) == 0;
141 myWrittenDeadlocks.insert(seen);
143 MSRailSignalConstraint* resolved = nullptr;
144 const SUMOVehicle* resolvedUnblocked = nullptr;
145 const MSRailSignal* resolvedSignal = nullptr;
146 if (!constraints.empty() && oc.getBool("time-to-teleport.remove-constraint")) {
147 resolved = constraints.front();
148 if (newDeadlock) {
149 std::vector<std::string> vehicles;
150 for (auto item : list) {
151 vehicles.push_back(item.foe->getID());
152 }
153 WRITE_WARNINGF("Deactivating constraint to resolve deadlock between vehicles % at time %.", toString(vehicles), time2string(SIMSTEP));
154 resolved->setActive(false);
155 resolvedUnblocked = constraintBlocked.front();
156 resolvedSignal = constraintSignals.front();
157 }
158 }
159
160 if (oc.isSet("deadlock-output")) {
161 if (newDeadlock) {
162 myWrittenDeadlocks.insert(seen);
163 std::vector<std::string> signals;
164 std::vector<std::string> vehicles;
165 std::vector<std::string> tripIDs;
166 for (auto item : list) {
167 signals.push_back(item.railSignal == nullptr ? "INSERTION" : item.railSignal->getID());
168 vehicles.push_back(item.foe->getID());
169 tripIDs.push_back(item.foe->getParameter().getParameter("tripId", item.foe->getID()));
170 }
171 OutputDevice& od = OutputDevice::getDeviceByOption("deadlock-output");
172 if (constraints.empty()) {
174 } else {
175 od.openTag("constraintDeadlock");
176 }
178 od.writeAttr(SUMO_ATTR_SIGNALS, signals);
179 od.writeAttr("vehicles", vehicles);
180 if (!constraints.empty()) {
181 od.writeAttr("tripIds", tripIDs);
182 }
183 if (resolved != nullptr) {
184 od.openTag("resolvedConstraint");
185 od.writeAttr(SUMO_ATTR_ID, resolvedSignal->getID());
186 resolved->write(od, resolvedUnblocked->getParameter().getParameter("tripId", resolvedUnblocked->getID()));
187 od.closeTag();
188 }
189 od.closeTag();
190
191 }
192 }
193 return resolved == nullptr;
194 } else {
195 // it's a deadlock but does not involve veh
196 return false;
197 }
198}
199
200
201void
202MSRailSignalControl::addDeadlockCheck(std::vector<const MSRailSignal*> signals) {
204 WRITE_WARNING("Deadlocks should be loaded before any vehicles");
205 }
206 const int n = (int)signals.size();
207 for (int i = 0; i < n; i++) {
208 std::vector<const MSRailSignal*> others;
209 for (int j = 0; j < n; j++) {
210 others.push_back(signals[(i + j + 1) % n]);
211 }
212 myDeadlockChecks[signals[i]] = others;
213 }
214}
215
216void
218 //std::cout << " addDrivewayFollower " << dw->getID() << " " << dw2->getID() << "\n";
219 myDriveWaySucc[dw].insert(dw2);
220 myDriveWayPred[dw2].insert(dw);
221}
222
223
224void
228 return;
229 }
230 const std::vector<const MSRailSignal*>& others = itDL->second;
231 // the driveway could be part of a deadlock. check whether it would be blocked by the next signal in the circle
232 std::vector<const MSDriveWay*> deadlockFoes;
233 findDeadlockFoes(dw, others, deadlockFoes);
234}
235
236
237void
238MSRailSignalControl::findDeadlockFoes(const MSDriveWay* dw, const std::vector<const MSRailSignal*>& others, std::vector<const MSDriveWay*> deadlockFoes) {
239#ifdef DEBUG_BUILD_DEADLOCK_CHECK
240 //std::cout << " findDLfoes dw=" << dw->getID() << " dlFoes=" << toString(deadlockFoes) << "\n";
241#endif
242 int circleIndex = (int)deadlockFoes.size();
243 if (circleIndex < (int)others.size()) {
244 const MSRailSignal* other = others[circleIndex];
245 deadlockFoes.push_back(dw);
246 for (const MSDriveWay* follower : myDriveWaySucc[dw]) {
247 for (MSDriveWay* foe : follower->getFoes()) {
248 if (foe->getForward().back()->getEdge().getToJunction()->getID() == other->getID()) {
249 findDeadlockFoes(foe, others, deadlockFoes);
250 }
251 }
252 }
253 } else {
254#ifdef DEBUG_BUILD_DEADLOCK_CHECK
255 std::cout << " add deadlock check foes=" << toString(deadlockFoes) << "\n";;
256#endif
257 for (const MSDriveWay* dldw : deadlockFoes) {
258 if (dldw->isDepartDriveway()) {
259 const_cast<MSDriveWay*>(dldw)->addDWDeadlock(deadlockFoes);
260 } else {
261 for (const MSDriveWay* pred : myDriveWayPred[dldw]) {
262 if (!pred->isDepartDriveway()) {
263 const MSRailSignal* predRS = dynamic_cast<const MSRailSignal*>(pred->getOrigin()->getTLLogic());
264 if (std::find(others.begin(), others.end(), predRS) != others.end()) {
265 // driveways that participate in the deadlock don't need to
266 // do checking since they cannot prevent the deadlock
267 // (unless they are departDriveways)
268 continue;
269 }
270 const_cast<MSDriveWay*>(pred)->addDWDeadlock(deadlockFoes);
271 }
272 }
273 }
274 }
275 }
276}
277
278
279void
281 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
282 assert(rs != nullptr);
283 myActiveSignals.insert(const_cast<MSRailSignal*>(rs));
284}
285
286
287void
290 // there are 4 states for a signal
291 // 1. approached and green
292 // 2. approached and red
293 // 3. not approached and trains could pass
294 // 4. not approached and trains coult not pass
295 //
296 // for understanding conflicts better in sumo-gui, we want to show (3) as green. This
297 // means we have to keep updating signals in state (4) until they change to (3)
298
299 //std::cout << SIMTIME << " activeSignals=" << myActiveSignals.size() << "\n";
300 for (auto it = myActiveSignals.begin(); it != myActiveSignals.end();) {
301 MSRailSignal* rs = *it;
302 //std::cout << SIMTIME << " update " << rs->getID() << "\n";
303 const bool keepActive = rs->updateCurrentPhase();
304 if (rs->isActive()) {
306 }
307 if (!keepActive) {
308 it = myActiveSignals.erase(it);
309 } else {
310 it++;
311 }
312 }
313}
314
315
316/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define SIMSTEP
Definition SUMOTime.h:61
const SVCPermissions SVC_UNSPECIFIED
permissions not specified
bool isRailwayOrShared(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge or a shared road/rail edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const long long int VEHPARS_FORCE_REROUTE
@ SUMO_TAG_DEADLOCK
Saved deadlock information, also for loading as an extra check.
@ SUMO_ATTR_SIGNALS
@ SUMO_ATTR_ID
@ SUMO_ATTR_TIME
trigger: the time of the step
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static bool haveDriveWays()
Definition MSDriveWay.h:72
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition MSEdge.h:658
SumoXMLEdgeFunc getFunction() const
Returns the edge type (SumoXMLEdgeFunc)
Definition MSEdge.h:259
VehicleState
Definition of a vehicle state.
Definition MSNet.h:626
@ BUILT
The vehicle was built, but has not yet departed.
@ NEWROUTE
The vehicle got a new route.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:187
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1325
A base class for constraints.
virtual void setActive(bool active)=0
virtual void write(OutputDevice &out, const std::string &tripId) const =0
A signal for rails.
void notifyApproach(const MSLink *link)
switch rail signal to active
void addSignal(MSRailSignal *signal)
void vehicleStateChanged(const SUMOVehicle *const vehicle, MSNet::VehicleState to, const std::string &info="")
Called if a vehicle changes its state.
std::map< const MSDriveWay *, std::set< const MSDriveWay * > > myDriveWaySucc
void addDeadlockCheck(std::vector< const MSRailSignal * > signals)
void addDrivewayFollower(const MSDriveWay *dw, const MSDriveWay *dw2)
std::vector< MSRailSignal * > mySignals
list of all rail signals
std::map< const MSRailSignal *, std::vector< const MSRailSignal * > > myDeadlockChecks
MSRailSignalControl()
Constructor.
void addWaitRelation(const SUMOVehicle *waits, const MSRailSignal *rs, const SUMOVehicle *reason, MSRailSignalConstraint *constraint=nullptr)
static MSRailSignalControl * myInstance
std::map< const SUMOVehicle *, WaitRelation > myWaitRelations
void addDWDeadlockChecks(const MSRailSignal *rs, MSDriveWay *dw)
check whether the given signal and driveway are part of a deadlock circle
static MSRailSignalControl & getInstance()
std::map< const MSDriveWay *, std::set< const MSDriveWay * > > myDriveWayPred
const std::map< const MSRailSignal *, std::vector< const MSRailSignal * > > & getDeadlockChecks() const
static SVCPermissions mySignalizedClasses
signalized classes
bool haveDeadlock(const SUMOVehicle *veh) const
whether there is a circle in the waiting-for relationships that contains the given vehicle
std::set< std::set< const SUMOVehicle * > > myWrittenDeadlocks
void updateSignals(SUMOTime t)
update active rail signals
std::set< MSRailSignal *, ComparatorNumericalIdLess > myActiveSignals
std::map< std::pair< int, int >, bool > myDriveWayCompatibility
static void clearState()
Perform resets events when quick-loading state.
static SVCPermissions myMBClasses
void findDeadlockFoes(const MSDriveWay *dw, const std::vector< const MSRailSignal * > &others, std::vector< const MSDriveWay * > deadlockFoes)
A signal for rails.
bool updateCurrentPhase()
returns the state of the signal that actually required
static void initDriveWays(const SUMOVehicle *ego, bool update)
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
bool isActive() const
whether this logic is the active program
bool setTrafficLightSignals(SUMOTime t) const
Applies the current signal states to controlled links.
const std::string & getID() const
Returns the id.
Definition Named.h:74
A storage for options typed value containers)
Definition OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
Representation of a vehicle.
Definition SUMOVehicle.h:62
virtual bool isRail() const =0
virtual bool hasValidRoute(std::string &msg, ConstMSRoutePtr route=0) const =0
Validates the current or given route.
bool wasSet(long long int what) const
Returns whether the given parameter was set.
#define UNUSED_PARAMETER(x)