diff --git a/backend/src/Service/Ingestion/IngestionService.php b/backend/src/Service/Ingestion/IngestionService.php index f5d6a89..2efb191 100644 --- a/backend/src/Service/Ingestion/IngestionService.php +++ b/backend/src/Service/Ingestion/IngestionService.php @@ -28,25 +28,16 @@ class IngestionService ) {} /** - * Tente l'ingestion Sentinel-2, puis Sentinel-3 OLCI en fallback si la - * couverture nuageuse est trop élevée ou si la scène S2 est indisponible. + * Ingestion Sentinel-2 uniquement. + * Pas de fallback S3 : sans bande SWIR, S3 OLCI génère trop de faux positifs + * (brume de sable, sun glint) pour être exploitable en production. + * Préférer aucune donnée à de mauvaises données. + * + * @param array $bbox */ - /** @param array $bbox */ public function ingestWithFallback(array $bbox, \DateTimeImmutable $date): void { - try { - $this->ingest($bbox, $date, 'Sentinel-2', 'sentinel-2-l2a'); - } catch (HighCloudCoverageException $e) { - $this->logger->info('S2 cloud too high, falling back to Sentinel-3', ['reason' => $e->getMessage()]); - $this->ingest($bbox, $date, 'Sentinel-3', 'sentinel-3-olci'); - } catch (\Throwable $e) { - // Erreur S2 non liée à la couverture nuageuse (HTTP 4xx/5xx, timeout…) - // → tenter S3 plutôt que perdre tout le cycle pour cette zone - $this->logger->warning('S2 ingestion error, falling back to Sentinel-3', [ - 'reason' => $e->getMessage(), - ]); - $this->ingest($bbox, $date, 'Sentinel-3', 'sentinel-3-olci'); - } + $this->ingest($bbox, $date, 'Sentinel-2', 'sentinel-2-l2a'); } /** @param array $bbox */ diff --git a/backend/src/Service/SentinelHub/SentinelHubClient.php b/backend/src/Service/SentinelHub/SentinelHubClient.php index 264aa4f..d635a41 100644 --- a/backend/src/Service/SentinelHub/SentinelHubClient.php +++ b/backend/src/Service/SentinelHub/SentinelHubClient.php @@ -45,18 +45,12 @@ class SentinelHubClient } /** - * Retourne la couverture nuageuse (%) de la meilleure scène disponible. - * collection : 'sentinel-2-l2a' (défaut) ou 'sentinel-3-olci' + * Retourne la couverture nuageuse (%) de la meilleure scène Sentinel-2 disponible. + * + * @param array $bbox */ - /** @param array $bbox */ public function getCloudCoverage(array $bbox, \DateTimeImmutable $date, string $collection = 'sentinel-2-l2a'): float { - // Sentinel-3 OLCI n'expose pas eo:cloud_cover dans le Catalog ; on renvoie 0 - // pour laisser le Process API décider. - if ($collection === 'sentinel-3-olci') { - return 0.0; - } - $token = $this->getToken(); $dateStr = $date->format('Y-m-d'); @@ -97,9 +91,7 @@ class SentinelHubClient $token = $this->getToken(); $dateStr = $date->format('Y-m-d'); - $evalscript = $collection === 'sentinel-3-olci' - ? $this->getFaiBinaryEvalscriptS3() - : $this->getAfaiBinaryEvalscript(); + $evalscript = $this->getAfaiBinaryEvalscript(); $response = $this->httpClient->request('POST', self::PROCESS_URL, [ 'headers' => ['Authorization' => "Bearer {$token}"], @@ -196,56 +188,4 @@ function evaluatePixel(sample) { EVALSCRIPT; } - /** - * Evalscript Sentinel-3 OLCI — MCI (Maximum Chlorophyll Index) adapté sargasses. - * - * OLCI bands (nm) : B03=442.5 (Bleu), B06=560 (Vert), B08=665 (Rouge), - * B11=708.75 (RedEdge), B17=865 (NIR) - * - * Limite fondamentale : S3 OLCI n'a pas de bande SWIR → impossible de filtrer - * les aérosols comme S2. La bande bleue B03 (442nm) compense partiellement : - * la poussière saharienne a un ratio bleu/rouge >> 2 (sargasses : ≈ 0.7–1.0). - * - * Seuil MCI relevé 0.020 → 0.030 pour compenser l'absence de SWIR. - */ - private function getFaiBinaryEvalscriptS3(): string - { - return <<<'EVALSCRIPT' -//VERSION=3 -function setup() { - return { - input: [{ bands: ["B03", "B06", "B08", "B11", "B17"], units: "REFLECTANCE" }], - output: { bands: 1, sampleType: "UINT8" } - }; -} - -function evaluatePixel(sample) { - // NIR élevé = sun glint - if (sample.B17 > 0.05) { return [0]; } - - // Filtre brume de sable via bande bleue B03 (442.5nm) : - // - bleu absolu > 0.08 : atmosphère trop chargée en aérosols - // - B03/B08 (bleu/rouge) > 2.0 : signature poussière saharienne - // (sargasses : ratio ≈ 0.7 | brume sahélienne : ratio > 2) - if (sample.B03 > 0.08) { return [0]; } - if (sample.B08 > 0.001 && (sample.B03 / sample.B08) > 2.0) { return [0]; } - - // Masque eau : NDWI = (Green B06 560nm - NIR B17 865nm) / (Green + NIR) - const ndwiDenom = sample.B06 + sample.B17; - if (ndwiDenom === 0) { return [0]; } - const ndwi = (sample.B06 - sample.B17) / ndwiDenom; - if (ndwi <= 0.05) { return [0]; } - - // MCI — baseline interpolée entre rouge (B08) et redEdge (B11) - const lambdaRed = 665.0; - const lambdaRedEdge = 708.75; - const lambdaNir = 865.0; - const baseline = sample.B08 + (sample.B11 - sample.B08) * (lambdaNir - lambdaRed) / (lambdaRedEdge - lambdaRed); - const mci = sample.B17 - baseline; - - // Seuil 0.030 (vs 0.020) : compense l'absence de SWIR pour meilleure spécificité - return [mci > 0.030 ? 1 : 0]; -} -EVALSCRIPT; - } }