def calcDistAndLoops(rInfo, net, options): if net.hasInternal: rInfo.airDist = euclidean( net.getEdge(rInfo.edges[0]).getShape()[0], net.getEdge(rInfo.edges[-1]).getShape()[-1]) else: rInfo.airDist = euclidean( net.getEdge(rInfo.edges[0]).getFromNode().getCoord(), net.getEdge(rInfo.edges[-1]).getToNode().getCoord()) rInfo.length = sumolib.route.getLength(net, rInfo.edges) rInfo.airDistRatio = rInfo.length / rInfo.airDist rInfo.edgeLoop = False rInfo.nodeLoop = False if options.edge_loops: seen = set() for e in rInfo.edges: if e in seen: rInfo.edgeLoop = True rInfo.nodeLoop = True break seen.add(e) if options.node_loops and not rInfo.nodeLoop: seen = set() for e in rInfo.edges: t = net.getEdge(e).getToNode() if t in seen: rInfo.nodeLoop = True break seen.add(t)
def mapTrace(trace, net, delta, verbose=False, airDistFactor=2): """ matching a list of 2D positions to consecutive edges in a network. The positions are assumed to be dense (i.e. covering each edge of the route) and in the correct order. """ result = () paths = {} lastPos = None if verbose: print("mapping trace with %s points" % len(trace)) for pos in trace: newPaths = {} candidates = net.getNeighboringEdges(pos[0], pos[1], delta) if len(candidates) == 0 and verbose: print("Found no candidate edges for %s,%s" % pos) for edge, d in candidates: base = polygonOffsetWithMinimumDistanceToPoint( pos, edge.getShape()) if paths: advance = euclidean(lastPos, pos) minDist = 1e400 minPath = None for path, (dist, lastBase) in paths.items(): if dist < minDist: if edge == path[-1]: baseDiff = lastBase + advance - base extension = () elif edge in path[-1].getOutgoing(): baseDiff = lastBase + advance - path[-1].getLength( ) - base extension = (edge, ) else: extension, cost = net.getShortestPath( path[-1], edge, airDistFactor * advance) if extension is None: airLineDist = euclidean( path[-1].getToNode().getCoord(), edge.getFromNode().getCoord()) baseDiff = lastBase + advance - path[ -1].getLength() - base - airLineDist extension = (edge, ) else: baseDiff = lastBase + advance - base - cost + path[ -1].getLength() extension = extension[1:] if dist + baseDiff * baseDiff < minDist: minDist = dist + baseDiff * baseDiff minPath = path + extension if minPath: newPaths[minPath] = (minDist, base) else: newPaths[(edge, )] = (d * d, base) if not newPaths: if paths: result += _getMinPath(paths) paths = newPaths lastPos = pos if paths: return result + _getMinPath(paths) return result
def mapTrace(trace, net, delta, verbose=False, airDistFactor=2, fillGaps=False, gapPenalty=-1): """ matching a list of 2D positions to consecutive edges in a network. The positions are assumed to be dense (i.e. covering each edge of the route) and in the correct order. """ result = () paths = {} lastPos = None if verbose: print("mapping trace with %s points" % len(trace)) for pos in trace: newPaths = {} candidates = net.getNeighboringEdges(pos[0], pos[1], delta) if len(candidates) == 0 and verbose: print("Found no candidate edges for %s,%s" % pos) for edge, d in candidates: base = polygonOffsetWithMinimumDistanceToPoint(pos, edge.getShape()) if paths: advance = euclidean(lastPos, pos) minDist = 1e400 minPath = None for path, (dist, lastBase) in paths.items(): if dist < minDist: if edge == path[-1]: baseDiff = lastBase + advance - base extension = () elif edge in path[-1].getOutgoing(): baseDiff = lastBase + advance - path[-1].getLength() - base extension = (edge,) else: extension = None if fillGaps: extension, cost = net.getShortestPath(path[-1], edge, airDistFactor * advance) if extension is None: airLineDist = euclidean( path[-1].getToNode().getCoord(), edge.getFromNode().getCoord()) if gapPenalty < 0: gapPenalty = airLineDist baseDiff = abs(lastBase + advance - path[-1].getLength() - base - airLineDist) + gapPenalty extension = (edge,) else: baseDiff = lastBase + advance - base - cost + path[-1].getLength() extension = extension[1:] if dist + baseDiff * baseDiff < minDist: minDist = dist + baseDiff * baseDiff minPath = path + extension if minPath: newPaths[minPath] = (minDist, base) else: newPaths[(edge,)] = (d * d, base) if not newPaths: if paths: result += _getMinPath(paths) paths = newPaths lastPos = pos if paths: return result + _getMinPath(paths) return result
def mapTrace(trace, net, delta, verbose=False): """ matching a list of 2D positions to consecutive edges in a network """ result = () paths = {} if verbose: print("mapping trace with %s points" % len(trace)) for pos in trace: newPaths = {} candidates = net.getNeighboringEdges(pos[0], pos[1], delta) if len(candidates) == 0 and verbose: print("Found no candidate edges for %s" % pos) for edge, d in candidates: base = polygonOffsetWithMinimumDistanceToPoint( pos, edge.getShape()) if paths: advance = euclidean(lastPos, pos) minDist = 1e400 minPath = None for path, (dist, lastBase) in paths.items(): if dist < minDist: if edge == path[-1]: baseDiff = lastBase + advance - base elif edge in path[-1].getOutgoing(): baseDiff = lastBase + advance - path[-1].getLength( ) - base else: airLineDist = euclidean( path[-1].getToNode().getCoord(), edge.getFromNode().getCoord()) baseDiff = lastBase + advance - path[-1].getLength( ) - base - airLineDist if dist + baseDiff * baseDiff < minDist: minDist = dist + baseDiff * baseDiff minPath = path if edge == path[-1] else path + ( edge, ) if minPath: newPaths[minPath] = (minDist, base) else: newPaths[(edge, )] = (d * d, base) if not newPaths: if paths: result += _getMinPath(paths) paths = newPaths lastPos = pos if paths: return result + _getMinPath(paths) return result
def get_trip(self, min_distance, max_distance, maxtries=100, junctionTaz=False): for _ in range(maxtries): source_edge = self.source_generator.get() intermediate = [ self.via_generator.get() for i in range(self.intermediate) ] sink_edge = self.sink_generator.get() if self.pedestrians: destCoord = sink_edge.getFromNode().getCoord() else: destCoord = sink_edge.getToNode().getCoord() coords = ([source_edge.getFromNode().getCoord()] + [e.getFromNode().getCoord() for e in intermediate] + [destCoord]) distance = sum( [euclidean(p, q) for p, q in zip(coords[:-1], coords[1:])]) if (distance >= min_distance and (not junctionTaz or source_edge.getFromNode() != sink_edge.getToNode()) and (max_distance is None or distance < max_distance)): return source_edge, sink_edge, intermediate raise Exception("no trip found after %s tries" % maxtries)
def _parking_to_edge(self, parking): """ Given a parking lot, return the closest edge (lane_0) and all the other info required by SUMO for the parking areas: (edge_info, lane_info, location, parking.coords, parking.capacity) """ edge_info = None lane_info = None dist_edge = sys.float_info.max # distance.euclidean(a,b) location = None for edge in self._net.getEdges(): if not (edge.allows('passenger') and edge.allows('pedestrian')): continue if self._is_too_short(edge.getLength()): continue stop_lane = None index = 0 while not stop_lane: try: stop_lane = edge.getLane(index) if not stop_lane.allows('passenger'): stop_lane = None index += 1 except IndexError: stop_lane = None break if stop_lane: # compute all the distances counter = 0 for point in stop_lane.getShape(): dist = euclidean( (float(parking['x']), float(parking['y'])), point) if dist < dist_edge: edge_info = edge lane_info = stop_lane dist_edge = dist location = counter counter += 1 if dist_edge > 50.0: logging.info("Alert: parking lots %s is %d meters from edge %s.", parking['id'], dist_edge, edge_info.getID()) return (edge_info, lane_info, location)
def _parkings_sumo(self): """ Compute the parking lots stops location for SUMO. """ for plid, (_, lane, location) in self._parkings_edges_dict.items(): new_pl = { 'id': plid, 'lane': lane.getID(), 'start': -self._PARKING_LEN / 2, 'end': self._PARKING_LEN / 2, 'capacity': self._get_capacity(plid), 'coords': (float(self._osm_parkings[plid]['x']), float(self._osm_parkings[plid]['y'])), } _prec = None _counter = 0 for point in lane.getShape(): if _prec is None: _prec = point _counter += 1 continue if _counter <= location: dist = euclidean(_prec, point) new_pl['start'] += dist new_pl['end'] += dist _prec = point _counter += 1 else: break if new_pl['start'] < self._BUFFER: new_pl['start'] = self._BUFFER new_pl['end'] = new_pl['start'] + self._PARKING_LEN if new_pl['end'] > lane.getLength() - self._BUFFER: new_pl['end'] = lane.getLength() - self._BUFFER new_pl['start'] = new_pl['end'] - self._PARKING_LEN self._sumo_parkings[plid] = new_pl
def get_trip(self, min_distance, max_distance, maxtries=100): for i in range(maxtries): source_edge = self.source_generator.get() intermediate = [self.via_generator.get() for i in range(self.intermediate)] sink_edge = self.sink_generator.get() if self.pedestrians: destCoord = sink_edge.getFromNode().getCoord() else: destCoord = sink_edge.getToNode().getCoord() coords = ([source_edge.getFromNode().getCoord()] + [e.getFromNode().getCoord() for e in intermediate] + [destCoord]) distance = sum([euclidean(p, q) for p, q in zip(coords[:-1], coords[1:])]) if distance >= min_distance and (max_distance is None or distance < max_distance): return source_edge, sink_edge, intermediate raise Exception("no trip found after %s tries" % maxtries)
def mapTrace(trace, net, delta, verbose=False): """ matching a list of 2D positions to consecutive edges in a network """ result = [] paths = {} if verbose: print("mapping trace with %s points" % len(trace)) for pos in trace: newPaths = {} candidates = net.getNeighboringEdges(pos[0], pos[1], delta) if len(candidates) == 0 and verbose: print("Found no candidate edges for %s,%s" % pos) for edge, d in candidates: if paths: minDist = 1e400 minPath = None for path, dist in paths.iteritems(): if dist < minDist: if edge == path[-1]: minPath = path minDist = dist elif edge in path[-1].getOutgoing(): minPath = path + (edge, ) minDist = dist else: minPath = path + (edge, ) minDist = dist + euclidean( path[-1].getToNode().getCoord(), edge.getFromNode().getCoord()) if minPath: newPaths[minPath] = minDist + d * d else: newPaths[(edge, )] = d * d if not newPaths: if paths: result += [e.getID() for e in _getMinPath(paths)] paths = newPaths if paths: return result + [e.getID() for e in _getMinPath(paths)] return result
def _bus_stops_for_sumo(self, stops_to_edges): """ Compute the bus stops location for SUMO. """ for ptid, (lane, location) in tqdm(stops_to_edges.items()): new_pt = { 'id': ptid, 'name': self._get_stop_name(self._osm_bus_stops[ptid]), 'pt_type': self._osm_bus_stops[ptid]['pt_type'], 'lane': lane.getID(), } _start = -BUS_PLATFORM_LEN / 2 _end = BUS_PLATFORM_LEN / 2 _prec = None _counter = 0 for point in lane.getShape(): if _prec is None: _prec = point _counter += 1 continue if _counter <= location: dist = euclidean(_prec, point) _start += dist _end += dist _prec = point _counter += 1 else: break if _start < 5.0: _start = 5.0 _end = _start + BUS_PLATFORM_LEN if _end > lane.getLength() - 5.0: _end = lane.getLength() - 5.0 _start = _end - BUS_PLATFORM_LEN new_pt['start'] = _start new_pt['end'] = _end self._sumo_bus_stops[ptid] = new_pt
def _bus_stop_to_lane(self, stop): """ Given the coords of a bus stop, return te closest lane_0. """ lane_info = None dist_edge = sys.float_info.max # distance.euclidean(a,b) location = None for edge in self._net.getEdges(): if not (edge.allows('bus') and edge.allows('pedestrian')): continue if edge.getLength() < (BUS_PLATFORM_LEN * 1.5): continue stop_lane = None try: stop_lane = edge.getLane(1) except IndexError: stop_lane = edge.getLane(0) # compute all the distances counter = 0 for point in stop_lane.getShape(): dist = euclidean((float(stop['x']), float(stop['y'])), point) if dist < dist_edge: lane_info = stop_lane dist_edge = dist location = counter counter += 1 if dist_edge > 50.0: logging.info("Alert: stop %s [%s] is %d meters from lane %s.", stop['id'], stop['pt_type'], dist_edge, lane_info.getID()) return (lane_info, location)
def _train_stop_to_lane(self, stop): """ Given the coords of a stop, return te closest lane_0 """ lane_info = None dist_edge = None location = None railway_lane_info = None railway_dist_edge = sys.float_info.max # distance.euclidean(a,b) railway_location = None street_lane_info = None street_dist_edge = sys.float_info.max # distance.euclidean(a,b) street_location = None for edge in self._net.getEdges(): if edge.allows('rail'): if edge.getLength() < (TRAIN_PLATFORM_LEN * 1.5): continue lane_info = railway_lane_info dist_edge = railway_dist_edge location = railway_location elif edge.allows('pedestrian'): lane_info = street_lane_info dist_edge = street_dist_edge location = street_location else: continue stop_lane = None try: stop_lane = edge.getLane(1) except IndexError: stop_lane = edge.getLane(0) # compute all the distances counter = 0 for point in stop_lane.getShape(): dist = euclidean((float(stop['x']), float(stop['y'])), point) if dist < dist_edge: lane_info = stop_lane dist_edge = dist location = counter counter += 1 if edge.allows('rail'): railway_lane_info = lane_info railway_dist_edge = dist_edge railway_location = location else: street_lane_info = lane_info street_dist_edge = dist_edge street_location = location railway_access = (railway_lane_info, railway_location) if railway_dist_edge > 50.0: logging.info("Alert: stop %s [%s] is %d meters from lane %s.", stop['id'], stop['pt_type'], railway_dist_edge, railway_lane_info.getID()) street_access = (street_lane_info, street_location) logging.info( "Alert: Street access for stop %s [%s] is %d meters from edge %s.", stop['id'], stop['pt_type'], street_dist_edge, street_lane_info.getID()) if street_dist_edge > 500.0: street_access = None logging.info( "Alert: Street access for stop %s too far and it will be removed.", stop['id']) return (railway_access, street_access)
def main(): DUAROUTER = sumolib.checkBinary('duarouter') options = get_options() net = readNet(options.network) routeInfos = {} # id-> RouteInfo if options.standalone: for route in parse(options.routeFile, 'route'): ri = RouteInfo() ri.edges = route.edges.split() routeInfos[route.id] = ri else: for vehicle in parse(options.routeFile, 'vehicle'): ri = RouteInfo() ri.edges = vehicle.route[0].edges.split() routeInfos[vehicle.id] = ri for rInfo in routeInfos.values(): rInfo.airDist = euclidean( net.getEdge(rInfo.edges[0]).getShape()[0], net.getEdge(rInfo.edges[-1]).getShape()[-1]) rInfo.length = getRouteLength(net, rInfo.edges) rInfo.airDistRatio = rInfo.length / rInfo.airDist duarouterInput = options.routeFile if options.standalone: # generate suitable input file for duarouter duarouterInput += ".vehRoutes.xml" with open(duarouterInput, 'w') as outf: outf.write('<routes>\n') for rID, rInfo in routeInfos.items(): outf.write(' <vehicle id="%s" depart="0">\n' % rID) outf.write(' <route edges="%s"/>\n' % ' '.join(rInfo.edges)) outf.write(' </vehicle>\n') outf.write('</routes>\n') duarouterOutput = options.routeFile + '.rerouted.rou.xml' duarouterAltOutput = options.routeFile + '.rerouted.rou.alt.xml' subprocess.call([ DUAROUTER, '-n', options.network, '-r', duarouterInput, '-o', duarouterOutput, '--no-step-log' ]) for vehicle in parse(duarouterAltOutput, 'vehicle'): routeAlts = vehicle.routeDistribution[0].route if len(routeAlts) == 1: routeInfos[vehicle.id].detour = 0 routeInfos[vehicle.id].detourRatio = 1 routeInfos[vehicle.id].shortest_path_distance = routeInfos[ vehicle.id].length else: oldCosts = float(routeAlts[0].cost) newCosts = float(routeAlts[1].cost) assert (routeAlts[0].edges.split() == routeInfos[vehicle.id].edges) routeInfos[vehicle.id].shortest_path_distance = getRouteLength( net, routeAlts[1].edges.split()) if oldCosts <= newCosts: routeInfos[vehicle.id].detour = 0 routeInfos[vehicle.id].detourRatio = 1 if oldCosts < newCosts: sys.stderr.write(( "Warning: fastest route for '%s' is slower than original route " + "(old=%s, new=%s). Check vehicle types\n") % (vehicle.id, oldCosts, newCosts)) else: routeInfos[vehicle.id].detour = oldCosts - newCosts routeInfos[vehicle.id].detourRatio = oldCosts / newCosts implausible = [] allRoutesStats = Statistics("overal implausiblity") implausibleRoutesStats = Statistics("implausiblity above threshold") for rID in sorted(routeInfos.keys()): ri = routeInfos[rID] ri.implausibility = ( options.airdist_ratio_factor * ri.airDistRatio + options.detour_factor * ri.detour + options.detour_ratio_factor * ri.detourRatio + max(0, options.min_dist / ri.shortest_path_distance - 1) + max(0, options.min_air_dist / ri.airDist - 1)) allRoutesStats.add(ri.implausibility, rID) if ri.implausibility > options.threshold: implausible.append((ri.implausibility, rID, ri)) implausibleRoutesStats.add(ri.implausibility, rID) # generate restrictions if options.restrictions_output is not None: with open(options.restrictions_output, 'w') as outf: for score, rID, ri in sorted(implausible): edges = ri.edges if options.odrestrictions and len(edges) > 2: edges = [edges[0], edges[-1]] outf.write("0 %s\n" % " ".join(edges)) if options.ignore_routes is not None: numImplausible = len(implausible) ignored = set([r.strip() for r in open(options.ignore_routes)]) implausible = [r for r in implausible if r not in ignored] print( "Loaded %s routes to ignore. Reducing implausible from %s to %s" % (len(ignored), numImplausible, len(implausible))) # generate polygons polyOutput = options.routeFile + '.implausible.add.xml' colorgen = Colorgen(("random", 1, 1)) with open(polyOutput, 'w') as outf: outf.write('<additional>\n') for score, rID, ri in sorted(implausible): generate_poly(options, net, rID, colorgen(), ri.edges, outf, score) outf.write('</additional>\n') sys.stdout.write( 'score\troute\t(airDistRatio, detourRatio, detour, shortestDist, airDist)\n' ) for score, rID, ri in sorted(implausible): # , ' '.join(ri.edges))) sys.stdout.write('%.7f\t%s\t%s\n' % (score, rID, (ri.airDistRatio, ri.detourRatio, ri.detour, ri.shortest_path_distance, ri.airDist))) print(allRoutesStats) print(implausibleRoutesStats)
def mapTrace(trace, net, delta, verbose=False, airDistFactor=2, fillGaps=False, gapPenalty=-1, debug=False): """ matching a list of 2D positions to consecutive edges in a network. The positions are assumed to be dense (i.e. covering each edge of the route) and in the correct order. """ result = () paths = {} lastPos = None if verbose: print("mapping trace with %s points" % len(trace)) for pos in trace: newPaths = {} candidates = net.getNeighboringEdges(pos[0], pos[1], delta, not net.hasInternal) if debug: print("\n\npos:%s, %s" % (pos[0], pos[1])) print("candidates:%s\n" % candidates) if len(candidates) == 0 and verbose: print("Found no candidate edges for %s,%s" % pos) for edge, d in candidates: base = polygonOffsetWithMinimumDistanceToPoint( pos, edge.getShape()) if paths: advance = euclidean(lastPos, pos) # should become a vector minDist = 1e400 minPath = None for path, (dist, lastBase) in paths.items(): if debug: print("*** extending path %s by edge '%s'" % ([e.getID() for e in path], edge.getID())) print( " lastBase: %s, base: %s, advance: %s, old dist: %s, minDist: %s" % (lastBase, base, advance, dist, minDist)) if dist < minDist: if edge == path[-1]: baseDiff = lastBase + advance - base extension = () if debug: print("---------- same edge") else: extension, cost = net.getShortestPath( path[-1], edge, airDistFactor * advance + edge.getLength() + path[-1].getLength()) if extension is not None and not fillGaps and len( extension) > 2: extension = None if extension is None: airLineDist = euclidean( path[-1].getToNode().getCoord(), edge.getFromNode().getCoord()) if gapPenalty < 0: gapPenalty = airDistFactor * advance baseDiff = abs(lastBase + advance - path[-1].getLength() - base - airLineDist) + gapPenalty extension = (edge, ) else: baseDiff = lastBase + advance - ( cost - edge.getLength()) - base extension = extension[1:] if debug: print( "---------- extension path: %s, cost: %s, baseDiff: %s" % (extension, cost, baseDiff)) dist += baseDiff * baseDiff if dist < minDist: minDist = dist minPath = path + extension if debug: print("*** new dist: %s baseDiff: %s minDist: %s" % (dist, baseDiff, minDist)) if minPath: newPaths[minPath] = (minDist, base) else: newPaths[(edge, )] = (d * d, base) if not newPaths: if paths: result += _getMinPath(paths) paths = newPaths lastPos = pos if paths: if debug: print("**************** result:") for i in result + _getMinPath(paths): print("path:%s" % i.getID()) return result + _getMinPath(paths) return result
def main(): DUAROUTER = sumolib.checkBinary('duarouter') options = get_options() net = readNet(options.network) routeInfos = {} # id-> RouteInfo if options.standalone: for route in parse(options.routeFile, 'route'): ri = RouteInfo() ri.edges = route.edges.split() routeInfos[route.id] = ri else: for vehicle in parse(options.routeFile, 'vehicle'): ri = RouteInfo() ri.edges = vehicle.route[0].edges.split() routeInfos[vehicle.id] = ri for rInfo in routeInfos.values(): rInfo.airDist = euclidean( net.getEdge(rInfo.edges[0]).getShape()[0], net.getEdge(rInfo.edges[-1]).getShape()[-1]) rInfo.length = getRouteLength(net, rInfo.edges) rInfo.airDistRatio = rInfo.length / rInfo.airDist duarouterInput = options.routeFile if options.standalone: # generate suitable input file for duarouter duarouterInput += ".vehRoutes.xml" with open(duarouterInput, 'w') as outf: outf.write('<routes>\n') for rID, rInfo in routeInfos.items(): outf.write(' <vehicle id="%s" depart="0">\n' % rID) outf.write(' <route edges="%s"/>\n' % ' '.join(rInfo.edges)) outf.write(' </vehicle>\n') outf.write('</routes>\n') duarouterOutput = options.routeFile + '.rerouted.rou.xml' duarouterAltOutput = options.routeFile + '.rerouted.rou.alt.xml' subprocess.call([DUAROUTER, '-n', options.network, '-r', duarouterInput, '-o', duarouterOutput, '--no-step-log']) for vehicle in parse(duarouterAltOutput, 'vehicle'): routeAlts = vehicle.routeDistribution[0].route if len(routeAlts) == 1: routeInfos[vehicle.id].detour = 0 routeInfos[vehicle.id].detourRatio = 1 routeInfos[vehicle.id].shortest_path_distance = routeInfos[vehicle.id].length else: oldCosts = float(routeAlts[0].cost) newCosts = float(routeAlts[1].cost) assert(routeAlts[0].edges.split() == routeInfos[vehicle.id].edges) routeInfos[vehicle.id].shortest_path_distance = getRouteLength(net, routeAlts[1].edges.split()) if oldCosts <= newCosts: routeInfos[vehicle.id].detour = 0 routeInfos[vehicle.id].detourRatio = 1 if oldCosts < newCosts: sys.stderr.write(("Warning: fastest route for '%s' is slower than original route " + "(old=%s, new=%s). Check vehicle types\n") % ( vehicle.id, oldCosts, newCosts)) else: routeInfos[vehicle.id].detour = oldCosts - newCosts routeInfos[vehicle.id].detourRatio = oldCosts / newCosts implausible = [] allRoutesStats = Statistics("overal implausiblity") implausibleRoutesStats = Statistics("implausiblity above threshold") for rID in sorted(routeInfos.keys()): ri = routeInfos[rID] ri.implausibility = (options.airdist_ratio_factor * ri.airDistRatio + options.detour_factor * ri.detour + options.detour_ratio_factor * ri.detourRatio + max(0, options.min_dist / ri.shortest_path_distance - 1) + max(0, options.min_air_dist / ri.airDist - 1)) allRoutesStats.add(ri.implausibility, rID) if ri.implausibility > options.threshold: implausible.append((ri.implausibility, rID, ri)) implausibleRoutesStats.add(ri.implausibility, rID) # generate restrictions if options.restrictions_output is not None: with open(options.restrictions_output, 'w') as outf: for score, rID, ri in sorted(implausible): edges = ri.edges if options.odrestrictions and len(edges) > 2: edges = [edges[0], edges[-1]] outf.write("0 %s\n" % " ".join(edges)) if options.ignore_routes is not None: numImplausible = len(implausible) ignored = set([r.strip() for r in open(options.ignore_routes)]) implausible = [r for r in implausible if r not in ignored] print("Loaded %s routes to ignore. Reducing implausible from %s to %s" % ( len(ignored), numImplausible, len(implausible))) # generate polygons polyOutput = options.routeFile + '.implausible.add.xml' colorgen = Colorgen(("random", 1, 1)) with open(polyOutput, 'w') as outf: outf.write('<additional>\n') for score, rID, ri in sorted(implausible): generate_poly(net, rID, colorgen(), 100, False, ri.edges, options.blur, outf, score) outf.write('</additional>\n') sys.stdout.write('score\troute\t(airDistRatio, detourRatio, detour, shortestDist, airDist)\n') for score, rID, ri in sorted(implausible): # , ' '.join(ri.edges))) sys.stdout.write('%.7f\t%s\t%s\n' % (score, rID, (ri.airDistRatio, ri.detourRatio, ri.detour, ri.shortest_path_distance, ri.airDist))) print(allRoutesStats) print(implausibleRoutesStats)
def _train_stops_for_sumo(self, stops_to_edges): """ Compute the train stops location for SUMO. """ for ptid, values in tqdm(stops_to_edges.items()): railway_access, street_access = values railway_lane_info, railway_location = railway_access new_pt = { 'id': ptid, 'name': self._get_stop_name(self._osm_train_stops[ptid]), 'pt_type': self._osm_train_stops[ptid]['pt_type'], 'lane': railway_lane_info.getID(), } ### Compute the position for the railway _start = -TRAIN_PLATFORM_LEN / 2 _end = TRAIN_PLATFORM_LEN / 2 _prec = None _counter = 0 for point in railway_lane_info.getShape(): if _prec is None: _prec = point _counter += 1 continue if _counter <= railway_location: dist = euclidean(_prec, point) _start += dist _end += dist _prec = point _counter += 1 else: break if _start < 5.0: _start = 5.0 _end = _start + TRAIN_PLATFORM_LEN if _end > railway_lane_info.getLength() - 5.0: _end = railway_lane_info.getLength() - 5.0 _start = _end - TRAIN_PLATFORM_LEN if railway_lane_info.getLength() <= TRAIN_PLATFORM_LEN: _start = 5.0 _end = railway_lane_info.getLength() - 5.0 new_pt['start'] = _start new_pt['end'] = _end street_lane_info, street_location = (None, None) if street_access: street_lane_info, street_location = street_access new_pt['access'] = {'lane': street_lane_info.getID()} ### Compute the position for the street _start = -TRAIN_PLATFORM_LEN / 2 _end = TRAIN_PLATFORM_LEN / 2 _prec = None _counter = 0 for point in street_lane_info.getShape(): if _prec is None: _prec = point _counter += 1 continue if _counter <= street_location: dist = euclidean(_prec, point) _start += dist _end += dist _prec = point _counter += 1 else: break if _start < 5.0: _start = 5.0 _end = _start + TRAIN_PLATFORM_LEN if _end > street_lane_info.getLength() - 5.0: _end = street_lane_info.getLength() - 5.0 _start = _end - TRAIN_PLATFORM_LEN if street_lane_info.getLength() <= TRAIN_PLATFORM_LEN: _start = 5.0 _end = street_lane_info.getLength() - 5.0 new_pt['access']['pos'] = (_start + _end) / 2 self._sumo_train_stops[ptid] = new_pt
def rectify_input(options): # convert depart-time to seconds # add random seconds from [-options.diffuse/2, options.diffuse/2] to reduce traffic bursts # (right now the most important trip for each person is aligned to 5min slot # and some of these slots are very crowded) # gaps # NaN # ordering assumptions # every "person" appears only once. A person is defined by (person_id, household_id) # trips for each person are sorted by departure # report overlapping times # filter trips wich start on the next day # filter trips by mode (optional) # diffuse geoCoordinates with a gausian (mu = 0, sigma = spatialDiffuse meters) # since tapas inputs tends to show strong spatial clustering (call it # parking related diffusion) diffusion_map = {} modes = options.modes.split(",") if options.max_spatial_diffusion > 0: loc_count = collections.defaultdict(int) for row in csv.DictReader(open(options.tapas_trips)): if row[TH.mode] in modes: loc_count[(row[TH.source_long], row[TH.source_lat])] += 1 loc_count[(row[TH.dest_long], row[TH.dest_lat])] += 1 for coord, count in loc_count.items(): if count >= options.spatial_diffusion_bounds[0]: scale = float(count - options.spatial_diffusion_bounds[0]) / ( options.spatial_diffusion_bounds[1] - options.spatial_diffusion_bounds[0]) diffusion = scale * ( options.max_spatial_diffusion - options.spatial_diffusion) + options.spatial_diffusion if diffusion < options.max_spatial_diffusion: diffusion_map[coord] = diffusion if os.path.exists(options.location_priority_file): for loc in sumolib.xml.parse(options.location_priority_file, "poi"): diffusion_map[(loc.lon, loc.lat)] = 0 with open(options.rectified_log, 'w') as logfile: log = get_logger(logfile) writer = csv.DictWriter(open(options.rectified, 'w'), THX.fieldnames, extrasaction='ignore', lineterminator='\n') writer.writeheader() persons = 0 rows = 0 gaps = 0 gap_sum = 0 max_gap = 0 max_gap_uid = None max_depart = 0 max_depart_uid = None inconsistent = 0 skipped_wrong_mode = 0 skipped_wrong_depart = 0 # asserts that each person appears only in one consecutive sequence of # # entries gen = csv_sequence_generator(options.tapas_trips, (TH.person_id, TH.household_id), assertUniqe=True) for (pid, hid), trip_sequence in gen: persons += 1 previous_row = None previous_dest = None previous_end = None previous_depart = None spatial_offset = None # smooth bursts due to low resolution smoothing_offset = int( random.random() * (options.time_diffusion + 1)) - options.time_diffusion // 2 for row in trip_sequence: rows += 1 uid = build_uid(row) source_coord = (row[TH.source_long], row[TH.source_lat]) source = options.net.convertLonLat2XY(*source_coord) if spatial_offset is None: if source_coord in diffusion_map: spatial_offset = [ random.gauss(0, diffusion_map[source_coord]) for i in range(2) ] elif options.max_spatial_diffusion <= 0 and options.spatial_diffusion > 0: spatial_offset = [ random.gauss(0, options.spatial_diffusion) for i in range(2) ] dest_coord = (row[TH.dest_long], row[TH.dest_lat]) dest = options.net.convertLonLat2XY(*dest_coord) depart_minute = int(row[TH.depart_minute]) depart = depart_minute * 60 + smoothing_offset duration = float(row[TH.duration]) activity_duration = int(row[TH.activity_duration_minutes]) * 60 if depart_minute - 24 * 60 >= TAPAS_DAY_OVERLAP_MINUTES or depart_minute <= -TAPAS_DAY_OVERLAP_MINUTES: log("Warning: dropping trip %s because it starts on the wrong day (minute %s)" % (uid, depart_minute)) skipped_wrong_depart += 1 if depart_minute > max_depart: max_depart = depart_minute max_depart_uid = uid continue row[THX.depart_second] = depart if math.isnan(duration): log('Warning: NaN value in duration of trip %s' % uid) duration = 1 row[TH.duration] = duration if previous_end is not None and depart < previous_end: if (previous_end - depart >= 60): # input data only has minute resolution anyway and may # suffer from rounding inconsistent += 1 log("Warning: inconsistent depart time for trip %s (%s seconds)" % (uid, previous_end - depart)) depart = previous_end previous_end = int(depart + duration + activity_duration) if previous_depart is not None and depart < previous_depart: raise MappingError( 'Unordered trips for person %s at departure %s' % (pid, depart_minute)) previous_depart = depart # close gaps in trip sequence if previous_dest and previous_dest != source and not options.ignore_gaps: gaps += 1 gap = euclidean(previous_dest, source) gap_sum += gap max_gap = max(max_gap, gap) max_gap_uid = uid # to many to list them all # print('Warning: gap in edge sequence at trip %s (length %s)' % (uid, gap)) # XXX add teleport-trip for closing the gap # row[TH.source_long] = previous_row[TH.dest_long] # row[TH.source_lat] = previous_row[TH.dest_lat] continue previous_row = row previous_dest = dest if spatial_offset is not None: row[TH.source_long], row[ TH.source_lat] = options.net.convertXY2LonLat( source[0] + spatial_offset[0], source[1] + spatial_offset[1]) if dest_coord in diffusion_map: spatial_offset = [ random.gauss(0, diffusion_map[dest_coord]) for i in range(2) ] else: spatial_offset = [ random.gauss(0, options.spatial_diffusion) for i in range(2) ] row[TH.dest_long], row[ TH.dest_lat] = options.net.convertXY2LonLat( dest[0] + spatial_offset[0], dest[1] + spatial_offset[1]) if row[TH.mode] in modes: writer.writerow(row) else: skipped_wrong_mode += 1 log('Read %s persons with a total of %s trips from input file "%s".' % (persons, rows, options.tapas_trips)) if skipped_wrong_mode > 0: log('Dropped %s trips because they have the wrong mode' % skipped_wrong_mode) log('%s trips have inconsistent depart times.' % inconsistent) if gaps > 0: log('Dropped %s trips because of gaps, avg: %s, maximum: %s (for trip %s).' % (gaps, gap_sum / gaps, max_gap, max_gap_uid)) if skipped_wrong_depart > 0: log('Dropped %d trips because they start on the wrong day (maximum: %s for trip %s).' % (skipped_wrong_depart, max_depart, max_depart_uid))