Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Large area simulation rework #203

Merged
merged 31 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b1b95a3
Added model version, seeds, and multiple simulations to area driving.
Apr 15, 2024
5d13394
Merge branch 'large_map_utilities' into large_area_simulation_rework
Apr 15, 2024
9bd027e
Created Region data type and updated region_initialize with this class.
Apr 17, 2024
a2f03ae
Fixed region_initialize bugs and logical errors.
Apr 17, 2024
bfde9fa
Troubleshooting initialize server errors.
Apr 17, 2024
31c7b40
Fixed initialize bugs and successfully tested.
Apr 17, 2024
7630467
Added region_drive functionality.
Apr 18, 2024
71e88ca
Changed example code for updated region_drive.
Apr 18, 2024
0d60645
Resolved async functionality and agent order bug
Apr 19, 2024
f81fe86
Fixed logic issues with agents being inserted to multiple regions or …
Apr 22, 2024
f68700c
Placed floating point prevention mechanism in region_drive instead of…
Apr 22, 2024
6a2a6b9
Some cleanup of unused depencies and comments.
Apr 22, 2024
f7f9804
Removed unnecessary features and added more and clearer documentation.
Apr 23, 2024
eab4b25
Further comment and code cleanup.
Apr 23, 2024
d6cf618
Changed the names of the main functions to be more descriptive.
Apr 23, 2024
a9cc5fc
Removed birdview functionality and removed useless intialize filter.
Apr 24, 2024
8f8c75a
Removed error catching in initialize and changed to total number of a…
Apr 24, 2024
de78033
Added flag to control whether to raise an exception if a region can't…
Apr 24, 2024
4e85a8d
Fixed typo.
Apr 24, 2024
af76d20
Changed Optional tag on parameters and updated error message.
Apr 24, 2024
137fa7b
Made cleanup changes to large_drive.
Apr 25, 2024
bfd48d5
Removed breakpoint
Apr 25, 2024
c6210c4
Made edits to comments and docstrings. Added a more robust buffer to …
Apr 25, 2024
e9beb2c
Added various documentation and naming changes for clarity and mainta…
Apr 26, 2024
08b8183
Added large initialize tests and corrected conditional agent function…
Apr 29, 2024
bbe9d2a
Added tests for large_drive
Apr 29, 2024
7055584
Fixed large example file for default map_center selection.
May 3, 2024
c7aa31f
Changed message in large_initialize to debug instead of warning.
May 14, 2024
dd2b4ba
Fixed scope issue with response variable.
May 15, 2024
abff43a
Merged in develop branch.
KieranRatcliffeInvertedAI May 28, 2024
23539c3
Deactivate unused tests.
KieranRatcliffeInvertedAI May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dev/
dev.py
img/
gifs/
examples/output
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down Expand Up @@ -179,3 +180,4 @@ bazel-*
# Demos
*.avi
*.gif
examples/*.png
6 changes: 4 additions & 2 deletions examples/area_drive/area_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class AreaDriverConfig:
agent_density: Optional[float] = 10 #: The number of agents to spawn in each 100x100m region
initialize_stride: Optional[float] = 50 #: The space between regions to be initialized
random_seed: Optional[int] = None
model_version: Optional[str] = None
#Visualization parameters
rendered_static_map: Optional[np.ndarray] = None #: Map image from location info to render vehicles upon
render_fov: Optional[float] = 100 #: Field of view of any visualizations
Expand Down Expand Up @@ -89,6 +90,7 @@ def __init__(
self.height = cfg.map_height
self.agent_per_region = cfg.agent_density
self.random_seed = cfg.random_seed
self.model_version = cfg.model_version
self.initialize_stride = cfg.initialize_stride
self.quad_re_initialization = cfg.quadtree_reconstruction_period
self.timer = 1
Expand Down Expand Up @@ -188,7 +190,7 @@ def create_quadtree(self):

async def async_drive(self):
regions = self.quadtree.get_regions()
results = await asyncio.gather(*[region.async_drive(self.light_recurrent_states) for region in regions])
results = await asyncio.gather(*[region.async_drive(self.light_recurrent_states,random_seed=self.random_seed,api_model_version=self.model_version) for region in regions])
for result in results:
if result[0] is not None:
self.traffic_lights_states = result[0]
Expand All @@ -200,7 +202,7 @@ def sync_drive(self):
is_new_traffic_lights = True
current_light_recurrent_states = self.light_recurrent_states
for region in regions:
traffic_lights_states, light_recurrent_states = region.sync_drive(current_light_recurrent_states)
traffic_lights_states, light_recurrent_states = region.sync_drive(current_light_recurrent_states,random_seed=self.random_seed,api_model_version=self.model_version)

if is_new_traffic_lights and traffic_lights_states is not None:
self.traffic_lights_states = traffic_lights_states
Expand Down
10 changes: 6 additions & 4 deletions examples/area_drive/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def post_drive(self, drive_response):
remaining_npcs.append(npc)
self.npcs = remaining_npcs

def sync_drive(self, light_recurrent_states = None):
def sync_drive(self, light_recurrent_states = None, random_seed = None, api_model_version = None):
"""_summary_
updates the state of all NPCs inside the region (agents outside the region that are visible to inside NPCs are included to the call to drive but their state is not changed)
"""
Expand All @@ -67,14 +67,15 @@ def sync_drive(self, light_recurrent_states = None):
agent_states=agent_states,
recurrent_states=recurrent_states,
light_recurrent_states=light_recurrent_states,
get_birdview=DEBUG
get_birdview=DEBUG,
random_seed=random_seed
)

self.post_drive(drive_response=drive_response)

return drive_response.traffic_lights_states, drive_response.light_recurrent_states

async def async_drive(self, light_recurrent_states = None):
async def async_drive(self, light_recurrent_states = None, random_seed = None, api_model_version = None):
"""_summary_
async version:
updates the state of all NPCs inside the region (agents outside the region that are visible to inside NPCs are included to the call to drive but their state is not changed)
Expand All @@ -89,7 +90,8 @@ async def async_drive(self, light_recurrent_states = None):
agent_states=agent_states,
recurrent_states=recurrent_states,
light_recurrent_states=light_recurrent_states,
get_birdview=DEBUG
get_birdview=DEBUG,
random_seed=random_seed
)
self.post_drive(drive_response=drive_response)

Expand Down
174 changes: 91 additions & 83 deletions examples/large_map_example.py
Original file line number Diff line number Diff line change
@@ -1,99 +1,101 @@
import sys
sys.path.append('../')

import invertedai as iai
from area_drive.area_drive import AreaDriver, AreaDriverConfig

import argparse
import pygame
from tqdm import tqdm
import matplotlib.pyplot as plt
import time
import random

def main(args):
if args.model_version_drive == "None":
model_version = None
else:
model_version = args.model_version_drive
for i in range(args.num_simulations):
initialize_seed = random.randint(1,10000)
drive_seed = random.randint(1,10000)

map_center = tuple(args.map_center)

print(f"Call location info.")
location_info_response = iai.location_info(
location = args.location,
rendering_fov = args.fov,
rendering_center = map_center
)

print(f"Begin initialization.")
initialize_response = iai.utils.area_initialization(
location = args.location,
agent_density = args.agent_density,
scaling_factor = 1.0,
width = int(args.width/2),
height = int(args.height/2),
map_center = map_center
)
map_center = tuple(args.map_center)

print(f"Set up simulation.")
map_extent = max([args.width,args.height])
cfg = AreaDriverConfig(
location = args.location,
area_center = map_center,
area_fov = map_extent,
quadtree_capacity = args.capacity,
render_fov=args.fov,
pygame_window = args.display_sim,
show_quadtree = args.display_quadtree,
rendered_static_map = location_info_response.birdview_image.decode()
)

simulation = AreaDriver(
cfg = cfg,
location_response = location_info_response,
initialize_response = initialize_response
)
print(f"Call location info.")
location_info_response = iai.location_info(
location = args.location,
rendering_fov = args.fov,
rendering_center = map_center
)

if args.save_sim_gif:
rendered_static_map = location_info_response.birdview_image.decode()
scene_plotter = iai.utils.ScenePlotter(
rendered_static_map,
args.fov,
map_center,
location_info_response.static_actors,
resolution=(1080,1080),
dpi=200
print(f"Begin initialization.")
regions = iai.get_regions_default(
location = args.location,
total_num_agents = args.num_agents,
area_size = tuple([int(args.width/2),int(args.height/2)]),
map_center = map_center,
)
scene_plotter.initialize_recording(
agent_states=initialize_response.agent_states,
agent_attributes=initialize_response.agent_attributes,

response = iai.large_initialize(
location = args.location,
regions = regions,
random_seed = initialize_seed
)

print(f"Set up simulation.")
if args.save_sim_gif:
rendered_static_map = location_info_response.birdview_image.decode()
scene_plotter = iai.utils.ScenePlotter(
rendered_static_map,
args.fov,
map_center,
location_info_response.static_actors,
resolution=(2048,2048),
dpi=300
)
scene_plotter.initialize_recording(
agent_states=response.agent_states,
agent_attributes=response.agent_attributes,
traffic_light_states=response.traffic_lights_states
)

total_num_agents = len(simulation.agent_states)
print(f"Number of agents in simulation: {total_num_agents}")
total_num_agents = len(response.agent_states)
print(f"Number of agents in simulation: {total_num_agents}")

print(f"Begin stepping through simulation.")
for _ in tqdm(range(args.sim_length)):
simulation.drive()

if args.save_sim_gif: scene_plotter.record_step(simulation.agent_states,simulation.traffic_lights_states)
print(f"Begin stepping through simulation.")
agent_attributes = response.agent_attributes
for _ in tqdm(range(args.sim_length)):
response = iai.large_drive(
location = args.location,
agent_states = response.agent_states,
agent_attributes = agent_attributes,
recurrent_states = response.recurrent_states,
light_recurrent_states = response.light_recurrent_states,
random_seed = drive_seed,
api_model_version = model_version,
single_call_agent_limit = args.capacity,
async_api_calls = args.is_async
)

if args.save_sim_gif: scene_plotter.record_step(response.agent_states,response.traffic_lights_states)

if args.save_sim_gif:
print("Simulation finished, save visualization.")
# save the visualization to disk
fig, ax = plt.subplots(constrained_layout=True, figsize=(50, 50))
gif_name = f'large_map_example_{int(time.time())}_{total_num_agents}agents.gif'
scene_plotter.animate_scene(
output_name=gif_name,
ax=ax,
direction_vec=False,
velocity_vec=False,
plot_frame_number=True,
)
print("Done")
if args.save_sim_gif:
print("Simulation finished, save visualization.")
# save the visualization to disk
fig, ax = plt.subplots(constrained_layout=True, figsize=(50, 50))
plt.axis('off')
current_time = int(time.time())
gif_name = f'large_map_example_{current_time}_location-{args.location.split(":")[-1]}_density-{args.num_agents}_center-x{map_center[0]}y{map_center[1]}_width-{args.width}_height-{args.height}_initseed-{initialize_seed}_driveseed-{drive_seed}_modelversion-{model_version}.gif'
scene_plotter.animate_scene(
output_name=gif_name,
ax=ax,
direction_vec=False,
velocity_vec=False,
plot_frame_number=True,
)
print("Done")

if __name__ == '__main__':
argparser = argparse.ArgumentParser(description=__doc__)
argparser.add_argument(
'-D',
'--agent-density',
'-N',
'--num-agents',
metavar='D',
default=1,
type=int,
Expand Down Expand Up @@ -142,23 +144,29 @@ def main(args):
help=f"Center of the area to initialize",
default=[0,0]
)
argparser.add_argument(
'--is-async',
type=bool,
help=f"Whether to call drive asynchronously.",
default=True
)
argparser.add_argument(
'--save-sim-gif',
type=bool,
help=f"Should the simulation be saved with visualization tool.",
default=True
)
argparser.add_argument(
'--display-sim',
type=bool,
help=f"Should the in-simulation visualization be displayed.",
default=False
'--num-simulations',
type=int,
help=f"Number of simulations to run one after the other.",
default=1
)
argparser.add_argument(
'--display-quadtree',
type=bool,
help=f"If the in-simulation visualization is active, display the quadtree as well.",
default=False
'--model-version-drive',
type=str,
help=f"Version of the DRIVE model to use during the simulation.",
default="None"
)
args = argparser.parse_args()

Expand Down
2 changes: 2 additions & 0 deletions invertedai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from invertedai.api.blame import blame, async_blame
from invertedai.cosimulation import BasicCosimulation
from invertedai.utils import Jupyter_Render, IAILogger, Session
from invertedai.large.initialize import get_regions_in_grid, get_number_of_agents_per_region_by_drivable_area, get_regions_default, large_initialize
from invertedai.large.drive import large_drive

dev = strtobool(os.environ.get("IAI_DEV", "false"))
if dev:
Expand Down
44 changes: 20 additions & 24 deletions invertedai/api/initialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,16 @@ class InitializeResponse(BaseModel):

@validate_call
def initialize(
location: str,
agent_attributes: Optional[List[AgentAttributes]] = None,
states_history: Optional[List[List[AgentState]]] = None,
traffic_light_state_history: Optional[
List[TrafficLightStatesDict]
] = None,
get_birdview: bool = False,
location_of_interest: Optional[Tuple[float, float]] = None,
get_infractions: bool = False,
agent_count: Optional[int] = None,
random_seed: Optional[int] = None,
api_model_version: Optional[str] = None # Model version used for this API call
location: str,
agent_attributes: Optional[List[AgentAttributes]] = None,
states_history: Optional[List[List[AgentState]]] = None,
traffic_light_state_history: Optional[List[TrafficLightStatesDict]] = None,
get_birdview: bool = False,
location_of_interest: Optional[Tuple[float, float]] = None,
get_infractions: bool = False,
agent_count: Optional[int] = None,
random_seed: Optional[int] = None,
api_model_version: Optional[str] = None # Model version used for this API call
) -> InitializeResponse:
"""
Initializes a simulation in a given location, using a combination of **user-defined** and **sampled** agents.
Expand Down Expand Up @@ -206,18 +204,16 @@ def initialize(

@validate_call
async def async_initialize(
location: str,
agent_attributes: Optional[List[AgentAttributes]] = None,
states_history: Optional[List[List[AgentState]]] = None,
traffic_light_state_history: Optional[
List[TrafficLightStatesDict]
] = None,
get_birdview: bool = False,
location_of_interest: Optional[Tuple[float, float]] = None,
get_infractions: bool = False,
agent_count: Optional[int] = None,
random_seed: Optional[int] = None,
api_model_version: Optional[str] = None
location: str,
agent_attributes: Optional[List[AgentAttributes]] = None,
states_history: Optional[List[List[AgentState]]] = None,
traffic_light_state_history: Optional[List[TrafficLightStatesDict]] = None,
get_birdview: bool = False,
location_of_interest: Optional[Tuple[float, float]] = None,
get_infractions: bool = False,
agent_count: Optional[int] = None,
random_seed: Optional[int] = None,
api_model_version: Optional[str] = None
) -> InitializeResponse:
"""
The async version of :func:`initialize`
Expand Down
Loading
Loading