Line data Source code
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 : /****************************************************************************/
14 : /// @file MSRailSignalControl.cpp
15 : /// @author Jakob Erdmann
16 : /// @date Sept 2020
17 : ///
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"
31 : #include "MSRailSignalConstraint.h"
32 : #include "MSDriveWay.h"
33 : #include "MSRailSignalControl.h"
34 :
35 :
36 : //#define DEBUG_BUILD_DEADLOCK_CHECK
37 :
38 : // ===========================================================================
39 : // static value definitions
40 : // ===========================================================================
41 : MSRailSignalControl* MSRailSignalControl::myInstance(nullptr);
42 :
43 : // ===========================================================================
44 : // method definitions
45 : // ===========================================================================
46 959 : MSRailSignalControl::MSRailSignalControl()
47 959 : {}
48 :
49 : MSRailSignalControl&
50 16557108 : MSRailSignalControl::getInstance() {
51 16557108 : if (myInstance == nullptr) {
52 959 : myInstance = new MSRailSignalControl();
53 959 : MSNet::getInstance()->addVehicleStateListener(myInstance);
54 : }
55 16557108 : return *myInstance;
56 : }
57 :
58 : void
59 40275 : MSRailSignalControl::cleanup() {
60 40275 : delete myInstance;
61 40275 : myInstance = nullptr;
62 40275 : }
63 :
64 : void
65 177 : MSRailSignalControl::clearState() {
66 177 : if (myInstance != nullptr) {
67 : myInstance->myDriveWayCompatibility.clear();
68 10 : myInstance->myDriveWaySucc.clear();
69 10 : myInstance->myDriveWayPred.clear();
70 10 : myInstance->myWrittenDeadlocks.clear();
71 10 : myInstance->myDeadlockChecks.clear();
72 : //myInstance->myActiveSignals.clear();
73 : }
74 177 : }
75 :
76 :
77 1918 : MSRailSignalControl::~MSRailSignalControl() {
78 1918 : }
79 :
80 : void
81 14487 : MSRailSignalControl::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
82 14487 : if (isRailway(vehicle->getVClass())) {
83 : std::string dummyMsg;
84 16037 : if ((to == MSNet::VehicleState::BUILT && (!vehicle->getParameter().wasSet(VEHPARS_FORCE_REROUTE) || vehicle->hasValidRoute(dummyMsg)))
85 14135 : || (!vehicle->hasDeparted() && to == MSNet::VehicleState::NEWROUTE)) {
86 : // @note we could delay initialization until the departure time
87 2345 : if (vehicle->getEdge()->getFunction() != SumoXMLEdgeFunc::CONNECTOR) {
88 2345 : MSRailSignal::initDriveWays(vehicle, to == MSNet::VehicleState::NEWROUTE);
89 : }
90 : }
91 : }
92 14487 : }
93 :
94 :
95 : void
96 3485 : MSRailSignalControl::addSignal(MSRailSignal* signal) {
97 3485 : mySignals.push_back(signal);
98 3485 : }
99 :
100 :
101 : void
102 100261 : MSRailSignalControl::addWaitRelation(const SUMOVehicle* waits, const MSRailSignal* rs, const SUMOVehicle* reason, MSRailSignalConstraint* constraint) {
103 : //std::cout << time2string(SIMSTEP) << " addWaitRelation waits=" << waits->getID() << " foe=" << reason->getID() << "\n";
104 100261 : myWaitRelations[waits] = WaitRelation(rs, reason, constraint);
105 100261 : }
106 :
107 :
108 : bool
109 2970 : MSRailSignalControl::haveDeadlock(const SUMOVehicle* veh) const {
110 : std::set<const SUMOVehicle*> seen;
111 : std::vector<WaitRelation> list;
112 2970 : 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 5762 : if (it != myWaitRelations.end()) {
120 2846 : if (it->second.constraint != nullptr) {
121 69 : constraints.push_back(it->second.constraint);
122 69 : constraintBlocked.push_back(cur);
123 69 : constraintSignals.push_back(it->second.railSignal);
124 : }
125 : seen.insert(cur);
126 2846 : list.push_back(it->second);
127 2846 : cur = it->second.foe;
128 : } else {
129 : return false;
130 : }
131 : }
132 54 : if (cur == veh) {
133 : const bool newDeadlock = myWrittenDeadlocks.count(seen) == 0;
134 : myWrittenDeadlocks.insert(seen);
135 54 : const OptionsCont& oc = OptionsCont::getOptions();
136 : MSRailSignalConstraint* resolved = nullptr;
137 : const SUMOVehicle* resolvedUnblocked = nullptr;
138 : const MSRailSignal* resolvedSignal = nullptr;
139 90 : if (!constraints.empty() && oc.getBool("time-to-teleport.remove-constraint")) {
140 21 : resolved = constraints.front();
141 21 : if (newDeadlock) {
142 : std::vector<std::string> vehicles;
143 54 : for (auto item : list) {
144 36 : vehicles.push_back(item.foe->getID());
145 : }
146 36 : WRITE_WARNINGF("Deactivating constraint to resolve deadlock between vehicles % at time %.", toString(vehicles), time2string(SIMSTEP));
147 18 : resolved->setActive(false);
148 18 : resolvedUnblocked = constraintBlocked.front();
149 18 : resolvedSignal = constraintSignals.front();
150 18 : }
151 : }
152 :
153 108 : if (oc.isSet("deadlock-output")) {
154 54 : 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 151 : for (auto item : list) {
160 312 : signals.push_back(item.railSignal == nullptr ? "INSERTION" : item.railSignal->getID());
161 108 : vehicles.push_back(item.foe->getID());
162 324 : tripIDs.push_back(item.foe->getParameter().getParameter("tripId", item.foe->getID()));
163 : }
164 86 : OutputDevice& od = OutputDevice::getDeviceByOption("deadlock-output");
165 43 : if (constraints.empty()) {
166 10 : od.openTag(SUMO_TAG_DEADLOCK);
167 : } else {
168 66 : od.openTag("constraintDeadlock");
169 : }
170 86 : od.writeAttr(SUMO_ATTR_TIME, time2string(SIMSTEP));
171 : od.writeAttr(SUMO_ATTR_SIGNALS, signals);
172 86 : od.writeAttr("vehicles", vehicles);
173 43 : if (!constraints.empty()) {
174 66 : od.writeAttr("tripIds", tripIDs);
175 : }
176 43 : if (resolved != nullptr) {
177 36 : od.openTag("resolvedConstraint");
178 : od.writeAttr(SUMO_ATTR_ID, resolvedSignal->getID());
179 54 : resolved->write(od, resolvedUnblocked->getParameter().getParameter("tripId", resolvedUnblocked->getID()));
180 36 : od.closeTag();
181 : }
182 43 : od.closeTag();
183 :
184 43 : }
185 : }
186 54 : return resolved == nullptr;
187 : } else {
188 : // it's a deadlock but does not involve veh
189 : return false;
190 : }
191 2970 : }
192 :
193 :
194 : void
195 15 : MSRailSignalControl::addDeadlockCheck(std::vector<const MSRailSignal*> signals) {
196 15 : if (MSDriveWay::haveDriveWays()) {
197 0 : WRITE_WARNING("Deadlocks should be loaded before any vehicles");
198 : }
199 15 : const int n = (int)signals.size();
200 78 : for (int i = 0; i < n; i++) {
201 : std::vector<const MSRailSignal*> others;
202 342 : for (int j = 0; j < n; j++) {
203 279 : others.push_back(signals[(i + j + 1) % n]);
204 : }
205 63 : myDeadlockChecks[signals[i]] = others;
206 63 : }
207 15 : }
208 :
209 : void
210 9272 : MSRailSignalControl::addDrivewayFollower(const MSDriveWay* dw, const MSDriveWay* dw2) {
211 : //std::cout << " addDrivewayFollower " << dw->getID() << " " << dw2->getID() << "\n";
212 9272 : myDriveWaySucc[dw].insert(dw2);
213 9272 : myDriveWayPred[dw2].insert(dw);
214 9272 : }
215 :
216 :
217 : void
218 9272 : MSRailSignalControl::addDWDeadlockChecks(const MSRailSignal* rs, MSDriveWay* dw) {
219 9272 : auto itDL = MSRailSignalControl::getInstance().getDeadlockChecks().find(rs);
220 9272 : if (itDL == MSRailSignalControl::getInstance().getDeadlockChecks().end()) {
221 9152 : return;
222 : }
223 120 : 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 120 : findDeadlockFoes(dw, others, deadlockFoes);
227 120 : }
228 :
229 :
230 : void
231 717 : MSRailSignalControl::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 717 : int circleIndex = (int)deadlockFoes.size();
236 717 : if (circleIndex < (int)others.size()) {
237 558 : const MSRailSignal* other = others[circleIndex];
238 558 : deadlockFoes.push_back(dw);
239 1061 : for (const MSDriveWay* follower : myDriveWaySucc[dw]) {
240 2010 : for (MSDriveWay* foe : follower->getFoes()) {
241 1507 : if (foe->getForward().back()->getEdge().getToJunction()->getID() == other->getID()) {
242 597 : 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 784 : for (const MSDriveWay* dldw : deadlockFoes) {
251 625 : if (dldw->isDepartDriveway()) {
252 216 : const_cast<MSDriveWay*>(dldw)->addDWDeadlock(deadlockFoes);
253 : } else {
254 844 : for (const MSDriveWay* pred : myDriveWayPred[dldw]) {
255 435 : if (!pred->isDepartDriveway()) {
256 144 : const MSRailSignal* predRS = dynamic_cast<const MSRailSignal*>(pred->getOrigin()->getTLLogic());
257 144 : 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 86 : continue;
262 : }
263 58 : const_cast<MSDriveWay*>(pred)->addDWDeadlock(deadlockFoes);
264 : }
265 : }
266 : }
267 : }
268 : }
269 717 : }
270 :
271 :
272 : void
273 467835 : MSRailSignalControl::notifyApproach(const MSLink* link) {
274 467835 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
275 : assert(rs != nullptr);
276 467835 : myActiveSignals.insert(const_cast<MSRailSignal*>(rs));
277 467835 : }
278 :
279 :
280 : void
281 7972581 : MSRailSignalControl::updateSignals(SUMOTime t) {
282 : UNUSED_PARAMETER(t);
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 24261457 : for (auto it = myActiveSignals.begin(); it != myActiveSignals.end();) {
294 16288876 : MSRailSignal* rs = *it;
295 : //std::cout << SIMTIME << " update " << rs->getID() << "\n";
296 16288876 : const bool keepActive = rs->updateCurrentPhase();
297 16288876 : if (rs->isActive()) {
298 16288861 : rs->setTrafficLightSignals(t);
299 : }
300 16288876 : if (!keepActive) {
301 : it = myActiveSignals.erase(it);
302 : } else {
303 : it++;
304 : }
305 : }
306 7972581 : }
307 :
308 :
309 : /****************************************************************************/
|