diff --git a/experiments/bulk_running_experiments.ipynb b/experiments/bulk_running_experiments.ipynb index 083112feae71fdfd90d2543e2878337e64a2b7d7..0f1e0554a03e03bcd2913469c1ccab9a737504b0 100644 --- a/experiments/bulk_running_experiments.ipynb +++ b/experiments/bulk_running_experiments.ipynb @@ -210,6 +210,8 @@ " # # f\"observation.pdm_hybrid_ckpt={hybrid_ckpt}\",\n", " f\"observation.occlusion_cfg.occlusion=true\",\n", " f\"observation.occlusion_cfg.manager_type=wedge\",\n", + " \"+modify_scenario_simulations=true\",\n", + " \"+modifier_types=[left-and-right]\",\n", " \"+occlusion=true\",\n", " \"+occlusion.manager_type=wedge\", # options: [range, shadow, wedge]\n", " \"+occlusion.uncloak_reaction_time=1.5\",\n", diff --git a/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py b/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py index 0fbfb6fd9d10fefa429ded367f81a7723c72528b..3d2629dc4185a686713a565e9b41def48376601f 100644 --- a/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py +++ b/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py @@ -121,6 +121,7 @@ class NuPlanScenario(AbstractScenario): # So, we must check and download the file here as well. self._log_file = download_file_if_necessary(self._data_root, self._log_file_load_path) self._log_name: str = absolute_path_to_log_name(self._log_file) + self.modifier = "" def __reduce__(self) -> Tuple[Type[NuPlanScenario], Tuple[Any, ...]]: """ @@ -190,7 +191,7 @@ class NuPlanScenario(AbstractScenario): @property def scenario_name(self) -> str: """Inherited, see superclass.""" - return self.token + return self.token + self.modifier @property def scenario_type(self) -> str: diff --git a/nuplan/planning/scenario_builder/scenario_modifier/abstract_scenario_modifier.py b/nuplan/planning/scenario_builder/scenario_modifier/abstract_scenario_modifier.py new file mode 100644 index 0000000000000000000000000000000000000000..c19fa792597cb63d169a2fed9cb598e8d25a0a01 --- /dev/null +++ b/nuplan/planning/scenario_builder/scenario_modifier/abstract_scenario_modifier.py @@ -0,0 +1,14 @@ +from abc import ABCMeta, abstractmethod +from typing import List + +from nuplan.planning.scenario_builder.abstract_scenario import AbstractScenario +from nuplan.planning.simulation.runner.simulations_runner import SimulationRunner + +class AbstractScenarioModifier(metaclass=ABCMeta): + @abstractmethod + def modify_scenario(self, runner: SimulationRunner) -> List[SimulationRunner]: + """We convert one abstract scenario into many abstract scenarios by modifying the scenario in some way. + :param runner: a simualtion runner + :return: we return a list of scenarios that are modified versions of the input scenario + """ + pass \ No newline at end of file diff --git a/nuplan/planning/scenario_builder/scenario_modifier/left_and_right_modifier.py b/nuplan/planning/scenario_builder/scenario_modifier/left_and_right_modifier.py new file mode 100644 index 0000000000000000000000000000000000000000..69bea3ad9ccdeb4cded77c9b42fb35c373b718b2 --- /dev/null +++ b/nuplan/planning/scenario_builder/scenario_modifier/left_and_right_modifier.py @@ -0,0 +1,78 @@ +from typing import List + +import copy +from nuplan.common.actor_state.tracked_objects_types import TrackedObjectType + +from nuplan.planning.scenario_builder.abstract_scenario import AbstractScenario +from nuplan.planning.scenario_builder.scenario_modifier.abstract_scenario_modifier import AbstractScenarioModifier + + +from nuplan.common.actor_state.agent import Agent +from nuplan.common.actor_state.oriented_box import OrientedBox +from nuplan.common.actor_state.scene_object import SceneObjectMetadata +from nuplan.common.actor_state.state_representation import StateSE2, StateVector2D +import math + +from nuplan.planning.simulation.runner.simulations_runner import SimulationRunner +class LeftAndRightModifier(AbstractScenarioModifier): + def __init__(self): + super().__init__() #maybe we will need this later + + def modify_scenario(self, runner: SimulationRunner) -> List[SimulationRunner]: + """We convert one abstract scenario into many abstract scenarios by modifying the scenario in some way. + :param scenario: a scenario + :return: we return a list of scenarios that are modified versions of the input scenario + """ + modified_simulation_runners = [] + print('original object', runner) + left = copy.deepcopy(runner) + right = copy.deepcopy(runner) + + scenario = runner.scenario + + + angle = scenario.initial_ego_state.center.heading + inserted_agent = Agent( + tracked_object_type=TrackedObjectType.VEHICLE, + oriented_box=OrientedBox(StateSE2(scenario.initial_ego_state.center.x - 2, scenario.initial_ego_state.center.y, angle), 5, 2, 2), + velocity=StateVector2D(scenario.initial_ego_state.agent._velocity.x, scenario.initial_ego_state.agent._velocity.y), + metadata=SceneObjectMetadata(1623707858950113, "inserted_left", -2, "inserted_left"), + angular_velocity=0.0, + ) + + inserted_goal = StateSE2(scenario.initial_ego_state.center.x+100, scenario.initial_ego_state.center.y+100, 1.25) + + iter = runner.simulation._time_controller.get_iteration() + left.simulation._observations.add_agent_to_scene( + inserted_agent, inserted_goal, iter.time_point + ) + + left.scenario.modifier = "left" + + ############################## + + angle = scenario.initial_ego_state.center.heading + inserted_agent = Agent( + tracked_object_type=TrackedObjectType.VEHICLE, + oriented_box=OrientedBox(StateSE2(scenario.initial_ego_state.center.x + 2, scenario.initial_ego_state.center.y, angle), 5, 2, 2), + velocity=StateVector2D(scenario.initial_ego_state.agent._velocity.x, scenario.initial_ego_state.agent._velocity.y), + metadata=SceneObjectMetadata(1623707858950113, "inserted_right", -2, "inserted_right"), + angular_velocity=0.0, + ) + + inserted_goal = StateSE2(scenario.initial_ego_state.center.x+100, scenario.initial_ego_state.center.y+100, 1.25) + + iter = runner.simulation._time_controller.get_iteration() + right.simulation._observations.add_agent_to_scene( + inserted_agent, inserted_goal, iter.time_point + ) + + right.scenario.modifier = "right" + print('modded scenario') + print(right.scenario.scenario_name) + ####################################### + + modified_simulation_runners.append(left) + modified_simulation_runners.append(right) + + return modified_simulation_runners \ No newline at end of file diff --git a/nuplan/planning/script/builders/scenario_modifier_builder.py b/nuplan/planning/script/builders/scenario_modifier_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..1a49e6cab69c407bdb73d8b42dc1a7e8f4d6cdae --- /dev/null +++ b/nuplan/planning/script/builders/scenario_modifier_builder.py @@ -0,0 +1,19 @@ +from typing import List + +from nuplan.planning.scenario_builder.scenario_modifier.abstract_scenario_modifier import AbstractScenarioModifier +from nuplan.planning.scenario_builder.scenario_modifier.left_and_right_modifier import LeftAndRightModifier + + +def build_scenario_modifiers(scenario_modifier_types: List[str]) -> List[AbstractScenarioModifier]: + modifiers = [] + for type in scenario_modifier_types: + if type == "left-and-right": + modifiers.append(LeftAndRightModifier()) #this one is an example and just injects an agent to the left of ego in one modifiecation of the scenario and to the right in another + # elif type == "occluder-injection": + # modifiers.append(OccluderInjection()) + # elif type == "occludie-injection": + # modifiers.append(OccludieInjection()) + else: + raise ValueError(f"Unknown scenario modifier type: {type}") + + return modifiers \ No newline at end of file diff --git a/nuplan/planning/script/builders/simulation_builder.py b/nuplan/planning/script/builders/simulation_builder.py index 52abd74a11c3fc7fc3104946adc9b33a3da52f44..7c12b4127f6c25502afde3bfa9b6f83e322956f0 100644 --- a/nuplan/planning/script/builders/simulation_builder.py +++ b/nuplan/planning/script/builders/simulation_builder.py @@ -27,6 +27,8 @@ from nuplan.planning.simulation.simulation_time_controller.abstract_simulation_t ) from nuplan.planning.utils.multithreading.worker_pool import WorkerPool +from nuplan.planning.script.builders.scenario_modifier_builder import build_scenario_modifiers + logger = logging.getLogger(__name__) @@ -138,6 +140,20 @@ def build_simulations( simulation_history_buffer_duration=cfg.simulation_history_buffer_duration, ) simulations.append(SimulationRunner(simulation, planner)) - + + # here we need to convert those simulations to our special scenarios + if 'modify_scenario_simulations' in cfg and cfg.modify_scenario_simulations: + offshoot_scenario_simulations = [] + scenario_modifiers = build_scenario_modifiers(cfg.modifier_types) + logger.info('Modyfing Scenarios...') + original_num_runners = len(simulations) + for simulation in simulations: + for modifier in scenario_modifiers: + offshoot_scenario_simulations.extend(modifier.modify_scenario(simulation)) + simulations = offshoot_scenario_simulations + logger.info(f'Created {len(simulations)} modified scenarios from {original_num_runners} scenarios.') + for simulation in simulations: + print('c') + print(simulation.scenario.scenario_name) logger.info('Building simulations...DONE!') return simulations diff --git a/nuplan/planning/script/run_simulation.py b/nuplan/planning/script/run_simulation.py index 9e3e5cff00c21868b1afcc9dc35d52371cce640f..469e8a3afb028c84cc75cd4bc0ded007171f4223 100644 --- a/nuplan/planning/script/run_simulation.py +++ b/nuplan/planning/script/run_simulation.py @@ -106,6 +106,9 @@ def run_simulation(cfg: DictConfig, planners: Optional[Union[AbstractPlanner, Li pre_built_planners=planners, callbacks_worker=callbacks_worker_pool, ) + + for runner in runners: + print('d', runner.scenario.scenario_name) if common_builder.profiler: # Stop simulation construction profiling diff --git a/nuplan/planning/simulation/observation/ml_planner_agents.py b/nuplan/planning/simulation/observation/ml_planner_agents.py index 07179e423bfb08b3c582c6704f7c6ea6389f2b57..2fde6f896ed84289797ed1589b6d22d44020ffee 100644 --- a/nuplan/planning/simulation/observation/ml_planner_agents.py +++ b/nuplan/planning/simulation/observation/ml_planner_agents.py @@ -306,8 +306,12 @@ class MLPlannerAgents(AbstractObservation): def add_agent_to_scene(self, agent: Agent, goal: StateSE2, timepoint_record: TimePoint): """ Adds agent to the scene with a given goal during the simulation runtime. + Gets dict of tracked agents, or lazily creates them it + from vehicles at simulation start if it does not exist. """ + self._agents = self._get_agents() #this action is idempotent + route_plan = self._get_roadblock_path(agent, goal) if route_plan: diff --git a/nuplan/planning/simulation/runner/executor.py b/nuplan/planning/simulation/runner/executor.py index 1f42051ee29ae02c36815748d65abab64cc058ee..33b6633783e52c5ff61838e34c7137f49bf4a9ff 100644 --- a/nuplan/planning/simulation/runner/executor.py +++ b/nuplan/planning/simulation/runner/executor.py @@ -23,6 +23,10 @@ def run_simulation(sim_runner: AbstractRunner, exit_on_failure: bool = False) -> """ # Store start time so that if the simulations fail, we know how long they ran for start_time = time.perf_counter() + print('hihihi') + print(sim_runner.scenario.modifier) + print(sim_runner) + print('a', sim_runner.scenario.scenario_name) try: return sim_runner.run() except Exception as e: @@ -80,9 +84,23 @@ def execute_runners( # Start simulations number_of_sims = len(runners) logger.info(f"Starting {number_of_sims} simulations using {worker.__class__.__name__}!") + + for runner in runners: + print('hohoho') + print(runner.scenario.modifier) + print(runner) + print('e', runner.scenario.scenario_name) + + #run_simulation(runners[0], exit_on_failure) this if you just want to run one without ray.map + + reports: List[RunnerReport] = worker.map( Task(fn=run_simulation, num_gpus=num_gpus, num_cpus=num_cpus), runners, exit_on_failure, verbose=verbose ) + reports = [] + print(len(reports)) + for report in reports: + print(report.scenario_name, report.planner_name, report.log_name) # Store the results in a dictionary so we can easily store error tracebacks in the next step, if needed results: Dict[Tuple[str, str, str], RunnerReport] = { (report.scenario_name, report.planner_name, report.log_name): report for report in reports @@ -116,6 +134,7 @@ def execute_runners( failed_simulations = str() number_of_successful = 0 runner_reports: List[RunnerReport] = list(results.values()) + print(len(runner_reports)) for result in runner_reports: if result.succeeded: number_of_successful += 1