def markOvertaken(options, vehicleStopRoutes, stopRoutes): # mark stops that should not participate in constraint generation # once a vehice appears to be "overtaken" (based on inconsistent # arrival/until timing), all subsequent stops of that vehicle should no # longer be used for contraint generation for vehicle, stopRoute in vehicleStopRoutes.items(): overtaken = False for i, (edgesBefore, stop) in enumerate(stopRoute): if not (stop.hasAttribute("arrival") and stop.hasAttribute("until")): continue if options.skipParking and parseBool(stop.getAttributeSecure("parking", "false")): continue if not overtaken: arrival = parseTime(stop.arrival) until = parseTime(stop.until) for edgesBefore2, stop2 in stopRoutes[stop.busStop]: if stop2.vehID == stop.vehID: continue if not stop2.hasAttribute("arrival") or not stop2.hasAttribute("until"): continue if options.skipParking and parseBool(stop2.getAttributeSecure("parking", "false")): continue arrival2 = parseTime(stop2.arrival) until2 = parseTime(stop2.until) if arrival2 > arrival and until2 < until: overtaken = True print(("Vehicle %s (%s, %s) overtaken by %s (%s, %s) " + "at stop %s (index %s) and ignored afterwards") % (stop.vehID, humanReadableTime(arrival), humanReadableTime(until), stop2.vehID, humanReadableTime(arrival2), humanReadableTime(until2), stop.busStop, i), file=sys.stderr) break if overtaken: stop.setAttribute("invalid", True)
def findInsertionConflicts(options, net, stopEdges, stopRoutes, vehicleStopRoutes): """find routes that start at a stop with a traffic light at end of the edge and routes that pass this stop. Ensure insertion happens in the correct order""" # signal -> [(tripID, otherSignal, otherTripID, limit, line, otherLine, vehID, otherVehID), ...] conflicts = defaultdict(list) numConflicts = 0 numIgnoredConflicts = 0 for busStop, stops in stopRoutes.items(): stopEdge = stopEdges[busStop] node = net.getEdge(stopEdge).getToNode() signal = node.getID() untils = [] for edgesBefore, stop in stops: if stop.hasAttribute("until") and not options.untilFromDuration: until = parseTime(stop.until) elif stop.hasAttribute("arrival"): until = parseTime(stop.arrival) + parseTime( stop.getAttributeSecure("duration", "0")) else: continue untils.append((until, edgesBefore, stop)) # only use 'until' for sorting and keep the result stable otherwise untils.sort(key=itemgetter(0)) prevPassing = None ignore = False for i, (nUntil, nEdges, nStop) in enumerate(untils): nVehStops = vehicleStopRoutes[nStop.vehID] nIndex = nVehStops.index((nEdges, nStop)) nIsPassing = nIndex < len(nVehStops) - 1 nIsDepart = len(nEdges) == 1 if options.verbose and busStop == options.debugStop: print(i, "n:", humanReadableTime(nUntil), nStop.tripId, nStop.vehID, nIndex, len(nVehStops), "passing:", nIsPassing, "depart:", nIsDepart) if prevPassing is not None and nIsDepart: pUntil, pEdges, pStop = prevPassing pVehStops = vehicleStopRoutes[pStop.vehID] pIndex = pVehStops.index((pEdges, pStop)) # no need to constrain subsequent departures (simulation should maintain ordering) if len(pEdges) > 1 or pIndex > 0: # find edges after stop if busStop == options.debugStop: print(i, "p:", humanReadableTime(pUntil), pStop.tripId, pStop.vehID, pIndex, len(pVehStops), "n:", humanReadableTime(nUntil), nStop.tripId, nStop.vehID, nIndex, len(nVehStops)) if nIsPassing: # both vehicles move past the stop pNextEdges = pVehStops[pIndex + 1][0] nNextEdges = nVehStops[nIndex + 1][0] limit = 1 # recheck pSignal = signal nSignal = signal if node.getType() != "rail_signal": # find signal in nextEdges pSignal = findSignal(net, pNextEdges) nSignal = findSignal(net, nNextEdges) if pSignal is None or nSignal is None: print(( "Ignoring insertion conflict between %s and %s at stop '%s' " + "because no rail signal was found after the stop" ) % (nStop.prevTripId, pStop.prevTripId, busStop), file=sys.stderr) continue # check for inconsistent ordering if (ignore or (options.abortUnordered and pStop.hasAttribute("arrival") and nStop.hasAttribute("arrival") and (not options.ignoreParking or not parseBool( nStop.getAttributeSecure("parking", "false"))) and parseTime(pStop.arrival) > parseTime( nStop.arrival))): numIgnoredConflicts += 1 # ignore conflict and any that follow if not ignore: # sort output by arrival again print( "Found inconsistent times at stop %s " "for vehicle %s (%s, %s) and vehicle %s (%s, %s)" % (busStop, nStop.vehID, humanReadableTime( parseTime(nStop.arrival)), humanReadableTime(nUntil), pStop.vehID, humanReadableTime( parseTime(pStop.arrival)), humanReadableTime(pUntil)), file=sys.stderr) ignore = True continue # predecessor tripId after stop is needed pTripId = pStop.getAttributeSecure( "tripId", pStop.vehID) conflicts[nSignal].append(( nStop.prevTripId, pSignal, pTripId, limit, # attributes for adding comments nStop.prevLine, pStop.prevLine, nStop.vehID, pStop.vehID)) numConflicts += 1 if busStop == options.debugStop: print( " found insertionConflict pSignal=%s nSignal=%s pTripId=%s" % (pSignal, nSignal, pTripId)), if nIsPassing: prevPassing = (nUntil, nEdges, nStop) print("Found %s insertion conflicts" % numConflicts) if numIgnoredConflicts > 0: print("Ignored %s insertion conflicts" % (numIgnoredConflicts)) return conflicts
def findConflicts(options, switchRoutes, mergeSignals, signalTimes): """find stops that target the same busStop from different branches of the prior merge switch and establish their ordering""" numConflicts = 0 numIgnoredConflicts = 0 # signal -> [(tripID, otherSignal, otherTripID, limit, line, otherLine, vehID, otherVehID), ...] conflicts = defaultdict(list) ignoredVehicles = set() for switch, stopRoutes2 in switchRoutes.items(): numSwitchConflicts = 0 numIgnoredSwitchConflicts = 0 if switch == options.debugSwitch: print("Switch %s lies ahead of busStops %s" % (switch, stopRoutes2.keys())) for busStop, stops in stopRoutes2.items(): arrivals = [] for edges, stop in stops: if stop.hasAttribute("arrival"): arrival = parseTime(stop.arrival) elif stop.hasAttribute("until"): arrival = parseTime(stop.until) - parseTime( stop.getAttributeSecure("duration", "0")) else: print( "ignoring stop at %s without schedule information (arrival, until)" % busStop) continue arrivals.append((arrival, edges, stop)) arrivals.sort(key=itemgetter(0)) ignore = False for (pArrival, pEdges, pStop), (nArrival, nEdges, nStop) in zip(arrivals[:-1], arrivals[1:]): pSignal, pTimeSiSt = mergeSignals[(switch, pEdges)] nSignal, nTimeSiSt = mergeSignals[(switch, nEdges)] if switch == options.debugSwitch: print(pSignal, nSignal, pStop, nStop) if pSignal != nSignal and pSignal is not None and nSignal is not None: if (ignore or (options.abortUnordered and pStop.hasAttribute("until") and nStop.hasAttribute("until") and (not options.ignoreParking or not parseBool( pStop.getAttributeSecure("parking", "false"))) and parseTime(pStop.until) > parseTime(nStop.until))): numIgnoredConflicts += 1 numIgnoredSwitchConflicts += 1 # ignore conflict and any that follow if not ignore: print( "Found inconsistent times at stop %s " "for vehicle %s (%s, %s) and vehicle %s (%s, %s)" % (busStop, pStop.vehID, humanReadableTime(pArrival), humanReadableTime(parseTime(pStop.until)), nStop.vehID, humanReadableTime(nArrival), humanReadableTime(parseTime(nStop.until))), file=sys.stderr) # ignoredVehicles.insert(pStop.vehID) ignoredVehicles.add(nStop.vehID) ignore = True continue if (options.abortUnordered and nStop.vehID in ignoredVehicles): # no constraints for inconsistent vehicle to avoid deadlock numIgnoredConflicts += 1 numIgnoredSwitchConflicts += 1 continue if options.skipParking and parseBool( nStop.getAttributeSecure("parking", "false")): print( "ignoring stop at %s for parking vehicle %s (%s, %s)" % (busStop, nStop.vehID, humanReadableTime(nArrival), (humanReadableTime(parseTime(nStop.until)) if nStop.hasAttribute("until") else "-"))) numIgnoredConflicts += 1 numIgnoredSwitchConflicts += 1 continue if options.skipParking and parseBool( pStop.getAttributeSecure("parking", "false")): print( "ignoring stop at %s for %s (%s, %s) after parking vehicle %s (%s, %s)" % (busStop, nStop.vehID, humanReadableTime(nArrival), (humanReadableTime(parseTime(nStop.until)) if nStop.hasAttribute("until") else "-"), pStop.vehID, humanReadableTime(pArrival), (humanReadableTime(parseTime(pStop.until)) if pStop.hasAttribute("until") else "-"))) numIgnoredConflicts += 1 numIgnoredSwitchConflicts += 1 continue numConflicts += 1 numSwitchConflicts += 1 # check for trains that pass the switch in between the # current two trains (heading to another stop) and raise the limit limit = 1 pTimeAtSignal = pArrival - pTimeSiSt nTimeAtSignal = nArrival - nTimeSiSt end = nTimeAtSignal + options.delay if options.verbose and options.debugSignal == pSignal: print( "check vehicles between %s and %s (including delay %s) at signal %s pStop=%s nStop=%s" % (humanReadableTime(pTimeAtSignal), humanReadableTime(end), options.delay, pSignal, pStop, nStop)) limit += countPassingTrainsToOtherStops( options, pSignal, busStop, pTimeAtSignal, end, signalTimes) conflicts[nSignal].append(( nStop.prevTripId, pSignal, pStop.prevTripId, limit, # attributes for adding comments nStop.prevLine, pStop.prevLine, nStop.vehID, pStop.vehID)) if options.verbose: print("Found %s conflicts at switch %s" % (numSwitchConflicts, switch)) if numIgnoredSwitchConflicts > 0: print("Ignored %s conflicts at switch %s" % (numIgnoredSwitchConflicts, switch)) print("Found %s conflicts" % numConflicts) if numIgnoredConflicts > 0: print("Ignored %s conflicts" % numIgnoredConflicts) return conflicts
def findFoeInsertionConflicts(options, net, stopEdges, stopRoutes, vehicleStopRoutes): """find routes that start at a stop with a traffic light at end of the edge and routes that pass this stop. Ensure insertion happens in the correct order (finds constrains on entering the stop segment ahead of insertion) """ # signal -> [(tripID, otherSignal, otherTripID, limit, line, otherLine, vehID, otherVehID), ...] conflicts = defaultdict(list) numConflicts = 0 numIgnoredConflicts = 0 for busStop, stops in stopRoutes.items(): if busStop == options.debugStop: print("findFoeInsertionConflicts at stop %s" % busStop) stopEdge = stopEdges[busStop] node = net.getEdge(stopEdge).getToNode() signal = node.getID() arrivals = [] for edgesBefore, stop in stops: if stop.hasAttribute("arrival") and not options.untilFromDuration: arrival = parseTime(stop.until) elif stop.hasAttribute("until"): arrival = parseTime(stop.until) - parseTime( stop.getAttributeSecure("duration", "0")) else: continue arrivals.append((arrival, edgesBefore, stop)) # only use 'arrival' for sorting and keep the result stable otherwise arrivals.sort(key=itemgetter(0)) prevDepart = None for i, (nArrival, nEdges, nStop) in enumerate(arrivals): nVehStops = vehicleStopRoutes[nStop.vehID] nIndex = nVehStops.index((nEdges, nStop)) nIsPassing = nIndex < len(nVehStops) - 1 nIsDepart = len(nEdges) == 1 and nIndex == 0 if options.verbose and busStop == options.debugStop: print(i, "n:", humanReadableTime(nArrival), nStop.tripId, nStop.vehID, nIndex, len(nVehStops), "passing:", nIsPassing, "depart:", nIsDepart) if prevDepart is not None and nIsPassing and not nIsDepart: pArrival, pEdges, pStop = prevDepart pVehStops = vehicleStopRoutes[pStop.vehID] pIndex = pVehStops.index((pEdges, pStop)) # no need to constrain subsequent passing (simulation should maintain ordering) if len(nEdges) > 1 or nIndex > 0: # find edges after stop if busStop == options.debugStop: print(i, "p:", humanReadableTime(pArrival), pStop.tripId, pStop.vehID, pIndex, len(pVehStops), "n:", humanReadableTime(nArrival), nStop.tripId, nStop.vehID, nIndex, len(nVehStops)) # both vehicles move past the stop pNextEdges = pVehStops[pIndex + 1][0] limit = 1 # recheck # insertion vehicle must pass signal after the stop pSignal = signal if node.getType() != "rail_signal": # find signal in nextEdges pSignal = findSignal(net, pNextEdges) if pSignal is None: print(( "Ignoring insertion foe conflict between %s and %s at stop '%s' " + "because no rail signal was found after the stop" ) % (nStop.prevTripId, pStop.prevTripId, busStop), file=sys.stderr) continue # passing vehicle must wait before the stop nPrevEdges = nVehStops[nIndex][0] nSignal = findSignal(net, list(reversed(nPrevEdges)), True) if nSignal is None: print(( "Ignoring foe insertion conflict between %s and %s at stop '%s' " + "because no rail signal was found before the stop") % (nStop.prevTripId, pStop.prevTripId, busStop), file=sys.stderr) continue # check for inconsistent ordering if pStop.getAttributeSecure("invalid", False): numIgnoredConflicts += 1 continue if options.skipParking: if parseBool( nStop.getAttributeSecure("parking", "false")): print( "ignoring stop at %s for parking vehicle %s (%s, %s)" % (busStop, nStop.vehID, humanReadableTime(nArrival), (humanReadableTime(parseTime(nStop.until)) if nStop.hasAttribute("until") else "-"))) numIgnoredConflicts += 1 continue # if parseBool(pStop.getAttributeSecure("parking", "false")): # # additional check for until times # print("ignoring stop at %s for %s (%s, %s) after parking vehicle %s (%s, %s)" % ( # busStop, nStop.vehID, humanReadableTime(nArrival), # (humanReadableTime(parseTime(nStop.until)) if nStop.hasAttribute("until") else "-"), # pStop.vehID, humanReadableTime(pArrival), # (humanReadableTime(parseTime(pStop.until)) if pStop.hasAttribute("until") else "-"))) # numIgnoredConflicts += 1 # continue # hotfix for strange input pNextStop = pVehStops[pIndex + 1][1] if pNextStop.lane is not None: print(( "Ignoring foe insertion conflict between %s and %s at stop '%s' " + "because the inserted train does not leave the stop edge (laneStop)" ) % (nStop.prevTripId, pStop.prevTripId, busStop), file=sys.stderr) continue # predecessor tripId after stop is needed pTripId = pStop.getAttributeSecure("tripId", pStop.vehID) conflicts[nSignal].append( Conflict( nStop.prevTripId, pSignal, pTripId, limit, # attributes for adding comments nStop.prevLine, pStop.prevLine, nStop.vehID, pStop.vehID, nStop.arrival, foeInsertion=True)) numConflicts += 1 if busStop == options.debugStop: print( " found foe insertion conflict pSignal=%s nSignal=%s pVehId=%s pTripId=%s" % (pSignal, nSignal, pStop.vehID, pTripId)), if nIsDepart and nIsPassing: prevDepart = (nArrival, nEdges, nStop) if numConflicts > 0: print("Found %s foe insertion conflicts" % numConflicts) if numIgnoredConflicts > 0: print("Ignored %s foe insertion conflicts" % (numIgnoredConflicts)) return conflicts
def findConflicts(options, switchRoutes, mergeSignals, signalTimes): """find stops that target the same busStop from different branches of the prior merge switch and establish their ordering""" numConflicts = 0 numRedundant = 0 numIgnoredConflicts = 0 numIgnoredStops = 0 # signal -> [(tripID, otherSignal, otherTripID, limit, line, otherLine, vehID, otherVehID), ...] conflicts = defaultdict(list) for switch, stopRoutes2 in switchRoutes.items(): numSwitchConflicts = 0 numRedundantSwitchConflicts = 0 numIgnoredSwitchConflicts = 0 numIgnoredSwitchStops = 0 if switch == options.debugSwitch: print("Switch %s lies ahead of busStops %s" % (switch, stopRoutes2.keys())) for busStop, stops in stopRoutes2.items(): arrivals = [] for edges, stop in stops: if stop.hasAttribute("arrival"): arrival = parseTime(stop.arrival) elif stop.hasAttribute("until"): arrival = parseTime(stop.until) - parseTime( stop.getAttributeSecure("duration", "0")) else: print( "ignoring stop at %s without schedule information (arrival, until)" % busStop) continue if stop.getAttributeSecure("invalid", False): numIgnoredSwitchStops += 1 numIgnoredStops += 1 continue arrivals.append((arrival, edges, stop)) arrivals.sort(key=itemgetter(0)) arrivalsBySignal = defaultdict(list) for (pArrival, pEdges, pStop), (nArrival, nEdges, nStop) in zip(arrivals[:-1], arrivals[1:]): pSignal, pTimeSiSt = mergeSignals[(switch, pEdges)] nSignal, nTimeSiSt = mergeSignals[(switch, nEdges)] if switch == options.debugSwitch: print(pSignal, nSignal, pStop, nStop) if pSignal != nSignal and pSignal is not None and nSignal is not None: if options.skipParking and parseBool( nStop.getAttributeSecure("parking", "false")): print( "ignoring stop at %s for parking vehicle %s (%s, %s)" % (busStop, nStop.vehID, humanReadableTime(nArrival), (humanReadableTime(parseTime(nStop.until)) if nStop.hasAttribute("until") else "-"))) numIgnoredConflicts += 1 numIgnoredSwitchConflicts += 1 continue if options.skipParking and parseBool( pStop.getAttributeSecure("parking", "false")): print( "ignoring stop at %s for %s (%s, %s) after parking vehicle %s (%s, %s)" % (busStop, nStop.vehID, humanReadableTime(nArrival), (humanReadableTime(parseTime(nStop.until)) if nStop.hasAttribute("until") else "-"), pStop.vehID, humanReadableTime(pArrival), (humanReadableTime(parseTime(pStop.until)) if pStop.hasAttribute("until") else "-"))) numIgnoredConflicts += 1 numIgnoredSwitchConflicts += 1 continue numConflicts += 1 numSwitchConflicts += 1 # check for trains that pass the switch in between the # current two trains (heading to another stop) and raise the limit limit = 1 pTimeAtSignal = pArrival - pTimeSiSt nTimeAtSignal = nArrival - nTimeSiSt end = nTimeAtSignal + options.delay if options.verbose and options.debugSignal == pSignal: print( "check vehicles between %s and %s (including delay %s) at signal %s pStop=%s nStop=%s" % (humanReadableTime(pTimeAtSignal), humanReadableTime(end), options.delay, pSignal, pStop, nStop)) limit += countPassingTrainsToOtherStops( options, pSignal, busStop, pTimeAtSignal, end, signalTimes) conflicts[nSignal].append( Conflict( nStop.prevTripId, pSignal, pStop.prevTripId, limit, # attributes for adding comments nStop.prevLine, pStop.prevLine, nStop.vehID, pStop.vehID, nArrival)) if options.redundant >= 0: prevBegin = pTimeAtSignal for p2Arrival, p2Stop in reversed( arrivalsBySignal[pSignal]): if pArrival - p2Arrival > options.redundant: break numRedundant += 1 numRedundantSwitchConflicts += 1 p2TimeAtSignal = p2Arrival - pTimeSiSt limit += 1 limit += countPassingTrainsToOtherStops( options, pSignal, busStop, p2TimeAtSignal, prevBegin, signalTimes) conflicts[nSignal].append( Conflict( nStop.prevTripId, pSignal, p2Stop.prevTripId, limit, # attributes for adding comments nStop.prevLine, p2Stop.prevLine, nStop.vehID, p2Stop.vehID, nArrival)) prevBegin = p2TimeAtSignal if pSignal is not None and not ( options.skipParking and parseBool( pStop.getAttributeSecure("parking", "false"))): arrivalsBySignal[pSignal].append((pArrival, pStop)) if options.verbose: print("Found %s conflicts at switch %s" % (numSwitchConflicts, switch)) if numRedundantSwitchConflicts > 0: print("Found %s redundant conflicts at switch %s" % (numRedundantSwitchConflicts, switch)) if numIgnoredSwitchConflicts > 0 or numIgnoredSwitchStops > 0: print( "Ignored %s conflicts and % stops at switch %s" % (numIgnoredSwitchConflicts, numIgnoredSwitchStops, switch)) print("Found %s conflicts" % numConflicts) if numRedundant > 0: print("Found %s redundant conflicts" % numRedundant) if numIgnoredConflicts > 0 or numIgnoredStops > 0: print("Ignored %s conflicts and %s stops" % (numIgnoredConflicts, numIgnoredStops)) return conflicts
def markOvertaken(options, vehicleStopRoutes, stopRoutes): # mark stops that should not participate in constraint generation # once a vehice appears to be "overtaken" (based on inconsistent # arrival/until timing), all subsequent stops of that vehicle should no # longer be used for contraint generation for vehicle, stopRoute in vehicleStopRoutes.items(): overtaken = False for i, (edgesBefore, stop) in enumerate(stopRoute): if not (stop.hasAttribute("arrival") and stop.hasAttribute("until")): continue parking = parseBool(stop.getAttributeSecure("parking", "false")) if not overtaken: arrival = parseTime(stop.arrival) until = parseTime(stop.until) for edgesBefore2, stop2 in stopRoutes[stop.busStop]: if stop2.vehID == stop.vehID: continue if not stop2.hasAttribute( "arrival") or not stop2.hasAttribute("until"): continue parking2 = parseBool( stop2.getAttributeSecure("parking", "false")) hasParking = parking or parking2 arrival2 = parseTime(stop2.arrival) until2 = parseTime(stop2.until) # if parking stops have the same until-time their depart order # is undefined so we could get deadlocks if options.skipParking and hasParking and until != until2: continue if arrival2 > arrival and until2 < until: overtaken = True print( ("Vehicle %s (%s, %s) overtaken by %s (%s, %s) " + "at stop %s (index %s) and ignored afterwards") % (stop.vehID, humanReadableTime(arrival), humanReadableTime(until), stop2.vehID, humanReadableTime(arrival2), humanReadableTime(until2), stop.busStop, i), file=sys.stderr) break elif until == until2 and hasParking: overtaken = True if stop.vehID < stop2.vehID: # only warn once print(( "Undefined departure at stop %s" + " (index %s) for %svehicle %s (%s, %s)" + " and %svehicle %s (%s, %s)." + " No constraints will be generated for them afterwards" ) % ( stop.busStop, i, 'parking ' if parking else ' ', stop.vehID, humanReadableTime(arrival), humanReadableTime(until), 'parking ' if parking2 else ' ', stop2.vehID, humanReadableTime(arrival2), humanReadableTime(until2), ), file=sys.stderr) break if overtaken: # print("invalid veh=%s stop=%s arrival=%s until=%s" % # (stop.vehID, stop.busStop, # humanReadableTime(parseTime(stop.arrival)), # humanReadableTime(parseTime(stop.until)))) stop.setAttribute("invalid", True)