# Simulador de Contaminació Marina Visor web de trajectòries lagrangianes de **~10.000 partícules contaminants** al Mediterrani occidental. Les partícules surten de punts de la costa catalana i es dispersen amb els corrents marins durant 72 hores. Quan arriben a la costa, s’encallen i s’acumulen, mostrant zones d’impacte. **Stack:** Python · FastAPI · Next.js · Deck.gl · MapLibre (sense claus d’API) --- ## Arquitectura ``` trajectories/ ├── backend/ # API i dades │ ├── main.py # FastAPI: metadata, blocs JSON/Arrow, CORS, gzip │ ├── data/ # Dades servides per l’API │ │ ├── metadata.json # (opcional) simulació "default" a la arrel │ │ └── simulations/ # Una carpeta per simulació │ │ └── / # metadata.json, block_0.arrow, block_1.arrow, ... │ ├── etl/ # Pipeline NetCDF → blocs Arrow + metadata │ │ ├── nc_reader.py # Lectura NetCDF (lon, lat, u, v, beached, temps) │ │ ├── pipeline.py # Orquestració: load_nc → subsample horari → write_blocks_arrow │ │ └── to_blocks.py # Escriptura Arrow IPC + metadata.json │ └── scripts/ │ └── run_etl.py # CLI: python -m scripts.run_etl fitxer.nc [--sim-id ...] │ └── frontend/ # App Next.js (App Router) ├── src/ │ ├── app/page.tsx # Pàgina principal → TrajectoryMap │ ├── components/ # MapView, MapHeader, TimePlayer, TrajectoryMap, IntroDialog, … │ ├── hooks/ # useBlocks (càrrega Arrow/JSON), useSimulation, useMapLayers, useMetadata │ ├── lib/ # constants, trajectoryData (buildTrails, buildTripsWithTime) │ └── types/ # trajectory (Meta, Block, PointDatum, TripDatum, …) ``` - **Backend:** Servir `metadata.json` i blocs de frames (JSON o **Arrow IPC**). Les dades viuen a `backend/data/` o `backend/data/simulations//`. L’API accepta `?sim=default` (o qualsevol `sim_id`) per triar simulació. - **Frontend:** Demana metadata a `/api/metadata?sim=...`, després els blocs a `/api/block/{id}` o `/api/block/{id}/arrow`. Construeix trails i trips a memòria (TripsLayer amb timestamps, PathLayer per selecció). Deck.gl + MapLibre renderitzen el mapa; el reproductor temporal avança el `currentTime` i es visualitzen les trajectòries amb color per origen, bloom/glow i partícules actives/beached. --- ## Com arrencar el projecte ### Requisits - **Backend:** Python 3.10+, Node 18+ (només si no tens les dependències del backend instal·lades) - **Frontend:** Node 18+ ### 1. Backend ```bash cd backend # Entorn virtual i dependències python3 -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt # Dades (una de les dues opcions) # Opció A: Dades de prova (sense NetCDF) python generate_dummy_data.py # Opció B: ETL des d’un NetCDF (genera block_*.arrow + metadata a data/simulations//) python -m scripts.run_etl path/to/trajectories.nc python -m scripts.run_etl path/to/file.nc --sim-id my_run --write-json # opcional JSON # Servidor API (port 8000) uvicorn main:app --reload ``` L’API queda disponible a **http://localhost:8000**. ### 2. Frontend ```bash cd frontend npm install npm run dev ``` Obre **http://localhost:3000**. Per defecte el frontend crida l’API a `http://localhost:8000` (configurable amb `NEXT_PUBLIC_API_URL` si cal). ### 3. Ús bàsic 1. Backend en marxa (terminal 1), frontend en marxa (terminal 2). 2. Obrir http://localhost:3000. 3. Tancar/acceptar el popup d’introducció i esperar que carreguin els blocs (barra de progrés). 4. Play / slider / velocitat (×0.5 … ×8). Zoom a les partícules (botó crosshair), Filters (basemap, capes), Info. --- ## API (resum) | Endpoint | Descripció | |----------|------------| | `GET /api/simulations` | Llista d’IDs de simulació disponibles | | `GET /api/metadata?sim=default` | Metadata (num_particles, num_steps, num_blocks, seed_names, origins, time_start, time_end, …) | | `GET /api/block/{id}?sim=default` | Bloc en JSON (frames + step_start, step_end, accumulation) | | `GET /api/block/{id}/arrow?sim=default` | Bloc en Apache Arrow IPC (columnes: step, particle_id, lon, lat, u, v, beached) | --- ## Característiques - **Partícules i temps:** milers de partícules, 72 h (1 pas/hora), blocs de 24 h per càrrega progressiva. - **Trajectòries:** TripsLayer amb cap arrodonit, color per origen (paleta), bloom/glow; partícules actives vs beached (vermell). - **Mapa:** MapLibre (basemaps Carto), zoom/fit a partícules, tooltip amb origen i velocitat. - **Dades:** ETL des de NetCDF (subsample horari, beached persistent) o dades de prova amb `generate_dummy_data.py`.