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-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
16 // A rail signal logic
17 /****************************************************************************/
18 
19 
20 // ===========================================================================
21 // included modules
22 // ===========================================================================
23 #include <config.h>
24 
25 #include <cassert>
26 #include <utility>
27 #include <vector>
28 #include <bitset>
31 #include <microsim/MSNet.h>
32 #include <microsim/MSEdge.h>
33 #include <microsim/MSLane.h>
34 #include <microsim/MSLink.h>
36 #include <microsim/MSVehicle.h>
39 #include <microsim/MSLane.h>
40 
41 #include "MSTLLogicControl.h"
42 #include "MSTrafficLightLogic.h"
43 #include "MSPhaseDefinition.h"
44 #include "MSTLLogicControl.h"
45 #include "MSRailSignal.h"
46 
47 // typical block length in germany on main lines is 3-5km on branch lines up to 7km
48 // special branches that are used by one train exclusively could also be up to 20km in length
49 // minimum block size in germany is 37.5m (LZB)
50 // larger countries (USA, Russia) might see blocks beyond 20km)
51 #define MAX_BLOCK_LENGTH 20000
52 #define MAX_SIGNAL_WARNINGS 10
53 
54 //#define DEBUG_BUILD_DRIVEWAY
55 //#define DEBUG_CHECK_FLANKS
56 
57 #define DEBUG_SIGNALSTATE
58 #define DEBUG_SIGNALSTATE_PRIORITY
59 #define DEBUG_FIND_PROTECTION
60 //#define DEBUG_REROUTE
61 
62 #define DEBUG_COND DEBUG_HELPER(this)
63 #define DEBUG_COND_LINKINFO DEBUG_HELPER(myLink->getTLLogic())
64 #define DEBUG_HELPER(obj) ((obj)->isSelected())
65 //#define DEBUG_HELPER(obj) ((obj)->getID() == "w2")
66 //#define DEBUG_HELPER(obj) (true)
67 
68 // ===========================================================================
69 // static value definitions
70 // ===========================================================================
72 
73 // ===========================================================================
74 // method definitions
75 // ===========================================================================
77  const std::string& id, const std::string& programID,
78  const std::map<std::string, std::string>& parameters) :
79  MSTrafficLightLogic(tlcontrol, id, programID, TLTYPE_RAIL_SIGNAL, DELTA_T, parameters),
80  myCurrentPhase(DELTA_T, std::string(SUMO_MAX_CONNECTIONS, 'X'), -1), // dummy phase
81  myPhaseIndex(0) {
83 }
84 
85 void
87  assert(myLanes.size() > 0);
88  for (LinkVector& links : myLinks) { //for every link index
89  if (links.size() != 1) {
90  throw ProcessError("At railSignal '" + getID() + "' found " + toString(links.size())
91  + " links controlled by index " + toString(links[0]->getTLIndex()));
92  }
93  myLinkInfos.push_back(LinkInfo(links[0]));
94  }
96  setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
97 }
98 
99 
101 }
102 
103 
104 // ----------- Handling of controlled links
105 void
109 }
110 
111 
112 // ------------ Switching and setting current rows
113 SUMOTime
116  return DELTA_T;
117 }
118 
119 
120 
121 void
123 #ifdef DEBUG_SIGNALSTATE
125 #endif
126  // green by default so vehicles can be inserted at the borders of the network
127  std::string state(myLinks.size(), 'G');
128  for (LinkInfo& li : myLinkInfos) {
129  if (li.myLink->getApproaching().size() > 0) {
130  Approaching closest = getClosest(li.myLink);
131  DriveWay& driveway = li.getDriveWay(closest.first);
132  //std::cout << SIMTIME << " signal=" << getTLLinkID(li.myLink) << " veh=" << closest.first->getID() << " dw:\n";
133  //driveway.writeBlocks(*OutputDevice_COUT::getDevice());
134  MSEdgeVector occupied;
135  if (!driveway.reserve(closest, occupied)) {
136  state[li.myLink->getTLIndex()] = 'r';
137  if (occupied.size() > 0) {
138  li.reroute(const_cast<SUMOVehicle*>(closest.first), occupied);
139  }
140 #ifdef DEBUG_SIGNALSTATE
141  if (gDebugFlag4) {
142  std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " notReserved\n";
143  }
144 #endif
145  } else {
146  state[li.myLink->getTLIndex()] = 'G';
147 #ifdef DEBUG_SIGNALSTATE
148  if (gDebugFlag4) {
149  std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " reserved\n";
150  }
151 #endif
152  }
153  } else {
154  DriveWay& driveway = li.myDriveways.front();
155  if (driveway.conflictLaneOccupied() || driveway.conflictLinkApproached()) {
156 #ifdef DEBUG_SIGNALSTATE
157  if (gDebugFlag4) {
158  std::cout << SIMTIME << " rsl=" << li.getID() << " red for default driveway\n";
159  }
160 #endif
161  state[li.myLink->getTLIndex()] = 'r';
162  }
163  }
164  }
165  if (myCurrentPhase.getState() != state) {
166  myCurrentPhase.setState(state);
168  }
169 #ifdef DEBUG_SIGNALSTATE
170  gDebugFlag4 = false;
171 #endif
172 }
173 
174 
175 // ------------ Static Information Retrieval
176 int
178  return 0;
179 }
180 
183  return myPhases;
184 }
185 
186 const MSPhaseDefinition&
188  return myCurrentPhase;
189 }
190 
191 // ------------ Dynamic Information Retrieval
192 int
194  return myPhaseIndex;
195 }
196 
197 const MSPhaseDefinition&
199  return myCurrentPhase;
200 }
201 
202 // ------------ Conversion between time and phase
203 SUMOTime
205  return 0;
206 }
207 
208 SUMOTime
210  return 0;
211 }
212 
213 int
215  return 0;
216 }
217 
218 
219 void
220 MSRailSignal::addLink(MSLink* link, MSLane* lane, int pos) {
221  if (pos >= 0) {
222  MSTrafficLightLogic::addLink(link, lane, pos);
223  } // ignore uncontrolled link
224 }
225 
226 
227 std::string
229  return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
230 }
231 
232 std::string
234  return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
235 }
236 
237 std::string
238 MSRailSignal::describeLinks(std::vector<MSLink*> links) {
239  std::string result;
240  for (MSLink* link : links) {
241  result += link->getDescription() + " ";
242  }
243  return result;
244 }
245 
248  assert(link->getApproaching().size() > 0);
249  double minDist = std::numeric_limits<double>::max();
250  auto closestIt = link->getApproaching().begin();
251  for (auto apprIt = link->getApproaching().begin(); apprIt != link->getApproaching().end(); apprIt++) {
252  if (apprIt->second.dist < minDist) {
253  minDist = apprIt->second.dist;
254  closestIt = apprIt;
255  }
256  }
257  // maybe a parallel link has a closer vehicle
258  /*
259  for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
260  if (link2 != link) {
261  for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
262  if (apprIt2->second.dist < minDist) {
263  minDist = apprIt2->second.dist;
264  closestIt = apprIt2;
265  }
266  }
267  }
268  }
269  */
270  return *closestIt;
271 }
272 
273 void
275  od.openTag("railSignal");
277  for (const LinkInfo& li : myLinkInfos) {
278  MSLink* link = li.myLink;
279  od.openTag("link");
283  for (const DriveWay& dw : li.myDriveways) {
284  dw.writeBlocks(od);
285  }
286  od.closeTag(); // link
287  }
288  od.closeTag(); // railSignal
289 }
290 
291 
292 bool
294  if (link->getJunction()->getType() == NODETYPE_RAIL_SIGNAL && link->getState() == LINKSTATE_TL_RED) {
295  const MSEdge* bidi = link->getLaneBefore()->getEdge().getBidiEdge();
296  if (bidi == nullptr) {
297  return false;
298  }
299  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
300  if (rs != nullptr) {
301  const LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
302  for (const DriveWay& dw : li.myDriveways) {
303  //std::cout << SIMTIME <<< " hasOncomingRailTraffic link=" << getTLLinkID(link) << " dwRoute=" << toString(dw.myRoute) << " bidi=" << toString(dw.myBidi) << "\n";
304  for (MSLane* lane : dw.myBidi) {
305  if (!lane->isEmpty()) {
306  return true;
307  }
308  }
309  for (const MSLane* lane : dw.myFlank) {
310  if (!lane->isEmpty()) {
311  MSVehicle* veh = lane->getFirstAnyVehicle();
312  if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
313  return true;
314  }
315  }
316  }
317  for (MSLink* foeLink : dw.myConflictLinks) {
318  if (foeLink->getApproaching().size() != 0) {
319  Approaching closest = getClosest(foeLink);
320  const SUMOVehicle* veh = closest.first;
321  if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
322  return true;
323  }
324  }
325  }
326  }
327  }
328  }
329  return false;
330 }
331 
332 // ===========================================================================
333 // LinkInfo method definitions
334 // ===========================================================================
335 
337  myLink(link), myUniqueDriveWay(false),
338  myLastRerouteTime(-1),
339  myLastRerouteVehicle(nullptr) {
340  ConstMSEdgeVector dummyRoute;
341  dummyRoute.push_back(&link->getLane()->getEdge());
342  buildDriveWay(dummyRoute.begin(), dummyRoute.end());
343 }
344 
345 
346 std::string
348  return myLink->getTLLogic()->getID() + "_" + toString(myLink->getTLIndex());
349 }
350 
351 
354  if (myUniqueDriveWay) {
355  return myDriveways.front();
356  }
357  MSEdge* first = &myLink->getLane()->getEdge();
358  MSRouteIterator firstIt = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), first);
359  if (firstIt == veh->getRoute().end()) {
360  WRITE_WARNING("Invalid approach information after rerouting");
361  return myDriveways.front();
362  }
363  //std::cout << SIMTIME << " veh=" << veh->getID() << " rsl=" << getID() << " dws=" << myDriveways.size() << "\n";
364  for (DriveWay& dw : myDriveways) {
365  // @todo optimize: it is sufficient to check for specific edges (after each switch)
366  auto itRoute = firstIt;
367  auto itDwRoute = dw.myRoute.begin();
368  bool match = true;
369  while (itRoute != veh->getRoute().end() && itDwRoute != dw.myRoute.end()) {
370  if (*itRoute != *itDwRoute) {
371  match = false;
372  //std::cout << " check dw=" << dw.myIndex << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
373  break;
374  }
375  itRoute++;
376  itDwRoute++;
377  }
378  if (match) {
379  //std::cout << " using dw=" << dw.myIndex << "\n";
380  return dw;
381  }
382  }
383  return buildDriveWay(firstIt, veh->getRoute().end());
384 }
385 
386 
389  // collect lanes and links that are relevant for setting this signal for the current driveWay
390  // For each driveway we collect
391  // - conflictLanes (signal must be red if any conflict lane is occupied)
392  // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
393  // - that cannot break in time (arrivalSpeedBraking > 0)
394  // - approached by a vehicle with higher switching priority (see #3941)
395  // These objects are construct in steps:
396  //
397  // forwardBlock
398  // - search forward recursive from outgoing lane until controlled railSignal link found
399  // -> add all found lanes to conflictLanes
400  //
401  // bidiBlock (if any forwardBlock edge edge has bidi edge)
402  // - search bidi backward recursive until first switch
403  // - from switch search backward recursive all other incoming until controlled rail signal link
404  // -> add final links to conflictLinks
405  //
406  // flanks
407  // - search backward recursive from flanking switches
408  // until controlled railSignal link or protecting switch is found
409  // -> add all found lanes to conflictLanes
410  // -> add final links to conflictLinks
411 
412  DriveWay dw((int)myDriveways.size());
413  LaneSet visited;
414  std::vector<MSLane*> before;
415  visited.insert(myLink->getLaneBefore());
416  MSLane* fromBidi = myLink->getLaneBefore()->getBidiLane();
417  if (fromBidi != nullptr) {
418  // do not extend to forward block beyond the entering track (in case of a loop)
419  visited.insert(fromBidi);
420  before.push_back(fromBidi);
421  }
422  dw.buildRoute(myLink, 0., first, end, visited);
423  dw.checkFlanks(dw.myForward, visited, true);
424  dw.checkFlanks(dw.myBidi, visited, false);
425  dw.checkFlanks(before, visited, true);
426 
427  for (MSLink* link : dw.myFlankSwitches) {
428  //std::cout << getID() << " flankSwitch=" << link->getDescription() << "\n";
429  dw.findFlankProtection(link, 0, visited, link);
430  }
431 
432 #ifdef DEBUG_BUILD_DRIVEWAY
433  if (DEBUG_COND_LINKINFO || true) {
434  std::cout << " buildDriveWay railSignal=" << getID() << " dw=" << dw.myIndex
435  << "\n route=" << toString(dw.myRoute)
436  << "\n forward=" << toString(dw.myForward)
437  << "\n bidi=" << toString(dw.myBidi)
438  << "\n protSwitch=" << describeLinks(dw.myProtectingSwitches)
439  << "\n";
440  }
441 #endif
442 
443  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myForward.begin(), dw.myForward.end());
444  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myBidi.begin(), dw.myBidi.end());
445  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myFlank.begin(), dw.myFlank.end());
446 
447  myDriveways.push_back(dw);
448  return myDriveways.back();
449 }
450 
451 
452 void
454  MSDevice_Routing* rDev = static_cast<MSDevice_Routing*>(veh->getDevice(typeid(MSDevice_Routing)));
456  if (rDev != nullptr &&
457  (myLastRerouteVehicle != veh
458  // reroute each vehicle only once if no periodic routing is allowed,
459  // otherwise with the specified period
460  || (rDev->getPeriod() > 0 && myLastRerouteTime + rDev->getPeriod() <= now))) {
461  myLastRerouteVehicle = veh;
462  myLastRerouteTime = now;
463 
465 #ifdef DEBUG_REROUTE
466  ConstMSEdgeVector oldRoute = veh->getRoute().getEdges();
467  if (DEBUG_COND_LINKINFO) {
468  std::cout << SIMTIME << " reroute veh=" << veh->getID() << " rs=" << getID() << " occupied=" << toString(occupied) << "\n";
469  }
470 #endif
471  try {
472  veh->reroute(now, "railSignal:" + getID(), router, false, false, true); // silent
473 #ifdef DEBUG_REROUTE
474  if (DEBUG_COND_LINKINFO) {
475  if (veh->getRoute().getEdges() != oldRoute) {
476  std::cout << " rerouting successful\n";
477  }
478  }
479 #endif
480  } catch (ProcessError& error) {
481 #ifdef DEBUG_REROUTE
482  if (DEBUG_COND_LINKINFO) {
483  std::cout << " rerouting failed: " << error.what() << "\n";
484  }
485 #else
486  UNUSED_PARAMETER(error);
487 #endif
488  }
489  }
490 }
491 
492 
493 // ===========================================================================
494 // DriveWay method definitions
495 // ===========================================================================
496 
497 bool
499  if (conflictLaneOccupied()) {
500  for (MSLane* bidi : myBidi) {
501  if (!bidi->empty() && bidi->getBidiLane() != nullptr) {
502  occupied.push_back(&bidi->getBidiLane()->getEdge());
503  }
504  }
505 #ifdef DEBUG_SIGNALSTATE
506  if (gDebugFlag4) {
507  std::cout << " conflictLaneOccupied\n";
508  }
509 #endif
510  return false;
511  }
512  for (MSLink* link : myProtectingSwitches) {
513  if (!findProtection(closest, link)) {
514 #ifdef DEBUG_SIGNALSTATE
515  if (gDebugFlag4) {
516  std::cout << " no protection at switch " << link->getDescription() << "\n";
517  }
518 #endif
519  return false;
520  }
521  }
522  for (MSLink* foeLink : myConflictLinks) {
523  if (hasLinkConflict(closest, foeLink)) {
524 #ifdef DEBUG_SIGNALSTATE
525  if (gDebugFlag4) {
526  std::cout << " linkConflict with " << getTLLinkID(foeLink) << "\n";
527  }
528 #endif
529  return false;
530  }
531  }
532  myActive = closest.first;
533  return true;
534 }
535 
536 
537 bool
539  for (MSLink* foeLink : myConflictLinks) {
540  if (foeLink->getApproaching().size() > 0) {
541  return true;
542  }
543  }
544  return false;
545 }
546 
547 
548 bool
550 #ifdef DEBUG_SIGNALSTATE_PRIORITY
551  if (gDebugFlag4) {
552  std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << "\n";
553  }
554 #endif
555  if (foeLink->getApproaching().size() > 0) {
556  Approaching foe = getClosest(foeLink);
557 #ifdef DEBUG_SIGNALSTATE_PRIORITY
558  if (gDebugFlag4) {
559  std::cout << " approaching foe=" << foe.first->getID() << "\n";
560  }
561 #endif
562  const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
563  assert(foeTLL != nullptr);
564  const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
565  MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
566  if (foeRS != nullptr) {
567  const DriveWay& foeDriveWay = foeRS->myLinkInfos[foeLink->getTLIndex()].getDriveWay(foe.first);
568  if (foeDriveWay.conflictLaneOccupied() ||
569  !overlap(foeDriveWay)) {
570 #ifdef DEBUG_SIGNALSTATE_PRIORITY
571  if (gDebugFlag4) {
572  if (foeDriveWay.conflictLaneOccupied()) {
573  std::cout << " foe blocked\n";
574  } else {
575  std::cout << " no overlap\n";
576  }
577  }
578 #endif
579  return false;
580  }
581 #ifdef DEBUG_SIGNALSTATE_PRIORITY
582  if (gDebugFlag4) {
583  std::cout
584  << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
585  << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
586  << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
587  << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
588  << "\n";
589  }
590 #endif
591  if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
592  if (foe.second.arrivalTime == veh.second.arrivalTime) {
593  if (foe.first->getSpeed() == veh.first->getSpeed()) {
594  if (foe.second.dist == veh.second.dist) {
595  return foe.first->getNumericalID() < veh.first->getNumericalID();
596  } else {
597  return foe.second.dist < veh.second.dist;
598  }
599  } else {
600  return foe.first->getSpeed() > veh.first->getSpeed();
601  }
602  } else {
603  return foe.second.arrivalTime < veh.second.arrivalTime;
604  }
605  } else {
606  return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
607  }
608  }
609  }
610  return false;
611 }
612 
613 
614 bool
616  for (const MSLane* lane : myConflictLanes) {
617  if (!lane->isEmpty()) {
618 #ifdef DEBUG_SIGNALSTATE
619  if (gDebugFlag4) {
620  std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied\n";
621  }
622 #endif
623  return true;
624  }
625  }
626  return false;
627 }
628 
629 
630 bool
632  double flankApproachingDist = std::numeric_limits<double>::max();
633  if (link->getApproaching().size() > 0) {
634  Approaching closest = getClosest(link);
635  flankApproachingDist = closest.second.dist;
636  }
637 #ifdef DEBUG_FIND_PROTECTION
638  if (gDebugFlag4) {
639  std::cout << SIMTIME << " findProtection for link=" << link->getDescription() << " flankApproachingDist=" << flankApproachingDist << "\n";
640  }
641 #endif
642  for (MSLink* l2 : link->getLaneBefore()->getLinkCont()) {
643  if (l2->getLane() != link->getLane()) {
644 #ifdef DEBUG_FIND_PROTECTION
645  if (gDebugFlag4) {
646  std::cout << " protectionCandidate=" << l2->getDescription() << " l2Via=" << Named::getIDSecure(l2->getViaLane()) << " occupied=" << !l2->getViaLane()->isEmpty() << "\n";
647  }
648 #endif
649  if (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) {
650 #ifdef DEBUG_FIND_PROTECTION
651  if (gDebugFlag4) {
652  std::cout << " protection from internal=" << l2->getViaLane()->getID() << "\n";
653  }
654 #endif
655  return true;
656  }
657  if (l2->getApproaching().size() > 0) {
658  Approaching closest2 = getClosest(l2);
659  if (closest2.second.dist < flankApproachingDist) {
660 #ifdef DEBUG_FIND_PROTECTION
661  if (gDebugFlag4) {
662  std::cout << " protection from veh=" << closest2.first->getID() << "\n";
663  }
664 #endif
665  return true;
666  }
667  }
668  }
669  }
670  if (link->getApproaching().size() == 0) {
671  return true;
672  } else {
673  // find protection further upstream
674  DriveWay tmp(-myIndex);
675  const MSLane* before = link->getLaneBefore();
676  tmp.myFlank.push_back(before);
677  LaneSet visited;
678  for (auto ili : before->getIncomingLanes()) {
679  tmp.findFlankProtection(ili.viaLink, myMaxFlankLength, visited, ili.viaLink);
680  }
681  tmp.myConflictLanes = tmp.myFlank;
682  tmp.myRoute = myRoute;
683  MSEdgeVector occupied;
684  if (gDebugFlag4) std::cout << SIMTIME << " tmpDW flank=" << toString(tmp.myFlank)
685  << " protSwitch=" << describeLinks(tmp.myProtectingSwitches) << " cLinks=" << describeLinks(tmp.myConflictLinks) << "\n";
686  return tmp.reserve(veh, occupied);
687  }
688 }
689 
690 
691 bool
693  for (const MSEdge* edge : myRoute) {
694  for (const MSEdge* edge2 : other.myRoute) {
695  if (edge->getToJunction() == edge2->getToJunction()
696  || edge->getToJunction() == edge2->getFromJunction()) {
697  // XXX might be rail_crossing with parallel tracks
698  return true;
699  }
700  }
701  }
702  return false;
703 }
704 
705 void
707  od.openTag("driveWay");
708  od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
709  od.openTag("forward");
710  od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
711  od.closeTag();
712  od.openTag("bidi");
713  od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
714  od.closeTag();
715  od.openTag("flank");
716  od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
717  od.closeTag();
718  od.openTag("conflictLinks");
719  std::vector<std::string> signals;
720  for (MSLink* link : myConflictLinks) {
721  signals.push_back(getTLLinkID(link));
722  }
723  od.writeAttr("signals", joinToString(signals, " "));
724  od.closeTag();
725  od.closeTag(); // driveWay
726 }
727 
728 
729 void
732  LaneSet& visited) {
733  bool seekForwardSignal = true;
734  bool seekBidiSwitch = true;
735  MSLane* toLane = origin->getViaLaneOrLane();
736  //std::cout << "buildRoute origin=" << getTLLinkID(origin) << " vehRoute=" << toString(ConstMSEdgeVector(next, end)) << " visited=" << joinNamedToString(visited, " ") << "\n";
737  while ((seekForwardSignal || seekBidiSwitch)) {
738  if (length > MAX_BLOCK_LENGTH) {
740  WRITE_WARNING("Block after rail signal " + getClickableTLLinkID(origin) +
741  " exceeds maximum length (stopped searching after edge '" + toLane->getEdge().getID() + "' (length=" + toString(length) + "m).");
742  }
743  myNumWarnings++;
744  // length exceeded
745  return;
746  }
747  //std::cout << " toLane=" << toLane->getID() << " visited=" << joinNamedToString(visited, " ") << "\n";
748  if (visited.count(toLane) != 0) {
749  WRITE_WARNING("Found circular block after railSignal " + getClickableTLLinkID(origin) + " (" + toString(myRoute.size()) + " edges, length " + toString(length) + ")");
750  return;
751  }
752  if (toLane->getEdge().isNormal()) {
753  myRoute.push_back(&toLane->getEdge());
754  if (next != end) {
755  next++;
756  }
757  }
758  visited.insert(toLane);
759  length += toLane->getLength();
760  MSLane* bidi = toLane->getBidiLane();
761  if (seekForwardSignal) {
762  myForward.push_back(toLane);
763  } else if (bidi == nullptr) {
764  seekBidiSwitch = false;
765  }
766  if (bidi != nullptr) {
767  myBidi.push_back(bidi);
768  visited.insert(bidi);
769  if (!seekForwardSignal) {
770  // look for switch that could protect from oncoming vehicles
771  for (const auto& ili : bidi->getIncomingLanes()) {
772  if (ili.viaLink->getDirection() == LINKDIR_TURN) {
773  continue;
774  }
775  for (MSLink* link : ili.lane->getLinkCont()) {
776  if (link->getDirection() == LINKDIR_TURN) {
777  continue;
778  }
779  if (link->getViaLaneOrLane() != bidi) {
780  // this switch is special beause it still lies on the current route
781  myProtectingSwitches.push_back(ili.viaLink);
782  return;
783  }
784  }
785  }
786  }
787  }
788  const MSLinkCont& links = toLane->getLinkCont();
789  toLane = nullptr;
790  for (MSLink* link : links) {
791  if (((next != end && &link->getLane()->getEdge() == *next) ||
792  (next == end && link->getDirection() != LINKDIR_TURN))
793  && isRailway(link->getViaLaneOrLane()->getPermissions())) {
794  toLane = link->getViaLaneOrLane();
795  if (link->getTLLogic() != nullptr) {
796  if (link->getTLLogic() == origin->getTLLogic()) {
797  WRITE_WARNING("Found circular block at railSignal " + getClickableTLLinkID(origin) + " (" + toString(myRoute.size()) + " edges, length " + toString(length) + ")");
798  return;
799  }
800  seekForwardSignal = false;
801  seekBidiSwitch = bidi != nullptr;
802  }
803  break;
804  }
805  }
806  if (toLane == nullptr) {
807  if (next != end) {
808  // no connection found, jump to next route edge
809  toLane = (*next)->getLanes()[0];
810  } else {
811  return;
812  }
813  }
814  }
815 }
816 
817 
818 void
819 MSRailSignal::DriveWay::checkFlanks(const std::vector<MSLane*>& lanes, const LaneSet& visited, bool allFoes) {
820 #ifdef DEBUG_CHECK_FLANKS
821  std::cout << " checkFlanks lanes=" << toString(lanes) << "\n visited=" << joinNamedToString(visited, " ") << " allFoes=" << allFoes << "\n";
822 #endif
823  for (MSLane* lane : lanes) {
824  if (lane->isInternal()) {
825  continue;
826  }
827  for (auto ili : lane->getIncomingLanes()) {
828  if (visited.count(ili.lane->getNormalPredecessorLane()) == 0) {
829 #ifdef DEBUG_CHECK_FLANKS
830  std::cout << " add flankSwitch junction=" << ili.viaLink->getJunction()->getID() << " index=" << ili.viaLink->getIndex() << "\n";
831 #endif
832  myFlankSwitches.push_back(ili.viaLink);
833  } else if (allFoes) {
834  // link is part of the driveway, find foes that cross the driveway without entering
835  checkCrossingFlanks(ili.viaLink, visited);
836  }
837  }
838  }
839 }
840 
841 
842 void
844 #ifdef DEBUG_CHECK_FLANKS
845  std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << joinNamedToString(visited, " ") << "\n";
846 #endif
847  const MSJunction* junction = dwLink->getJunction();
848  const MSJunctionLogic* logic = junction->getLogic();
849  assert(logic != nullptr);
850  for (const MSEdge* in : junction->getIncoming()) {
851  if (in->isInternal()) {
852  continue;
853  }
854  for (MSLane* inLane : in->getLanes()) {
855  if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0) {
856  for (MSLink* link : inLane->getLinkCont()) {
857  if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
858  && visited.count(link->getLane()) == 0) {
859 #ifdef DEBUG_CHECK_FLANKS
860  std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
861 #endif
862  if (link->getViaLane() == nullptr) {
863  myFlankSwitches.push_back(link);
864  } else {
865  myFlankSwitches.push_back(link->getViaLane()->getLinkCont().front());
866  }
867  }
868  }
869  }
870  }
871  }
872 }
873 
874 void
875 MSRailSignal::DriveWay::findFlankProtection(MSLink* link, double length, LaneSet& visited, MSLink* origLink) {
876 #ifdef DEBUG_CHECK_FLANKS
877  std::cout << " findFlankProtection link=" << link->getDescription() << " length=" << length << " origLink=" << origLink->getDescription() << "\n";
878 #endif
879  if (link->getTLLogic() != nullptr) {
880  // guarded by signal
881  myConflictLinks.push_back(link);
882  } else if (length > MAX_BLOCK_LENGTH) {
883  // length exceeded
885  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).");
886  }
887  myNumWarnings++;
888  } else {
889  // find normal lane before this link
890  const MSLane* lane = link->getLaneBefore();
891  if (visited.count(lane) == 0) {
892  visited.insert(lane);
893  length += lane->getLength();
894  if (lane->isInternal()) {
895  myFlank.push_back(lane);
896  findFlankProtection(lane->getIncomingLanes().front().viaLink, length, visited, origLink);
897  } else {
898  bool foundPSwitch = false;
899  for (MSLink* l2 : lane->getLinkCont()) {
900 #ifdef DEBUG_CHECK_FLANKS
901  std::cout << " lane=" << lane->getID() << " cand=" << l2->getDescription() << "\n";
902 #endif
903  if (l2->getDirection() != LINKDIR_TURN && l2->getLane() != link->getLane()) {
904  foundPSwitch = true;
905  // found potential protection
906 #ifdef DEBUG_CHECK_FLANKS
907  std::cout << " protectingSwitch=" << l2->getDescription() << " for flank=" << link->getDescription() << "\n";
908 #endif
909  myProtectingSwitches.push_back(link);
910  }
911  }
912  if (!foundPSwitch) {
913  myFlank.push_back(lane);
914  // continue search for protection upstream recursively
915  for (auto ili : lane->getIncomingLanes()) {
916  if (ili.viaLink->getDirection() != LINKDIR_TURN) {
917  findFlankProtection(ili.viaLink, length, visited, origLink);
918  }
919  }
920  }
921  }
922  }
923  }
924  myMaxFlankLength = MAX2(myMaxFlankLength, length);
925 }
926 
927 
928 /****************************************************************************/
929 
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:819
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
const std::string & getState() const
Returns the state within this phase.
Builds detectors for microsim.
void writeBlocks(OutputDevice &od) const
write rail signal block output for all links and driveways
virtual void reroute(SUMOTime t, const std::string &info, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, const bool onInit=false, const bool withTaz=false, const bool silent=false)=0
Performs a rerouting using the given router.
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:670
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:80
long long int SUMOTime
Definition: SUMOTime.h:35
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition: ToString.h:281
std::vector< const MSLane * > myConflictLanes
the lanes that must be clear of trains before this signal can switch to green
Definition: MSRailSignal.h:255
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:121
static bool hasOncomingRailTraffic(MSLink *link)
void updateCurrentPhase()
returns the state of the signal that actually required
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
const MSPhaseDefinition & getPhase(int givenstep) const
Returns the definition of the phase from the given position within the plan.
virtual MSVehicleDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
virtual const MSRoute & getRoute() const =0
Returns the current route.
static std::string getClickableTLLinkID(MSLink *link)
return logicID_linkIndex in a way that allows clicking in sumo-gui
A signal for rails.
Definition: MSRailSignal.h:47
The base class for an intersection.
Definition: MSJunction.h:61
The link is a 180 degree turn.
std::vector< MSLink * > myConflictLinks
Definition: MSRailSignal.h:270
A device that performs vehicle rerouting based on current edge speeds.
std::vector< LinkInfo > myLinkInfos
data storage for every link at this node (more than one when directly guarding a switch) ...
Definition: MSRailSignal.h:346
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2036
void checkCrossingFlanks(MSLink *dwLink, const LaneSet &visited)
find links that cross the driveway without entering it
int getIndexFromOffset(SUMOTime offset) const
Returns the step (the phasenumber) of a given position of the cycle.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:168
T MAX2(T a, T b)
Definition: StdDefs.h:80
bool conflictLinkApproached() const
Whether any of the conflict linkes have approaching vehicles.
#define SUMO_MAX_CONNECTIONS
the maximum number of connections across an intersection
Definition: StdDefs.h:43
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
double getLength() const
Returns the lane&#39;s length.
Definition: MSLane.h:541
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:70
const MSRoute & getRoute() const
Returns the current route.
std::vector< MSLane * > myBidi
Definition: MSRailSignal.h:248
std::vector< MSLink * > myProtectingSwitches
Definition: MSRailSignal.h:265
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:73
const std::string & getID() const
Returns the id.
Definition: Named.h:77
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
#define DEBUG_COND_LINKINFO
static SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const MSEdgeVector &prohibited=MSEdgeVector())
return the router instance
bool hasLinkConflict(const Approaching &closest, MSLink *foeLink) const
Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link...
#define MAX_BLOCK_LENGTH
const MSJunction * getToJunction() const
Definition: MSEdge.h:361
bool setTrafficLightSignals(SUMOTime t) const
Applies the current signal states to controlled links.
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:32
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition: MSEdge.h:247
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:239
#define SIMTIME
Definition: SUMOTime.h:64
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index...
static int myNumWarnings
Definition: MSRailSignal.h:374
A class that stores and controls tls and switching of their programs.
bool isInternal() const
Definition: MSLane.cpp:1999
std::vector< const MSEdge * > myRoute
list of lanes for matching against train routes
Definition: MSRailSignal.h:239
A road/street connecting two junctions.
Definition: MSEdge.h:76
void findFlankProtection(MSLink *link, double length, LaneSet &visited, MSLink *origLink)
find upstream protection from the given link
bool findProtection(const Approaching &veh, MSLink *link) const
find protection for the given vehicle starting at a switch
void setState(const std::string &_state)
the edges of a route
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:48
SUMOTime myDefaultCycleTime
The cycle time (without changes)
Representation of a vehicle.
Definition: SUMOVehicle.h:61
void buildRoute(MSLink *origin, double length, MSRouteIterator next, MSRouteIterator end, LaneSet &visited)
void init(NLDetectorBuilder &nb)
Initialises the rail signal with information about adjacent rail signals.
Phases myPhases
The list of phases this logic uses.
Definition: MSRailSignal.h:366
bool isEmpty() const
Definition: MSLane.cpp:1994
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition: MSRoute.h:58
const Phases & getPhases() const
Returns the phases of this tls program.
const MSPhaseDefinition & getCurrentPhaseDef() const
Returns the definition of the current phase.
virtual void adaptLinkInformationFrom(const MSTrafficLightLogic &logic)
Applies information about controlled links and lanes from the given logic.
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:284
virtual const MSLogicJunction::LinkBits & getFoesFor(int linkIndex) const
Returns the foes for the given link.
const ConstMSEdgeVector & getIncoming() const
Definition: MSJunction.h:102
static std::string describeLinks(std::vector< MSLink *> links)
print link descriptions
int getPhaseNumber() const
Returns the number of phases.
#define MAX_SIGNAL_WARNINGS
bool gDebugFlag4
Definition: StdDefs.cpp:36
std::vector< const MSLane * > myFlank
Definition: MSRailSignal.h:252
SUMOTime trySwitch()
Switches to the next phase.
SUMOTime getPeriod() const
#define DEBUG_COND
int myPhaseIndex
MSTrafficLightLogic requires that the phase index changes whenever signals change their state...
Definition: MSRailSignal.h:372
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
LinkVectorVector myLinks
The list of LinkVectors; each vector contains the links that belong to the same link index...
MSRailSignal(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const std::map< std::string, std::string > &parameters)
Constructor.
void addLink(MSLink *link, MSLane *lane, int pos)
Adds a link on building.
std::set< const MSLane *, ComparatorNumericalIdLess > LaneSet
Definition: MSRailSignal.h:211
void adaptLinkInformationFrom(const MSTrafficLightLogic &logic)
Applies information about controlled links and lanes from the given logic.
bool reserve(const Approaching &closest, MSEdgeVector &occupied)
attempt reserve this driveway for the given vehicle
bool conflictLaneOccupied() const
whether any of myConflictLanes is occupied
static Approaching getClosest(MSLink *link)
get the closest vehicle approaching the given link
const MSJunction * getFromJunction() const
Definition: MSEdge.h:357
The link has red light (must brake)
virtual void addLink(MSLink *link, MSLane *lane, int pos)
Adds a link on building.
void checkFlanks(const std::vector< MSLane *> &lanes, const LaneSet &visited, bool allFoes)
find switches that threathen this driveway
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition: MSLane.cpp:3684
std::pair< const SUMOVehicle *const, const MSLink::ApproachingVehicleInformation > Approaching
Definition: MSRailSignal.h:210
void writeBlocks(OutputDevice &od) const
Write block items for this driveway.
SUMOTime getPhaseIndexAtTime(SUMOTime simStep) const
Returns the index of the logic at the given simulation step.
The parent class for traffic light logics.
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
link: the index of the link within the traffic light
bool isNormal() const
return whether this edge is an internal edge
Definition: MSEdge.h:228
MSPhaseDefinition myCurrentPhase
The current phase.
Definition: MSRailSignal.h:369
std::vector< MSEdge * > MSEdgeVector
Definition: MSEdge.h:72
const MSLinkCont & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.cpp:2099
SUMOTime getOffsetFromIndex(int index) const
Returns the position (start of a phase during a cycle) from of a given step.
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles route.
Representation of a lane in the micro simulation.
Definition: MSLane.h:83
The definition of a single phase of a tls logic.
virtual const MSJunctionLogic * getLogic() const
Definition: MSJunction.h:135
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:76
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:247
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool overlap(const DriveWay &other) const
Wether this driveway overlaps with the given one.
int getCurrentPhaseIndex() const
Returns the current index within the program.
SumoXMLNodeType getType() const
return the type of this Junction
Definition: MSJunction.h:127
~MSRailSignal()
Destructor.