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-2025 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// ===========================================================================
43
44// ===========================================================================
45// method definitions
46// ===========================================================================
49
58
59void
61 delete myInstance;
62 myInstance = nullptr;
63}
64
65void
67 if (myInstance != nullptr) {
73 //myInstance->myActiveSignals.clear();
74 }
75}
76
77
80
81void
82MSRailSignalControl::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
83 if (vehicle->isRail()) {
84 std::string dummyMsg;
85 if ((to == MSNet::VehicleState::BUILT && (!vehicle->getParameter().wasSet(VEHPARS_FORCE_REROUTE) || vehicle->hasValidRoute(dummyMsg)))
87 // @note we could delay initialization until the departure time
90 }
91 }
92 }
93}
94
95
96void
98 mySignals.push_back(signal);
99 for (const auto& links : signal->getLinks()) {
100 for (const MSLink* link : links) {
101 mySignalizedClasses |= link->getPermissions();
102 }
103 }
104}
105
106
107void
109 //std::cout << time2string(SIMSTEP) << " addWaitRelation waits=" << waits->getID() << " foe=" << reason->getID() << "\n";
110 myWaitRelations[waits] = WaitRelation(rs, reason, constraint);
111}
112
113
114bool
116 std::set<const SUMOVehicle*> seen;
117 std::vector<WaitRelation> list;
118 const SUMOVehicle* cur = veh;
119 std::vector<MSRailSignalConstraint*> constraints;
120 std::vector<const SUMOVehicle*> constraintBlocked;
121 std::vector<const MSRailSignal*> constraintSignals;
122 //std::cout << time2string(SIMSTEP) << " haveDeadlock veh=" << veh->getID() << "\n";
123 while (seen.count(cur) == 0) {
124 auto it = myWaitRelations.find(cur);
125 if (it != myWaitRelations.end()) {
126 if (it->second.constraint != nullptr) {
127 constraints.push_back(it->second.constraint);
128 constraintBlocked.push_back(cur);
129 constraintSignals.push_back(it->second.railSignal);
130 }
131 seen.insert(cur);
132 list.push_back(it->second);
133 cur = it->second.foe;
134 } else {
135 return false;
136 }
137 }
138 if (cur == veh) {
139 const bool newDeadlock = myWrittenDeadlocks.count(seen) == 0;
140 myWrittenDeadlocks.insert(seen);
142 MSRailSignalConstraint* resolved = nullptr;
143 const SUMOVehicle* resolvedUnblocked = nullptr;
144 const MSRailSignal* resolvedSignal = nullptr;
145 if (!constraints.empty() && oc.getBool("time-to-teleport.remove-constraint")) {
146 resolved = constraints.front();
147 if (newDeadlock) {
148 std::vector<std::string> vehicles;
149 for (auto item : list) {
150 vehicles.push_back(item.foe->getID());
151 }
152 WRITE_WARNINGF("Deactivating constraint to resolve deadlock between vehicles % at time %.", toString(vehicles), time2string(SIMSTEP));
153 resolved->setActive(false);
154 resolvedUnblocked = constraintBlocked.front();
155 resolvedSignal = constraintSignals.front();
156 }
157 }
158
159 if (oc.isSet("deadlock-output")) {
160 if (newDeadlock) {
161 myWrittenDeadlocks.insert(seen);
162 std::vector<std::string> signals;
163 std::vector<std::string> vehicles;
164 std::vector<std::string> tripIDs;
165 for (auto item : list) {
166 signals.push_back(item.railSignal == nullptr ? "INSERTION" : item.railSignal->getID());
167 vehicles.push_back(item.foe->getID());
168 tripIDs.push_back(item.foe->getParameter().getParameter("tripId", item.foe->getID()));
169 }
170 OutputDevice& od = OutputDevice::getDeviceByOption("deadlock-output");
171 if (constraints.empty()) {
173 } else {
174 od.openTag("constraintDeadlock");
175 }
177 od.writeAttr(SUMO_ATTR_SIGNALS, signals);
178 od.writeAttr("vehicles", vehicles);
179 if (!constraints.empty()) {
180 od.writeAttr("tripIds", tripIDs);
181 }
182 if (resolved != nullptr) {
183 od.openTag("resolvedConstraint");
184 od.writeAttr(SUMO_ATTR_ID, resolvedSignal->getID());
185 resolved->write(od, resolvedUnblocked->getParameter().getParameter("tripId", resolvedUnblocked->getID()));
186 od.closeTag();
187 }
188 od.closeTag();
189
190 }
191 }
192 return resolved == nullptr;
193 } else {
194 // it's a deadlock but does not involve veh
195 return false;
196 }
197}
198
199
200void
201MSRailSignalControl::addDeadlockCheck(std::vector<const MSRailSignal*> signals) {
203 WRITE_WARNING("Deadlocks should be loaded before any vehicles");
204 }
205 const int n = (int)signals.size();
206 for (int i = 0; i < n; i++) {
207 std::vector<const MSRailSignal*> others;
208 for (int j = 0; j < n; j++) {
209 others.push_back(signals[(i + j + 1) % n]);
210 }
211 myDeadlockChecks[signals[i]] = others;
212 }
213}
214
215void
217 //std::cout << " addDrivewayFollower " << dw->getID() << " " << dw2->getID() << "\n";
218 myDriveWaySucc[dw].insert(dw2);
219 myDriveWayPred[dw2].insert(dw);
220}
221
222
223void
227 return;
228 }
229 const std::vector<const MSRailSignal*>& others = itDL->second;
230 // the driveway could be part of a deadlock. check whether it would be blocked by the next signal in the circle
231 std::vector<const MSDriveWay*> deadlockFoes;
232 findDeadlockFoes(dw, others, deadlockFoes);
233}
234
235
236void
237MSRailSignalControl::findDeadlockFoes(const MSDriveWay* dw, const std::vector<const MSRailSignal*>& others, std::vector<const MSDriveWay*> deadlockFoes) {
238#ifdef DEBUG_BUILD_DEADLOCK_CHECK
239 //std::cout << " findDLfoes dw=" << dw->getID() << " dlFoes=" << toString(deadlockFoes) << "\n";
240#endif
241 int circleIndex = (int)deadlockFoes.size();
242 if (circleIndex < (int)others.size()) {
243 const MSRailSignal* other = others[circleIndex];
244 deadlockFoes.push_back(dw);
245 for (const MSDriveWay* follower : myDriveWaySucc[dw]) {
246 for (MSDriveWay* foe : follower->getFoes()) {
247 if (foe->getForward().back()->getEdge().getToJunction()->getID() == other->getID()) {
248 findDeadlockFoes(foe, others, deadlockFoes);
249 }
250 }
251 }
252 } else {
253#ifdef DEBUG_BUILD_DEADLOCK_CHECK
254 std::cout << " add deadlock check foes=" << toString(deadlockFoes) << "\n";;
255#endif
256 for (const MSDriveWay* dldw : deadlockFoes) {
257 if (dldw->isDepartDriveway()) {
258 const_cast<MSDriveWay*>(dldw)->addDWDeadlock(deadlockFoes);
259 } else {
260 for (const MSDriveWay* pred : myDriveWayPred[dldw]) {
261 if (!pred->isDepartDriveway()) {
262 const MSRailSignal* predRS = dynamic_cast<const MSRailSignal*>(pred->getOrigin()->getTLLogic());
263 if (std::find(others.begin(), others.end(), predRS) != others.end()) {
264 // driveways that participate in the deadlock don't need to
265 // do checking since they cannot prevent the deadlock
266 // (unless they are departDriveways)
267 continue;
268 }
269 const_cast<MSDriveWay*>(pred)->addDWDeadlock(deadlockFoes);
270 }
271 }
272 }
273 }
274 }
275}
276
277
278void
280 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
281 assert(rs != nullptr);
282 myActiveSignals.insert(const_cast<MSRailSignal*>(rs));
283}
284
285
286void
289 // there are 4 states for a signal
290 // 1. approached and green
291 // 2. approached and red
292 // 3. not approached and trains could pass
293 // 4. not approached and trains coult not pass
294 //
295 // for understanding conflicts better in sumo-gui, we want to show (3) as green. This
296 // means we have to keep updating signals in state (4) until they change to (3)
297
298 //std::cout << SIMTIME << " activeSignals=" << myActiveSignals.size() << "\n";
299 for (auto it = myActiveSignals.begin(); it != myActiveSignals.end();) {
300 MSRailSignal* rs = *it;
301 //std::cout << SIMTIME << " update " << rs->getID() << "\n";
302 const bool keepActive = rs->updateCurrentPhase();
303 if (rs->isActive()) {
305 }
306 if (!keepActive) {
307 it = myActiveSignals.erase(it);
308 } else {
309 it++;
310 }
311 }
312}
313
314
315/****************************************************************************/
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:657
SumoXMLEdgeFunc getFunction() const
Returns the edge type (SumoXMLEdgeFunc)
Definition MSEdge.h:258
VehicleState
Definition of a vehicle state.
Definition MSNet.h:622
@ 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:186
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1318
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.
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)