def execute(self): # Current working directory for project Logger.info(f'Current directory: {os.getcwd()}') while True: # acquire and store the readings of all sensors self.acquirer.execute() # generate and publish the output. self.outputter.execute(self.acquirer.sensors) time.sleep(self.sleep_secs)
def _prep_sensors(self): # prep the sensors from the sensors config # get hold of the locations info from the global config if 'locations' in SysWideConfig.loaded_config: locations_config = SysWideConfig.loaded_config('locations') else: Logger.err( f"Failed to find the locations within the site configuration. Aborting." ) sys.exit() Logger.info(f"Creating and adding the sensors") for location, config in locations_config: # exclude inactive sensors state = config['state'] if not state: continue # TODO: add try-excepts are all of these calls as we cannot assume that the config is correct. sensor_id = config['sensor_id'] reg_temp = config['reg_temp'] reg_humidity = config['reg_humidity'] reg_co2 = config['reg_co2'] reg_last_updated = config['reg_last_updated'] # make and record the sensor sensor = Sensor(wbu_conn=self.wbu_conn, location=location, sensor_id=sensor_id, reg_temp=reg_temp, reg_humidity=reg_humidity, reg_co2=reg_co2, reg_last_updated=reg_last_updated) self.sensors.append(sensor)
class RequestList: timestamp = -1 def __init__(self): self.__logger = Logger("RequestList") #self.__logger.setLevel(logging.INFO) self.__logger.info(RequestList.timestamp, "__INIT__", None, None, "Create RequestList Object.") self.__items = [] def __str__(self): ret = "[" for i in range(0, len(self.__items)): ret = ret + str(self.__items[i]) + ", " ret = ret + "]" return ret def first_element(self): if self.is_empty(): self.__logger.error(RequestList.timestamp, "__INIT__", None, None, "No First element exists.") raise Exception("No First element exists.") return self.__items[0] def remove(self): item = self.__items.pop(0) self.__logger.info(RequestList.timestamp, "remove", None, None, str(item)) return item def is_empty(self): return len(self.__items) == 0 def __len__(self): return len(self.__items) def add(self, item): self.__logger.info(RequestList.timestamp, "add", None, None, str(item)) self.__items.append(item)
class Rider: timestamp = -1 def __init__(self, uID, sT, sZ, dZ, dP, pat, srcX, srcY, destX, destY): # logger in Dispatcher self.__logger = Logger('Rider') #self.__logger.setLevel(logging.DEBUG) self.__logger.info(Rider.timestamp, "__INIT__", None, None, "Create A Rider Object") self.__id = uID self.__request_timestamp = sT self.__srcZone = sZ self.__destZone = dZ self.__default_price = dP self.__price = math.inf self.__patience = pat self.__dirID = self.__assignDirID(srcX, srcY, destX, destY) self.__shortest_time = Graph.queryTravelCost(sZ, dZ) self.__arrival_timestamp = None self.__groupID = None self.__status = WAITING self.__wait_time = 0 self.__detour_time = -1 self.__sat = 0 if self.__default_price > 100: self.__logger.warning(Rider.timestamp, "__INIT__", None, self.getID(), str(self)) def __str__(self): ret = "{" + str(self.__id) + ', ' + str(self.__request_timestamp) + ", " + str(self.__srcZone) + ", " + str(self.__destZone) + ", " + \ str(self.__default_price) + ", " + str(self.__price) + ", " + str(self.__patience) + ", " + str(self.__dirID) +", " + \ str(self.__shortest_time) + ", " + str(self.__arrival_timestamp) + ", " + str(self.__groupID) + ", " +\ str(self.__status) + ", " + str(self.__wait_time) + ", " + str(self.__detour_time) + ", " + str(self.__sat) + "}" return ret #https://stackoverflow.com/questions/13226038/calculating-angle-between-two-vectors-in-python #The range is [-180, 180) def __calcDirection(self, srcX, srcY, destX, destY): p1 = [srcX, srcY] p0 = [destX, destY] p2 = p1 + np.array([1, 0]) v0 = np.array(p0) - np.array(p1) v1 = np.array(p2) - np.array(p1) angle = np.math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1)) return np.degrees(angle)*(-1) #Tansfer from [-180,180) to [0,360). #calculate DirID by dividing the DIR_THRESHOLD def __assignDirID(self, srcX, srcY, destX, destY): dir = self.__calcDirection(srcX, srcY, destX, destY) return int((dir+180)/DIR_THRESHOLD) def setDirID(self, dir): self.__dirID = dir def getDirID(self): return self.__dirID def setGroupID(self, grpID): self.__groupID = grpID def getGroupID(self): return self.__groupID def tickWaitTime(self): self.__wait_time += 1 def getWaitTime(self): return self.__wait_time def getShortestTime(self): return self.__shortest_time def calcDetourTime(self, time): self.__detour_time = time - self.__shortest_time def getDetourTime(self): return self.__detour_time def setArrivalTimestamp(self, time): self.__arrival_timestamp = time def getArrivalTimestamp(self): return self.__arrival_timestamp #prerequest: calc detour time first def calcPrice(self, n_shared): if self.__detour_time < 0: self.__logger.error(Rider.timestamp, "calcPrice", None, self.getID(), "Detour time is unreasonable.") raise Exception("Detour time is unreasonable.") self.__price = self.__default_price * math.exp(DETOUR_WEIGH * -self.__detour_time) if n_shared == 1: self.__price = self.__price * DISCOUNT_1 elif n_shared == 2: self.__price = self.__price * DISCOUNT_2 elif n_shared == 3: self.__price = self.__price * DISCOUNT_3 elif n_shared == 4: self.__price = self.__price * DISCOUNT_4 else: self.__logger.error(Rider.timestamp, "calcPrice", None, self.getID(), "Shared number is incorret.") raise Exception("Shared number is incorret.") def getPrice(self): return self.__price def getDefaultPrice(self): return self.__default_price def calcSat(self): if self.__detour_time < 0: self.__logger.error(Rider.timestamp, "calcSat", None, self.getID(), "Detour time is unreasonable.") raise Exception("Detour time is unreasonable.") elif self.__price > self.__default_price: self.__logger.error(Rider.timestamp, "calcSat", None, self.getID(), "Price is unreasonable.") raise Exception("Price is unreasonable.") else: self.__sat = (self.__default_price-self.__price)*SAT_PRICE - math.expm1(self.__detour_time) if self.__sat > 10000000: self.__logger.warning(Rider.timestamp, "calcPrice", None, self.getID(), "SAT is too large", str(self)) def getSat(self): return self.__sat def getID(self): return self.__id def getRequestTimeStamp(self): return self.__request_timestamp def getSrcZone(self): return self.__srcZone def getDestZone(self): return self.__destZone def getPatience(self): return self.__patience def setStatus(self, status): self.__status = status def getStatus(self): return self.__status
class ClusteringStrategy(ABC): timestamp = -1 def __init__(self, rider_waiting_dict): self.logger = Logger('ClusteringStrategy') # self.logger.setLevel(logging.DEBUG) self.logger.info(ClusteringStrategy.timestamp, "__INIT__", None, None, "Initialize ClusteringStrategy") self.__assign_gid_dict = {} self.__rider_dict = rider_waiting_dict # Assign Group ID for zone_id in range(1, 78): self.__assign_gid_dict[zone_id] = {} for dir_id in range(-1, 12): self.__assign_gid_dict[zone_id][dir_id] = 1 def showAssignGidDict(self): ret = "{" for zone_id in self.__assign_gid_dict.keys(): ret = ret + str(zone_id) + ": {" for dir_id in self.__assign_gid_dict[zone_id].keys(): ret = ret + str(dir_id) + ": [" + str( self.__assign_gid_dict[zone_id][dir_id]) + "], " ret = ret + "}, \n" ret = ret + "}" return ret def getGroupID(self, zone_id, dir_id): return self.__assign_gid_dict[zone_id][dir_id] def tickGroupID(self, zone_id, dir_id): self.__assign_gid_dict[zone_id][dir_id] += 1 def groupRiderByDir(self, rider, group_vulumn): # Rider's zone ID and dir ID zone_id = rider.getSrcZone() dir_id = rider.getDirID() group_id = self.getGroupID(zone_id, dir_id) # self.__rider_waiting_dict[rider.getSrcZone()][rider.getDirID()] is defaultdict(dict) # group_num is the dict if rider.getID( ) not in self.__rider_dict[zone_id][dir_id][group_id].keys(): self.__rider_dict[zone_id][dir_id][group_id][rider.getID()] = rider rider.setGroupID(group_id) else: self.logger.error(ClusteringStrategy.timestamp, "groupRiderByDir", None, rider.getID(), "Rider has been in the Pool") # check how many riders in the zone&direction&group_num to determine group id rider_num = len(self.__rider_dict[zone_id][dir_id][group_id]) # When the number of rider in group up to VEHICLE_CAPACITY if rider_num == group_vulumn: self.tickGroupID(zone_id, dir_id) @abstractmethod def cluster(self, rider): pass
class Driver: timestamp = -1 def __init__(self, id, pCurr): # logger in Dispatcher self.__logger = Logger('Driver') #self.__logger.setLevel(logging.DEBUG) self.__logger.info(Driver.timestamp, "__INIT__", None, None, "Create A Driver Object") self.__id = id self.__pos = pCurr self.__status = IDLE self.__riders = {} self.__trip_route = [] self.__trip_effort = 0 self.__trip_profit = 0 self.__idle_time = 0 self.__finish_trip_time = -1 def __str__(self): ret = "{" + str(self.__id) + ", " + str(self.__pos) + ", " + str( self.__status) + ", " + str(self.__trip_effort) + ", " ret = ret + str(self.__trip_profit) + ", " ret = ret + "Riders: " + self.showRidersOnBoard() + ", " ret = ret + "Route: " + self.showTripRoute() + "}" return ret def showRidersOnBoard(self): ret = "[" if len(self.__riders): for rider_id in OrderedDict( sorted(self.__riders.items(), key=lambda t: t[0])).keys(): ret = ret + rider_id + ", " ret = ret[0:len(ret) - 2] + "]" else: ret = ret + "]" return ret def showTripRoute(self): ret = "[" if len(self.__trip_route): for elem in self.__trip_route: ret = ret + str(elem.getZoneID()) + ", " ret = ret[0:len(ret) - 2] + "]" else: ret = ret + "]" return ret def getID(self): return self.__id def setRiders(self, riders): for rider_id, rider in riders.items(): self.__riders[rider_id] = rider def getRider(self, id): if id in self.__riders.keys(): return self.__riders[id] else: self.__logger.error(Driver.timestamp, "getRider", self.getID(), id, "Rider not in vehicle.") raise Exception("Rider not in vehicle.") def removeRider(self, id): if id in self.__riders.keys(): del self.__riders[id] else: self.__logger.error(Driver.timestamp, "removeRider", self.getID(), id, "Rider not in vehicle.") raise Exception("Rider not in vehicle.") def calcTripRoute(self): if len(self.__trip_route) == 0: route_strategy = RoutingInDistance(self.__riders, self.__trip_route) route_strategy.planRoute() else: self.__logger.error(Driver.timestamp, "calcTripRoute", self.getID(), None, "Trip route is empty.") raise Exception("Trip route is empty.") def popTripRoute(self): if len(self.__trip_route) > 0: return self.__trip_route.pop(0) else: self.__logger.error(Driver.timestamp, "popTripRoute", self.getID(), None, "Nothing to be poped.") raise Exception("Nothing to be poped.") def getTripRoute(self): return self.__trip_route #must calc route first def calcTripEffort(self): trip_time = 0 trip_effort = 0 pos = self.getPos() for elem in self.__trip_route: if Graph.queryTravelCost(pos, elem.getZoneID()) != 0: trip_effort = trip_effort + Graph.queryTravelCost( pos, elem.getZoneID()) else: trip_effort += 0.5 trip_time = trip_time + Graph.queryTravelCost( pos, elem.getZoneID()) elem.setEventTime(Driver.timestamp + trip_time) if elem.getEvent() == DROPOFF: rider = self.__riders[elem.getRiderID()] rider.setArrivalTimestamp(Driver.timestamp + trip_time) rider.calcDetourTime( trip_time ) #detour time is b/w the rerquest accepted and arrive at destination. pos = elem.getZoneID() if trip_effort < 0: self.__logger.warning(Driver.timestamp, "calcTripEffort", self.getID(), None, "Trip effort value is unresonable ") raise Exception("Trip effort value is unresonable ") else: self.__trip_effort += trip_effort def tickTripEffort(self): self.__trip_effort += 1 def getTripEffort(self): return self.__trip_effort def notifyRiderPrice(self): shared_number = len(self.__riders) for rider in self.__riders.values(): rider.calcPrice(shared_number) #must calc route effort and rider price first def calcTripProfit(self): trip_revenue = 0 if len(self.__riders) > 0: for rider in self.__riders.values(): if rider.getPrice() is not math.inf: trip_revenue += rider.getPrice() else: self.__logger.error(Driver.timestamp, "calcTripEffort", self.getID(), None, "Price value is unresonable ") raise Exception("Price value is unresonable ") self.__trip_profit += trip_revenue else: self.__logger.error(Driver.timestamp, "calcTripEffort", self.getID(), None, "No riders in vehicle.") raise Exception("No riders in vehicle.") def getTripProfit(self): return self.__trip_profit def setPos(self, zid): self.__pos = zid def getPos(self): return self.__pos def setStatus(self, status): self.__status = status def getStatus(self): return self.__status def tickIdleTime(self): self.__idle_time += 1 def getIdleTime(self): return self.__idle_time def setFinishTripTime(self, time): self.__finish_trip_time = time def getFinishTripTime(self): return self.__finish_trip_time
class Dispatcher: # Sync timestamp for logging timestamp = -1 def __init__(self): #logger in Dispatcher self.__logger = Logger('Dispatcher') self.__logger.setLevel(logging.DEBUG) self.__logger.info(Dispatcher.timestamp, "__INIT__", None, None, "Create A Dispatcher Object") #Storage for drivers and riders self.__driver_dict = {} self.__rider_wait_dict = {} self.__rider_serve_dict = {} self.__rider_finish_dict = {} self.__rider_cancel_dict = {} #Performance of driver and rider self.wait_rider={} self.no_work_driver={} self.idle_driver_before_match={} self.grp_in_4=0 self.grp_in_3=0 self.grp_in_2=0 self.grp_in_1=0 #Cluser Strategy self.__cluster_strategy = ClusteringByDir(self.__rider_wait_dict) #Matching Strategy self.__match_strategy = MatchingInQueue(self.__driver_dict, self.__rider_wait_dict, self.__rider_serve_dict) #Driver Status Tracker self.__driver_tracker = DriverStatusTracker(self.__driver_dict) #Rider Status tracker self.__rider_tracker = RiderStatusTracker(self.__rider_wait_dict, self.__rider_serve_dict, self.__rider_finish_dict, self.__rider_cancel_dict) #Driver Dict for zone_id in range(1,78): self.__driver_dict[zone_id] = {} #Rider Dict for zone_id in range(1,78): self.__rider_wait_dict[zone_id] = {} for dir_id in range(-1, 12): self.__rider_wait_dict[zone_id][dir_id] = defaultdict(dict) # for cycle in range(SIMULATION_CYCLE_START, SIMULATION_CYCLE_END): self.wait_rider[cycle] = [] self.no_work_driver[cycle] = [] for zone_id in range(0,78): self.wait_rider[cycle].append(0) self.no_work_driver[cycle].append(0) def showDriverDict(self, zone_id): ret = str(zone_id) + ": {" for driver_id in OrderedDict(sorted(self.__driver_dict[zone_id].items(), key=lambda t: t[0])).keys(): ret = ret + driver_id + ", " ret = ret + "}" return ret def getDriverFromDriverDict(self, zone_id, driver_id): for id, driver in self.__driver_dict[zone_id].items(): if id == driver_id: return driver return None def getDriverNumberOfZone(self, zone_id): return len(self.__driver_dict[zone_id]) def showRiderWaitDict(self, zone_id): ret = str(zone_id) + ": {" for dir_id in self.__rider_wait_dict[zone_id].keys(): ret = ret + str(dir_id) + ": {" for group_id in self.__rider_wait_dict[zone_id][dir_id].keys(): ret = ret + str(group_id) + ": [" for rider_id in OrderedDict(sorted(self.__rider_wait_dict[zone_id][dir_id][group_id].items(), key=lambda t: t[0])).keys(): ret = ret + str(rider_id) + ", " ret = ret + "], " ret = ret + "}, " ret = ret + "}" return ret def getRiderFromWaitDict(self, zone_id, dir_id, group_id, rider_id): for id, rider in self.__rider_wait_dict[zone_id][dir_id][group_id].items(): if id == rider_id: return rider return None def getGroupFromWaitDict(self, zone_id, dir_id, group_id): for id, group in self.__rider_wait_dict[zone_id][dir_id].items(): if id == group_id: return group return None def getRequestNumberOfZone(self, zone_id): total_num = 0 for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].keys(): total_num += len(self.__rider_wait_dict[zone_id][dir_id][group_id]) return total_num def showRiderServedDict(self): ret = "{" for rider_id in OrderedDict(sorted(self.__rider_serve_dict.items(), key=lambda t: t[0])).keys(): ret=ret+str(rider_id)+", " ret=ret+"}" return ret def getRiderFromServedDict(self, rider_id): for id, rider in self.__rider_serve_dict.items(): if id == rider_id: return rider return None def showRiderFinishedDict(self): ret = "{" for rider_id in OrderedDict(sorted(self.__rider_finish_dict.items(), key=lambda t: t[0])).keys(): ret = ret + str(rider_id) + ", " ret = ret + "}" return ret def getRiderFromFinishedDict(self, rider_id): for id, rider in self.__rider_finish_dict.items(): if id == rider_id: return rider return None def showRiderCanceledDict(self): ret = "{" for rider_id in OrderedDict(sorted(self.__rider_cancel_dict.items(), key=lambda t: t[0])).keys(): ret = ret + str(rider_id) + ", " ret = ret + "}" return ret def getRiderFromCanceledDict(self, rider_id): for id, rider in self.__rider_cancel_dict.items(): if id == rider_id: return rider return None #put driver into Driver Dict at start def handleDriverIntoDict(self, driver): if isinstance(driver, Driver): if driver.getID() not in self.__driver_dict[driver.getPos()].keys(): self.__driver_dict[driver.getPos()][driver.getID()] = driver else: self.__logger.error(Dispatcher.timestamp, "handleDriverRequest", driver.getID(), None, "Driver has been in the Pool.") raise Exception("Driver has been in the Pool.") else: self.__logger.error(Dispatcher.timestamp, "handleDriverRequest", None, None, "Driver's type is wrong.") raise Exception("Driver's type is wrong.") def handleRiderIntoDict(self, rider): if isinstance(rider, Rider): self.__cluster_strategy.cluster(rider) else: self.__logger.error(Dispatcher.timestamp, "handleRiderRequest", None, None, "Rider's type is wrong.") raise Exception("Rider's type is wrong.") def matchRidertoDriver(self): for zone_id in self.__rider_wait_dict.keys(): for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].copy().keys(): driver = self.__match_strategy.match(zone_id) if driver is not None: self.__logger.info(Dispatcher.timestamp, "matchRidertoDriver", driver.getID(), None, "Driver be Chosen to Serve Riders.") self.__logger.debug(Dispatcher.timestamp, "matchRidertoDriver", None, None, "Driver Zone ===> Rider Zone: ", str(driver.getPos()) + "===>" + str(zone_id)) # update driver status driver.setRiders(self.__rider_wait_dict[zone_id][dir_id][group_id]) self.__driver_tracker.updateDriverStatusAfterMatching(driver) self.__logger.debug(Dispatcher.timestamp, "matchRidertoDriver", driver.getID(), None, str(driver)) #update rider status if len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 4: self.grp_in_4 += 1 elif len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 3: self.grp_in_3 += 1 elif len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 2: self.grp_in_2 += 1 elif len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 1: self.grp_in_1 += 1 else: self.__logger.warning(Dispatcher.timestamp, "calcPoolingPerformanceInWaitDict", None, None, "Grp len is 0.") for rider in self.__rider_wait_dict[zone_id][dir_id][group_id].values(): self.__rider_tracker.updateRiderStatusAfterMatching(rider) self.__logger.debug(Dispatcher.timestamp, "matchRidertoDriver", driver.getID(), rider.getID(), str(rider)) del self.__rider_wait_dict[zone_id][dir_id][group_id] else: self.__logger.info(Dispatcher.timestamp, "matchRidertoDriver", None, None, "No Driver is available.") break def updateDriverInDict(self): for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].copy().values(): if driver.getStatus() == IDLE: self.__logger.info(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, "Update Driver when IDLE.") self.__driver_tracker.updateDriverStatusWhenIdle(driver, self.no_work_driver) elif driver.getStatus() == INSERVICE: self.__logger.info(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, "Update Driver Who is INSERVICE.") self.__driver_tracker.updateDriverStatusWhenInService(driver, self.__rider_tracker) self.__logger.debug(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, str(driver)) else: self.__logger.error(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, "Driver Status is Wrong.") raise Exception("Driver Status is Wrong.") def updateRidersInWaitDict(self): for zone_id in self.__rider_wait_dict.keys(): for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].copy().keys(): for rider in self.__rider_wait_dict[zone_id][dir_id][group_id].copy().values(): if rider.getStatus() == WAITING: self.__rider_tracker.updateRiderStatusWhenWait(rider, self.wait_rider) self.__rider_tracker.checkRiderStatusIfTimeOut(rider) def countTotalDriverNumber(self): total_len = 0 for zone_id in self.__driver_dict.keys(): total_len = total_len + len(self.__driver_dict[zone_id]) return total_len def countDriverNumberEachZone(self): self.idle_driver_before_match[Dispatcher.timestamp] = [0] for zone_id in self.__driver_dict.keys(): cnt=0 for driver in self.__driver_dict[zone_id].values(): if driver.getStatus() == IDLE: cnt+=1 self.idle_driver_before_match[Dispatcher.timestamp].append(cnt) def countRiderNumberInWaitDict(self): total_len = 0 for zone_id in self.__rider_wait_dict.keys(): for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].keys(): total_len = total_len + len(self.__rider_wait_dict[zone_id][dir_id][group_id]) return total_len def countRiderNumberInServeDict(self): return len(self.__rider_serve_dict) def countRiderNumberInFinishDict(self): return len(self.__rider_finish_dict) def countRiderNumberInCancelDict(self): return len(self.__rider_cancel_dict) def countCurrentTotalRiderNumber(self): return self.countRiderNumberInWaitDict() + self.countRiderNumberInServeDict() + self.countRiderNumberInFinishDict() + self.countRiderNumberInCancelDict() def calcAverageProfitOfDrivers(self): totalProfit = 0 for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].values(): totalProfit += driver.getTripProfit() return totalProfit / self.countTotalDriverNumber() def calcAverageIdleTimeOfDrivers(self): totalIdleTime = 0 for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].values(): totalIdleTime += driver.getIdleTime() return totalIdleTime / self.countTotalDriverNumber() def calcAverageTripEffortOfDrivers(self): totalTripEffort = 0 for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].values(): totalTripEffort += driver.getTripEffort() return totalTripEffort / self.countTotalDriverNumber() def calcAverageWaitTimeOfRiders(self): totalWaitTime = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict, **self.__rider_cancel_dict} for rider in riders.values(): totalWaitTime +=rider.getWaitTime() return totalWaitTime/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()+self.countRiderNumberInCancelDict()) def calcAverageDetourTimeOfRiders(self): totalDetourTime = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict} for rider in riders.values(): totalDetourTime += rider.getDetourTime() return totalDetourTime/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()) def calcAverageFareOfRiders(self): totalFare = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict} for rider in riders.values(): totalFare += rider.getPrice() return totalFare/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()) def calcAverageDefaultFareRiders(self): totalDefaultFare = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict} for rider in riders.values(): totalDefaultFare += rider.getDefaultPrice() return totalDefaultFare/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()) def calcAverageSatOfRiders(self): totalSat = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict, **self.__rider_cancel_dict} for rider in riders.values(): totalSat += rider.getSat() return totalSat/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()+self.countRiderNumberInCancelDict())
class Simulation: def __init__(self): self.__logger = Logger('Simulation') #self.__logger.setLevel(logging.DEBUG) self.__logger.info(-1, "__INIT__", None, None, "Create Simulation Object.") self.__driver_list = RequestList() self.__rider_list = RequestList() self.__dispatcher = Dispatcher() self.__cycle = 0 self.__sim_time = [] def importData(self, ): ImportData.importDriverData(FILENAME_D, self.__driver_list) ImportData.importRiderData(FILENAME_R, self.__rider_list) def run(self): #Run simulation cycle for self.__cycle in range(SIMULATION_CYCLE_START, SIMULATION_CYCLE_END): # Synchronization the time with Modules(Driver, Dispatcher, Rider, and so on) self.__logger.info(self.__cycle, "RUN", None, None, "1. Synchronizing Time With Each Module.") #Dispatcher Module Dispatcher.timestamp = self.__cycle ClusteringStrategy.timestamp = self.__cycle MatchingStrategy.timestamp = self.__cycle DriverStatusTracker.timestamp = self.__cycle RiderStatusTracker.timestamp = self.__cycle #Driver Module Driver.timestamp = self.__cycle RoutingStrategy.timestamp = self.__cycle #Rider Module Rider.timestamp = self.__cycle #Import Module RequestList.timestamp = self.__cycle ImportDemandEvaluation.timestamp = self.__cycle # Start simulation time of this cycle print("The Cycle Number: ", self.__cycle) #print("Time: ", ImportDemandEvaluation.time) # Put the driver requests to dispatcher (The Driver List) self.__logger.info( self.__cycle, "RUN", None, None, "2. Put Drivers' Requests To Dispatcher From RequestList.") while not self.__driver_list.is_empty(): curr_driver = self.__driver_list.remove() self.__logger.debug( self.__cycle, "RUN", None, None, "Current Driver Moved into Dict of Dispatcher: ", str(curr_driver)) self.__dispatcher.handleDriverIntoDict(curr_driver) self.__dispatcher.countDriverNumberEachZone( ) #count idle driver number before match # Put the rider requests to dispatcher (The Rider List) self.__logger.info( self.__cycle, "RUN", None, None, "3. Put Rider' Requests To Dispatcher From RequestList.") while not self.__rider_list.is_empty( ) and self.__rider_list.first_element().getRequestTimeStamp( ) == self.__cycle: curr_rider = self.__rider_list.remove() self.__logger.debug( self.__cycle, "RUN", None, None, "Current Rider Moved into Dict of Dispatcher: ", str(curr_rider)) self.__dispatcher.handleRiderIntoDict(curr_rider) #Show dispatch dicts print("waiting, serving, finished, canceled: ", self.__dispatcher.countRiderNumberInWaitDict(), self.__dispatcher.countRiderNumberInServeDict(), self.__dispatcher.countRiderNumberInFinishDict(), self.__dispatcher.countRiderNumberInCancelDict()) #match driver and rider by dispatcher self.__logger.info( self.__cycle, "RUN", None, None, "4. Match Riders' Request to AN Appropriate Driver.") self.__dispatcher.matchRidertoDriver() # Update simulator's states self.__logger.info(self.__cycle, "RUN", None, None, "5. Update State of Simulator.") self.__dispatcher.updateDriverInDict() self.__dispatcher.updateRidersInWaitDict() #Show up results self.__logger.info(self.__cycle, "RUN", None, None, "6. Show Up All Results of this Cycle.") #print(self.__dispatcher.cancel_rider) #print(self.__dispatcher.no_work_driver) #if self.__cycle % SHOWN_INTERVAL == 0 and self.__cycle != SIMULATION_CYCLE_START: # self.showPerformanceMetrics() #print("\n") self.showPerformanceMetrics() print("Simulation Terminated.\n") #self.drawMonitorDict(self.__dispatcher.wait_rider, self.__dispatcher.no_work_driver) def drawMonitorDict(self, monitor_dict1, monitor_dict2): for time1, item1 in monitor_dict1.items(): for time2, item2 in monitor_dict2.items(): if time1 == time2: #plt.figure(figsize=(30, 20)) fig, (ax1, ax2) = plt.subplots(2, figsize=(30, 20)) fig.suptitle(str(time1)) ax1.plot(item1[0:78], label='Wait Rider# after match', color='r') ax1.plot(item2[0:78], label='Idle Driver# after match', color='b') ax1.set_xticks(np.arange(0, 78, step=1)) ax1.set_yticks(np.arange(0, 300, step=20)) ax1.set_ylabel("driver#") ax1.legend() ax2.plot(self.__dispatcher.idle_driver_before_match[time1], label='Idle Driver# before match', color='b') ax2.set_xticks(np.arange(0, 78, step=1)) ax2.set_yticks(np.arange(0, 300, step=20)) ax2.set_xlabel("zones") ax2.set_ylabel("driver#") ax2.legend() plt.savefig(SAVE_PATH.format(time1)) plt.close() def showPerformanceMetrics(self): print("\n") print("The Number of Riders occured so far: ", self.__dispatcher.countCurrentTotalRiderNumber()) print("The Number of Drivers: ", self.__dispatcher.countTotalDriverNumber()) print("The Number of Cycles: ", self.__cycle) print( "***************************************************************") print("Driver Performace Metrics:") print("Average Revenue: ", round(self.__dispatcher.calcAverageProfitOfDrivers(), 2)) print("Average Trip Effort: ", round(self.__dispatcher.calcAverageTripEffortOfDrivers(), 2)) print( "Average Profit: ", round( self.__dispatcher.calcAverageProfitOfDrivers() - COST_PER_CYCLE * self.__dispatcher.calcAverageTripEffortOfDrivers(), 2)) print( "Average Utilization: ", round( (260 - self.__dispatcher.calcAverageIdleTimeOfDrivers()) / 260, 2)) print( "***************************************************************") print("Rider Performace Metrics:") print("Average Waiting Time (Cycles): ", round(self.__dispatcher.calcAverageWaitTimeOfRiders(), 2)) print("Average Detour Time (Cycles): ", round(self.__dispatcher.calcAverageDetourTimeOfRiders(), 2)) print("Average Fare: ", round(self.__dispatcher.calcAverageFareOfRiders(), 2)) print("Average Default Fare: ", round(self.__dispatcher.calcAverageDefaultFareRiders(), 2)) print( "***************************************************************") print("System Performace Metrics:") print( "Serving Rate: ", round( 1 - self.__dispatcher.countRiderNumberInCancelDict() / self.__dispatcher.countCurrentTotalRiderNumber(), 2)) total = self.__dispatcher.countRiderNumberInServeDict( ) + self.__dispatcher.countRiderNumberInFinishDict() print("Pooling Rate in 4: ", round(self.__dispatcher.grp_in_4 * 4 / total, 3)) print("Pooling Rate in 3: ", round(self.__dispatcher.grp_in_3 * 3 / total, 3)) print("Pooling Rate in 2: ", round(self.__dispatcher.grp_in_2 * 2 / total, 3)) print("Pooling Rate in 1: ", round(self.__dispatcher.grp_in_1 / total, 3)) print( "***************************************************************")