---
name: "sentinel-2-water"
version: 4.0.0
description: "Generates Google Earth Engine JavaScript script for Sentinel-2 water body detection using MNDWI (Modified Normalized Difference Water Index) from AOI and event date."
model_tier: 2
triggers:
  - "sentinel-2 water detection"
  - "mndwi script"
  - "gee water mapping"
  - "alluvione script gee"
  - "water body detection"
tools:
  - exec
  - web_search
  - web_extract
  - read_file

---

# 🛰️ Sentinel-2 Water Detection — MNDWI (Google Earth Engine)

## Scopo

Genera uno script JavaScript pronto all'uso per **Google Earth Engine (GEE)** che esegue la mappatura delle acque superficiali usando l'indice **MNDWI** da immagini Sentinel-2.

L'utente deve incollare lo script generato nel Code Editor di GEE (`code.earthengine.google.com`).

## Input Richiesti

| Parametro | Formato | Esempio |
|---|---|---|
| **AOI** | GeoJSON (Multi)Polygon, EPSG:4326 | `{"type":"Polygon","coordinates":[[[41.5,4.4],[41.9,4.4],...]]}` |
| **Event Date** | `YYYY-MM-DD` | `2023-10-01` |

## Output

- Script GEE JavaScript (stampato in chat o salvato su file nella directory `generated/`)
- Include: ricerca immagini, debug conteggio, calcolo MNDWI, **4 layer di visualizzazione**

## Workflow Skill

1. **Ricevi** AOI (da file GeoJSON o stringa) + event date
2. **Valuta dimensione AOI** — se > 80×80 km, dividi in MultiPolygon (le tile S2 sono 100×100 km)
3. **Genera** script GEE personalizzato con coordinate reali, cloud filter, date corrette
4. **Salva** script in `~/.hermes/generated/sentinel2_water_<data>.js`
5. **Consegna** all'utente:
   - **Utente su stesso PC** → MEDIA:path via Telegram
   - **Utente su altro PC** → HTTP server (vedi Consegna Script §2)
6. **Attendi feedback** — se count=0, alza cloud filter (Africa: 50%+), allarga finestra date

## Script Template v4 (Finale — MultiPolygon Melkadida)

Template finale con coordinate reali, 5 layer di debug, statistiche, export commentato.
**Default cloud filter: 50% per Africa tropicale.** Se zona temperata, stringi a 20%.

```javascript
// 🛰️ Sentinel-2 Water Detection — Friz 🦎
// Evento: 2023-11-03 | Cloud: < 50% (Africa tropicale)

var aoi = ee.Geometry.MultiPolygon([
  [[[41.568,4.643],[41.948,4.643],[41.948,4.409],[41.568,4.409]]],
  [[[41.948,4.643],[42.200,4.643],[42.200,4.409],[41.948,4.409]]],
  [[[41.568,4.409],[41.948,4.409],[41.948,4.200],[41.568,4.200]]]
]);

Map.centerObject(aoi, 10);
Map.addLayer(aoi, {color: 'red'}, 'AOI');

// ─── Sentinel-2 Collection: in Africa parti da 50% cloud, non 20% ───
var dataset = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
  .filterBounds(aoi)
  .filterDate('2023-10-03', '2023-12-03')
  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 50));

var count = dataset.size();
print('Immagini trovate:', count);

// Prende la migliore disponibile
var image = dataset.sort('CLOUDY_PIXEL_PERCENTAGE').first();
var clipped = image.clip(aoi);

print('Data:', image.date());
print('Cloud %:', image.get('CLOUDY_PIXEL_PERCENTAGE'));
print('Scene ID:', image.id());

// Se count=0: prova L1C con 80% cloud
if (count.eq(0)) {
  var l1c = ee.ImageCollection('COPERNICUS/S2_HARMONIZED')
    .filterBounds(aoi).filterDate('2023-10-03', '2023-12-03')
    .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 80)).first();
  clipped = l1c.clip(aoi);
  print('⚠ Fallback a L1C (cloud < 80%)');
}

// ─── Layer 1: True Color ───
Map.addLayer(clipped,
  {bands: ['B4','B3','B2'], min:0, max:3000, gamma:1.4},
  '1. True Color');

// ─── Layer 2: False Color ───
Map.addLayer(clipped,
  {bands: ['B12','B8','B4'], min:0, max:4000, gamma:1.2},
  '2. False Color SWIR/NIR/R');

// ─── Layer 3: MNDWI ───
var mndwi = clipped.normalizedDifference(['B3','B11']).rename('MNDWI');
Map.addLayer(mndwi,
  {min:-0.5, max:0.5, palette:['brown','white','blue']},
  '3. MNDWI (acqua = blu)');

// ─── Layer 4: MNDWI dettaglio ───
Map.addLayer(mndwi,
  {min:-0.3, max:0.3, palette:['ff0000','ffffff','0000ff']},
  '4. MNDWI dettaglio');

// ─── Water Mask ───
var water = mndwi.gt(0).rename('water_mask');
Map.addLayer(water,
  {palette:['000000','0000ff']},
  '5. Water Mask (MNDWI>0)');

// ─── STATISTICHE ───
var stats = water.reduceRegion({
  reducer: ee.Reducer.sum(),
  geometry: aoi, scale: 10, bestEffort: true, maxPixels: 1e9
});
var waterPx = ee.Number(stats.get('water_mask'));
print('Area acqua (kmq):', waterPx.multiply(100).divide(1e6));
print('Copertura acqua %:', waterPx.divide(aoi.area()).multiply(100));
```

## Fallback Strategy (Cloud Filter + Collection)

Il filtro nuvole può dare 0 immagini in zone nuvolose (es. Etiopia/Kenya in stagione umida).

```
1. PROVA: SR_HARMONIZED con CLOUD < 20%
2. SE 0 IMMAGINI: aumenta CLOUD a 50%
3. SE ANCORA 0: passa a COPERNICUS/S2_HARMONIZED (L1C) con CLOUD < 80%
4. SE ANCORA 0: raddoppia finestra date (±60gg invece di ±30gg)
```

**Regola d'oro: in Africa tropicale, parti da 50% cloud, non 20%.**

## Esportazione su Hard Disk (da GEE → QGIS)

Dopo aver validato visivamente i layer:

### Metodo 1 — Export su Google Drive (consigliato)

Aggiungi alla fine dello script (scommenta l'export che ti serve):

```javascript
// ─── EXPORT SU GOOGLE DRIVE ───
// Togli i // dall'export che vuoi e clicca Run

// Esporta MNDWI raster (valori continui)
// Export.image.toDrive({
//   image: mndwi.float(),
//   description: 'MNDWI_' + image.id().replace('/','_'),
//   folder: 'GEE_exports', region: aoi, scale: 10,
//   crs: 'EPSG:4326', maxPixels: 1e9, fileFormat: 'GeoTIFF'
// });

// Esporta Water Mask binaria (0/1)
// Export.image.toDrive({
//   image: water.int8(),
//   description: 'WaterMask_' + image.id().replace('/','_'),
//   folder: 'GEE_exports', region: aoi, scale: 10,
//   crs: 'EPSG:4326', maxPixels: 1e9, fileFormat: 'GeoTIFF'
// });

// Esporta True Color RGB
// Export.image.toDrive({
//   image: clipped.select(['B4','B3','B2']).uint16(),
//   description: 'TrueColor_' + image.id().replace('/','_'),
//   folder: 'GEE_exports', region: aoi, scale: 10,
//   crs: 'EPSG:4326', maxPixels: 1e9, fileFormat: 'GeoTIFF'
// });
```

**Procedura:**
1. Togli i `//` dall'export che vuoi attivare (UNO alla volta!)
2. Clicca **Run**
3. Vai al tab **Tasks** (destra)
4. Clicca **Run** sul task → scegli Google Drive
5. I file arrivano in Google Drive > cartella `GEE_exports/`
6. Scarica da Google Drive e carica in QGIS (Layer → Add Layer → Add Raster Layer)

### Metodo 2 — Export diretto (solo GEE a pagamento)

Usa Export.image.toAsset() per salvare nel tuo asset GEE, poi scarica da lì.

## Note

- **4 layer di default**: True Color, False Color SWIR/NIR/G (acqua scura), MNDWI binario (blu), MNDWI continuo (regolazione soglia), Zoom dettaglio.
- La maschera acqua ha soglia MNDWI > 0. Regola con `.gt(0.1)` per acque chiare o `.gt(-0.1)` per acque torbide/fluviali.
- **Debug immagini zero**: stampa `count` — se 0, allarga finestra date o abbassa filtro cloud.
- Periodo di ricerca: ±30 giorni da event date (modificabile in `filterDate`).
- Per acque torbide/fluviali, il False Color (Layer 2) è lo strumento migliore per validazione visiva.
- **Collect** stat: usa `print('Pixel acqua:', waterPixels)` con `reduceRegion` per area stimata.
- Non usare solo `ee.Geometry.Polygon` per AOI grandi — potrebbero coprire più tile S2. Usa `ee.Geometry.MultiPolygon` o unisci rettangoli vicini in un'unica geometria.

## Consegna Script

**REGOLA PRIORITARIA (preferenza esplicita dell'utente: "questa forma è la migliore, ricordatelo per il futuro"):**
- **PC diverso** → SEMPRE HTTP server (vedi `references/delivery-cross-pc.md`)
- **Stesso PC** → Telegram MEDIA:path

### 1. HTTP Server (preferito — utente su altro PC)
Salva lo script e avvia un server temporaneo:

```bash
write_file(path="~/.hermes/generated/sentinel2_water_<data>.js", content="...")
# Poi avvia server:
python3 -m http.server 8088 --directory ~/.hermes/generated &
```

Trova l'IP del ProBook (Tailscale, se disponibile):
```bash
ip addr show tailscale0 2>/dev/null | grep inet | awk '{print $2}' | cut -d/ -f1
```

L'utente apre `http://<tailscale-ip>:8088/sentinel2_water_<data>.js` dal browser dell'altro PC.

Uccidere il server a consegna completata:
```bash
pkill -f 'http.server.*8088'
```

### 2. Telegram (file attachment — solo se utente è sullo stesso PC)
Usa `write_file` per salvare in `~/.hermes/generated/` poi includi `MEDIA:path` nel messaggio.
**NON usare questo metodo se l'utente è su un altro PC — non può vedere il file.**
Salva sempre una copia su ~/.hermes/generated/ anche se consegni via Telegram, così lo script è recuperabile via HTTP.

## Pitfalls

### SR_HARMONIZED ha meno immagini in Africa
La collezione `COPERNICUS/S2_SR_HARMONIZED` è processata a livello atmosferico, quindi ha meno passate disponibili rispetto alla `COPERNICUS/S2` (L1C). In Etiopia/Somalia è comune trovare 0 immagini SR anche con cloud 50% — il fallback automatico a L1C è essenziale.

### Cloud filter troppo stretto in zone tropicali
In Etiopia, Kenya, Somalia la stagione umida (ottobre-dicembre) ha copertura nuvolosa costante >60%. Partire da cloud <20% dà **sempre 0 immagini**. Usare <50% come default iniziale, poi stringere solo se necessario.

### GeoJSON non sempre utilizzabile direttamente
Il file `.geojson` può contenere un `Feature` con geometria annidata. Estrarre sempre le coordinate esatte. Se è un `MultiPolygon`, GEE vuole `ee.Geometry.MultiPolygon(...)`, non `ee.Geometry.Polygon(...)`.

### AOI grande copre più tile S2
Le tile Sentinel-2 sono 100×100 km. Se l'AOI supera queste dimensioni, usare MultiPolygon per unire più rettangoli contigui — GEE fa il mosaic automaticamente quando si usa `image.clip(aoi)` sulla geometria composita.

## Riferimenti Skill Correlate

- `sentinel-1-flood-v3` — mappatura alluvioni SAR (funziona anche sotto le nuvole)
- `flood-riverine` — flood hazard HAND + GRASS workflow
- `site-planning` — camp assessment umanitario

## Riferimenti

- `references/sentinel-mndwi.md` — metodologia MNDWI e confronto con altri indici
- `references/4-layer-visualization.md` — strategia a 4 layer per validazione incrociata, soglie e debug
- `references/cloud-fallback-strategy.md` — cloud filter per regione, fallback SR→L1C, implementazione GEE
- `references/delivery-cross-pc.md` — come consegnare script quando utente è su PC diverso
- `templates/sentinel2-mndwi-template.js` — template GEE riutilizzabile con placeholders
