def main(): # read inputs argParser = initOptions() options = argParser.parse_args() r_all = {} rv_dict = {} memory_problems = [0] # start traci if options.sumocfg: run_traci = [ options.sumo, "-c", options.sumocfg, '--tripinfo-output.write-unfinished' ] else: run_traci = [ options.sumo, '--net-file', '%s' % options.network, '-r', '%s,%s' % (options.reservations, options.taxis), '-l', 'log.txt', '--device.taxi.dispatch-algorithm', 'traci', '--tripinfo-output', '%s' % options.output, '--tripinfo-output.write-unfinished' ] if options.gui_settings: run_traci.extend(['-g', '%s' % options.gui_settings]) traci.start(run_traci) # execute the TraCI control loop step = traci.simulation.getTime() + 10 v_type = None rerouting = True while rerouting: traci.simulationStep(step) # get vType for route calculation if not v_type: fleet = traci.vehicle.getTaxiFleet(-1) v_type = traci.vehicle.getTypeID(fleet[0]) # get new reservations r_id_new = [] for x in traci.person.getTaxiReservations(1): # search direct travel time direct = int( traci.simulation.findRoute(x.fromEdge, x.toEdge, v_type, x.depart, routingMode=0).travelTime) # add new reservation attributes setattr(x, 'direct', direct) # direct travel time setattr(x, 'vehicle', False) # id of assigned vehicle setattr(x, 'delay', 0) # difference between assigned pick up time and real one setattr( x, 'tw_pickup', [x.depart, x.depart + options.max_wait]) # pickup time window # drop off time window if x.direct * options.drf < options.drf_min: setattr(x, 'tw_dropoff', [ x.tw_pickup[0] + direct, x.tw_pickup[1] + direct + options.drf_min ]) else: setattr(x, 'tw_dropoff', [ x.tw_pickup[0] + direct, x.tw_pickup[1] + direct * options.drf ]) # add id to new reservations r_id_new.append(x.id) # add reservation to list r_all[x.id] = x # unassigned reservations r_id_unassigned = [x.id for x_id, x in r_all.items() if not x.vehicle] # if reservations pending if r_id_unassigned: if options.debug: print('\nRun dispatcher') if r_id_new: print('New reservations: ', r_id_new) print('Unassigned reservations: ', list(set(r_id_unassigned) - set(r_id_new))) # get fleet fleet = traci.vehicle.getTaxiFleet(-1) if set(fleet) != set(fleet) & set( traci.vehicle.getIDList()): # TODO manage teleports print("\nVehicle %s is being teleported, skip to next step" % (set(fleet) - set(traci.vehicle.getIDList()))) step += options.sim_step continue # if a vehicle is being teleported skip to next step # remove reservations already served r_id_current = [x.id for x in traci.person.getTaxiReservations(0)] r_id_served = list(set(r_all.keys()) - set(r_id_current)) [r_all.pop(key) for key in r_id_served] [ rv_dict.pop(key) for key in list(rv_dict) if set(r_id_served) & set(rv_dict[key][2]) ] # reservations already picked up r_id_picked = [x.id for x in traci.person.getTaxiReservations(8)] # search request-vehicles pairs if options.debug: print('Calculate RV-Graph') get_rv(options, r_id_new, r_id_picked, r_id_served, r_all, fleet, v_type, rv_dict, step) # search trips (rtv graph) # TODO define/import algorithm before to avoid checking each time # Maybe a list with the function as element and get the element (0, 1, 2) if options.debug: print('Calculate RTV-Graph') if options.rtv_algorithm == '0': rtv_dict, r_id_rtv, memory_problems = rtvAlgorithm.exhaustive_search( options, r_id_unassigned, r_id_picked, r_all, fleet, v_type, rv_dict, step, memory_problems) elif options.rtv_algorithm == '1': rtv_dict, r_id_rtv = rtvAlgorithm.simple( options, r_id_unassigned, r_id_picked, r_id_served, r_all, fleet, v_type, rv_dict, step) elif options.rtv_algorithm == '2': rtv_dict, r_id_rtv = rtvAlgorithm.simple_rerouting( options, r_id_unassigned, r_id_picked, r_id_served, r_all, fleet, v_type, rv_dict, step) # rtv_dict, r_id_rtv = get_rtv(options, r_id_unassigned, r_id_picked, r_id_served, r_all, fleet, v_type, rv_dict, step) if len(rtv_dict) == 0: step += options.sim_step continue # if no routes found elif len(rtv_dict.keys()) == 1: # if one vehicle darp, assign route best_routes = list(rtv_dict.keys()) else: # if multiple vehicle darp, solve ILP with pulp vehicle_constraints = {} request_constraints = {} costs = {} trips = list(rtv_dict.keys() ) # list of all trips for ILP solution parse # add bonus_cost to trip cost (makes trips with more served requests cheaper than splitting the requests to more # vehicles with smaller trips if both strategies would yield a similar cost) for idx, trip_id in enumerate(trips): # rtv_dict[route] = [travel_time, v_bin, r_bin, value] bonus_cost = ( sum(rtv_dict[trip_id][2]) + 1 ) * options.cost_per_trip # TODO specific cost for vehicle can be consider here costs.update({idx: rtv_dict[trip_id][0] + bonus_cost }) # generate dict with cost vehicle_constraints.update({ idx: rtv_dict[trip_id][1] }) # generate dict with vehicle used in the trip request_constraints.update({ idx: rtv_dict[trip_id][2] }) # generate dict with served requests in the trip if options.debug: print('Solve ILP') ilp_result = ilp_solve(options, len(fleet), len(r_id_rtv), costs, vehicle_constraints, request_constraints) # parse ILP result best_routes = [ trips[int(route_index)] for route_index in ilp_result ] # assign routes to vehicles for route_id in best_routes: stops = route_id.replace('y', '') stops = stops.replace('z', '') stops = stops.split("_") # first check if route different or better (when no optimal solution) than already assigned current_route = [] try: # get current route for taxi_stop in traci.vehicle.getStops(stops[0]): sub_stops = taxi_stop.actType.split( ",") # if more than 1 reservation in stop for sub_stop in sub_stops: current_route.append(sub_stop.split(" ")[2][1:-1]) except: current_route = ['None'] if current_route == stops[1:]: # route is the same continue elif set(current_route) == set( stops[1:]) and len(current_route) == len(stops[1:]): # if route serve same request, check if new is faster tt_current_route = 0 edges = [ taxi_stops.lane.split("_")[0] for taxi_stops in traci.vehicle.getStops(stops[0]) ] # TODO check next_act update edges.insert( 0, traci.vehicle.getLaneID( stops[0]).split("_")[0]) # add current edge for idx, edge in enumerate(edges[:-1]): tt_current_route += int( traci.simulation.findRoute( edge, edges[idx + 1], v_type, step, routingMode=0).travelTime ) + 60 # TODO default stop time ticket #6714 tt_new_route = rtv_dict[route_id][0] if tt_new_route >= tt_current_route: continue # current route better than new found if options.debug: print('Dispatch: ', route_id) traci.vehicle.dispatchTaxi(stops[0], stops[1:]) # assign vehicle to requests # TODO to avoid major changes in the pick-up time when assigning new passengers, # tw_pickup should be updated, whit some constant X seconds, e.g. 10 Minutes for x_id in set(stops[1:]): x = r_all[x_id] x.vehicle = stops[0] if step > options.end_time or ( not traci.simulation.getMinExpectedNumber() > 0 and not traci.person.getIDList()): #TODO ticket #8385 rerouting = False step += options.sim_step if options.rtv_algorithm == 0: # if exhaustive search if sum(memory_problems) == 0: print('Optimal solution found') else: print( 'The maximum specified time for the calculation with the exact method was exceeded. Solution could not be optimal' ) print('DRT simulation ended') traci.close()
def main(): # read inputs ap = initOptions() options = ap.parse_args() res_all = {} rv_dict = {} exact_sol = [0] if options.sumo == 'sumo': SUMO = checkBinary('sumo') else: SUMO = checkBinary('sumo-gui') # start traci if options.sumocfg: run_traci = [ SUMO, "-c", options.sumocfg, '--tripinfo-output.write-unfinished' ] else: run_traci = [ SUMO, '--net-file', '%s' % options.network, '-r', '%s,%s' % (options.reservations, options.taxis), '-l', 'log.txt', '--device.taxi.dispatch-algorithm', 'traci', '--tripinfo-output', '%s' % options.output, '--tripinfo-output.write-unfinished' ] if options.gui_settings: run_traci.extend(['-g', '%s' % options.gui_settings]) traci.start(run_traci) # execute the TraCI control loop step = traci.simulation.getTime() + 10 veh_type = None rerouting = True while rerouting: traci.simulationStep(step) # get vType for route calculation if not veh_type: fleet = traci.vehicle.getTaxiFleet(-1) veh_type = traci.vehicle.getTypeID(fleet[0]) # get new reservations res_id_new = [] for res in traci.person.getTaxiReservations(1): # search direct travel time direct = int( findRoute(res.fromEdge, res.toEdge, veh_type, res.depart, routingMode=0).travelTime) # add new reservation attributes setattr(res, 'direct', direct) # direct travel time setattr(res, 'vehicle', False) # id of assigned vehicle setattr(res, 'delay', 0) # real pick up time - assigned time # pickup time window setattr(res, 'tw_pickup', [res.depart, res.depart + options.max_wait]) # drop off time window if res.direct * options.drf < options.drf_min: setattr(res, 'tw_dropoff', [ res.tw_pickup[0] + direct, res.tw_pickup[1] + direct + options.drf_min ]) else: setattr(res, 'tw_dropoff', [ res.tw_pickup[0] + direct, res.tw_pickup[1] + direct * options.drf ]) # add reservation id to new reservations res_id_new.append(res.id) # add reservation object to list res_all[res.id] = res # unassigned reservations res_id_unassigned = [ res.id for res_id, res in res_all.items() if not res.vehicle ] # if reservations pending if res_id_unassigned: if options.debug: print('\nRun dispatcher') if res_id_new: print('New reservations: ', res_id_new) print('Unassigned reservations: ', list(set(res_id_unassigned) - set(res_id_new))) # get fleet fleet = traci.vehicle.getTaxiFleet(-1) if set(fleet) != set(fleet) & set( traci.vehicle.getIDList()): # TODO manage teleports # noqa print("\nVehicle %s is being teleported, skip to next step" % (set(fleet) - set(traci.vehicle.getIDList()))) step += options.sim_step continue # if a vehicle is being teleported skip to next step # remove reservations already served res_id_current = [ res.id for res in traci.person.getTaxiReservations(0) ] # noqa res_id_served = list(set(res_all.keys()) - set(res_id_current)) [res_all.pop(key) for key in res_id_served] [ rv_dict.pop(key) for key in list(rv_dict) if set(res_id_served) & set(rv_dict[key][2]) ] # reservations already picked up res_id_picked = [ res.id for res in traci.person.getTaxiReservations(8) ] # noqa # search reservation-vehicles pairs if options.debug: print('Calculate RV-Graph') get_rv(options, res_id_new, res_id_picked, res_id_served, res_all, fleet, veh_type, rv_dict, step) # search trips (rtv graph) if options.debug: print('Calculate RTV-Graph') if options.rtv_algorithm == '0': rtv_dict, rtv_res, exact_sol = rtvAlgorithm.exhaustive_search( options, res_id_unassigned, res_id_picked, res_all, fleet, veh_type, rv_dict, step, exact_sol) elif options.rtv_algorithm == '1': rtv_dict, rtv_res = rtvAlgorithm.simple( options, res_id_unassigned, res_id_picked, res_id_served, res_all, fleet, veh_type, rv_dict, step) elif options.rtv_algorithm == '2': rtv_dict, rtv_res = rtvAlgorithm.simple_rerouting( options, res_id_unassigned, res_id_picked, res_id_served, res_all, fleet, veh_type, rv_dict, step) if len(rtv_dict) == 0: step += options.sim_step continue # if no routes found elif len(rtv_dict.keys()) == 1: # if one vehicle darp, assign route best_routes = list(rtv_dict.keys()) else: # if multiple vehicle darp, solve ILP with pulp veh_constraints = {} res_constraints = {} costs = {} trips = list(rtv_dict.keys()) # trips for parsing ILP solution # add bonus_cost to trip cost (makes trips with more served # reservations cheaper than splitting the reservations to more # vehicles with smaller trips if both strategies would yield # a similar cost) for idx, trip_id in enumerate(trips): # rtv_dict[route] = [travel_time, veh_bin, res_bin, value] # TODO specific cost for vehicle can be consider here bonus_cost = (sum(rtv_dict[trip_id][2]) + 1) * \ options.cost_per_trip # generate dict with costs costs.update({idx: rtv_dict[trip_id][0] + bonus_cost}) # generate dict with vehicle used in the trip veh_constraints.update({idx: rtv_dict[trip_id][1]}) # generate dict with served reservations in the trip res_constraints.update({idx: rtv_dict[trip_id][2]}) if options.debug: print('Solve ILP') ilp_result = ilp_solve(options, len(fleet), len(rtv_res), costs, veh_constraints, res_constraints) # parse ILP result best_routes = [ trips[int(route_index)] for route_index in ilp_result ] # noqa # assign routes to vehicles for route_id in best_routes: stops = route_id.replace('y', '') stops = stops.replace('z', '') stops = stops.split("_") veh_id = stops[0] # first check if new route is better than the current one current_route = [] if len(traci.vehicle.getStops(veh_id)) > 1: for taxi_stop in traci.vehicle.getStops(veh_id): # get reservations served at each stop sub_stops = taxi_stop.actType.split(",") # if more than 1 reservation in stop for sub_stop in sub_stops: current_route.append(sub_stop.split(" ")[2][1:-1]) if current_route == stops[1:]: # route is the same continue elif (set(current_route) == set(stops[1:]) and len(current_route) == len(stops[1:])): # if route serve same reservations and have the same stops # get travel time of current route tt_current_route = 0 edges = [ taxi_stop.lane.split("_")[0] for taxi_stop in traci.vehicle.getStops(veh_id) ] # add current edge to list edges.insert( 0, traci.vehicle.getLaneID(veh_id).split("_")[0]) # noqa # calculate travel time for idx, edge in enumerate(edges[:-1]): # TODO default stop time ticket #6714 tt_current_route += int( findRoute(edge, edges[idx + 1], veh_type, step, routingMode=0).travelTime) + 60 # get travel time of the new route tt_new_route = rtv_dict[route_id][0] if tt_new_route >= tt_current_route: continue # current route better than new found if options.debug: print('Dispatch: ', route_id) traci.vehicle.dispatchTaxi(veh_id, stops[1:]) # assign vehicle to reservations # TODO to avoid major changes in the pick-up time when assigning new passengers, # noqa # tw_pickup should be updated, whit some constant X seconds, e.g. 10 Minutes # noqa for res_id in set(stops[1:]): res = res_all[res_id] res.vehicle = veh_id # TODO ticket #8385 if step > options.end_time or (traci.simulation.getMinExpectedNumber() <= 0 and not traci.person.getIDList()): rerouting = False step += options.sim_step if options.rtv_algorithm == 0: # if exhaustive search if sum(exact_sol) == 0: print('Optimal solution found.') else: print( 'The maximal specified calculation time has been exceeded. Solution could be not optimal.' ) # noqa print('DRT simulation ended') traci.close()