Compare commits
2 Commits
e45b083067
...
8f295a4531
| Author | SHA1 | Date |
|---|---|---|
|
|
8f295a4531 | |
|
|
705fa846da |
|
|
@ -127,6 +127,7 @@ class SUMOEdgeVSLEnvironment:
|
||||||
)
|
)
|
||||||
self.controlled_length_km = corridor_assets.controlled_length_m / 1000.0
|
self.controlled_length_km = corridor_assets.controlled_length_m / 1000.0
|
||||||
self.default_edge_speeds = self._build_default_segment_speeds()
|
self.default_edge_speeds = self._build_default_segment_speeds()
|
||||||
|
self.max_segment_speeds = self.default_edge_speeds.copy()
|
||||||
|
|
||||||
self.action_dims = [self.num_speed_actions] * self.num_edges
|
self.action_dims = [self.num_speed_actions] * self.num_edges
|
||||||
self.features_per_edge = 3
|
self.features_per_edge = 3
|
||||||
|
|
@ -345,14 +346,22 @@ class SUMOEdgeVSLEnvironment:
|
||||||
self._close_sumo()
|
self._close_sumo()
|
||||||
|
|
||||||
def _decode_action(self, action: np.ndarray) -> np.ndarray:
|
def _decode_action(self, action: np.ndarray) -> np.ndarray:
|
||||||
return np.array([self.speed_actions_ms[int(a)] for a in action])
|
requested_speeds = np.array([self.speed_actions_ms[int(a)] for a in action], dtype=float)
|
||||||
|
return np.minimum(requested_speeds, self.max_segment_speeds)
|
||||||
|
|
||||||
def _apply_vsl(self, edge_speeds: np.ndarray):
|
def _apply_vsl(self, edge_speeds: np.ndarray):
|
||||||
for idx, segment_id in enumerate(self.control_edges):
|
for idx, segment_id in enumerate(self.control_edges):
|
||||||
if idx in self.passive_segment_indices:
|
if idx in self.passive_segment_indices:
|
||||||
continue
|
continue
|
||||||
for edge_id in self.segment_edge_map.get(segment_id, []):
|
for edge_id in self.segment_edge_map.get(segment_id, []):
|
||||||
traci.edge.setMaxSpeed(edge_id, float(edge_speeds[idx]))
|
edge_info = self.parser.edge_info.get(edge_id)
|
||||||
|
original_edge_speed = (
|
||||||
|
float(edge_info.speed_limit)
|
||||||
|
if edge_info is not None
|
||||||
|
else float(edge_speeds[idx])
|
||||||
|
)
|
||||||
|
safe_speed = min(float(edge_speeds[idx]), original_edge_speed)
|
||||||
|
traci.edge.setMaxSpeed(edge_id, safe_speed)
|
||||||
|
|
||||||
def _get_edge_detector_data(self) -> Tuple[List[float], List[float], List[int], List[float]]:
|
def _get_edge_detector_data(self) -> Tuple[List[float], List[float], List[int], List[float]]:
|
||||||
speeds, occs, counts, valid_speeds = [], [], [], []
|
speeds, occs, counts, valid_speeds = [], [], [], []
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,12 @@ def parse_args():
|
||||||
default=None,
|
default=None,
|
||||||
help="Override SUMO simulation step length for evaluation only. Default: use training config.",
|
help="Override SUMO simulation step length for evaluation only. Default: use training config.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--route-file",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="Override SUMO route/flow file for evaluation only. Supports absolute paths or project-relative paths.",
|
||||||
|
)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -221,6 +227,14 @@ def deep_merge_dicts(base: dict, override: dict) -> dict:
|
||||||
return merged
|
return merged
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_project_path(path_str: Optional[str]) -> Optional[str]:
|
||||||
|
if not path_str:
|
||||||
|
return None
|
||||||
|
if os.path.isabs(path_str):
|
||||||
|
return path_str
|
||||||
|
return os.path.abspath(os.path.join(PROJECT_ROOT, path_str))
|
||||||
|
|
||||||
|
|
||||||
def resolve_model_load_path(model_name: str, checkpoint_dir: str) -> str:
|
def resolve_model_load_path(model_name: str, checkpoint_dir: str) -> str:
|
||||||
if model_name in {"ppo", "gpro", "appo", "mappo", "tcamappo", "dcmappo", "dqn"}:
|
if model_name in {"ppo", "gpro", "appo", "mappo", "tcamappo", "dcmappo", "dqn"}:
|
||||||
best_path = os.path.join(checkpoint_dir, "model_best.pt")
|
best_path = os.path.join(checkpoint_dir, "model_best.pt")
|
||||||
|
|
@ -482,6 +496,7 @@ def evaluate_single_model(
|
||||||
end_time: int,
|
end_time: int,
|
||||||
with_gui: bool,
|
with_gui: bool,
|
||||||
step_length: Optional[float],
|
step_length: Optional[float],
|
||||||
|
route_file: Optional[str],
|
||||||
) -> Tuple[pd.DataFrame, pd.DataFrame, dict]:
|
) -> Tuple[pd.DataFrame, pd.DataFrame, dict]:
|
||||||
config = load_config_for_checkpoint(checkpoint_dir, fallback_config_path) if checkpoint_dir else load_config_for_checkpoint("", fallback_config_path)
|
config = load_config_for_checkpoint(checkpoint_dir, fallback_config_path) if checkpoint_dir else load_config_for_checkpoint("", fallback_config_path)
|
||||||
runtime_config = copy.deepcopy(config)
|
runtime_config = copy.deepcopy(config)
|
||||||
|
|
@ -497,6 +512,8 @@ def evaluate_single_model(
|
||||||
runtime_config["sumo"]["gui"] = with_gui
|
runtime_config["sumo"]["gui"] = with_gui
|
||||||
if step_length is not None:
|
if step_length is not None:
|
||||||
runtime_config["sumo"]["step_length"] = step_length
|
runtime_config["sumo"]["step_length"] = step_length
|
||||||
|
if route_file is not None:
|
||||||
|
runtime_config["sumo"]["route_file"] = route_file
|
||||||
runtime_config.setdefault("runtime", {})["output_dir"] = os.path.join(output_dir, model_name)
|
runtime_config.setdefault("runtime", {})["output_dir"] = os.path.join(output_dir, model_name)
|
||||||
runtime_config["runtime"]["metrics_subdir"] = "eval_sumo_metrics"
|
runtime_config["runtime"]["metrics_subdir"] = "eval_sumo_metrics"
|
||||||
runtime_config["runtime"]["collect_detector_cells"] = True
|
runtime_config["runtime"]["collect_detector_cells"] = True
|
||||||
|
|
@ -631,11 +648,12 @@ def evaluate_single_model(
|
||||||
"end_time": effective_end_time,
|
"end_time": effective_end_time,
|
||||||
"with_gui": with_gui,
|
"with_gui": with_gui,
|
||||||
"step_length": runtime_config["sumo"].get("step_length"),
|
"step_length": runtime_config["sumo"].get("step_length"),
|
||||||
|
"route_file": runtime_config["sumo"].get("route_file", ""),
|
||||||
}
|
}
|
||||||
return step_df, edge_df, detector_df, meta
|
return step_df, edge_df, detector_df, meta
|
||||||
|
|
||||||
|
|
||||||
def evaluate_worker(task: Tuple[str, Optional[str], str, str, int, Optional[int], Optional[int], bool, Optional[float]]):
|
def evaluate_worker(task: Tuple[str, Optional[str], str, str, int, Optional[int], Optional[int], bool, Optional[float], Optional[str]]):
|
||||||
return evaluate_single_model(*task)
|
return evaluate_single_model(*task)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -873,6 +891,9 @@ def print_summary(summary_df: pd.DataFrame, output_dir: str):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
route_file = resolve_project_path(args.route_file)
|
||||||
|
if route_file is not None and not os.path.isfile(route_file):
|
||||||
|
raise FileNotFoundError(f"Custom route file not found: {route_file}")
|
||||||
checkpoint_root = resolve_checkpoint_root(args.checkpoint_root)
|
checkpoint_root = resolve_checkpoint_root(args.checkpoint_root)
|
||||||
model_dirs = discover_model_dirs(checkpoint_root, args.models)
|
model_dirs = discover_model_dirs(checkpoint_root, args.models)
|
||||||
if not model_dirs:
|
if not model_dirs:
|
||||||
|
|
@ -904,6 +925,7 @@ def main():
|
||||||
args.end_time,
|
args.end_time,
|
||||||
args.with_gui,
|
args.with_gui,
|
||||||
args.step_length,
|
args.step_length,
|
||||||
|
route_file,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -922,6 +944,7 @@ def main():
|
||||||
args.end_time,
|
args.end_time,
|
||||||
args.with_gui,
|
args.with_gui,
|
||||||
args.step_length,
|
args.step_length,
|
||||||
|
route_file,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue