1
0
mirror of https://github.com/Ahp06/SUMO_Emissions.git synced 2024-11-22 03:26:30 +00:00

Added docstrings to all methods of the application

This commit is contained in:
Ahp06 2019-01-17 18:02:24 +01:00
parent 0ba52d2c9a
commit 5b812d2dc1
5 changed files with 900 additions and 594 deletions

View File

@ -3,26 +3,37 @@ Created on 17 oct. 2018
@author: Axel Huynh-Phuc, Thibaud Gasser @author: Axel Huynh-Phuc, Thibaud Gasser
""" """
import traci
from traci._trafficlight import Logic
from typing import Iterable from typing import Iterable
from shapely.geometry.linestring import LineString import traci
from model import Area, Vehicle from model import Area, Vehicle
"""
This module defines all possible actions on the simulation
"""
def compute_edge_weight(edge_id): def compute_edge_weight(edge_id):
"""
Sum the different pollutant emissions on the edge with the identifier edge_id
:param edge_id: The edge ID
:return: The sum (in mg) of all pollutant emissions
"""
co2 = traci.edge.getCO2Emission(edge_id) co2 = traci.edge.getCO2Emission(edge_id)
co = traci.edge.getCOEmission(edge_id) co = traci.edge.getCOEmission(edge_id)
nox = traci.edge.getNOxEmission(edge_id) nox = traci.edge.getNOxEmission(edge_id)
hc = traci.edge.getHCEmission(edge_id) hc = traci.edge.getHCEmission(edge_id)
pmx = traci.edge.getPMxEmission(edge_id) pmx = traci.edge.getPMxEmission(edge_id)
return (co2 + co + nox + hc + pmx) return co2 + co + nox + hc + pmx
def adjust_edges_weights(area): def adjust_edges_weights(area):
"""
Changes the edge weight of all edges into the area
:param area: The Area object
:return:
"""
area.weight_adjusted = True area.weight_adjusted = True
for lane in area._lanes: for lane in area._lanes:
edge_id = traci.lane.getEdgeID(lane.lane_id) edge_id = traci.lane.getEdgeID(lane.lane_id)
@ -32,37 +43,79 @@ def adjust_edges_weights(area):
for veh_id in traci.vehicle.getIDList(): for veh_id in traci.vehicle.getIDList():
traci.vehicle.rerouteEffort(veh_id) traci.vehicle.rerouteEffort(veh_id)
def limit_speed_into_area(area: Area, vehicles: Iterable[Vehicle], speed_rf):
def limit_speed_into_area(area: Area, speed_rf):
"""
Limit the speed into the area by speed_rf factor
:param area: The Area object
:param speed_rf: The speed reduction factor (must be positive)
:return:
"""
area.limited_speed = True area.limited_speed = True
for lane in area._lanes: for lane in area._lanes:
traci.lane.setMaxSpeed(lane.lane_id, speed_rf * lane.initial_max_speed) traci.lane.setMaxSpeed(lane.lane_id, speed_rf * lane.initial_max_speed)
def modifyLogic(logic, rf): #rf for "reduction factor"
def modifyLogic(logic, rf):
"""
Change the logic of a traffic light by decreasing the overall duration of the traffic light
:param logic: The Logic object
:param rf: The reduction factor (must be positive)
:return: A new Logic object with all phases modified
"""
new_phases = [] new_phases = []
for phase in logic._phases: for phase in logic._phases:
new_phase = traci.trafficlight.Phase(phase.duration*rf,phase.minDuration*rf,phase.maxDuration*rf,phase.phaseDef) new_phase = traci.trafficlight.Phase(phase.duration * rf, phase.minDuration * rf, phase.maxDuration * rf,
phase.phaseDef)
new_phases.append(new_phase) new_phases.append(new_phase)
return traci.trafficlight.Logic("new-program", 0, 0, 0, new_phases) return traci.trafficlight.Logic("new-program", 0, 0, 0, new_phases)
def adjust_traffic_light_phase_duration(area, reduction_factor): def adjust_traffic_light_phase_duration(area, reduction_factor):
"""
Set all logics modification on traffic lights into the area
:param area: The Area object
:param reduction_factor: The reduction factor (must be positive)
:return:
"""
area.tls_adjusted = True area.tls_adjusted = True
for tl in area._tls: for tl in area._tls:
for logic in tl._logics: for logic in tl._logics:
traci.trafficlights.setCompleteRedYellowGreenDefinition(tl.tl_id, modifyLogic(logic, reduction_factor)) traci.trafficlights.setCompleteRedYellowGreenDefinition(tl.tl_id, modifyLogic(logic, reduction_factor))
def count_vehicles_in_area(area): def count_vehicles_in_area(area):
"""
Count the vehicles number into the area
:param area: The Area object
:return: The number of vehicles into the area
"""
vehicles_in_area = 0 vehicles_in_area = 0
for lane in area._lanes: for lane in area._lanes:
vehicles_in_area += traci.lane.getLastStepVehicleNumber(lane.lane_id) vehicles_in_area += traci.lane.getLastStepVehicleNumber(lane.lane_id)
return vehicles_in_area return vehicles_in_area
def lock_area(area): def lock_area(area):
"""
Prohibits access to the area to a particular vehicle class
NOT FIXED : Some vehicles continue to go into the area if they can not turn around and stay there
:param area: The Area object
:return:
"""
area.locked = True area.locked = True
for lane in area._lanes: for lane in area._lanes:
# The passenger class is an example, you have to adapt this code
traci.lane.setDisallowed(lane.lane_id, 'passenger') traci.lane.setDisallowed(lane.lane_id, 'passenger')
def reverse_actions(area): def reverse_actions(area):
"""
Reverse all actions made in an area
:param area: The Area object
:return:
"""
# Reset max speed to original # Reset max speed to original
if area.limited_speed: if area.limited_speed:
area.limited_speed = False area.limited_speed = False
@ -81,5 +134,3 @@ def reverse_actions(area):
area.locked = False area.locked = False
for lane in area._lanes: for lane in area._lanes:
traci.lane.setAllowed(lane.lane_id, '') # empty means all classes are allowed traci.lane.setAllowed(lane.lane_id, '') # empty means all classes are allowed

View File

@ -1,5 +1,7 @@
""" """
Global configuration for the simulation Created on 17 oct. 2018
@author: Axel Huynh-Phuc, Thibaud Gasser
""" """
import datetime import datetime
@ -10,17 +12,32 @@ import sys
from model import Emission from model import Emission
"""
This module defines the global configuration for the simulation
"""
class Config: class Config:
"""
The Config class defines all simulation properties that can be changed
"""
# Total of emissions of all pollutants in mg for n steps of simulation without acting on areas # Total of emissions of all pollutants in mg for n steps of simulation without acting on areas
# These constants are simulation dependant, you must change them according to your simulation # These constants are simulation dependant, you must change them according to your simulation
ref200 = Emission(co2=42816869.05436445, co=1128465.0343051048, nox=18389.648337283958, hc=6154.330914019103, ref200 = Emission(co2=42816869.05436445, co=1128465.0343051048, nox=18389.648337283958, hc=6154.330914019103,
pmx=885.0829265236318) pmx=885.0829265236318)
def __init__(self): def __init__(self):
"""Default constructor""" """
Default constructor
"""
def import_config_file(self, config_file): def import_config_file(self, config_file):
"""
Import your configuration file in JSON format
:param config_file: The path to your configuration file
:return:
"""
with open(config_file, 'r') as f: with open(config_file, 'r') as f:
data = json.load(f) data = json.load(f)
@ -43,6 +60,10 @@ class Config:
self.check_config() self.check_config()
def check_config(self): def check_config(self):
"""
Check the relevance of user configuration choices
:return:
"""
# Weight routing mode cannot be combinated with other actions # Weight routing mode cannot be combinated with other actions
if self.weight_routing_mode: if self.weight_routing_mode:
self.limit_speed_mode = False self.limit_speed_mode = False
@ -57,6 +78,9 @@ class Config:
self.lock_area_mode = False self.lock_area_mode = False
def __repr__(self) -> str: def __repr__(self) -> str:
"""
:return: All properties chosen by the user
"""
return ( return (
f'grid : {self.areas_number}x{self.areas_number}\n' f'grid : {self.areas_number}x{self.areas_number}\n'
f'step number = {self.n_steps}\n' f'step number = {self.n_steps}\n'
@ -69,6 +93,10 @@ class Config:
) )
def init_traci(self): def init_traci(self):
"""
Init the Traci API
:return:
"""
if 'SUMO_HOME' in os.environ: if 'SUMO_HOME' in os.environ:
tools = os.path.join(os.environ['SUMO_HOME'], 'tools') tools = os.path.join(os.environ['SUMO_HOME'], 'tools')
sys.path.append(tools) sys.path.append(tools)
@ -79,6 +107,11 @@ class Config:
self.sumo_cmd = [sumo_binary, "-c", self._SUMOCFG] self.sumo_cmd = [sumo_binary, "-c", self._SUMOCFG]
def init_logger(self, save_logs=False): def init_logger(self, save_logs=False):
"""
Init the application logger
:param save_logs: If save_logs is True, it will save the logs into the logs directory
:return:
"""
now = datetime.datetime.now() now = datetime.datetime.now()
current_date = now.strftime("%Y_%m_%d_%H_%M_%S") current_date = now.strftime("%Y_%m_%d_%H_%M_%S")
@ -103,5 +136,8 @@ class Config:
return logger return logger
def get_ref_emissions(self): def get_ref_emissions(self):
"""
:return: Return the sum of all emissions (in mg) from the simulation of reference
"""
if self.n_steps == 200: if self.n_steps == 200:
return self.ref200 return self.ref200

View File

@ -7,12 +7,12 @@
"n_steps": 200, "n_steps": 200,
"window_size":100, "window_size":100,
"without_actions_mode": true, "without_actions_mode": false,
"limit_speed_mode": false, "limit_speed_mode": true,
"speed_rf": 0.1, "speed_rf": 0.1,
"adjust_traffic_light_mode": false, "adjust_traffic_light_mode": true,
"trafficLights_duration_rf": 0.2, "trafficLights_duration_rf": 0.2,
"weight_routing_mode": false, "weight_routing_mode": false,

View File

@ -1,3 +1,9 @@
"""
Created on 17 oct. 2018
@author: Axel Huynh-Phuc, Thibaud Gasser
"""
import argparse import argparse
import csv import csv
import datetime import datetime
@ -7,15 +13,25 @@ import sys
import time import time
from typing import List from typing import List
import actions
import traci import traci
from config import Config
from model import Area, Vehicle, Lane, TrafficLight, Phase, Logic, Emission
from parse import search from parse import search
from shapely.geometry import LineString from shapely.geometry import LineString
import actions """
from config import Config This module defines the entry point of the application
from model import Area, Vehicle, Lane, TrafficLight, Phase, Logic, Emission """
def init_grid(simulation_bounds, areas_number, window_size): def init_grid(simulation_bounds, areas_number, window_size):
"""
Initialize the grid of the loaded map from the configuration
:param simulation_bounds: The map bounds
:param areas_number: The number of areas
:param window_size: The size of the acquisition window
:return: A list of areas
"""
grid = list() grid = list()
width = simulation_bounds[1][0] / areas_number width = simulation_bounds[1][0] / areas_number
height = simulation_bounds[1][1] / areas_number height = simulation_bounds[1][1] / areas_number
@ -32,6 +48,10 @@ def init_grid(simulation_bounds, areas_number, window_size):
def get_all_lanes() -> List[Lane]: def get_all_lanes() -> List[Lane]:
"""
Recover and creates a list of Lane objects
:return: The lanes list
"""
lanes = [] lanes = []
for lane_id in traci.lane.getIDList(): for lane_id in traci.lane.getIDList():
polygon_lane = LineString(traci.lane.getShape(lane_id)) polygon_lane = LineString(traci.lane.getShape(lane_id))
@ -41,6 +61,12 @@ def get_all_lanes() -> List[Lane]:
def parse_phase(phase_repr): def parse_phase(phase_repr):
"""
Because the SUMO object Phase does not contain accessors,
we parse the string representation to retrieve data members.
:param phase_repr: The Phase string representation
:return: An new Phase instance
"""
duration = search('duration: {:f}', phase_repr) duration = search('duration: {:f}', phase_repr)
min_duration = search('minDuration: {:f}', phase_repr) min_duration = search('minDuration: {:f}', phase_repr)
max_duration = search('maxDuration: {:f}', phase_repr) max_duration = search('maxDuration: {:f}', phase_repr)
@ -55,6 +81,11 @@ def parse_phase(phase_repr):
def add_data_to_areas(areas: List[Area]): def add_data_to_areas(areas: List[Area]):
"""
Adds all recovered data to different areas
:param areas: The list of areas
:return:
"""
lanes = get_all_lanes() lanes = get_all_lanes()
for area in areas: for area in areas:
for lane in lanes: # add lanes for lane in lanes: # add lanes
@ -72,6 +103,11 @@ def add_data_to_areas(areas: List[Area]):
def compute_vehicle_emissions(veh_id): def compute_vehicle_emissions(veh_id):
"""
Recover the emissions of different pollutants from a vehicle and create an Emission instance
:param veh_id:
:return: A new Emission instance
"""
co2 = traci.vehicle.getCO2Emission(veh_id) co2 = traci.vehicle.getCO2Emission(veh_id)
co = traci.vehicle.getCOEmission(veh_id) co = traci.vehicle.getCOEmission(veh_id)
nox = traci.vehicle.getNOxEmission(veh_id) nox = traci.vehicle.getNOxEmission(veh_id)
@ -82,6 +118,10 @@ def compute_vehicle_emissions(veh_id):
def get_all_vehicles() -> List[Vehicle]: def get_all_vehicles() -> List[Vehicle]:
"""
Recover all useful information about vehicles and creates a vehicles list
:return: A list of vehicles instances
"""
vehicles = list() vehicles = list()
for veh_id in traci.vehicle.getIDList(): for veh_id in traci.vehicle.getIDList():
veh_pos = traci.vehicle.getPosition(veh_id) veh_pos = traci.vehicle.getPosition(veh_id)
@ -92,6 +132,16 @@ def get_all_vehicles() -> List[Vehicle]:
def get_emissions(grid: List[Area], vehicles: List[Vehicle], current_step, config, logger): def get_emissions(grid: List[Area], vehicles: List[Vehicle], current_step, config, logger):
"""
For each area retrieves the acquired emissions in the window,
and acts according to the configuration chosen by the user
:param grid: The list of areas
:param vehicles: The list of vehicles
:param current_step: The simulation current step
:param config: The simulation configuration
:param logger: The simulation logger
:return:
"""
for area in grid: for area in grid:
total_emissions = Emission() total_emissions = Emission()
for vehicle in vehicles: for vehicle in vehicles:
@ -100,11 +150,11 @@ def get_emissions(grid: List[Area], vehicles: List[Vehicle], current_step, confi
area.emissions_by_step.append(total_emissions) area.emissions_by_step.append(total_emissions)
if area.sum_emissions_into_window(current_step, config.window_size) >= config.emissions_threshold: if area.sum_emissions_into_window(current_step) >= config.emissions_threshold:
if config.limit_speed_mode and not area.limited_speed: if config.limit_speed_mode and not area.limited_speed:
logger.info(f'Action - Decreased max speed into {area.name} by {config.speed_rf * 100}%') logger.info(f'Action - Decreased max speed into {area.name} by {config.speed_rf * 100}%')
actions.limit_speed_into_area(area, vehicles, config.speed_rf) actions.limit_speed_into_area(area, config.speed_rf)
if config.adjust_traffic_light_mode and not area.tls_adjusted: if config.adjust_traffic_light_mode and not area.tls_adjusted:
logger.info( logger.info(
f'Action - Decreased traffic lights duration by {config.trafficLights_duration_rf * 100}%') f'Action - Decreased traffic lights duration by {config.trafficLights_duration_rf * 100}%')
@ -126,11 +176,23 @@ def get_emissions(grid: List[Area], vehicles: List[Vehicle], current_step, confi
def get_reduction_percentage(ref, total): def get_reduction_percentage(ref, total):
"""
Return the reduction percentage of total emissions between reference and an other simulation
:param ref:
:param total:
:return:
"""
return (ref - total) / ref * 100 return (ref - total) / ref * 100
def export_data_to_csv(config, grid): def export_data_to_csv(config, grid):
csv_dir = os.path.join(SCRIPTDIR, 'csv') """
Export all Emission objects as a CSV file into the csv directory
:param config: The simulation configuration
:param grid: The list of areas
:return:
"""
csv_dir = 'csv'
if not os.path.exists(csv_dir): if not os.path.exists(csv_dir):
os.mkdir(csv_dir) os.mkdir(csv_dir)
@ -147,6 +209,12 @@ def export_data_to_csv(config, grid):
def run(config, logger): def run(config, logger):
"""
Run the simulation with the configuration chosen
:param config: The simulation configuration
:param logger: The simulation logger
:return:
"""
grid = list() grid = list()
try: try:
traci.start(config.sumo_cmd) traci.start(config.sumo_cmd)
@ -199,6 +267,11 @@ def run(config, logger):
def add_options(parser): def add_options(parser):
"""
Add command line options
:param parser: The command line parser
:return:
"""
parser.add_argument("-f", "--configfile", type=str, default='configs/default_config.json', required=False, parser.add_argument("-f", "--configfile", type=str, default='configs/default_config.json', required=False,
help='Choose your configuration file from your working directory') help='Choose your configuration file from your working directory')
parser.add_argument("-save", "--save", action="store_true", parser.add_argument("-save", "--save", action="store_true",
@ -212,6 +285,11 @@ def add_options(parser):
def main(args): def main(args):
"""
The entry point of the application
:param args: Command line options
:return:
"""
parser = argparse.ArgumentParser(description="") parser = argparse.ArgumentParser(description="")
add_options(parser) add_options(parser)
args = parser.parse_args(args) args = parser.parse_args(args)

View File

@ -1,3 +1,9 @@
"""
Created on 17 oct. 2018
@author: Axel Huynh-Phuc, Thibaud Gasser
"""
import collections import collections
from typing import Tuple, Set from typing import Tuple, Set
@ -6,10 +12,25 @@ from shapely.geometry import Polygon
from shapely.geometry.base import BaseGeometry from shapely.geometry.base import BaseGeometry
from traci._trafficlight import Logic as SUMO_Logic from traci._trafficlight import Logic as SUMO_Logic
"""
This module defines the business model of our application
"""
class Lane: class Lane:
"""
The Lane class includes the polygon defining the lane
and keep in memory the initial maximum speed on the lane
"""
def __init__(self, lane_id: str, polygon: LineString, initial_max_speed: float): def __init__(self, lane_id: str, polygon: LineString, initial_max_speed: float):
"""
Lane constructor
:param lane_id: The ID of the lane
:param polygon: The polygon defining the shape of the lane
:param initial_max_speed: The initial maximum speed
"""
self.polygon = polygon self.polygon = polygon
self.lane_id = lane_id self.lane_id = lane_id
self.initial_max_speed = initial_max_speed self.initial_max_speed = initial_max_speed
@ -20,26 +41,62 @@ class Lane:
class Phase: class Phase:
"""
The Phase class defines a phase of a traffic light
"""
def __init__(self, duration: float, minDuration: float, maxDuration: float, phaseDef: str): def __init__(self, duration: float, minDuration: float, maxDuration: float, phaseDef: str):
"""
Phase constructor
:param duration: The duration of the phase (in seconds)
:param minDuration: The minimum duration of the phase
:param maxDuration: The maximum duration of the phase
:param phaseDef: The definition of the phase, following the definition rules of SUMO
(See : http://sumo.dlr.de/wiki/Simulation/Traffic_Lights#.3Cphase.3E_Attributes)
"""
self.duration = duration self.duration = duration
self.minDuration = minDuration self.minDuration = minDuration
self.maxDuration = maxDuration self.maxDuration = maxDuration
self.phaseDef = phaseDef self.phaseDef = phaseDef
def __repr__(self) -> str: def __repr__(self) -> str:
"""
:return: The Phase string representation
"""
repr = f'Phase(duration:{self.duration},minDuration:{self.minDuration},maxDuration:{self.maxDuration},phaseDef:{self.phaseDef})' repr = f'Phase(duration:{self.duration},minDuration:{self.minDuration},maxDuration:{self.maxDuration},phaseDef:{self.phaseDef})'
return str(repr) return str(repr)
class Logic: class Logic:
"""
The Logic class defines the strategy of a traffic light.
This class includes the Logic instance of SUMO with all phases corresponding to it.
A Logic object contains multiple phases.
"""
def __init__(self, logic: SUMO_Logic, phases: Set[Phase]): def __init__(self, logic: SUMO_Logic, phases: Set[Phase]):
"""
Logic constructor
:param logic: The SUMO Logic object
:param phases: The list of phases belonging to this logic
"""
self._logic = logic self._logic = logic
self._phases: Set[Phase] = phases self._phases: Set[Phase] = phases
class TrafficLight: class TrafficLight:
"""
This TrafficLight class defines a traffic light
"""
def __init__(self, tl_id: str, logics: Set[Logic]): def __init__(self, tl_id: str, logics: Set[Logic]):
"""
TrafficLight constructor
:param tl_id: The traffic light ID
:param logics: The list of logics belonging to the traffic light
"""
self.tl_id = tl_id self.tl_id = tl_id
self._logics: Set[Logic] = logics self._logics: Set[Logic] = logics
@ -49,7 +106,19 @@ class TrafficLight:
class Emission: class Emission:
"""
This class defines the different pollutant emissions
"""
def __init__(self, co2=0, co=0, nox=0, hc=0, pmx=0): def __init__(self, co2=0, co=0, nox=0, hc=0, pmx=0):
"""
Emission constructor
:param co2: Quantity of CO2(in mg)
:param co: Quantity of C0(in mg)
:param nox: Quantity of Nox(in mg)
:param hc: Quantity of HC(in mg)
:param pmx: Quantity of PMx(in mg)
"""
self.co2 = co2 self.co2 = co2
self.co = co self.co = co
self.nox = nox self.nox = nox
@ -57,20 +126,41 @@ class Emission:
self.pmx = pmx self.pmx = pmx
def __add__(self, other): def __add__(self, other):
"""
Add two emission objects
:param other: The other Emission object to add
:return: A new object whose emission values are the sum of both Emission object
"""
return Emission(self.co2 + other.co2, self.co + other.co, self.nox + other.nox, self.hc + other.hc, return Emission(self.co2 + other.co2, self.co + other.co, self.nox + other.nox, self.hc + other.hc,
self.pmx + other.pmx) self.pmx + other.pmx)
def value(self): def value(self):
"""
:return: The sum of all emissions
"""
return self.co2 + self.co + self.nox + self.hc + self.pmx return self.co2 + self.co + self.nox + self.hc + self.pmx
def __repr__(self) -> str: def __repr__(self) -> str:
"""
:return: The Emission string representation
"""
repr = f'Emission(co2={self.co2},co={self.co},nox={self.nox},hc={self.hc},pmx={self.pmx})' repr = f'Emission(co2={self.co2},co={self.co},nox={self.nox},hc={self.hc},pmx={self.pmx})'
return str(repr) return str(repr)
class Area: class Area:
"""
The Area class defines a grid area of the map
"""
def __init__(self, coords, name, window_size): def __init__(self, coords, name, window_size):
"""
Area constructor
:param coords: The coordinates of the zone,
defined by the bounds coordinates of this area : (xmin, ymin, xmax, ymax)
:param name: The Area name
:param window_size: The size of the acquisition window
"""
self.limited_speed = False self.limited_speed = False
self.locked = False self.locked = False
self.tls_adjusted = False self.tls_adjusted = False
@ -83,35 +173,75 @@ class Area:
self._tls: Set[TrafficLight] = set() self._tls: Set[TrafficLight] = set()
def __eq__(self, other): def __eq__(self, other):
"""
Overrides the equal definition
:param other: The other Area object
:return: True if the two rectangles are equals
"""
return self.rectangle.__eq__(other) return self.rectangle.__eq__(other)
def __contains__(self, item): def __contains__(self, item):
"""
:param item: A position on the map
:return: True if the area contains the item
"""
return self.rectangle.contains(item) return self.rectangle.contains(item)
@property @property
def bounds(self): def bounds(self):
"""
Return the bounds rectangle of this area
:return:
"""
return self.rectangle.bounds return self.rectangle.bounds
def intersects(self, other: BaseGeometry) -> bool: def intersects(self, other: BaseGeometry) -> bool:
"""
:param other: A BaseGeometry object
:return: True if this area intersects with other
"""
return self.rectangle.intersects(other) return self.rectangle.intersects(other)
def add_lane(self, lane: Lane): def add_lane(self, lane: Lane):
"""
Add a new lane object into lanes list
:param lane: A Lane object
:return:
"""
self._lanes.add(lane) self._lanes.add(lane)
def add_tl(self, tl: TrafficLight): def add_tl(self, tl: TrafficLight):
"""
Add a new trafficLight object into lanes list
:param tl: A TrafficLight object
:return:
"""
self._tls.add(tl) self._tls.add(tl)
def remove_lane(self, lane: Lane): def remove_lane(self, lane: Lane):
"""
Remove a lane from lanes list
:param lane: The Lane object to remove
:return:
"""
self._lanes.remove(lane) self._lanes.remove(lane)
def sum_all_emissions(self): def sum_all_emissions(self):
"""
Sum all Emissions object from initial step to final step
:return: The sum Emission object
"""
sum = Emission() sum = Emission()
for emission in self.emissions_by_step: for emission in self.emissions_by_step:
sum += emission sum += emission
return sum return sum
def sum_emissions_into_window(self, current_step, window_size): def sum_emissions_into_window(self, current_step):
"""
Sum all Emissions object into the acquisition window
:param current_step: The current step of the simulation
:return:
"""
self.window.appendleft(self.emissions_by_step[current_step].value()) self.window.appendleft(self.emissions_by_step[current_step].value())
sum = 0 sum = 0
@ -129,11 +259,22 @@ class Area:
class Vehicle: class Vehicle:
"""
The Vehicle class defines a vehicle object
"""
def __init__(self, veh_id: int, pos: Tuple[float, float]): def __init__(self, veh_id: int, pos: Tuple[float, float]):
"""
Vehicle constructor
:param veh_id: The vehicle ID
:param pos: The position of the vehicle one the map
"""
self.emissions: Emission = Emission() self.emissions: Emission = Emission()
self.veh_id = veh_id self.veh_id = veh_id
self.pos = Point(pos) self.pos = Point(pos)
def __repr__(self) -> str: def __repr__(self) -> str:
"""
:return: The Vehicle string representation
"""
return str(self.__dict__) return str(self.__dict__)