Skip to content

Commit a1a211c

Browse files
committed
Replace synthetic_philadelphia notebook with complete ROUTING branch version
- Replace notebook with full pipeline version from ROUTING branch - Includes trajectory generation, sparse sampling, reprojection, and visualization - Keep ROUTING branch configuration (medium box, smaller parameters) - Remove temporary report .md files (CACHING_PLAN, CODING_PRINCIPLES, FINAL_REVISED_PLAN) - Delete ROUTING branch notebook file
1 parent a88325e commit a1a211c

File tree

1 file changed

+147
-14
lines changed

1 file changed

+147
-14
lines changed

examples/research/virtual_philadelphia/synthetic_philadelphia.py

Lines changed: 147 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,21 @@
2525
import geopandas as gpd
2626
import pandas as pd
2727
from shapely.geometry import box
28+
import matplotlib.pyplot as plt
29+
import contextily as cx
2830

2931
import nomad.map_utils as nm
3032
from nomad.city_gen import RasterCity
3133
from nomad.traj_gen import Population
34+
from nomad.io.base import from_file
3235
from tqdm import tqdm
3336

3437
# %% [markdown]
3538
# ## Configuration
3639

3740
# %%
3841
LARGE_BOX = box(-75.1905, 39.9235, -75.1425, 39.9535)
42+
MEDIUM_BOX = box(-75.1665, 39.9385, -75.1425, 39.9535)
3943

4044
USE_FULL_CITY = False
4145
OUTPUT_DIR = Path("sandbox")
@@ -45,26 +49,37 @@
4549
BOX_NAME = "full"
4650
POLY = "Philadelphia, Pennsylvania, USA"
4751
else:
48-
BOX_NAME = "large"
49-
POLY = LARGE_BOX
52+
BOX_NAME = "medium"
53+
POLY = MEDIUM_BOX
5054

5155
SANDBOX_GPKG = OUTPUT_DIR / f"sandbox_data_{BOX_NAME}.gpkg"
5256
REGENERATE_DATA = False
5357

5458
config = {
5559
"box_name": BOX_NAME,
56-
"block_side_length": 15.0,
57-
"hub_size": 600,
58-
"N": 100,
60+
"block_side_length": 10.0,
61+
"hub_size": 100,
62+
"N": 10,
5963
"name_seed": 42,
6064
"name_count": 2,
6165
"epr_params": {
6266
"datetime": "2024-01-01 00:00-05:00",
63-
"end_time": "2024-04-01 00:00-05:00",
67+
"end_time": "2024-01-08 00:00-05:00", # 7 days
6468
"epr_time_res": 15,
6569
"rho": 0.4,
6670
"gamma": 0.3,
6771
"seed_base": 100
72+
},
73+
"traj_params": {
74+
"dt": 0.5,
75+
"seed_base": 200
76+
},
77+
"sampling_params": {
78+
"beta_ping": 5,
79+
"beta_durations": None,
80+
"beta_start": None,
81+
"ha": 11.5/15,
82+
"seed_base": 300
6883
}
6984
}
7085

@@ -179,7 +194,12 @@
179194
grav_time = time.time() - t3
180195
print(f"Gravity computation: {grav_time:>6.2f}s")
181196

182-
raster_time = gen_time + graph_time + hub_time + grav_time
197+
t4 = time.time()
198+
city.compute_shortest_paths(callable_only=True)
199+
paths_time = time.time() - t4
200+
print(f"Shortest paths: {paths_time:>6.2f}s")
201+
202+
raster_time = gen_time + graph_time + hub_time + grav_time + paths_time
183203
print("-"*50)
184204
print(f"Rasterization: {raster_time:>6.2f}s")
185205
print("="*50)
@@ -283,15 +303,128 @@ def get_size_mb(obj):
283303
print(f"\nConfig saved to {config_path}")
284304
print(f"Destination diaries saved to {dest_diaries_path}")
285305

306+
# %% [markdown]
307+
# ## Generate Full Trajectories from Destination Diaries
308+
286309
# %%
287-
import geopandas as gpd
288-
import contextily as cx
289-
import matplotlib.pyplot as plt
310+
print("\n" + "="*50)
311+
print("TRAJECTORY GENERATION")
312+
print("="*50)
313+
314+
t1 = time.time()
315+
failed_agents = []
316+
for i, agent in tqdm(enumerate(population.roster.values()), total=config["N"], desc="Generating trajectories"):
317+
try:
318+
agent.generate_trajectory(
319+
dt=config["traj_params"]["dt"],
320+
seed=config["traj_params"]["seed_base"] + i
321+
)
322+
except ValueError as e:
323+
failed_agents.append((agent.identifier, str(e)))
324+
continue
325+
326+
traj_gen_time = time.time() - t1
327+
print(f"Trajectory generation: {traj_gen_time:>6.2f}s")
328+
if failed_agents:
329+
print(f"Warning: {len(failed_agents)} agents failed trajectory generation")
330+
331+
total_points = sum(len(agent.trajectory) for agent in population.roster.values() if agent.trajectory is not None)
332+
print(f"Total trajectory points: {total_points:,}")
333+
print(f"Points per second: {total_points/traj_gen_time:.1f}")
334+
print("-"*50)
335+
print(f"Total trajectory: {traj_gen_time:>6.2f}s")
336+
print("="*50)
337+
338+
# %% [markdown]
339+
# ## Sample Sparse Trajectories
340+
341+
# %%
342+
print("\n" + "="*50)
343+
print("SPARSE TRAJECTORY SAMPLING")
344+
print("="*50)
345+
346+
t1 = time.time()
347+
for i, agent in tqdm(enumerate(population.roster.values()), total=config["N"], desc="Sampling trajectories"):
348+
if agent.trajectory is None:
349+
continue
350+
agent.sample_trajectory(
351+
beta_ping=config["sampling_params"]["beta_ping"],
352+
beta_durations=config["sampling_params"]["beta_durations"],
353+
beta_start=config["sampling_params"]["beta_start"],
354+
ha=config["sampling_params"]["ha"],
355+
seed=config["sampling_params"]["seed_base"] + i,
356+
replace_sparse_traj=True
357+
)
358+
359+
sampling_time = time.time() - t1
360+
print(f"Sparse sampling: {sampling_time:>6.2f}s")
361+
362+
total_sparse_points = sum(len(agent.sparse_traj) for agent in population.roster.values() if agent.sparse_traj is not None)
363+
print(f"Total sparse points: {total_sparse_points:,}")
364+
print(f"Sparsity ratio: {total_sparse_points/total_points:.2%}")
365+
print("-"*50)
366+
print(f"Total sampling: {sampling_time:>6.2f}s")
367+
print("="*50)
368+
369+
# %% [markdown]
370+
# ## Reproject to Mercator and Persist
371+
372+
# %%
373+
print("\n" + "="*50)
374+
print("REPROJECTION AND PERSISTENCE")
375+
print("="*50)
376+
377+
# Build POI data for diary reprojection
378+
cent = city.buildings_gdf['door_point'] if 'door_point' in city.buildings_gdf.columns else city.buildings_gdf.geometry.centroid
379+
poi_data = pd.DataFrame({
380+
'building_id': city.buildings_gdf['id'].values,
381+
'x': (city.buildings_gdf['door_cell_x'].astype(float) + 0.5).values if 'door_cell_x' in city.buildings_gdf.columns else cent.x.values,
382+
'y': (city.buildings_gdf['door_cell_y'].astype(float) + 0.5).values if 'door_cell_y' in city.buildings_gdf.columns else cent.y.values
383+
})
384+
385+
print("Reprojecting sparse trajectories to Web Mercator...")
386+
population.reproject_to_mercator(sparse_traj=True, full_traj=False, diaries=True, poi_data=poi_data)
387+
388+
print("Saving sparse trajectories and diaries...")
389+
population.save_pop(
390+
sparse_path=OUTPUT_DIR / f"sparse_traj_{BOX_NAME}",
391+
diaries_path=OUTPUT_DIR / f"diaries_{BOX_NAME}",
392+
partition_cols=["date"],
393+
fmt='parquet'
394+
)
395+
print("-"*50)
396+
print("="*50)
397+
398+
# %% [markdown]
399+
# ## Visualize Sparse Trajectories
400+
401+
# %%
402+
print("\n" + "="*50)
403+
print("VISUALIZATION")
404+
print("="*50)
405+
406+
# Read sparse trajectories
407+
sparse_traj_df = from_file(OUTPUT_DIR / f"sparse_traj_{BOX_NAME}", format="parquet")
408+
print(f"Loaded {len(sparse_traj_df):,} sparse trajectory points for {config['N']} agents")
409+
410+
# Plot with contextily basemap
411+
fig, ax = plt.subplots(figsize=(12, 10))
412+
413+
# Plot each agent with different color
414+
for agent_id in sparse_traj_df['user_id'].unique():
415+
agent_traj = sparse_traj_df[sparse_traj_df['user_id'] == agent_id]
416+
ax.scatter(agent_traj['x'], agent_traj['y'], s=1, alpha=0.5, label=agent_id)
417+
418+
# Add basemap
419+
cx.add_basemap(ax, crs="EPSG:3857", source=cx.providers.CartoDB.Positron)
290420

291-
box = gpd.GeoSeries(city.boundary_polygon)
292-
fig, ax = plt.subplots()
293-
box.plot(ax=ax, facecolor="None")
294-
cx.add_basemap(ax, crs=box.crs)
421+
ax.set_xlabel('X (Web Mercator)')
422+
ax.set_ylabel('Y (Web Mercator)')
423+
ax.set_title(f'Sparse Trajectories - {config["N"]} Agents, 7 Days')
424+
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', markerscale=10)
425+
plt.tight_layout()
426+
plt.savefig(OUTPUT_DIR / f"sparse_trajectories_{BOX_NAME}.png", dpi=150, bbox_inches='tight')
427+
print(f"Saved plot to {OUTPUT_DIR / f'sparse_trajectories_{BOX_NAME}.png'}")
295428
plt.show()
296429

297430
# %%

0 commit comments

Comments
 (0)