diff --git a/sumo_project/EmissionGetter.py b/sumo_project/EmissionGetter.py deleted file mode 100644 index b79bbf0..0000000 --- a/sumo_project/EmissionGetter.py +++ /dev/null @@ -1,94 +0,0 @@ -''' -Created on 11 oct. 2018 - -@author: Axel HUYNH-PHUC -''' - -import os, sys - -'''Launch traci''' -if 'SUMO_HOME' in os.environ: - tools = os.path.join(os.environ['SUMO_HOME'], 'tools') - sys.path.append(os.path.join(os.environ['SUMO_HOME'], tools)) - sumoBinary = os.path.join(os.environ['SUMO_HOME'], 'bin', 'sumo-gui') - sumoCmd = [sumoBinary, "-c", "mulhouse_simulation/osm.sumocfg"] -else: - sys.exit("please declare environment variable 'SUMO_HOME'") - -import traci -from traci import polygon - - -'''creating multiple zones of equal sizes''' -def init_grid(): - default_color = (0, 255, 0) - for i in range(cells_step): - for j in range(cells_step): - area = ((i * width, j * height), (i * width, (j + 1) * height), - ((i + 1) * width, (j + 1) * height), ((i + 1) * width, j * height)) - areas[i][j] = area - polygon.add("area " + str(i) + "," + str(j), area, default_color, False, "rectangle") - - -'''Emissions recovery by area''' -def getEmissionsByArea(i, j): - vehicles = [] - '''Vehicle IDs retrieving into this area''' - for veh_id in traci.vehicle.getIDList(): - pos = traci.vehicle.getPosition(veh_id) - if((i * width < pos[0] and (i + 1) * width > pos[0]) - and (j * height < pos[1] and (j + 1) * height > pos[1])): - vehicles.append(veh_id) - - '''Sum all emissions''' - emissions = 0.0 - for veh_id in vehicles: - emission = traci.vehicle.getCO2Emission(veh_id) - emissions += emission - - '''Change area color if emisssions exceeds the threshold''' - emissionsArea[i][j] += emissions - if(emissionsArea[i][j] >= CO2_threshold): - red = (255, 0, 0) - polygon.setColor("area " + str(i) + "," + str(j), red) - polygon.setFilled("area " + str(i) + "," + str(j), True) - -'''Recover emissions from all areas''' -def getAllEmissions(): - for i in range(cells_step): - for j in range(cells_step): - getEmissionsByArea(i, j) - -'''Display emissions information''' -def showEmissions(): - for i in range(cells_step): - for j in range(cells_step): - print("Total CO2 emissions into Area " + str(i) + "," + str(j) - + " = " , str(emissionsArea[i][j]) + " mg" ) - - -if __name__ == "__main__": - '''Simulation launch''' - traci.start(sumoCmd) - - '''Variables and constants declaration''' - cells_step = 10 - boundary = traci.simulation.getNetBoundary() - areas = [[0] * cells_step for _ in range(cells_step)] - emissionsArea = [[0] * cells_step for _ in range(cells_step)] - width = boundary[1][0] / cells_step # width/step - height = boundary[1][1] / cells_step # height/step - CO2_threshold = 500000 - - step = 0 - init_grid() - while traci.simulation.getMinExpectedNumber() > 0: - print("Vehicle count :", traci.vehicle.getIDCount()) - traci.simulationStep() - getAllEmissions() - step += 1 - - '''Display emissions information and close simulation''' - showEmissions() - traci.close() - sys.stdout.flush() diff --git a/sumo_project/actions.py b/sumo_project/actions.py new file mode 100644 index 0000000..7b0e776 --- /dev/null +++ b/sumo_project/actions.py @@ -0,0 +1,41 @@ +""" +Created on 17 oct. 2018 + +@author: Axel Huynh-Phuc, Thibaud Gasser +""" +from typing import Iterable + +import traci +from shapely.geometry.linestring import LineString + +from model import Area, Vehicle + + +def remove_vehicle(veh_id): + traci.vehicle.remove(veh_id, traci.constants.REMOVE_PARKING) + +def lanes_in_area(area): + for lane_id in traci.lane.getIDList(): + polygon_lane = LineString(traci.lane.getShape(lane_id)) + if area.rectangle.intersects(polygon_lane): + yield lane_id + +def computeEdgeWeight(edge_id): + return (traci.edge.getCOEmission(edge_id) + + traci.edge.getNOxEmission(edge_id) + + traci.edge.getHCEmission(edge_id) + + traci.edge.getPMxEmission(edge_id) + + traci.edge.getCO2Emission(edge_id)) + +def adjustEdgesWeight(): + for edge_id in traci.edge.getIDList(): + weight = computeEdgeWeight(edge_id) #by default edges weight = length/mean speed + traci.edge.adaptTraveltime(edge_id, weight) + +def lock_area(area: Area, vehicles: Iterable[Vehicle]): + max_speed = 30 + print(f'Setting max speed into {area.name} to {max_speed} km/h') + area.locked = True + for lane in area._lanes: + traci.lane.setMaxSpeed(lane.lane_id, max_speed/3.6) + diff --git a/sumo_project/config.py b/sumo_project/config.py new file mode 100644 index 0000000..a27bd0f --- /dev/null +++ b/sumo_project/config.py @@ -0,0 +1,26 @@ +""" +Global configuration for the simulation +""" + +import os +import sys + +if 'SUMO_HOME' in os.environ: + tools = os.path.join(os.environ['SUMO_HOME'], 'tools') + sys.path.append(tools) +else: + sys.exit("please declare environment variable 'SUMO_HOME'") + +_SUMOCMD = 'sumo' # use 'sumo-gui' cmd for UI +_SUMOCFG = "mulhouse_simulation/osm.sumocfg" +CELLS_NUMBER = 10 +EMISSIONS_THRESHOLD = 500000 +n_steps = 200 + +lock_mode = True +routing_mode = False + +sumo_binary = os.path.join(os.environ['SUMO_HOME'], 'bin', _SUMOCMD) +sumo_cmd = [sumo_binary, "-c", _SUMOCFG] + + diff --git a/sumo_project/emissions.py b/sumo_project/emissions.py new file mode 100644 index 0000000..6a1d077 --- /dev/null +++ b/sumo_project/emissions.py @@ -0,0 +1,111 @@ +from typing import List + +import traci +from shapely.geometry import LineString + +import actions +import config +import sys +from model import Area, Vehicle, Lane + +areas = list() + +def init_grid(simulation_bounds, cells_number): + width = simulation_bounds[1][0] / cells_number + height = simulation_bounds[1][1] / cells_number + for i in range(cells_number): + for j in range(cells_number): + # bounds coordinates for the area : (xmin, ymin, xmax, ymax) + ar_bounds = ((i * width, j * height), (i * width, (j + 1) * height), + ((i + 1) * width, (j + 1) * height), ((i + 1) * width, j * height)) + area = Area(ar_bounds) + area.name = 'area ({},{})'.format(i, j) + areas.append(area) + traci.polygon.add(area.name, ar_bounds, (0, 255, 0)) + return areas + +def compute_vehicle_emissions(veh_id): + return (traci.vehicle.getCOEmission(veh_id) + + traci.vehicle.getNOxEmission(veh_id) + + traci.vehicle.getHCEmission(veh_id) + + traci.vehicle.getPMxEmission(veh_id) + + traci.vehicle.getCO2Emission(veh_id)) + +def get_all_vehicles() -> List[Vehicle]: + vehicles = list() + for veh_id in traci.vehicle.getIDList(): + veh_pos = traci.vehicle.getPosition(veh_id) + vehicle = Vehicle(veh_id, veh_pos) + vehicle.emissions = compute_vehicle_emissions(veh_id) + traci.vehicle.setRoutingMode(veh_id, traci.constants.ROUTING_MODE_AGGREGATED) + vehicles.append(vehicle) + return vehicles + + +def get_all_lanes() -> List[Lane]: + lanes = [] + for lane_id in traci.lane.getIDList(): + polygon_lane = LineString(traci.lane.getShape(lane_id)) + lanes.append(Lane(lane_id, polygon_lane)) + return lanes + + +def get_emissions(grid: List[Area], vehicles: List[Vehicle]): + for area in grid: + for vehicle in vehicles: + if vehicle.pos in area: + area.emissions += vehicle.emissions + if config.lock_mode == True and area.emissions > config.EMISSIONS_THRESHOLD and area.locked == False: + actions.lock_area(area, vehicles) + traci.polygon.setColor(area.name, (255, 0, 0)) + traci.polygon.setFilled(area.name, True) + + +def add_lanes_to_areas(areas: List[Area]): + lanes = get_all_lanes() + for area in areas: + for lane in lanes: + if area.rectangle.intersects(lane.polygon): + area.add_lane(lane) + + +def main(): + try: + traci.start(config.sumo_cmd) + grid = init_grid(traci.simulation.getNetBoundary(), config.CELLS_NUMBER) + add_lanes_to_areas(grid) + + + + step = 0 + while step < config.n_steps : #traci.simulation.getMinExpectedNumber() > 0: + traci.simulationStep() + + vehicles = get_all_vehicles() + get_emissions(grid, vehicles) + + if config.routing_mode == True: + actions.adjustEdgesWeight() + actions.rerouteAllVehicles() + + step += 1 + sys.stdout.write(f'Simulation step = {step}/{config.n_steps}'+'\r') + sys.stdout.flush() + + finally: + traci.close(False) + + total_emissions = 0 + for area in areas: + total_emissions += area.emissions + + #Total of emissions of all pollutants in mg for 200 steps of simulation without locking areas + total_emissions200 = 43970763.15084749 + + print(f'\n**** Total emissions = {total_emissions} mg ****') + diff_with_lock = (total_emissions200 - total_emissions)/total_emissions200 + print(f'**** Reduction percentage of emissions = {diff_with_lock*100} % ****\n') + + +if __name__ == '__main__': + main() diff --git a/sumo_project/model.py b/sumo_project/model.py new file mode 100644 index 0000000..9853bed --- /dev/null +++ b/sumo_project/model.py @@ -0,0 +1,65 @@ +from typing import Tuple, Set + +from shapely.geometry import Point, LineString +from shapely.geometry import Polygon +from shapely.geometry.base import BaseGeometry + + +class Lane: + + def __init__(self, lane_id: str, polygon: LineString): + self.polygon = polygon + self.lane_id = lane_id + + def __hash__(self): + """Overrides the default implementation""" + return hash(self.lane_id) + + +class Area: + + def __init__(self, coords, name=''): + self.locked = False + self.rectangle = Polygon(coords) + self.name = name + self.emissions = 0.0 + self._lanes: Set[Lane] = set() + + def __eq__(self, other): + return self.rectangle.__eq__(other) + + def __contains__(self, item): + return self.rectangle.contains(item) + + @property + def bounds(self): + return self.rectangle.bounds + + def intersects(self, other: BaseGeometry) -> bool: + return self.rectangle.intersects(other) + + def add_lane(self, lane: Lane): + self._lanes.add(lane) + + def remove_lane(self, lane: Lane): + self._lanes.remove(lane) + + @classmethod + def from_bounds(cls, xmin, ymin, xmax, ymax): + return cls(( + (xmin, ymin), + (xmin, ymax), + (xmax, ymax), + (xmax, ymin))) + + +class Vehicle: + + def __init__(self, veh_id: int, pos: Tuple[float, float]): + self.emissions: float = None + self.veh_id = veh_id + self.pos = Point(pos) + + def __repr__(self) -> str: + return str(self.__dict__) +