Line data Source code
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 : /****************************************************************************/
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 : SVCPermissions MSRailSignalControl::mySignalizedClasses(SVC_UNSPECIFIED);
43 : SVCPermissions MSRailSignalControl::myMBClasses(SVC_UNSPECIFIED);
44 :
45 : // ===========================================================================
46 : // method definitions
47 : // ===========================================================================
48 1203 : MSRailSignalControl::MSRailSignalControl()
49 1203 : {}
50 :
51 : MSRailSignalControl&
52 18653317 : MSRailSignalControl::getInstance() {
53 18653317 : if (myInstance == nullptr) {
54 1203 : myInstance = new MSRailSignalControl();
55 1203 : MSNet::getInstance()->addVehicleStateListener(myInstance);
56 : }
57 18653317 : return *myInstance;
58 : }
59 :
60 : void
61 40907 : MSRailSignalControl::cleanup() {
62 40907 : delete myInstance;
63 40907 : myInstance = nullptr;
64 40907 : }
65 :
66 : void
67 186 : MSRailSignalControl::clearState() {
68 186 : if (myInstance != nullptr) {
69 : myInstance->myDriveWayCompatibility.clear();
70 10 : myInstance->myDriveWaySucc.clear();
71 10 : myInstance->myDriveWayPred.clear();
72 10 : myInstance->myWrittenDeadlocks.clear();
73 10 : myInstance->myDeadlockChecks.clear();
74 : //myInstance->myActiveSignals.clear();
75 : }
76 186 : }
77 :
78 :
79 2406 : MSRailSignalControl::~MSRailSignalControl() {
80 2406 : }
81 :
82 : void
83 16591 : MSRailSignalControl::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
84 16591 : if (vehicle->isRail()) {
85 : std::string dummyMsg;
86 18451 : if ((to == MSNet::VehicleState::BUILT && (!vehicle->getParameter().wasSet(VEHPARS_FORCE_REROUTE) || vehicle->hasValidRoute(dummyMsg)))
87 16315 : || to == MSNet::VehicleState::NEWROUTE) {
88 : // @note we could delay initialization until the departure time
89 3573 : if (vehicle->getEdge()->getFunction() != SumoXMLEdgeFunc::CONNECTOR && isRailwayOrShared(vehicle->getEdge()->getPermissions())) {
90 3568 : MSRailSignal::initDriveWays(vehicle, to == MSNet::VehicleState::NEWROUTE);
91 : }
92 : }
93 : }
94 16591 : }
95 :
96 :
97 : void
98 4697 : MSRailSignalControl::addSignal(MSRailSignal* signal) {
99 4697 : mySignals.push_back(signal);
100 10671 : for (const auto& links : signal->getLinks()) {
101 11948 : for (const MSLink* link : links) {
102 5974 : mySignalizedClasses |= link->getPermissions();
103 : }
104 : }
105 4697 : }
106 :
107 :
108 : void
109 152137 : MSRailSignalControl::addWaitRelation(const SUMOVehicle* waits, const MSRailSignal* rs, const SUMOVehicle* reason, MSRailSignalConstraint* constraint) {
110 : //std::cout << time2string(SIMSTEP) << " addWaitRelation waits=" << waits->getID() << " foe=" << reason->getID() << "\n";
111 152137 : myWaitRelations[waits] = WaitRelation(rs, reason, constraint);
112 152137 : }
113 :
114 :
115 : bool
116 13241 : MSRailSignalControl::haveDeadlock(const SUMOVehicle* veh) const {
117 : std::set<const SUMOVehicle*> seen;
118 : std::vector<WaitRelation> list;
119 13241 : 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 26104 : if (it != myWaitRelations.end()) {
127 12917 : if (it->second.constraint != nullptr) {
128 69 : constraints.push_back(it->second.constraint);
129 69 : constraintBlocked.push_back(cur);
130 69 : constraintSignals.push_back(it->second.railSignal);
131 : }
132 : seen.insert(cur);
133 12917 : list.push_back(it->second);
134 12917 : cur = it->second.foe;
135 : } else {
136 : return false;
137 : }
138 : }
139 54 : if (cur == veh) {
140 : const bool newDeadlock = myWrittenDeadlocks.count(seen) == 0;
141 : myWrittenDeadlocks.insert(seen);
142 54 : const OptionsCont& oc = OptionsCont::getOptions();
143 : MSRailSignalConstraint* resolved = nullptr;
144 : const SUMOVehicle* resolvedUnblocked = nullptr;
145 : const MSRailSignal* resolvedSignal = nullptr;
146 90 : if (!constraints.empty() && oc.getBool("time-to-teleport.remove-constraint")) {
147 21 : resolved = constraints.front();
148 21 : if (newDeadlock) {
149 : std::vector<std::string> vehicles;
150 54 : for (auto item : list) {
151 36 : vehicles.push_back(item.foe->getID());
152 : }
153 36 : WRITE_WARNINGF("Deactivating constraint to resolve deadlock between vehicles % at time %.", toString(vehicles), time2string(SIMSTEP));
154 18 : resolved->setActive(false);
155 18 : resolvedUnblocked = constraintBlocked.front();
156 18 : resolvedSignal = constraintSignals.front();
157 18 : }
158 : }
159 :
160 108 : if (oc.isSet("deadlock-output")) {
161 54 : 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 158 : for (auto item : list) {
167 330 : signals.push_back(item.railSignal == nullptr ? "INSERTION" : item.railSignal->getID());
168 114 : vehicles.push_back(item.foe->getID());
169 342 : tripIDs.push_back(item.foe->getParameter().getParameter("tripId", item.foe->getID()));
170 : }
171 88 : OutputDevice& od = OutputDevice::getDeviceByOption("deadlock-output");
172 44 : if (constraints.empty()) {
173 11 : od.openTag(SUMO_TAG_DEADLOCK);
174 : } else {
175 66 : od.openTag("constraintDeadlock");
176 : }
177 44 : od.writeAttr(SUMO_ATTR_TIME, time2string(SIMSTEP));
178 44 : od.writeAttr(SUMO_ATTR_SIGNALS, signals);
179 88 : od.writeAttr("vehicles", vehicles);
180 44 : if (!constraints.empty()) {
181 66 : od.writeAttr("tripIds", tripIDs);
182 : }
183 44 : if (resolved != nullptr) {
184 36 : od.openTag("resolvedConstraint");
185 18 : od.writeAttr(SUMO_ATTR_ID, resolvedSignal->getID());
186 54 : resolved->write(od, resolvedUnblocked->getParameter().getParameter("tripId", resolvedUnblocked->getID()));
187 36 : od.closeTag();
188 : }
189 44 : od.closeTag();
190 :
191 44 : }
192 : }
193 54 : return resolved == nullptr;
194 : } else {
195 : // it's a deadlock but does not involve veh
196 : return false;
197 : }
198 13241 : }
199 :
200 :
201 : void
202 15 : MSRailSignalControl::addDeadlockCheck(std::vector<const MSRailSignal*> signals) {
203 15 : if (MSDriveWay::haveDriveWays()) {
204 0 : WRITE_WARNING("Deadlocks should be loaded before any vehicles");
205 : }
206 15 : const int n = (int)signals.size();
207 78 : for (int i = 0; i < n; i++) {
208 : std::vector<const MSRailSignal*> others;
209 342 : for (int j = 0; j < n; j++) {
210 279 : others.push_back(signals[(i + j + 1) % n]);
211 : }
212 63 : myDeadlockChecks[signals[i]] = others;
213 63 : }
214 15 : }
215 :
216 : void
217 33173 : MSRailSignalControl::addDrivewayFollower(const MSDriveWay* dw, const MSDriveWay* dw2) {
218 : //std::cout << " addDrivewayFollower " << dw->getID() << " " << dw2->getID() << "\n";
219 33173 : myDriveWaySucc[dw].insert(dw2);
220 33173 : myDriveWayPred[dw2].insert(dw);
221 33173 : }
222 :
223 :
224 : void
225 33173 : MSRailSignalControl::addDWDeadlockChecks(const MSRailSignal* rs, MSDriveWay* dw) {
226 33173 : auto itDL = MSRailSignalControl::getInstance().getDeadlockChecks().find(rs);
227 33173 : if (itDL == MSRailSignalControl::getInstance().getDeadlockChecks().end()) {
228 33053 : return;
229 : }
230 120 : 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 120 : findDeadlockFoes(dw, others, deadlockFoes);
234 120 : }
235 :
236 :
237 : void
238 751 : MSRailSignalControl::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 751 : int circleIndex = (int)deadlockFoes.size();
243 751 : if (circleIndex < (int)others.size()) {
244 571 : const MSRailSignal* other = others[circleIndex];
245 571 : deadlockFoes.push_back(dw);
246 1062 : for (const MSDriveWay* follower : myDriveWaySucc[dw]) {
247 1991 : for (MSDriveWay* foe : follower->getFoes()) {
248 1500 : if (foe->getForward().back()->getEdge().getToJunction()->getID() == other->getID()) {
249 631 : 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 860 : for (const MSDriveWay* dldw : deadlockFoes) {
258 680 : if (dldw->isDepartDriveway()) {
259 233 : const_cast<MSDriveWay*>(dldw)->addDWDeadlock(deadlockFoes);
260 : } else {
261 861 : for (const MSDriveWay* pred : myDriveWayPred[dldw]) {
262 414 : if (!pred->isDepartDriveway()) {
263 113 : const MSRailSignal* predRS = dynamic_cast<const MSRailSignal*>(pred->getOrigin()->getTLLogic());
264 113 : 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 61 : continue;
269 : }
270 52 : const_cast<MSDriveWay*>(pred)->addDWDeadlock(deadlockFoes);
271 : }
272 : }
273 : }
274 : }
275 : }
276 751 : }
277 :
278 :
279 : void
280 641283 : MSRailSignalControl::notifyApproach(const MSLink* link) {
281 641283 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
282 : assert(rs != nullptr);
283 641283 : myActiveSignals.insert(const_cast<MSRailSignal*>(rs));
284 641283 : }
285 :
286 :
287 : void
288 8854466 : MSRailSignalControl::updateSignals(SUMOTime t) {
289 : UNUSED_PARAMETER(t);
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 26933355 : for (auto it = myActiveSignals.begin(); it != myActiveSignals.end();) {
301 18078889 : MSRailSignal* rs = *it;
302 : //std::cout << SIMTIME << " update " << rs->getID() << "\n";
303 18078889 : const bool keepActive = rs->updateCurrentPhase();
304 18078889 : if (rs->isActive()) {
305 18078874 : rs->setTrafficLightSignals(t);
306 : }
307 18078889 : if (!keepActive) {
308 : it = myActiveSignals.erase(it);
309 : } else {
310 : it++;
311 : }
312 : }
313 8854466 : }
314 :
315 :
316 : /****************************************************************************/
|