Eclipse SUMO - Simulation of Urban MObility
MSRailSignal.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2020 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 /****************************************************************************/
20 // A rail signal logic
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <cassert>
25 #include <utility>
26 #include <vector>
27 #include <bitset>
28 #ifdef HAVE_FOX
30 #endif
33 #include <microsim/MSNet.h>
34 #include <microsim/MSEdge.h>
35 #include <microsim/MSEdgeControl.h>
36 #include <microsim/MSLane.h>
37 #include <microsim/MSLink.h>
39 #include <microsim/MSVehicle.h>
42 #include <microsim/MSLane.h>
43 
44 #include "MSTLLogicControl.h"
45 #include "MSTrafficLightLogic.h"
46 #include "MSPhaseDefinition.h"
47 #include "MSTLLogicControl.h"
48 #include "MSRailSignalConstraint.h"
49 #include "MSRailSignalControl.h"
50 #include "MSRailSignal.h"
51 
52 // typical block length in germany on main lines is 3-5km on branch lines up to 7km
53 // special branches that are used by one train exclusively could also be up to 20km in length
54 // minimum block size in germany is 37.5m (LZB)
55 // larger countries (USA, Russia) might see blocks beyond 20km)
56 #define MAX_BLOCK_LENGTH 20000
57 #define MAX_SIGNAL_WARNINGS 10
58 
59 //#define DEBUG_BUILD_DRIVEWAY
60 //#define DEBUG_CHECK_FLANKS
61 //#define DEBUG_DRIVEWAY_BUILDROUTE
62 //#define DEBUG_DRIVEWAY_UPDATE
63 
64 #define DEBUG_SIGNALSTATE
65 #define DEBUG_SIGNALSTATE_PRIORITY
66 #define DEBUG_FIND_PROTECTION
67 //#define DEBUG_RECHECKGREEN
68 //#define DEBUG_REROUTE
69 
70 #define DEBUG_COND DEBUG_HELPER(this)
71 #define DEBUG_COND_LINKINFO DEBUG_HELPER(myLink->getTLLogic())
72 #define DEBUG_HELPER(obj) ((obj)->isSelected())
73 //#define DEBUG_HELPER(obj) ((obj)->getID() == "w2")
74 //#define DEBUG_HELPER(obj) (true)
75 
76 // ===========================================================================
77 // static value definitions
78 // ===========================================================================
80 
81 std::vector<std::pair<MSLink*, int> > MSRailSignal::mySwitchedGreenFlanks;
82 std::map<std::pair<int, int>, bool> MSRailSignal::myDriveWayCompatibility;
84 
90 
91 // ===========================================================================
92 // method definitions
93 // ===========================================================================
95  const std::string& id, const std::string& programID, SUMOTime delay,
96  const std::map<std::string, std::string>& parameters) :
97  MSTrafficLightLogic(tlcontrol, id, programID, TrafficLightType::RAIL_SIGNAL, delay, parameters),
98  myCurrentPhase(DELTA_T, std::string(SUMO_MAX_CONNECTIONS, 'X'), -1), // dummy phase
99  myPhaseIndex(0) {
101 }
102 
103 void
105  if (myLanes.size() == 0) {
106  WRITE_WARNINGF("Rail signal at junction '%' does not control any links", getID());
107  }
108  for (LinkVector& links : myLinks) { //for every link index
109  if (links.size() != 1) {
110  throw ProcessError("At railSignal '" + getID() + "' found " + toString(links.size())
111  + " links controlled by index " + toString(links[0]->getTLIndex()));
112  }
113  myLinkInfos.push_back(LinkInfo(links[0]));
114  }
116  setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
117  myNumLinks = (int)myLinks.size();
118 }
119 
120 
122  for (auto item : myConstraints) {
123  for (MSRailSignalConstraint* c : item.second) {
124  delete c;
125  }
126  }
127  myConstraints.clear();
128 }
129 
130 
131 // ----------- Handling of controlled links
132 void
136 }
137 
138 
139 // ------------ Switching and setting current rows
140 SUMOTime
143  return DELTA_T;
144 }
145 
146 
147 
148 void
150 #ifdef DEBUG_SIGNALSTATE
152 #endif
153  // green by default so vehicles can be inserted at the borders of the network
154  std::string state(myLinks.size(), 'G');
155  for (LinkInfo& li : myLinkInfos) {
156  if (li.myLink->getApproaching().size() > 0) {
157  Approaching closest = getClosest(li.myLink);
158  DriveWay& driveway = li.getDriveWay(closest.first);
159  //std::cout << SIMTIME << " signal=" << getTLLinkID(li.myLink) << " veh=" << closest.first->getID() << " dw:\n";
160  //driveway.writeBlocks(*OutputDevice_COUT::getDevice());
161  const bool mustWait = !constraintsAllow(closest.first);
162  MSEdgeVector occupied;
163  if (mustWait || !driveway.reserve(closest, occupied)) {
164  state[li.myLink->getTLIndex()] = 'r';
165  if (occupied.size() > 0) {
166  li.reroute(const_cast<SUMOVehicle*>(closest.first), occupied);
167  }
168 #ifdef DEBUG_SIGNALSTATE
169  if (gDebugFlag4) {
170  std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " notReserved\n";
171  }
172 #endif
173  } else {
174  state[li.myLink->getTLIndex()] = 'G';
175  if (driveway.myFlank.size() > 0 && myCurrentPhase.getState()[li.myLink->getTLIndex()] != 'G') {
176  // schedule recheck
177  mySwitchedGreenFlanks.push_back(std::make_pair(li.myLink, driveway.myNumericalID));
178  }
179 #ifdef DEBUG_SIGNALSTATE
180  if (gDebugFlag4) {
181  std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " reserved\n";
182  }
183 #endif
184  }
185  } else {
186  DriveWay& driveway = li.myDriveways.front();
187  if (driveway.conflictLaneOccupied() || driveway.conflictLinkApproached()) {
188 #ifdef DEBUG_SIGNALSTATE
189  if (gDebugFlag4) {
190  std::cout << SIMTIME << " rsl=" << li.getID() << " red for default driveway (" << toString(driveway.myRoute) << " conflictLinkApproached=" << driveway.conflictLinkApproached() << "\n";
191  }
192 #endif
193  state[li.myLink->getTLIndex()] = 'r';
194  } else {
195 #ifdef DEBUG_SIGNALSTATE
196  if (gDebugFlag4) {
197  std::cout << SIMTIME << " rsl=" << li.getID() << " green for default driveway (" << toString(driveway.myRoute) << ")\n";
198  }
199 #endif
200  }
201  }
202  }
203  if (myCurrentPhase.getState() != state) {
204  myCurrentPhase.setState(state);
206  }
207 #ifdef DEBUG_SIGNALSTATE
208  gDebugFlag4 = false;
209 #endif
210 }
211 
212 
213 bool
215  if (myConstraints.size() == 0) {
216  return true;
217  } else {
218  const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
219  auto it = myConstraints.find(tripID);
220  if (it != myConstraints.end()) {
221  for (MSRailSignalConstraint* c : it->second) {
222  if (!c->cleared()) {
223 #ifdef DEBUG_SIGNALSTATE
224  if (gDebugFlag4) {
225  std::cout << " constraint '" << c->getDescription() << "' not cleared\n";
226  }
227 #endif
228  if (myStoreVehicles) {
230  }
231  return false;
232  }
233  }
234  }
235  return true;
236  }
237 }
238 
239 
240 void
241 MSRailSignal::addConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
242  myConstraints[tripId].push_back(constraint);
243 }
244 
245 void
246 MSRailSignal::addInsertionConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
247  myInsertionConstraints[tripId].push_back(constraint);
248 }
249 
250 // ------------ Static Information Retrieval
251 int
253  return 0;
254 }
255 
258  return myPhases;
259 }
260 
261 const MSPhaseDefinition&
263  return myCurrentPhase;
264 }
265 
266 // ------------ Dynamic Information Retrieval
267 int
269  return myPhaseIndex;
270 }
271 
272 const MSPhaseDefinition&
274  return myCurrentPhase;
275 }
276 
277 // ------------ Conversion between time and phase
278 SUMOTime
280  return 0;
281 }
282 
283 SUMOTime
285  return 0;
286 }
287 
288 int
290  return 0;
291 }
292 
293 
294 void
295 MSRailSignal::addLink(MSLink* link, MSLane* lane, int pos) {
296  if (pos >= 0) {
297  MSTrafficLightLogic::addLink(link, lane, pos);
298  } // ignore uncontrolled link
299 }
300 
301 
302 std::string
304  return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
305 }
306 
307 std::string
309  return link->getJunction()->getID() + "_" + toString(link->getIndex());
310 }
311 
312 std::string
314  return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
315 }
316 
317 std::string
318 MSRailSignal::describeLinks(std::vector<MSLink*> links) {
319  std::string result;
320  for (MSLink* link : links) {
321  result += link->getDescription() + " ";
322  }
323  return result;
324 }
325 
326 std::string
328  std::vector<const MSLane*> lanes(visited.size(), nullptr);
329  for (auto item : visited) {
330  lanes[item.second] = item.first;
331  }
332  return toString(lanes);
333 }
334 
337  assert(link->getApproaching().size() > 0);
338  double minDist = std::numeric_limits<double>::max();
339  auto closestIt = link->getApproaching().begin();
340  for (auto apprIt = link->getApproaching().begin(); apprIt != link->getApproaching().end(); apprIt++) {
341  if (apprIt->second.dist < minDist) {
342  minDist = apprIt->second.dist;
343  closestIt = apprIt;
344  }
345  }
346  // maybe a parallel link has a closer vehicle
347  /*
348  for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
349  if (link2 != link) {
350  for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
351  if (apprIt2->second.dist < minDist) {
352  minDist = apprIt2->second.dist;
353  closestIt = apprIt2;
354  }
355  }
356  }
357  }
358  */
359  return *closestIt;
360 }
361 
362 void
364  od.openTag("railSignal");
366  for (const LinkInfo& li : myLinkInfos) {
367  MSLink* link = li.myLink;
368  od.openTag("link");
372  for (const DriveWay& dw : li.myDriveways) {
373  dw.writeBlocks(od);
374  }
375  od.closeTag(); // link
376  }
377  od.closeTag(); // railSignal
378 }
379 
380 
381 bool
384  const MSEdge* bidi = link->getLaneBefore()->getEdge().getBidiEdge();
385  if (bidi == nullptr) {
386  return false;
387  }
388  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
389  if (rs != nullptr) {
390  const LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
391  for (const DriveWay& dw : li.myDriveways) {
392  //std::cout << SIMTIME <<< " hasOncomingRailTraffic link=" << getTLLinkID(link) << " dwRoute=" << toString(dw.myRoute) << " bidi=" << toString(dw.myBidi) << "\n";
393  for (MSLane* lane : dw.myBidi) {
394  if (!lane->isEmpty()) {
395 #ifdef DEBUG_SIGNALSTATE
396  if (DEBUG_HELPER(rs)) {
397  std::cout << " oncoming vehicle on bidi-lane " << lane->getID() << "\n";
398  };
399 #endif
400  return true;
401  }
402  }
403  for (const MSLane* lane : dw.myFlank) {
404  if (!lane->isEmpty()) {
405  MSVehicle* veh = lane->getFirstAnyVehicle();
406  if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
407 #ifdef DEBUG_SIGNALSTATE
408  if (DEBUG_HELPER(rs)) {
409  std::cout << " oncoming vehicle on flank-lane " << lane->getID() << "\n";
410  };
411 #endif
412  return true;
413  }
414  }
415  }
416  for (MSLink* foeLink : dw.myConflictLinks) {
417  if (foeLink->getApproaching().size() != 0) {
418  Approaching closest = getClosest(foeLink);
419  const SUMOVehicle* veh = closest.first;
420  if (veh->getSpeed() > 0 && closest.second.arrivalSpeedBraking > 0
421  && std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
422 #ifdef DEBUG_SIGNALSTATE
423  if (DEBUG_HELPER(rs)) {
424  std::cout << " oncoming vehicle approaching foe link " << foeLink->getDescription() << "\n";
425  }
426 #endif
427  return true;
428  }
429  }
430  }
431  }
432  }
433  }
434  return false;
435 }
436 
437 bool
439  if (link->getJunction() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
440  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
441  if (rs != nullptr && rs->myInsertionConstraints.size() > 0) {
442  const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
443  auto it = rs->myInsertionConstraints.find(tripID);
444  if (it != rs->myInsertionConstraints.end()) {
445  for (MSRailSignalConstraint* c : it->second) {
446  if (!c->cleared()) {
447 #ifdef DEBUG_SIGNALSTATE
448  if (DEBUG_HELPER(rs)) {
449  std::cout << SIMTIME << " rsl=" << rs->getID() << " insertion constraint '" << c->getDescription() << "' for vehicle '" << veh->getID() << "' not cleared\n";
450  }
451 #endif
452  return true;
453  }
454  }
455  }
456  }
457  }
458  return false;
459 }
460 
461 // ===========================================================================
462 // LinkInfo method definitions
463 // ===========================================================================
464 
466  myLink(link), myUniqueDriveWay(false),
467  myLastRerouteTime(-1),
468  myLastRerouteVehicle(nullptr) {
469  ConstMSEdgeVector dummyRoute;
470  dummyRoute.push_back(&link->getLane()->getEdge());
471  DriveWay dw = buildDriveWay(dummyRoute.begin(), dummyRoute.end());
472  myDriveways.push_back(dw);
473 }
474 
475 
476 std::string
478  return myLink->getTLLogic()->getID() + "_" + toString(myLink->getTLIndex());
479 }
480 
481 
484  if (myUniqueDriveWay) {
485  return myDriveways.front();
486  }
487  MSEdge* first = &myLink->getLane()->getEdge();
488  MSRouteIterator firstIt = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), first);
489  if (firstIt == veh->getRoute().end()) {
490  // possibly the vehicle has already gone past the first edge (i.e.
491  // because first is short or the step-length is high)
492  // lets look backward along the route
493  // give some slack because the vehicle might have been braking from a higher speed and using ballistic integration
494  double lookBack = SPEED2DIST(veh->getSpeed() + 10);
495  int routeIndex = veh->getRoutePosition() - 1;
496  while (lookBack > 0 && routeIndex > 0) {
497  const MSEdge* prevEdge = veh->getRoute().getEdges()[routeIndex];
498  if (prevEdge == first) {
499  firstIt = veh->getRoute().begin() + routeIndex;
500  break;
501  }
502  lookBack -= prevEdge->getLength();
503  routeIndex--;
504  }
505  }
506  if (firstIt == veh->getRoute().end()) {
507  WRITE_WARNING("Invalid approach information to rail signal '" + getClickableTLLinkID(myLink) + "' after rerouting for vehicle '" + veh->getID()
508  + "' first driveway edge '" + first->getID() + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
509  return myDriveways.front();
510  }
511  //std::cout << SIMTIME << " veh=" << veh->getID() << " rsl=" << getID() << " dws=" << myDriveways.size() << "\n";
512  for (DriveWay& dw : myDriveways) {
513  // @todo optimize: it is sufficient to check for specific edges (after each switch)
514  auto itRoute = firstIt;
515  auto itDwRoute = dw.myRoute.begin();
516  bool match = true;
517  while (itRoute != veh->getRoute().end() && itDwRoute != dw.myRoute.end()) {
518  if (*itRoute != *itDwRoute) {
519  match = false;
520  //std::cout << " check dw=" << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
521  break;
522  }
523  itRoute++;
524  itDwRoute++;
525  }
526  if (match) {
527  //std::cout << " using dw=" << "\n";
528  return dw;
529  }
530  }
531  DriveWay dw = buildDriveWay(firstIt, veh->getRoute().end());
532  myDriveways.push_back(dw);
533  return myDriveways.back();
534 }
535 
536 
539  // collect lanes and links that are relevant for setting this signal for the current driveWay
540  // For each driveway we collect
541  // - conflictLanes (signal must be red if any conflict lane is occupied)
542  // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
543  // - that cannot break in time (arrivalSpeedBraking > 0)
544  // - approached by a vehicle with higher switching priority (see #3941)
545  // These objects are construct in steps:
546  //
547  // forwardBlock
548  // - search forward recursive from outgoing lane until controlled railSignal link found
549  // -> add all found lanes to conflictLanes
550  //
551  // bidiBlock (if any forwardBlock edge edge has bidi edge)
552  // - search bidi backward recursive until first switch
553  // - from switch search backward recursive all other incoming until controlled rail signal link
554  // -> add final links to conflictLinks
555  //
556  // flanks
557  // - search backward recursive from flanking switches
558  // until controlled railSignal link or protecting switch is found
559  // -> add all found lanes to conflictLanes
560  // -> add final links to conflictLinks
561 
562  DriveWay dw;
563  LaneVisitedMap visited;
564  std::vector<MSLane*> before;
565  visited[myLink->getLaneBefore()] = (int)visited.size();
566  MSLane* fromBidi = myLink->getLaneBefore()->getBidiLane();
567  if (fromBidi != nullptr) {
568  // do not extend to forward block beyond the entering track (in case of a loop)
569  visited[fromBidi] = (int)visited.size();
570  before.push_back(fromBidi);
571  }
572  dw.buildRoute(myLink, 0., first, end, visited);
573  if (dw.myProtectedBidi == nullptr) {
574  dw.myCoreSize = (int)dw.myRoute.size();
575  }
576  dw.checkFlanks(dw.myForward, visited, true);
577  dw.checkFlanks(dw.myBidi, visited, false);
578  dw.checkFlanks(before, visited, true);
579 
580  for (MSLink* link : dw.myFlankSwitches) {
581  //std::cout << getID() << " flankSwitch=" << link->getDescription() << "\n";
582  dw.findFlankProtection(link, 0, visited, link);
583  }
584 
585 #ifdef DEBUG_BUILD_DRIVEWAY
586  if (DEBUG_COND_LINKINFO || true) {
587  std::cout << " buildDriveWay railSignal=" << getID()
588  << "\n route=" << toString(dw.myRoute)
589  << "\n forward=" << toString(dw.myForward)
590  << "\n bidi=" << toString(dw.myBidi)
591  << "\n flank=" << toString(dw.myFlank)
592  << "\n flankSwitch=" << describeLinks(dw.myFlankSwitches)
593  << "\n protSwitch=" << describeLinks(dw.myProtectingSwitches)
594  << "\n coreSize=" << dw.myCoreSize
595  << "\n";
596  }
597 #endif
598 
599  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myForward.begin(), dw.myForward.end());
600  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myBidi.begin(), dw.myBidi.end());
601  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myFlank.begin(), dw.myFlank.end());
602  if (dw.myProtectedBidi != nullptr) {
603  MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(myLink->getTLLogic()));
605  }
606 
607  return dw;
608 }
609 
610 
611 void
613  MSDevice_Routing* rDev = static_cast<MSDevice_Routing*>(veh->getDevice(typeid(MSDevice_Routing)));
615  if (rDev != nullptr
616  && rDev->mayRerouteRailSignal()
617  && (myLastRerouteVehicle != veh
618  // reroute each vehicle only once if no periodic routing is allowed,
619  // otherwise with the specified period
620  || (rDev->getPeriod() > 0 && myLastRerouteTime + rDev->getPeriod() <= now))) {
621  myLastRerouteVehicle = veh;
622  myLastRerouteTime = now;
623 
624 #ifdef DEBUG_REROUTE
625  ConstMSEdgeVector oldRoute = veh->getRoute().getEdges();
626  if (DEBUG_COND_LINKINFO) {
627  std::cout << SIMTIME << " reroute veh=" << veh->getID() << " rs=" << getID() << " occupied=" << toString(occupied) << "\n";
628  }
629 #endif
630  MSRoutingEngine::reroute(*veh, now, "railSignal:" + getID(), false, true, occupied);
631 #ifdef DEBUG_REROUTE
632  // attention this works only if we are not parallel!
633  if (DEBUG_COND_LINKINFO) {
634  if (veh->getRoute().getEdges() != oldRoute) {
635  std::cout << " rerouting successful\n";
636  }
637  }
638 #endif
639  }
640 }
641 
642 
643 // ===========================================================================
644 // DriveWay method definitions
645 // ===========================================================================
646 
647 bool
649  std::string joinVehicle = "";
650  if (!MSGlobals::gUseMesoSim) {
651  const SUMOVehicleParameter::Stop* stop = closest.first->getNextStopParameter();
652  if (stop != nullptr) {
653  joinVehicle = stop->join;
654  }
655  }
656  if (conflictLaneOccupied(joinVehicle)) {
657  for (MSLane* bidi : myBidi) {
658  if (!bidi->empty() && bidi->getBidiLane() != nullptr) {
659  occupied.push_back(&bidi->getBidiLane()->getEdge());
660  }
661  }
662 #ifdef DEBUG_SIGNALSTATE
663  if (gDebugFlag4) {
664  std::cout << " conflictLaneOccupied\n";
665  }
666 #endif
667  return false;
668  }
669  for (MSLink* link : myProtectingSwitches) {
670  if (!findProtection(closest, link)) {
671 #ifdef DEBUG_SIGNALSTATE
672  if (gDebugFlag4) {
673  std::cout << " no protection at switch " << link->getDescription() << "\n";
674  }
675 #endif
676  return false;
677  }
678  }
679  for (MSLink* foeLink : myConflictLinks) {
680  if (hasLinkConflict(closest, foeLink)) {
681 #ifdef DEBUG_SIGNALSTATE
682  if (gDebugFlag4) {
683  std::cout << " linkConflict with " << getTLLinkID(foeLink) << "\n";
684  }
685 #endif
686  return false;
687  }
688  }
689  if (deadlockLaneOccupied()) {
690  return false;
691  }
692  myActive = closest.first;
693  return true;
694 }
695 
696 
697 bool
699  for (MSLink* foeLink : myConflictLinks) {
700  if (foeLink->getApproaching().size() > 0) {
701  return true;
702  }
703  }
704  return false;
705 }
706 
707 
708 bool
710 #ifdef DEBUG_SIGNALSTATE_PRIORITY
711  if (gDebugFlag4) {
712  std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << "\n";
713  }
714 #endif
715  if (foeLink->getApproaching().size() > 0) {
716  Approaching foe = getClosest(foeLink);
717 #ifdef DEBUG_SIGNALSTATE_PRIORITY
718  if (gDebugFlag4) {
719  std::cout << " approaching foe=" << foe.first->getID() << "\n";
720  }
721 #endif
722  const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
723  assert(foeTLL != nullptr);
724  const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
725  MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
726  if (foeRS != nullptr) {
727  const DriveWay& foeDriveWay = foeRS->myLinkInfos[foeLink->getTLIndex()].getDriveWay(foe.first);
728  if (foeDriveWay.conflictLaneOccupied("", false) ||
729  foeDriveWay.deadlockLaneOccupied(false) ||
730  !foeRS->constraintsAllow(foe.first) ||
731  !overlap(foeDriveWay)) {
732 #ifdef DEBUG_SIGNALSTATE_PRIORITY
733  if (gDebugFlag4) {
734  if (foeDriveWay.conflictLaneOccupied("", false)) {
735  std::cout << " foe blocked\n";
736  } else if (!foeRS->constraintsAllow(foe.first)) {
737  std::cout << " foe constrained\n";
738  } else {
739  std::cout << " no overlap\n";
740  }
741  }
742 #endif
743  return false;
744  }
745 #ifdef DEBUG_SIGNALSTATE_PRIORITY
746  if (gDebugFlag4) {
747  std::cout
748  << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
749  << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
750  << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
751  << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
752  << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
753  << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
754  << "\n";
755  }
756 #endif
757  const bool yield = mustYield(veh, foe);
758  if (myStoreVehicles) {
759  myRivalVehicles.push_back(foe.first);
760  if (yield) {
761  myPriorityVehicles.push_back(foe.first);
762  }
763  }
764  return yield;
765  }
766  }
767  return false;
768 }
769 
770 
771 bool
773  if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
774  if (foe.second.arrivalTime == veh.second.arrivalTime) {
775  if (foe.first->getSpeed() == veh.first->getSpeed()) {
776  if (foe.second.dist == veh.second.dist) {
777  if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
778  return foe.first->getNumericalID() < veh.first->getNumericalID();
779  } else {
780  return foe.first->getWaitingTime() > veh.first->getWaitingTime();
781  }
782  } else {
783  return foe.second.dist < veh.second.dist;
784  }
785  } else {
786  return foe.first->getSpeed() > veh.first->getSpeed();
787  }
788  } else {
789  return foe.second.arrivalTime < veh.second.arrivalTime;
790  }
791  } else {
792  return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
793  }
794 }
795 
796 
797 bool
798 MSRailSignal::DriveWay::conflictLaneOccupied(const std::string& joinVehicle, bool store) const {
799  for (const MSLane* lane : myConflictLanes) {
800  if (!lane->isEmpty()) {
801 #ifdef DEBUG_SIGNALSTATE
802  if (gDebugFlag4) {
803  std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied\n";
804  if (joinVehicle != "") {
805  std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
806  lane->releaseVehicles();
807  }
808  }
809 #endif
810  if (lane->getVehicleNumber() == 1 && joinVehicle != "") {
811  std::vector<MSVehicle*> vehs = lane->getVehiclesSecure();
812  const bool ignoreJoinTarget = vehs.front()->getID() == joinVehicle && vehs.front()->isStopped();
813  lane->releaseVehicles();
814  if (ignoreJoinTarget) {
815 #ifdef DEBUG_SIGNALSTATE
816  if (gDebugFlag4) {
817  std::cout << " ignore join-target '" << joinVehicle << ";\n";
818  }
819 #endif
820  continue;
821  }
822  }
823  if (myStoreVehicles && store) {
824  myBlockingVehicles.push_back(lane->getLastAnyVehicle());
825  }
826  return true;
827  }
828  }
829  return false;
830 }
831 
832 bool
834  for (MSLane* lane : myBidiExtended) {
835  if (!lane->empty()) {
836  assert(myBidi.size() != 0);
837  const MSEdge* lastBidi = myBidi.back()->getNextNormal();
838  MSVehicle* foe = lane->getVehiclesSecure().front();
839 #ifdef DEBUG_SIGNALSTATE
840  if (gDebugFlag4) {
841  std::cout << " check for deadlock with " << foe->getID() << "\n";
842  }
843 #endif
844  // check of foe will enter myBidi (need to check at most
845  // myBidiExtended.size edges)
846  const int minEdges = (int)myBidiExtended.size();
847  auto foeIt = foe->getCurrentRouteEdge() + 1;
848  auto foeEnd = foe->getRoute().end();
849  bool conflict = false;
850  for (int i = 0; i < minEdges && foeIt != foeEnd; i++) {
851  if ((*foeIt) == lastBidi) {
852 #ifdef DEBUG_SIGNALSTATE
853  if (gDebugFlag4) {
854  std::cout << " vehicle will enter " << lastBidi->getID() << "\n";
855  }
856 #endif
857  conflict = true;
858  break;
859  }
860  foeIt++;
861  }
862  lane->releaseVehicles();
863  if (conflict) {
864  if (myStoreVehicles && store) {
865  myBlockingVehicles.push_back(foe);
866  }
867  return true;
868  }
869  }
870  }
871  return false;
872 }
873 
874 
875 bool
877  double flankApproachingDist = std::numeric_limits<double>::max();
878  if (link->getApproaching().size() > 0) {
879  Approaching closest = getClosest(link);
880  flankApproachingDist = closest.second.dist;
881  }
882 #ifdef DEBUG_FIND_PROTECTION
883  if (gDebugFlag4) {
884  std::cout << SIMTIME << " findProtection for link=" << link->getDescription() << " flankApproachingDist=" << flankApproachingDist << "\n";
885  }
886 #endif
887  for (MSLink* l2 : link->getLaneBefore()->getLinkCont()) {
888  if (l2->getLane() != link->getLane()) {
889 #ifdef DEBUG_FIND_PROTECTION
890  if (gDebugFlag4) {
891  std::cout << " protectionCandidate=" << l2->getDescription() << " l2Via=" << Named::getIDSecure(l2->getViaLane())
892  << " occupied=" << (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) << "\n";
893  }
894 #endif
895  if (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) {
896 #ifdef DEBUG_FIND_PROTECTION
897  if (gDebugFlag4) {
898  std::cout << " protection from internal=" << l2->getViaLane()->getID() << "\n";
899  }
900 #endif
901  return true;
902  }
903  if (l2->getApproaching().size() > 0) {
904  Approaching closest2 = getClosest(l2);
905  if (closest2.second.dist < flankApproachingDist) {
906 #ifdef DEBUG_FIND_PROTECTION
907  if (gDebugFlag4) {
908  std::cout << " protection from veh=" << closest2.first->getID() << "\n";
909  }
910 #endif
911  return true;
912  }
913  }
914  }
915  }
916  if (link->getApproaching().size() == 0) {
917  return true;
918  } else {
919  // find protection further upstream
920  DriveWay tmp(true);
921  const MSLane* before = link->getLaneBefore();
922  tmp.myFlank.push_back(before);
923  LaneVisitedMap visited;
924  for (auto ili : before->getIncomingLanes()) {
925  tmp.findFlankProtection(ili.viaLink, myMaxFlankLength, visited, ili.viaLink);
926  }
927  tmp.myConflictLanes = tmp.myFlank;
928  tmp.myRoute = myRoute;
929  tmp.myCoreSize = myCoreSize;
930  MSEdgeVector occupied;
931  if (gDebugFlag4) std::cout << SIMTIME << " tmpDW flank=" << toString(tmp.myFlank)
932  << " protSwitch=" << describeLinks(tmp.myProtectingSwitches) << " cLinks=" << describeLinks(tmp.myConflictLinks) << "\n";
933  return tmp.reserve(veh, occupied);
934  }
935 }
936 
937 
938 bool
940  for (int i = 0; i < myCoreSize; i++) {
941  for (int j = 0; j < other.myCoreSize; j++) {
942  const MSEdge* edge = myRoute[i];
943  const MSEdge* edge2 = other.myRoute[j];
944  if (edge->getToJunction() == edge2->getToJunction()
945  || edge->getToJunction() == edge2->getFromJunction()) {
946  // XXX might be rail_crossing with parallel tracks
947  return true;
948  }
949  }
950  }
951  return false;
952 }
953 
954 bool
956  for (const MSLane* lane : myForward) {
957  for (const MSLane* lane2 : other.myForward) {
958  if (lane == lane2) {
959  return true;
960  }
961  }
962  for (const MSLane* lane2 : other.myBidi) {
963  if (lane == lane2) {
964  return true;
965  }
966  }
967  }
968  return false;
969 }
970 
971 void
973  od.openTag("driveWay");
974  od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
975  if (myCoreSize != (int)myRoute.size()) {
976  od.writeAttr("core", myCoreSize);
977  }
978  od.openTag("forward");
979  od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
980  od.closeTag();
981  od.openTag("bidi");
982  od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
983  if (myBidiExtended.size() > 0) {
984  od.lf();
985  od << " ";
986  od.writeAttr("deadlockCheck", toString(myBidiExtended));
987  }
988  od.closeTag();
989  od.openTag("flank");
990  od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
991  od.closeTag();
992 
993  od.openTag("protectingSwitches");
994  std::vector<std::string> links;
995  for (MSLink* link : myProtectingSwitches) {
996  links.push_back(getJunctionLinkID(link));
997  }
998  od.writeAttr("links", joinToString(links, " "));
999  od.closeTag();
1000 
1001  od.openTag("conflictLinks");
1002  std::vector<std::string> signals;
1003  for (MSLink* link : myConflictLinks) {
1004  signals.push_back(getTLLinkID(link));
1005  }
1006  od.writeAttr("signals", joinToString(signals, " "));
1007  od.closeTag();
1008  od.closeTag(); // driveWay
1009 }
1010 
1011 
1012 void
1014  MSRouteIterator next, MSRouteIterator end,
1015  LaneVisitedMap& visited) {
1016  bool seekForwardSignal = true;
1017  bool seekBidiSwitch = true;
1018  bool foundUnsafeSwitch = false;
1019  MSLane* toLane = origin->getViaLaneOrLane();
1020 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1021  gDebugFlag4 = true; //getClickableTLLinkID(origin) == "junction 's24', link 0";
1022  if (gDebugFlag4) std::cout << "buildRoute origin=" << getTLLinkID(origin) << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
1023  << " visited=" << formatVisitedMap(visited) << "\n";
1024 #endif
1025  while ((seekForwardSignal || seekBidiSwitch)) {
1026  if (length > MAX_BLOCK_LENGTH) {
1028  WRITE_WARNING("Block after rail signal " + getClickableTLLinkID(origin) +
1029  " exceeds maximum length (stopped searching after edge '" + toLane->getEdge().getID() + "' (length=" + toString(length) + "m).");
1030  }
1031  myNumWarnings++;
1032  // length exceeded
1033  return;
1034  }
1035 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1036  if (gDebugFlag4) {
1037  std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
1038  }
1039 #endif
1040  if (visited.count(toLane) != 0) {
1041  WRITE_WARNING("Found circular block after railSignal " + getClickableTLLinkID(origin) + " (" + toString(myRoute.size()) + " edges, length " + toString(length) + ")");
1042  //std::cout << getClickableTLLinkID(origin) << " circularBlock1=" << toString(myRoute) << " visited=" << formatVisitedMap(visited) << "\n";
1043  return;
1044  }
1045  if (toLane->getEdge().isNormal()) {
1046  myRoute.push_back(&toLane->getEdge());
1047  if (next != end) {
1048  next++;
1049  }
1050  }
1051  visited[toLane] = (int)visited.size();
1052  length += toLane->getLength();
1053  MSLane* bidi = toLane->getBidiLane();
1054  if (seekForwardSignal) {
1055  if (!foundUnsafeSwitch) {
1056  myForward.push_back(toLane);
1057  }
1058  } else if (bidi == nullptr) {
1059  seekBidiSwitch = false;
1060 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1061  if (gDebugFlag4) {
1062  std::cout << " noBidi, abort search for bidiSwitch\n";
1063  }
1064 #endif
1065  }
1066  if (bidi != nullptr) {
1067  if (foundUnsafeSwitch) {
1068  myBidiExtended.push_back(bidi);
1069  } else {
1070  myBidi.push_back(bidi);
1071  }
1072  visited[bidi] = (int)visited.size();
1073  if (!seekForwardSignal) {
1074  // look for switch that could protect from oncoming vehicles
1075  for (const auto& ili : bidi->getIncomingLanes()) {
1076  if (ili.viaLink->getDirection() == LinkDirection::TURN) {
1077  continue;
1078  }
1079  for (const MSLink* const link : ili.lane->getLinkCont()) {
1080  if (link->getDirection() == LinkDirection::TURN) {
1081  continue;
1082  }
1083  if (link->getViaLaneOrLane() != bidi) {
1084  // this switch is special beause it still lies on the current route
1085  //myProtectingSwitches.push_back(ili.viaLink);
1086  const MSEdge* const bidiNext = bidi->getNextNormal();
1087  myCoreSize = (int)myRoute.size();
1088  if (MSRailSignalControl::getInstance().getUsedEdges().count(bidiNext) == 0) {
1089 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1090  if (gDebugFlag4) {
1091  std::cout << " abort: found protecting switch " << ili.viaLink->getDescription() << "\n";
1092  }
1093 #endif
1094  // if bidi is actually used by a train (rather than
1095  // the other route) we must later adapt this driveway for additional checks (myBidiExtended)
1096  myProtectedBidi = bidiNext;
1097  return;
1098  } else {
1099 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1100  if (gDebugFlag4) {
1101  std::cout << " found unsafe switch " << ili.viaLink->getDescription() << " (used=" << bidiNext->getID() << ")\n";
1102  }
1103 #endif
1104  // trains along our route beyond this switch
1105  // might create deadlock
1106  foundUnsafeSwitch = true;
1107  // the switch itself must still be guarded to ensure safety
1108  for (const auto& ili2 : bidi->getIncomingLanes()) {
1109  if (ili2.viaLink->getDirection() != LinkDirection::TURN) {
1110  myFlankSwitches.push_back(ili.viaLink);
1111  }
1112  }
1113  }
1114  }
1115  }
1116  }
1117  }
1118  }
1119  const std::vector<MSLink*>& links = toLane->getLinkCont();
1120  const MSEdge* current = &toLane->getEdge();
1121  toLane = nullptr;
1122  for (const MSLink* const link : links) {
1123  if (((next != end && &link->getLane()->getEdge() == *next) ||
1124  (next == end && link->getDirection() != LinkDirection::TURN))
1125  && isRailway(link->getViaLaneOrLane()->getPermissions())) {
1126  toLane = link->getViaLaneOrLane();
1127  if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1128  // do not follow turn-arounds even if the route contains a reversal
1129 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1130  if (gDebugFlag4) {
1131  std::cout << " abort: turn-around\n";
1132  }
1133 #endif
1134  return;
1135  }
1136  if (link->getTLLogic() != nullptr) {
1137  if (link->getTLLogic() == origin->getTLLogic()) {
1138  WRITE_WARNING("Found circular block at railSignal " + getClickableTLLinkID(origin) + " (" + toString(myRoute.size()) + " edges, length " + toString(length) + ")");
1139  //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1140  return;
1141  }
1142  seekForwardSignal = false;
1143  seekBidiSwitch = bidi != nullptr;
1144 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1145  if (gDebugFlag4) {
1146  std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1147  }
1148 #endif
1149  }
1150  break;
1151  }
1152  }
1153  if (toLane == nullptr) {
1154  if (next != end) {
1155  // no connection found, jump to next route edge
1156  toLane = (*next)->getLanes()[0];
1157  } else {
1158 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1159  if (gDebugFlag4) {
1160  std::cout << " abort: no next lane available\n";
1161  }
1162 #endif
1163  return;
1164  }
1165  }
1166  }
1167 }
1168 
1169 
1170 void
1171 MSRailSignal::DriveWay::checkFlanks(const std::vector<MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes) {
1172 #ifdef DEBUG_CHECK_FLANKS
1173  std::cout << " checkFlanks lanes=" << toString(lanes) << "\n visited=" << formatVisitedMap(visited) << " allFoes=" << allFoes << "\n";
1174 #endif
1175  for (MSLane* lane : lanes) {
1176  if (lane->isInternal()) {
1177  continue;
1178  }
1179  for (auto ili : lane->getIncomingLanes()) {
1180  if (visited.count(ili.lane->getNormalPredecessorLane()) == 0) {
1181 #ifdef DEBUG_CHECK_FLANKS
1182  std::cout << " add flankSwitch junction=" << ili.viaLink->getJunction()->getID() << " index=" << ili.viaLink->getIndex() << "\n";
1183 #endif
1184  myFlankSwitches.push_back(ili.viaLink);
1185  } else if (allFoes) {
1186  // link is part of the driveway, find foes that cross the driveway without entering
1187  checkCrossingFlanks(ili.viaLink, visited);
1188  }
1189  }
1190  }
1191 }
1192 
1193 
1194 void
1196 #ifdef DEBUG_CHECK_FLANKS
1197  std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1198 #endif
1199  const MSJunction* junction = dwLink->getJunction();
1200  if (junction == nullptr) {
1201  return; // unregulated junction;
1202  }
1203  const MSJunctionLogic* logic = junction->getLogic();
1204  if (logic == nullptr) {
1205  return; // unregulated junction;
1206  }
1207  for (const MSEdge* in : junction->getIncoming()) {
1208  if (in->isInternal()) {
1209  continue;
1210  }
1211  for (MSLane* inLane : in->getLanes()) {
1212  if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0) {
1213  for (MSLink* link : inLane->getLinkCont()) {
1214  if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1215  && visited.count(link->getLane()) == 0) {
1216 #ifdef DEBUG_CHECK_FLANKS
1217  std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1218 #endif
1219  if (link->getViaLane() == nullptr) {
1220  myFlankSwitches.push_back(link);
1221  } else {
1222  myFlankSwitches.push_back(link->getViaLane()->getLinkCont().front());
1223  }
1224  }
1225  }
1226  }
1227  }
1228  }
1229 }
1230 
1231 void
1232 MSRailSignal::DriveWay::findFlankProtection(MSLink* link, double length, LaneVisitedMap& visited, MSLink* origLink) {
1233 #ifdef DEBUG_CHECK_FLANKS
1234  std::cout << " findFlankProtection link=" << link->getDescription() << " length=" << length << " origLink=" << origLink->getDescription() << "\n";
1235 #endif
1236  if (link->getTLLogic() != nullptr) {
1237  // guarded by signal
1238 #ifdef DEBUG_CHECK_FLANKS
1239  std::cout << " flank guarded by " << link->getTLLogic()->getID() << "\n";
1240 #endif
1241  myConflictLinks.push_back(link);
1242  } else if (length > MAX_BLOCK_LENGTH) {
1243  // length exceeded
1245  WRITE_WARNING("Incoming block at junction '" + origLink->getJunction()->getID() + "', link " + toString(origLink->getIndex()) + " exceeds maximum length (stopped searching after lane '" + link->getLane()->getID() + "' (length=" + toString(length) + "m).");
1246  }
1247  myNumWarnings++;
1248  } else {
1249  // find normal lane before this link
1250  const MSLane* lane = link->getLaneBefore();
1251  const bool isNew = visited.count(lane) == 0;
1252  if (isNew || (visited[lane] > visited[origLink->getLane()] && std::find(myForward.begin(), myForward.end(), lane) == myForward.end())) {
1253  if (isNew) {
1254  visited[lane] = (int)visited.size();
1255  }
1256  length += lane->getLength();
1257  if (lane->isInternal()) {
1258  myFlank.push_back(lane);
1259  findFlankProtection(lane->getIncomingLanes().front().viaLink, length, visited, origLink);
1260  } else {
1261  bool foundPSwitch = false;
1262  for (MSLink* l2 : lane->getLinkCont()) {
1263 #ifdef DEBUG_CHECK_FLANKS
1264  std::cout << " lane=" << lane->getID() << " visitedIndex=" << visited[lane] << " origIndex=" << visited[origLink->getLane()] << " cand=" << l2->getDescription() << "\n";
1265 #endif
1266  if (l2->getDirection() != LinkDirection::TURN && l2->getLane() != link->getLane()) {
1267  foundPSwitch = true;
1268  // found potential protection
1269 #ifdef DEBUG_CHECK_FLANKS
1270  std::cout << " protectingSwitch=" << l2->getDescription() << " for flank=" << link->getDescription() << "\n";
1271 #endif
1272  myProtectingSwitches.push_back(link);
1273  }
1274  }
1275  if (!foundPSwitch) {
1276  myFlank.push_back(lane);
1277  // continue search for protection upstream recursively
1278  for (auto ili : lane->getIncomingLanes()) {
1279  if (ili.viaLink->getDirection() != LinkDirection::TURN) {
1280  findFlankProtection(ili.viaLink, length, visited, origLink);
1281  }
1282  }
1283  }
1284  }
1285  } else {
1286 #ifdef DEBUG_CHECK_FLANKS
1287  std::cout << " laneBefore=" << lane->getID() << " already visited. index=" << visited[lane] << " origAfter=" << origLink->getLane()->getID() << " origIndex=" << visited[origLink->getLane()] << "\n";
1288 #endif
1289  }
1290  }
1291  myMaxFlankLength = MAX2(myMaxFlankLength, length);
1292 }
1293 
1294 void
1296  myBlockingVehicles.clear();
1297  myRivalVehicles.clear();
1298  myPriorityVehicles.clear();
1299  myConstraintInfo = "";
1300  myStoreVehicles = true;
1301  LinkInfo& li = myLinkInfos[linkIndex];
1302  if (li.myLink->getApproaching().size() > 0) {
1303  Approaching closest = getClosest(li.myLink);
1304  DriveWay& driveway = li.getDriveWay(closest.first);
1305  MSEdgeVector occupied;
1306  // call for side effects
1307  driveway.reserve(closest, occupied);
1308  constraintsAllow(closest.first);
1309  } else {
1310  li.myDriveways.front().conflictLaneOccupied();
1311  }
1312  myStoreVehicles = false;
1313 }
1314 
1317  storeTraCIVehicles(linkIndex);
1318  return myBlockingVehicles;
1319 }
1320 
1323  storeTraCIVehicles(linkIndex);
1324  return myRivalVehicles;
1325 }
1326 
1329  storeTraCIVehicles(linkIndex);
1330  return myPriorityVehicles;
1331 }
1332 
1333 std::string
1335  storeTraCIVehicles(linkIndex);
1336  return myConstraintInfo;
1337 }
1338 
1340 MSRailSignal::retrieveDriveWay(int numericalID) const {
1341  for (const LinkInfo& li : myLinkInfos) {
1342  for (const DriveWay& dw : li.myDriveways) {
1343  if (dw.myNumericalID == numericalID) {
1344  return dw;
1345  }
1346  }
1347  }
1348  throw ProcessError("Invalid driveway id " + toString(numericalID) + " at railSignal '" + getID() + "'");
1349 }
1350 
1351 
1352 void
1354  if (mySwitchedGreenFlanks.size() > 0) {
1355  for (const auto& item : mySwitchedGreenFlanks) {
1356  for (const auto& item2 : mySwitchedGreenFlanks) {
1357  if (item.second < item2.second) {
1358  bool conflict = false;
1359  std::pair<int, int> code(item.second, item2.second);
1360  auto it = myDriveWayCompatibility.find(code);
1361  if (it != myDriveWayCompatibility.end()) {
1362  conflict = it->second;
1363  } else {
1364  // new driveway pair
1365  const MSRailSignal* rs = static_cast<const MSRailSignal*>(item.first->getTLLogic());
1366  const MSRailSignal* rs2 = static_cast<const MSRailSignal*>(item2.first->getTLLogic());
1367  const DriveWay& dw = rs->retrieveDriveWay(item.second);
1368  const DriveWay& dw2 = rs2->retrieveDriveWay(item2.second);
1369  // overlap may return true if the driveways are consecutive forward sections
1370  conflict = dw.flankConflict(dw2) || dw2.flankConflict(dw);
1371  myDriveWayCompatibility[code] = conflict;
1372 #ifdef DEBUG_RECHECKGREEN
1373  std::cout << SIMTIME << " new code " << code.first << "," << code.second << " conflict=" << conflict << " dw=" << toString(dw.myRoute) << " dw2=" << toString(dw2.myRoute) << "\n";
1374 #endif
1375  }
1376  if (conflict) {
1377  MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(item.first->getTLLogic()));
1378  MSRailSignal* rs2 = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(item2.first->getTLLogic()));
1379  const Approaching& veh = rs->getClosest(item.first);
1380  const Approaching& veh2 = rs2->getClosest(item2.first);
1381  if (DriveWay::mustYield(veh, veh2)) {
1382  std::string state = rs->myCurrentPhase.getState();
1383  state[item.first->getTLIndex()] = 'r';
1384  rs->myCurrentPhase.setState(state);
1386 #ifdef DEBUG_RECHECKGREEN
1387  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item.first)
1388  << " (" << veh.first->getID() << " yields to " << veh2.first->getID() << "\n";
1389 #endif
1390 #ifdef DEBUG_SIGNALSTATE
1391  if (DEBUG_HELPER(rs)) {
1392  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item.first)
1393  << " (" << veh.first->getID() << " yields to " << veh2.first->getID() << "\n";
1394  }
1395 #endif
1396  } else {
1397  std::string state = rs2->myCurrentPhase.getState();
1398  state[item2.first->getTLIndex()] = 'r';
1399  rs2->myCurrentPhase.setState(state);
1400  rs2->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1401 #ifdef DEBUG_RECHECKGREEN
1402  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item2.first)
1403  << " (" << veh2.first->getID() << " yields to " << veh.first->getID() << "\n";
1404 #endif
1405 #ifdef DEBUG_SIGNALSTATE
1406  if (DEBUG_HELPER(rs2)) {
1407  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item2.first)
1408  << " (" << veh2.first->getID() << " yields to " << veh.first->getID() << "\n";
1409  }
1410 #endif
1411  }
1412  }
1413  }
1414  }
1415  }
1416  mySwitchedGreenFlanks.clear();
1417  }
1418 }
1419 
1420 void
1422  for (LinkInfo& li : myLinkInfos) {
1423  for (auto it = li.myDriveways.begin(); it != li.myDriveways.end(); it++) {
1424  const DriveWay& dw = *it;
1425  if (dw.myNumericalID == numericalID) {
1426 #ifdef DEBUG_DRIVEWAY_UPDATE
1427  std::cout << SIMTIME << " rail signal junction '" << getID() << "' requires update for driveway " << numericalID << "\n";
1428 #endif
1429  std::vector<const MSEdge*> route = dw.myRoute;
1430  li.myDriveways.erase(it);
1431  if (li.myDriveways.size() == 0) {
1432  // rebuild default driveway
1433  li.myDriveways.push_back(li.buildDriveWay(route.begin(), route.end()));
1434  }
1435  return;
1436  }
1437  }
1438  }
1439 }
1440 
1441 std::string
1443  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1444  if (myLinkInfos.size() == 1) {
1445  return toString(rs->getBlockingVehicles(0));
1446  } else {
1447  std::string result;
1448  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1449  result += toString(i) + ": " + toString(rs->getBlockingVehicles(i)) + ";";
1450  }
1451  return result;
1452  }
1453 }
1454 std::string
1456  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1457  if (myLinkInfos.size() == 1) {
1458  return toString(rs->getRivalVehicles(0));
1459  } else {
1460  std::string result;
1461  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1462  result += toString(i) + ": " + toString(rs->getRivalVehicles(i)) + ";";
1463  }
1464  return result;
1465  }
1466 }
1467 std::string
1469  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1470  if (myLinkInfos.size() == 1) {
1471  return toString(rs->getPriorityVehicles(0));
1472  } else {
1473  std::string result;
1474  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1475  result += toString(i) + ": " + toString(rs->getPriorityVehicles(i)) + ";";
1476  }
1477  return result;
1478  }
1479 }
1480 std::string
1482  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1483  if (myLinkInfos.size() == 1) {
1484  return rs->getConstraintInfo(0);
1485  } else {
1486  std::string result;
1487  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1488  result += toString(i) + ": " + rs->getConstraintInfo(i);
1489  }
1490  return result;
1491  }
1492 }
1493 
1494 /****************************************************************************/
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition: MSEdge.h:73
#define DEBUG_COND_LINKINFO
#define DEBUG_HELPER(obj)
#define MAX_SIGNAL_WARNINGS
#define DEBUG_COND
#define MAX_BLOCK_LENGTH
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition: MSRoute.h:54
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:277
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define SPEED2DIST(x)
Definition: SUMOTime.h:43
#define SIMTIME
Definition: SUMOTime.h:60
long long int SUMOTime
Definition: SUMOTime.h:31
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
TrafficLightType
@ TURN
The link is a 180 degree turn.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ SUMO_ATTR_EDGES
the edges of a route
@ SUMO_ATTR_LANES
@ SUMO_ATTR_TO
@ SUMO_ATTR_FROM
@ SUMO_ATTR_ID
@ SUMO_ATTR_TLLINKINDEX
link: the index of the link within the traffic light
bool gDebugFlag4
Definition: StdDefs.cpp:34
T MAX2(T a, T b)
Definition: StdDefs.h:79
#define SUMO_MAX_CONNECTIONS
the maximum number of connections across an intersection
Definition: StdDefs.h:40
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:250
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
const MSRoute & getRoute() const
Returns the current route.
A device that performs vehicle rerouting based on current edge speeds.
SUMOTime getPeriod() const
bool mayRerouteRailSignal() const
return whether the equipped vehicle may receive dispatch information at a rail signal
A road/street connecting two junctions.
Definition: MSEdge.h:77
bool isNormal() const
return whether this edge is an internal edge
Definition: MSEdge.h:251
const MSJunction * getFromJunction() const
Definition: MSEdge.h:388
double getLength() const
return the length of the edge
Definition: MSEdge.h:630
const MSJunction * getToJunction() const
Definition: MSEdge.h:392
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition: MSEdge.h:270
static bool gUseMesoSim
Definition: MSGlobals.h:88
The base class for an intersection.
Definition: MSJunction.h:58
const ConstMSEdgeVector & getIncoming() const
Definition: MSJunction.h:105
SumoXMLNodeType getType() const
return the type of this Junction
Definition: MSJunction.h:130
virtual const MSJunctionLogic * getLogic() const
Definition: MSJunction.h:138
virtual const MSLogicJunction::LinkBits & getFoesFor(int linkIndex) const
Returns the foes for the given link.
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:640
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2065
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition: MSLane.cpp:1884
double getLength() const
Returns the lane's length.
Definition: MSLane.h:539
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:825
bool isInternal() const
Definition: MSLane.cpp:2036
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:673
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition: MSLane.cpp:3835
bool isEmpty() const
Definition: MSLane.h:774
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:313
The definition of a single phase of a tls logic.
const std::string & getState() const
Returns the state within this phase.
void setState(const std::string &_state)
A base class for constraints.
virtual std::string getDescription() const
virtual bool cleared() const =0
whether the constraint has been met
const std::set< const MSEdge * > & getUsedEdges() const
static MSRailSignalControl & getInstance()
void registerProtectedDriveway(MSRailSignal *rs, int driveWayID, const MSEdge *protectedBidi)
mark driveway that must receive additional checks if protectedBidi is ever used by a train route
A signal for rails.
Definition: MSRailSignal.h:46
bool constraintsAllow(const SUMOVehicle *veh) const
whether the given vehicle is free to drive
static VehicleVector myRivalVehicles
Definition: MSRailSignal.h:457
std::string getBlockingVehicleIDs() const
int getIndexFromOffset(SUMOTime offset) const
Returns the step (the phasenumber) of a given position of the cycle.
Phases myPhases
The list of phases this logic uses.
Definition: MSRailSignal.h:430
std::string getConstraintInfo(int linkIndex)
return information regarding active rail signal constraints for the closest approaching vehicle
std::map< std::string, std::vector< MSRailSignalConstraint * > > myInsertionConstraints
Definition: MSRailSignal.h:440
static VehicleVector myPriorityVehicles
Definition: MSRailSignal.h:458
int myPhaseIndex
MSTrafficLightLogic requires that the phase index changes whenever signals change their state.
Definition: MSRailSignal.h:436
int getPhaseNumber() const
Returns the number of phases.
static std::string myConstraintInfo
Definition: MSRailSignal.h:459
MSPhaseDefinition myCurrentPhase
The current phase.
Definition: MSRailSignal.h:433
void addConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register contraint for signal switching
static std::string getClickableTLLinkID(MSLink *link)
return logicID_linkIndex in a way that allows clicking in sumo-gui
std::vector< LinkInfo > myLinkInfos
data storage for every link at this node (more than one when directly guarding a switch)
Definition: MSRailSignal.h:400
std::string getPriorityVehicleIDs() const
static int myDriveWayIndex
Definition: MSRailSignal.h:447
static std::string describeLinks(std::vector< MSLink * > links)
print link descriptions
VehicleVector getRivalVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and are in conflict with vehicles that wis...
void writeBlocks(OutputDevice &od) const
write rail signal block output for all links and driveways
~MSRailSignal()
Destructor.
VehicleVector getPriorityVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and have priority over vehicles that wish ...
const Phases & getPhases() const
Returns the phases of this tls program.
static VehicleVector myBlockingVehicles
Definition: MSRailSignal.h:456
void storeTraCIVehicles(int linkIndex)
update vehicle lists for traci calls
SUMOTime getOffsetFromIndex(int index) const
Returns the position (start of a phase during a cycle) from of a given step.
static Approaching getClosest(MSLink *link)
get the closest vehicle approaching the given link
std::map< std::string, std::vector< MSRailSignalConstraint * > > myConstraints
map from tripId to constraint list
Definition: MSRailSignal.h:439
static std::map< std::pair< int, int >, bool > myDriveWayCompatibility
Definition: MSRailSignal.h:446
std::pair< const SUMOVehicle *const, const MSLink::ApproachingVehicleInformation > Approaching
Definition: MSRailSignal.h:242
SUMOTime trySwitch()
Switches to the next phase.
static void recheckGreen()
final check for driveway compatibility of signals that switched green in this step
static std::string getJunctionLinkID(MSLink *link)
return junctionID_junctionLinkIndex
static int myNumWarnings
Definition: MSRailSignal.h:442
const DriveWay & retrieveDriveWay(int numericalID) const
static bool myStoreVehicles
Definition: MSRailSignal.h:455
void addInsertionConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register contraint for vehicle insertion
const MSPhaseDefinition & getPhase(int givenstep) const
Returns the definition of the phase from the given position within the plan.
std::map< const MSLane *, int, ComparatorNumericalIdLess > LaneVisitedMap
Definition: MSRailSignal.h:244
static std::vector< std::pair< MSLink *, int > > mySwitchedGreenFlanks
list of signals that switched green along with driveway index
Definition: MSRailSignal.h:445
void addLink(MSLink *link, MSLane *lane, int pos)
Adds a link on building.
SUMOTime getPhaseIndexAtTime(SUMOTime simStep) const
Returns the index of the logic at the given simulation step.
MSRailSignal(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, SUMOTime delay, const std::map< std::string, std::string > &parameters)
Constructor.
void init(NLDetectorBuilder &nb)
Initialises the rail signal with information about adjacent rail signals.
void updateDriveway(int numericalID)
update driveway for extended deadlock protection
const MSPhaseDefinition & getCurrentPhaseDef() const
Returns the definition of the current phase.
std::string getConstraintInfo() const
static std::string formatVisitedMap(const LaneVisitedMap &visited)
print link descriptions
void adaptLinkInformationFrom(const MSTrafficLightLogic &logic)
Applies information about controlled links and lanes from the given logic.
VehicleVector getBlockingVehicles(int linkIndex)
return vehicles that block the intersection/rail signal for vehicles that wish to pass the given link...
void updateCurrentPhase()
returns the state of the signal that actually required
static bool hasInsertionConstraint(MSLink *link, const MSVehicle *veh)
static bool hasOncomingRailTraffic(MSLink *link)
std::string getRivalVehicleIDs() const
int getCurrentPhaseIndex() const
Returns the current index within the program.
static std::string getTLLinkID(MSLink *link)
return logicID_linkIndex
MSRouteIterator end() const
Returns the end of the list of edges to pass.
Definition: MSRoute.cpp:75
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition: MSRoute.cpp:69
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:120
static void reroute(SUMOVehicle &vehicle, const SUMOTime currentTime, const std::string &info, const bool onInit=false, const bool silent=false, const MSEdgeVector &prohibited=MSEdgeVector())
initiate the rerouting, create router / thread pool on first use
A class that stores and controls tls and switching of their programs.
The parent class for traffic light logics.
virtual void adaptLinkInformationFrom(const MSTrafficLightLogic &logic)
Applies information about controlled links and lanes from the given logic.
std::vector< const SUMOVehicle * > VehicleVector
list of vehicles
SUMOTime myDefaultCycleTime
The cycle time (without changes)
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index.
int myNumLinks
number of controlled links
bool setTrafficLightSignals(SUMOTime t) const
Applies the current signal states to controlled links.
virtual void addLink(MSLink *link, MSLane *lane, int pos)
Adds a link on building.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
LinkVectorVector myLinks
The list of LinkVectors; each vector contains the links that belong to the same link index.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
Builds detectors for microsim.
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:66
const std::string & getID() const
Returns the id.
Definition: Named.h:73
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:60
void lf()
writes a line feed if applicable
Definition: OutputDevice.h:227
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:239
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
virtual double getSpeed() const =0
Returns the object's current speed.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
Representation of a vehicle.
Definition: SUMOVehicle.h:58
virtual const MSRoute & getRoute() const =0
Returns the current route.
virtual MSVehicleDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles route.
virtual int getRoutePosition() const =0
return index of edge within route
Definition of vehicle stop (position and duration)
std::string join
the id of the vehicle (train portion) to which this vehicle shall be joined
void checkFlanks(const std::vector< MSLane * > &lanes, const LaneVisitedMap &visited, bool allFoes)
find switches that threathen this driveway
void writeBlocks(OutputDevice &od) const
Write block items for this driveway.
void buildRoute(MSLink *origin, double length, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap &visited)
std::vector< MSLink * > myFlankSwitches
Definition: MSRailSignal.h:304
int myCoreSize
number of edges in myRoute where overlap with other driveways is forbidden
Definition: MSRailSignal.h:280
bool deadlockLaneOccupied(bool store=true) const
whether any of myBidiExtended is occupied by a vehicle that targets myBidi
const MSEdge * myProtectedBidi
switch assumed safe from bidi-traffic
Definition: MSRailSignal.h:274
std::vector< const MSLane * > myConflictLanes
the lanes that must be clear of trains before this signal can switch to green
Definition: MSRailSignal.h:300
bool overlap(const DriveWay &other) const
Wether this driveway (route) overlaps with the given one.
int myNumericalID
global driveway index
Definition: MSRailSignal.h:265
std::vector< MSLink * > myConflictLinks
Definition: MSRailSignal.h:315
void checkCrossingFlanks(MSLink *dwLink, const LaneVisitedMap &visited)
find links that cross the driveway without entering it
std::vector< MSLane * > myBidi
Definition: MSRailSignal.h:289
void findFlankProtection(MSLink *link, double length, LaneVisitedMap &visited, MSLink *origLink)
find upstream protection from the given link
bool conflictLaneOccupied(const std::string &joinVehicle="", bool store=true) const
whether any of myConflictLanes is occupied (vehicles that are the target of a join must be ignored)
std::vector< const MSLane * > myFlank
Definition: MSRailSignal.h:297
std::vector< const MSEdge * > myRoute
list of edges for matching against train routes
Definition: MSRailSignal.h:277
bool hasLinkConflict(const Approaching &closest, MSLink *foeLink) const
Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link...
bool findProtection(const Approaching &veh, MSLink *link) const
find protection for the given vehicle starting at a switch
std::vector< MSLink * > myProtectingSwitches
Definition: MSRailSignal.h:310
std::vector< MSLane * > myForward
Definition: MSRailSignal.h:284
bool conflictLinkApproached() const
Whether any of the conflict linkes have approaching vehicles.
bool reserve(const Approaching &closest, MSEdgeVector &occupied)
attempt reserve this driveway for the given vehicle
bool flankConflict(const DriveWay &other) const
Wether there is a flank conflict with the given driveway.
static bool mustYield(const Approaching &veh, const Approaching &foe)
Whether veh must yield to the foe train.