Spaces:
Sleeping
Sleeping
Download backend/src/world_model.py from agaroth/causalis-backend: direct link, hf CLI and curl.
- Browser
- Download file 3.73 kB
-
https://huggingface.co/spaces/agaroth/causalis-backend/resolve/main/backend/src/world_model.py
- Command line
-
hf download hf://spaces/agaroth/causalis-backend/backend/src/world_model.py
-
curl -L -o world_model.py https://huggingface.co/spaces/agaroth/causalis-backend/resolve/main/backend/src/world_model.py
3.73 kB
| import json | |
| from pathlib import Path | |
| import geopandas as gpd | |
| import networkx as nx | |
| import pandas as pd | |
| from shapely.geometry import Point, mapping | |
| from src.data_loader import load_ports, load_chokepoints, load_routes, load_vessels | |
| class MaritimeWorldModel: | |
| def __init__(self): | |
| self._ports = load_ports() | |
| self._chokepoints = load_chokepoints() | |
| self._routes = load_routes() | |
| self._vessels = load_vessels() | |
| self._graph = self._build_graph() | |
| def _build_graph(self) -> nx.Graph: | |
| graph = nx.Graph() | |
| for _, port in self._ports.iterrows(): | |
| graph.add_node(port["id"], name=port["name"], latitude=port["latitude"], longitude=port["longitude"]) | |
| for _, route in self._routes.iterrows(): | |
| graph.add_edge( | |
| route["origin_port_id"], | |
| route["destination_port_id"], | |
| weight=route["distance_nm"], | |
| route_id=route["id"], | |
| route_name=route["name"], | |
| transit_days=route["transit_days"], | |
| chokepoints_transited=route["chokepoints_transited"], | |
| ) | |
| return graph | |
| def get_port_graph(self) -> nx.Graph: | |
| return self._graph | |
| def get_chokepoints(self) -> gpd.GeoDataFrame: | |
| return self._chokepoints | |
| def get_routes(self) -> pd.DataFrame: | |
| return self._routes | |
| def get_connectivity(self, port_id: str) -> list: | |
| if port_id not in self._graph: | |
| return [] | |
| return list(self._graph.neighbors(port_id)) | |
| def get_chokepoints_in_region(self, min_lat: float, max_lat: float, min_lon: float, max_lon: float) -> gpd.GeoDataFrame: | |
| centroids = self._chokepoints.geometry.centroid | |
| mask = ( | |
| (centroids.y >= min_lat) & (centroids.y <= max_lat) & | |
| (centroids.x >= min_lon) & (centroids.x <= max_lon) | |
| ) | |
| return self._chokepoints[mask].copy() | |
| def get_shortest_path(self, origin_id: str, destination_id: str) -> list: | |
| if origin_id == destination_id: | |
| return [origin_id] | |
| try: | |
| return nx.shortest_path(self._graph, origin_id, destination_id, weight="weight") | |
| except nx.NetworkXNoPath: | |
| return [] | |
| def get_path_distance(self, origin_id: str, destination_id: str) -> float: | |
| path = self.get_shortest_path(origin_id, destination_id) | |
| if len(path) < 2: | |
| return 0.0 | |
| total = 0.0 | |
| for i in range(len(path) - 1): | |
| edge_data = self._graph.edges[path[i], path[i + 1]] | |
| total += edge_data["weight"] | |
| return total | |
| def to_geojson(self, entity_type: str) -> dict: | |
| if entity_type == "ports": | |
| features = [] | |
| for _, port in self._ports.iterrows(): | |
| feature = { | |
| "type": "Feature", | |
| "properties": { | |
| "id": port["id"], | |
| "name": port["name"], | |
| "country": port["country"], | |
| "type": port["type"], | |
| "annual_teu": int(port["annual_teu"]), | |
| "max_draft_meters": float(port["max_draft_meters"]), | |
| "typical_dwell_hours": int(port["typical_dwell_hours"]), | |
| }, | |
| "geometry": mapping(Point(port["longitude"], port["latitude"])), | |
| } | |
| features.append(feature) | |
| return {"type": "FeatureCollection", "features": features} | |
| elif entity_type == "chokepoints": | |
| return json.loads(self._chokepoints.to_json()) | |
| else: | |
| raise ValueError(f"Unknown entity type: {entity_type}") | |