def test_json_back_and_forth(self) -> None: """ test converting back and forth from and to json """ # GIVEN input_dict = TestPeriodicOrderInputValidation.get_default_inputs() # WHEN periodic_order = PeriodicOrder(**input_dict) # THEN converting back and forth should in the end give the same result periodic_order_dict = periodic_order.to_json() periodic_order_from_json = PeriodicOrder.from_json( order_dict=periodic_order_dict) self.assertDictEqual(periodic_order_dict, periodic_order_from_json.to_json())
def test_successful_validation(self) -> None: """ Test initializing PeriodicOrder object with correct input """ # GIVEN input_dict = TestPeriodicOrderInputValidation.get_default_inputs() # WHEN PeriodicOrder(**input_dict)
def test_duplicate_ids(self) -> None: """ Test that an error is raised when the same id is used multiple times """ # GIVEN input_dict = TestPeriodicOrderInputValidation.get_default_inputs() input_dict["order"].append("sg1") # WHEN initializing the periodic order with self.assertRaises(ValueError): PeriodicOrder(**input_dict)
def test_subsequent_non_conflicting_ids_in_periodic_order(self): # GIVEN input_dict = TestInputValidation.get_default_inputs() # WHEN input_dict["periodic_orders"] = [PeriodicOrder(["sg1", "sg2", "sg3"])] with self.assertRaises(ValueError): Intersection(**input_dict)
def test_unknown_ids_in_periodic_order(self): # GIVEN input_dict = TestInputValidation.get_default_inputs() # WHEN input_dict["periodic_orders"] = [PeriodicOrder(["sg1", "sg2", "unknown_id"])] with self.assertRaises(ValueError): Intersection(**input_dict)
def get_default_inputs() -> Dict: """ Function to get default (valid) inputs for Intersection() """ signalgroups = [SignalGroup(id=f"sg{i+1}", traffic_lights=[TrafficLight(capacity=1800, lost_time=1)], min_greenyellow=10, max_greenyellow=80, min_red=10, max_red=80) for i in range(6)] conflicts = [Conflict(id1="sg1", id2="sg2", setup12=1, setup21=2), Conflict(id1="sg1", id2="sg6", setup12=1, setup21=2), Conflict(id1="sg2", id2="sg6", setup12=1, setup21=2)] sync_starts = [SyncStart(from_id="sg1", to_id="sg3")] offsets = [Offset(from_id="sg1", to_id="sg4", seconds=10)] periodic_orders = [PeriodicOrder(order=["sg1", "sg2", "sg6"])] greenyellow_leads = [GreenyellowLead(from_id="sg1", to_id="sg5", min_seconds=1, max_seconds=10)] greenyellow_trails = [GreenyellowTrail(from_id="sg5", to_id="sg1", min_seconds=2, max_seconds=8)] return dict(signalgroups=signalgroups, conflicts=conflicts, sync_starts=sync_starts, offsets=offsets, greenyellow_leads=greenyellow_leads, greenyellow_trails=greenyellow_trails, periodic_orders=periodic_orders)
def _add_fixed_periodic_order(self, order: List[str]) -> None: self._fixed_orders.append(PeriodicOrder(order=order))
def from_json(intersection_dict: Dict) -> Intersection: """ Loading intersection from json (expected same json structure as generated with to_json) :param intersection_dict: :return: intersection object """ # load signal groups signalgroups = [ SignalGroup.from_json(signalgroup_dict=signalgroup_dict) for signalgroup_dict in intersection_dict["signalgroups"] ] if "periodic_orders" in intersection_dict: periodic_orders = [ PeriodicOrder.from_json(order_dict=order_dict) for order_dict in intersection_dict["periodic_orders"] ] else: periodic_orders = [] # load conflicts conflicts = [ Conflict.from_json(conflict_dict=conflict_dict) for conflict_dict in intersection_dict["conflicts"] ] # load other relations (synchronous starts, offsets and greenyellow_lead) sync_starts = [] offsets = [] greenyellow_leads = [] greenyellow_trails = [] for other_relation_dict in intersection_dict["other_relations"]: assert other_relation_dict["from_start_gy"] == other_relation_dict["to_start_gy"], \ "besides conflicts, at the moment the cloud api can only handle synchronous starts, offsets, " \ "greenyellow-leads and greenyellow-trails." if other_relation_dict[ "from_start_gy"] is True and other_relation_dict[ "to_start_gy"] is True: if other_relation_dict["min_time"] == other_relation_dict[ "max_time"]: if other_relation_dict["min_time"] == 0: # sync start sync_starts.append( SyncStart.from_json( sync_start_dict=other_relation_dict)) else: # offset offsets.append( Offset.from_json(offset_dict=other_relation_dict)) else: # greenyellow-leads greenyellow_leads.append( GreenyellowLead.from_json( json_dict=other_relation_dict)) elif other_relation_dict[ "from_start_gy"] is False and other_relation_dict[ "to_start_gy"] is False: greenyellow_trails.append( GreenyellowTrail.from_json(json_dict=other_relation_dict)) return Intersection(signalgroups=signalgroups, conflicts=conflicts, sync_starts=sync_starts, offsets=offsets, greenyellow_leads=greenyellow_leads, greenyellow_trails=greenyellow_trails, periodic_orders=periodic_orders)
def fix_order_and_optimize(): """ This example shows how to ask for a fixed-time schedule that adheres to a specified fix order in which the signalgroups should receive their greenyellow interval. """ logging.info(f"Running example '{os.path.basename(__file__)}'") # signal group consisting of two traffic light allowing 1 or 2 greenyellow intervals per repeating period. traffic_light1 = TrafficLight(capacity=1800, lost_time=2.2) traffic_light2 = TrafficLight(capacity=1810, lost_time=2.1) signalgroup1 = SignalGroup(id="2", traffic_lights=[traffic_light1, traffic_light2], min_greenyellow=10, max_greenyellow=100, min_red=10, max_red=100, min_nr=1, max_nr=2) # signal group consisting of one traffic light allowing 1 greenyellow interval (default) per repeating period. traffic_light3 = TrafficLight(capacity=1650, lost_time=3.0) signalgroup2 = SignalGroup(id="5", traffic_lights=[traffic_light3], min_greenyellow=10, max_greenyellow=100, min_red=10, max_red=100) # signal group consisting of one traffic light allowing 1 greenyellow interval (default) per repeating period. traffic_light4 = TrafficLight(capacity=1800, lost_time=2.1) signalgroup3 = SignalGroup(id="8", traffic_lights=[traffic_light4], min_greenyellow=10, max_greenyellow=100, min_red=10, max_red=100) # conflicts & clearance times conflict12 = Conflict(id1=signalgroup1.id, id2=signalgroup2.id, setup12=1, setup21=2) conflict13 = Conflict(id1=signalgroup1.id, id2=signalgroup3.id, setup12=2, setup21=1) conflict23 = Conflict(id1=signalgroup2.id, id2=signalgroup3.id, setup12=2, setup21=3) # initialize intersection object intersection = Intersection( signalgroups=[signalgroup1, signalgroup2, signalgroup3], conflicts=[conflict12, conflict13, conflict23]) # set associated arrival rates arrival_rates = ArrivalRates(id_to_arrival_rates={ "2": [800, 700], "5": [150], "8": [180] }) logging.info( f"Not yet requesting any fixed order of greenyellow intervals") logging.info(f"Minimizing average experienced delay") # optimize fixed-time schedule fixed_time_schedule, phase_diagram, objective_value, _ = SwiftMobilityCloudApi.get_optimized_fts( intersection=intersection, arrival_rates=arrival_rates, objective=ObjectiveEnum.min_delay) logging.info(f"Average experienced delay {objective_value: .3f} seconds") logging.info(fixed_time_schedule) logging.info(phase_diagram) logging.info(f"Requesting order: 2 -> 8 -> 5 -> ") # initialize intersection object intersection = Intersection( signalgroups=[signalgroup1, signalgroup2, signalgroup3], conflicts=[conflict12, conflict13, conflict23], periodic_orders=[PeriodicOrder(order=["2", "8", "5"])]) logging.info(f"Minimizing average experienced delay") # optimize fixed-time schedule fixed_time_schedule, phase_diagram, objective_value, _ = SwiftMobilityCloudApi.get_optimized_fts( intersection=intersection, arrival_rates=arrival_rates, objective=ObjectiveEnum.min_delay) logging.info(f"Average experienced delay {objective_value: .3f} seconds") logging.info(fixed_time_schedule) logging.info(phase_diagram)