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