Saltar al contenido principal

wiki-Documentación

Ver en Git


Documentación

Sentinel Ingest

Imágenes

General

Las imágenes de Sentinel son capturadas por 2 satélites (A y B) y manejadas por la ESA. Las mismas se disponibilizan en un sitio llamado copernicus que también maneja la ESA y luego distintos proveedores las disponibilizan a través de otros canales. El principal en AWS se puede encontrar en el registro de opendata de aws.

Las imágenes de sentinel se generan basadas en un grid de cuadrículas de 100×100 km2 y proyección UTM/WGS84. Cada cuadrícula recibe el nombre de Tile y tiene un nombre de 5 caracteres (EJ: 21HXE). Los primeros 3 corresponden a la zona UTM y los siguientes 2 a la subdivisión dentro de la zona. Esto significa que en una zona UTM entran múltiples tiles. Los tiles se superponen en sus bordes para tener cobertura de los objetos que están en los límites. Como las distintas zonas UTM tienen distintos códigos EPSG, según la zon los tiles se proporcionan con proyecciones de distintos EPSG.

Todas las imágenes se generan del tamaño del tile. Frecuentemente las imágenes no llegan a cubrir el tile entero, dejando los píxeles de la porción sin cubrir como NODATA.

Las imágenes de Sentinel tienen 13 bandas donde cada una corresponde a distintos rangos de frecuencia. Distintas bandas son capturadas con distinta resolución espacial: 60x60m, 20x20m y 10x10m.

Cada imagen incluye metadata con información sobre la misma:

  • porcentaje estimado de nubes sobre no nubes
  • porcentaje de datos (cobertura sobre el tile)
  • polígono que representa la cobertura
  • el satélite que capturó la imagen

Las imágenes capturadas contienen el Top Of Atmosphere (TOA), que representa la luz reflejada que llega al satélite por lo que incluye el efecto atmosférico. Estas imágenes son el producto de Level-1C (L1C). Sentinel incluyó un post-procesamiento que quitan el efecto atmosférico y permiten obtener la Surface Reflectance o Bottom-Of-Atmosphere (BOA) para generar el producto de Level-2A (L2A).

toda la documentación técnica se puede encontrar en https://sentinel.esa.int/documents/247904/685211/S2-PDGS-TAS-DI-PSD-V14.9.pdf/3d3b6c9c-4334-dcc4-3aa7-f7c0deffbaf7?t=1643013091529

Cada banda de una imagen está formateada con enteros sin signo de 16 bits (uint16). El 0 corresponde a NODATA y los valores de la imagen van de 1-65535 y reciben el valor de DIGITAL NUMBER (DN), correspondiendose a intensidad de luz capturada.

BOA OFFSET

A partir del 25 de enero 2022, se cambió el pipeline de procesamiento y movió el rango de la imagen. Básicamente los valores muy altos no existían y los más oscuros son de interés, por lo que se añadió un offset llamado BOA_OFFSET a las imágenes generadas a partir de esta fecha.

Esto implica que a estas imágenes se les debe restar el BOA_OFFSET para obtener los valores de SR.

L1C

Las imágenes L1C fueron las primeras disponibilizadas por Sentinel en el 2015. Al ver la composición visible de estas imágenes se nota un tono celeste según las condiciones de luz. Realmente no son de utilidad agronómica ya que el efecto distorsiona mucho los valores.

Existen métodos de corrección sencillos que permiten aproximar la BOA. Particularmente uno consiste en encontrar el valor de cierto bin del histograma del tile completo de la 4ta banda. Ese valor se resta del cada banda para obtener la imagen corregida. El método es el más preciso pero aún así depende mucho de la imagen y puede dar resultados no tan buenos.

El único motivo para consumir estas imágenes es el de la disponibilidad temporal desde 2015

En el OpenData Registry de AWS, estas imagenes se suben a S3 al bucket sentinel-s2-l1c de la región eu-central-1 muy poco luego de ser disponibilizadas en copernicus.

Los productos se organizan por tile y fecha, por ejemplo:

tiles/21/H/XE/2023/11/8/0/B04.jp2

corresponde al tile 21HXE, fecha 2023/11/8, primer pasada (0), banda 4.

En la misma carpeta se encuentra la metadata:

tiles/21/H/XE/2023/11/8/0/tileInfo.json

El formato de estas imágenes es .jp2.

Las consultas a este bucket son request-payer, es decir que el que realiza la consulta paga por la operación sobre el bucket y la cantidad de datos que esté moviendo. Hay que considerar que las imágenes son grandes (especialmente las de 10x10) y que hay que descargar todas las bandas por cada una.

L2A

Las L2A se disponibilizaron en Noviembre 2016 para Europa y globalmente desde Enero 2017. Sin embargo, la frecuencia temporal es muy baja y recién es aceptable a partir de mediados de 2019.

En el OpenData Registry de AWS, estas imagenes se suben a S3 al bucket sentinel-s2-l2a de la región eu-central-1 muy poco luego de ser disponibilizadas en copernicus.

Los productos se organizan por tile, fecha y resolución por ejemplo:

tiles/21/H/XE/2023/11/8/0/R10m/B04jp2

corresponde al tile 21HXE, fecha 2023/11/8, primer pasada (0), resolución 10x10, banda 4.

En la misma carpeta se encuentra la metadata:

tiles/21/H/XE/2023/11/8/0/tileInfo.json

El formato de estas imágenes es .jp2.

Las consultas a este bucket son request-payer, es decir que el que realiza la consulta paga por la operación sobre el bucket y la cantidad de datos que esté moviendo. Hay que considerar que las imágenes son grandes (especialmente las de 10x10) y que hay que descargar todas las bandas por cada una.

Inventario

Hay disponible buckets de inventario que básicamente tienen, por día, archivos con un "screenshot" de todos los archivos que hay en los buckets de imágenes hasta esa fecha. Sirven para hacer una ingesta masiva de la BBDD.

Notificaciones

Como parte del OpenData Registry de AWS, se incluyen notificaciones sobre la disponibilidad de nuevas imágenes en los buckets.

AWS publica en distintos tópicos de SNS la disponibilidad de nuevas imágenes en S3. A través de servicios como SQS se puede suscribir a esos tópicos para obtener en tiempo real cuando hay nuevas imágenes.

COGS

Otro proveedor de imágenes disponibiliza las imágenes en formato .tif, que por su compresión son denominados Cloud-Optimized-GeoTiffs (COGS). También se encuentra en el OpenData Registry: https://registry.opendata.aws/sentinel-2-l2a-cogs/.

Hay varios puntos importantes de este proveedor:

  • es open source
  • ES GRATUITO
  • los geotiffs pueden consumirse mediante Virtual File Systems (VFS) con GDAL, de manera de sólo descargar la zona de interés de la pisada (Ver sección de procesamiento)
  • no hay mailing list o manera de enterarse de novedades/cambios/disrupciones/etc.
  • tiene bugs

Las COGS están solo para las imágenes L2A y no todas las escenas están disponibles.

Las COGS se encuentran en S3 en el bucket sentinel-cogs de la región us-east-1. Se disponibilizan un tiempo después que se suben al bucket sentinel-s2-l2a.

Las keys en el bucket llevan un patrón de nombre distinto, que agrega la necesidad de conocer qué satélite (A o B) capturó la imagen. Por ejemplo:

sentinel-s2-l2a-cogs/20/H/NJ/2020/3/S2A_20HNJ_20200322_0_L2A/B02.tif

RODA

Hay un servicio de sentinel-hub que expone un proxy a la estructura de S3. El mismo permite explorar los archivos de los buckets de manera gratuita. Incluso se pueden visualizar los que no son imagenes .jp2(metadata, etc).

Lo más interesante es que las imágenes L1C tienen una preview .jpg de la pisada: https://roda.sentinel-hub.com/sentinel-s2-l1c/tiles/21/H/XE/2023/3/11/0/preview.jpg

O bien se pueden explorar los directorios del bucket: https://roda.sentinel-hub.com/sentinel-s2-l1c/tiles/21/H/XE/2023/

Auravant - Sentinel Ingest

image

Básicamente el sistema se centra en Celery, con una arquitectura basada en eventos sobre la infraestructura de AWS que permite escalar horizontalmente.

Hay dos servidores principales fijos:

  • sentinel_worker en us-east-1, el más importante, tiene: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la lógica de control para nuevos lotes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la lógica de control de los ASG Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la lógica de registro de resultados Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Celery Beat Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Redis, el broker de Celery Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Flower, para visualización
  • eu_sentinel_worker en eu-central-1 se encarga de la ingesta de imágenes nuevas.

En cada región hay un AutoScalingGroup dedicado a procesar imágenes que escala según la cantidad de imágenes por procesar.

Se consumen imágenes de los dos proveedores mencionados antes (Sentinel-Hub y COGS) según convenga. Como ambos están en regiones distintas, los workers sólo consumen imágenes del proveedor de la región en la que están.

Base de datos

La base de datos auravant_sentinel consiste de dos tablas:

  • sentinel_index que tiene las definiciones de los tiles Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js gid (id interno) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js terrestrial (indica si corresponde a tierra, de manera de sólo considerar estos para el procesamiento) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js nombre Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js geometría Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js epsg
  • sentinel_tiles que lleva registro de la disponibilidad de imágenes. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js fecha Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tile al que corresponde Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js footprint: geometría de la pisada por si la misma no cubre el tile entero Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js satelite que la captura

sentinel_index se encuentra duplicada en la base de datos auravantdb

Al tener todas las imágenes en sentinel_tiles (y que se van agregando a medida que aparecen nuevas), se evita tener que consultar las imágenes existentes cada vez que se crea un lote nuevo. De esta manera, se determina por geometría qué imágenes se deben procesar para un lote nuevo, y mediante los índices se logra una muy buena velocidad considerando el tamaño de esta tabla.

sentinel_tiles se encuentra indexada:

  • zone_id (tile al que corresponde)
  • footprint
  • UNIQUE(zone_id, fecha) para evitar duplicados

A su vez, el sistema se encuentra conectado a auravantdb para la búsqueda de los shapes de los lotes, la creación de las capas asociadas a las imágenes y la actualización del resultado su procesamiento.

  • tabla capas Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js crea el registro de la imagen para el lote, con el tipo de capa Sentinel2 y metadata en ciertos casos.
  • tabla sentinel_layers Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js relación 1 a 1 con los registros de la tabla capas que correspondan a Sentinel2. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Tiene los resultados del procesamiento de la imagen Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js status_id Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js PENDING = 0 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js ERROR_SHAPE = 1 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js ERROR_TILE = 2 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js ERROR_PROCESSED = 3 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js PROCESSED_NOT_STORED = 4 (deprecated) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js coverage: porcentaje del lote que tiene datos no-nube Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js cloudy: true si coverage < 95 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js medias y máximos de ndvi y gndvi DEL ÚLTIMO SHAPE DEL LOTE

Consumo de imágenes

Resumiendo ambos proveedores:

  • COGS Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js ES GRATIS Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js permite utilizar VFS, lo que implica un menor costo computacional para procesar las imágenes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js está en us-east-1, lo que conviene para tener menor costo de red y velocidad Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js no están todas las imágenes
  • SENTINEL-HUB Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Mediante el tópico de SNS es posible saber cuando hay nuevas imágenes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tiene las L1C Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Son pagas Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Hay que bajar la pisada completa por más que se quiera procesar 1 lote

Entonces se utilizan de manera de optimizar el sistema. Desde el punto de vista del flujo:

  • Para procesar lotes individuales (nuevos lotes o cambio de forma): Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Las L2A se consumen mediante VFS desde us-east-1 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Si la imagen no está en el bucket COGS, se reintenta la tarea consumiendo de Sentinel-Hub desde eu-central-1 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Las L1C se consumen de Sentinel-Hub desde eu-central-1
  • Para procesar nuevas imágenes: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Las imágenes nuevas sólo son las L2A Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Como las notificaciones corresponden al bucket de Sentinel-Hub, se consumen de ese bucket desde eu-central-1 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Para aprovechar la descarga de la pisada, se procesan múltiples lotes por cada imagen.

Tareas, Queues y Workers

En Celery, para poder ejecutar tareas con distintas prioridades, las mismas se asignan a distintas queues. Además, si se desea que distintas tareas corran bajo distinta infraestructura, se corren workers que consuman exclusivamente ciertas queues.

Los workers son (ver imágen del sistema):

US-EAST-1
  • beat: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js el cron que dispara las tareas de ingesta de imágenes, de escalado de los ASG y eliminación de imágenes viejas
  • new_shapes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: sentinel_control, sentinel_new_shape Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en us-east-1, para estar cerca de la BD Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js scale_workers Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js terminate_workers Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js new_shape_v2 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js new_shapes_v2 Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js reprocessing_lock Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js purge_s3
  • results: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: sentinel_results Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en us-east-1, para estar cerca de la BD Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la idea es que concentre las consultas a la BD para asi disminuir la cantidad de conexiones que se crean para guardar resultados. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js update_status Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js update_metadata Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js finish_batch_task Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js register_s3_purge
  • vfs - high priority Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: process_vfs.high Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js para darle prioridad a las imágenes recientes de los nuevos lotes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en us-east-1, para consumir del proveedor de COGS Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js process_tile (L2A)
  • vfs - mid priority (ASG) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: process_vfs.mid Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en us-east-1, para consumir del proveedor de COGS Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js se encuentran en servidores de un Auto Scaling Group, por lo que se escalan según necesidad Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js pensado para la masividad de las imágenes de nuevos lotes, contemplando que puedan haber muchas altas simultáneas Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js process_tile (L2A)
  • vfs - low priority (ASG) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: process_vfs.low Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en us-east-1, para consumir del proveedor de COGS Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js se encuentran en servidores de un Auto Scaling Group, por lo que se escalan según necesidad Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Se usa sólo para altas masivas de nuevos espacios, procesandose sólo las imágenes L2A, de manera de no ocupar la queue mid y degradar los tiempos de procesado para los nuevos lotes. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Este ASG está por defecto en 0 workers y se enciende sólo cuando hay altas masivas. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js process_tile (L2A)
  • Redis Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js el broker de todo el sistema
  • Flower Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js visualización de las tareas de celery
eu-central-1
  • tiles ingest Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: sentinel_ingest Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en eu-central-1 para consumir mensajes de SQS sobre nuevas imágenes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js receive_sqs_messages
  • download - low priority Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: process_dwn.low Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en eu-central-1, para consumir del proveedor de SENTINEL-HUB Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js worker que siempre está activo para las nuevas imágenes. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js process_tile (L2A)
  • download - low priority (ASG) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: process_dwn.low Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en eu-central-1, para consumir del proveedor de SENTINEL-HUB Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js el ASG se mantiene en 0 mientas el worker anterior pueda con la demanda. Si la cantidad de tareas crece, este ASG escala. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js process_tile (L2A)
  • download - mid priority (ASG) Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js queues: process_dwn.mid Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js en eu-central-1, para consumir del proveedor de SENTINEL-HUB Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js para procesar las imágenes de un nuevo lote que no están disponibles en el otro proveedor o las L1C Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js tareas: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js process_tile (L2A, L1C)

Con esta distribución se logra paralelizar las tareas de distintas prioridades y distribuir las tareas geográficamente según convenga.

Por ejemplo, para el procesamiento de imágenes, las queues son process_vfs para las de COGS y process_dwnl para las de Sentinel-Hub. Entonces los workers de cada región consumen de distintas queues, de manera que cuando se quiere consumir de Sentinel-hub por ejemplo, se envía a la queue process_dwnl.

Procesar imágenes para lotes

Sea un lote nuevo o que se quiera reprocesar, las funciones para disparar el procesamiento de imágenes se encuentra en trigger.py. La función principal es new_shape_v2, que tiene varias configuraciones y filtros para proceesar:

  • field_shape: dict con Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js field_id: id del lote Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js shape_wkt: shape sobre el cual calcular los índices Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js image_bbox_wkt: bbox de la imagen. En caso de no especificarlo, se toma el bbox de shape_wkt

Por polígonos por campaña, un lote puede tener múltiples shapes. Sin embargo actualmente los índices de ndvi se calculan sólo para el último shape. Esto significa que hay que procesar la imagen de manera que cubra todos los shapes pero calcular los índices solo para el último shape. Esto es el por qué de los parámetros shape_wkt y image_bbox_wkt.

  • target_layers: str Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la idea de esto es definir el comportamiento para no reprocesar imágenes innecesariamente. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js sus valores: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js new: solo procesar imágenes que no existan Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js pending: solo procesar imágenes que estén pendientes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js error: solo procesar imágenes que hayan fallado Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js de esta manera, si por ejemplo quedó un grupo de imágenes de un lote pendiente, se puede enviar a procesar sólo las pendientes, sin necesidad de tener que especificarlas una por una. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Por otro lado, si las imágenes ya existen, se asegura no crear nuevas imágenes y que haya duplicados.
  • priority: str Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js mid: Envía todas las tareas a la queue de prioridad mid Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js low: Envía todas las tareas a la queue de prioridad low -> para altas masivas Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js normal: Pensado para un alta de lote desde la plataforma, donde prioriza los últimos meses y el resto con prioridad media
  • date_from: para filtrar por rango de fechas
  • date_to: para filtrar por rango de fechas
  • l2a_only: para procesar solo las L2A, de manera que se use el proveedor COGS --> reduciendo costos. también para altas masivas

Asignación de tiles

Cada lote se vincula a un tile de sentinel en la tabla lotes_sentinel.

Esta asignación se hace en new_shape_v2 y es necesaria para que el lote tenga imágenes nuevas.

La búsqueda de imágenes, tanto para new_shape_v2 como para las imágenes nuevas, se hace según el zone_id que tenga asignado en la tabla, es decir que se procesarán sólo imágenes de ese tile.

La búsqueda de tile se hace buscando aquel que contenga todos los shapes del lote (+ un buffer). En caso de superposición, se prioriza el que tenga el epsg que le corresponde según su ubicación y en caso de haber múltiples se lo ordena alfabéticamente.

Es importante notar que la operación geométrica de verificar que el tile contenga los shapes se debe hacer en la proyección del tile, ya que de hacerse en 4326, las deformaciones por la reproyección puede dar resultados incorrectos.

La asignación de tile respeta el valor que exista en la BD. Es decir que:

  • podría cambiarse en la BD el tile asignado y mandar a reprocesar las imágenes, respetándose la zona de la BD
  • Se ignora el caso en que un lote pueda cambiar de zona por cambios de shape.

Processing Lock

Se utiliza Redis como lock distribuído para no permitir que se soliciten muchos cambios de shape. Si bien se puede hacer, podrían desordenarse las tareas y guardarse resultados de distintos shapes.

Lo primero que se hace en new_shape_v2 es verificar que el lote no se encuentre en el Lock.

Batches

Las tareas de procesamiento se agrupan en batches. La idea es que la consulta a la base de datos para actualizar los resultados se haga en batches y no por cada imagen. De esta manera se logra equilibrar la cantidad de consultas a la BD y la velocidad de disponibilización de imágenes.

Para esto se utilizan los chords de Celery, que ejecuta todas las tareas en paralelo y luego ejecuta un callback. Para cada batch se utilizan 2 callbacks. Uno es update_status, que es el que actualiza los resultados en la base de datos y envía las tareas de análisis de anomalías de aurapi. El otro es finish_batch_task que luego del último batch libera el Lock distribuído.

Esta tarea se podría utilizar para avisar por Notification Center al front sobre el avance del procesamiento

Múltiples lotes

La función new_shapes_v2 (notar el plural de shapes) es una alternativa para procesar múltiples lotes que se encuentran en un mismo tile. La idea es agrupar los lotes por tile, para luego procesar cada imagen 1 vez para múltiples lotes.

No está hecho el análisis de si conviene procesar altas masivas así o utilizando el proveedor COGS para los lotes individualmente

Cambio de shape

En el caso de polígonos por campaña, cuando se crea una nuevo shape para un lote, se ejecuta la función new_shape_modification que corre 2 pasos:

  1. Forzar el estado de todas las imágenes del lote a PENDING
  2. Ejecutar la función new_shape_v2 para las layers PENDING

Podría darse el caso en que el nuevo shape sea más pequeño que el anterior, de manera que se encuentra contenido por las imágenes ya procesadas. En este caso, no hace falta procesar las imágenes, sino que sólo re-calcular los índices para el nuevo shape. Para esto se ejecuta la función shape_indexes_calculation.

Nuevas imágenes

Como se explicó antes, el proveedor SENTINEL-HUB tiene un tópico en SNS donde se informa sobre nuevas imágenes que se disponibilizan.

Beat dispara cada 10 minutos la tarea de receive_sqs_messages que toma las notificaciones de la queue de SQS sobre nuevas imágenes disponibles. Ahí se toma la metadata necesaria y se guardan las nuevas tiles en la base de datos.

receive_sqs_messages originalmente buscaba también las nuevas imágenes de L1C, pero se dejó de hacer ya que no tiene mucho sentido. Por eso en el código se verán contempladas las L1C.

Luego de guardarlas en la base de datos se procede a buscar los lotes para los cual hay que procesar cada imagen. De eso se encarga la función new_tiles, que busca los lotes que están asociado a cada tile nuevo según lotes_sentinel y manda a procesar todos estos lotes para cada imagen. Se envían hasta 50 lotes por imagen para reducir la carga de los servidores.

De igual manera, este proceso se hace en batches.

Procesamiento

Las funciones de procesamiento están diseñadas para ser idempotentes. Hay 2 funciones, una para L2A y otra para L1C. SI bien el procesamiento que se hace es el mismo, en ambas las imágenes están organizadas y formatedas de maneras distintas en el proveedor. Además que para las L1C hay que hacer la corrección.

La idea es recibir una fecha a procesar y un listado de lotes, de manera de hacer la descarga una única vez para todos los lotes que pertenecen a la misma imagen. Esto es especialmente útil para la ingesta. Cada lote está asociado con una layer_id sobre la cual se guardarán los resultados. El resultado de estas funciones es un listado de capas, cada una con su layer_id y los resultados. Habrá tantos resultados como lotes indicados.

La función, además, sube la imagen procesada a S3.

En alto nivel, las funciones consisten de bloques try. Considerando que si falla una tarea de un Chord de celery, fallarían todas las demás, es necesario que éstas no fallen. Entonces todo se ejecuta en un try y en caso de haber un error, se devuelve un código que lo represente.

EL procesamiento consiste en:

  1. Descargar todas las bandas Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js qué bandas y su nomenclatura se encuentran hardcodeadas. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Cualquier error en este bloque se considera un "error de tile", y se aplica a todos los lotes recibidos. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Los errores más comunes se deben a que la imagen no esté publicada, debiéndose a un error del proveedor. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js L1C: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la capa de nubes se encuentra en un archivo vector GML Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Si no se provee el rs_red para corregir las imágenes, se calcula y envía una tarea para actualizarlo en la BD. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js L2A: Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js la capa de nubes se encuentra en un tiff llamado SCL, que tiene una clasificación pixel a pixel (vegetación, nubes, agua, etc.). Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js USE_VFS indica si el worker está configurado para trabajar con el proveedor COGS. Si es False, Todas las imágenes se descargan a disco. Si es True, este parte sólo verifica que la imagen exista en el bucket. Además, es necesario descargar la metadata. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Puede suceder que el worker busque la imagen en el proveedor COGS pero no esté disponible. En este caso, se envía la tarea mediante Celery a la Queue process_dwn.mid para tomarla de SENTINEL-HUB, ejecutándose por fuera del Chord o el contexto en el que se esté ejecutando.
  2. Determinar si aplicar el BOA_OFFSET. Sólo para las imágenes generadas a partir de la fecha correspondiente. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js El proveedor SENTINEL-HUB no aplica el offset, por lo que siempre se debe aplicar Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js El proveedor COGS indica en la metadata si el offset ya fue aplicado.
  3. Para cada lote provisto, procesar las bandas. Cada lote, con su imágen final, sus cálculos de nubes e índices se lleva en la clase Shape. Cualquier error en este bloque afecta sólo al lote correspondiente.
  4. Cargar el polígono del lote. Tanto el shape del lote sobre el cual se calcularán los resultados como el bbox que tendrá la imagen final. La imagen se procesa en su EPSG, por lo que los shapes se llevan a éste.
  5. Es necesario calcular el tamaño final de la imagen (el que se almacena en Shape). Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js En L2A se calcula procesando el SCL de la imagen. En L1C se toma una banda (cualquiera) de 10m.
  6. Ya teniendo el tamaño final de la imagen, se calcula la máscara del shape calculate_shape_mask, la que se usará al momento de realizar cálculos para quedarse sólo con los píxeles dentro del lote.
  7. Calcular las nubes Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js L2A: se aplica la máscara del lote a la banda SCL y luego se toman los píxeles cuyo valor representen vegetación, dejando de lado nubes y demás. Se crea la máscara scl_mask que indica qué pixels de la imagen tienen datos útiles. El resto de píxeles se considera nubes. Se calcula cloudy. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js L1C: En este caso, sólo se tiene información de las nubes en forma vectorial. La máscara de nubes se calcula rasterizando este vector.
  8. Cortar cada banda al tamaño final Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js llevando cada banda a 10m
  9. Setear metadata Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js datos que pueden ser de utilidad luego.
  10. Calcular índices Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Una vez ya recortadas todas las bandas, se utilizan las máscaras y se hacen los cálculos. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js L1C: se realiza la corrección de las bandas en base al rs_red antes de realizar los cálculos.
  11. Se sube a s3 la imagen final.

Es importante eliminar las imágenes que se guardan a disco en caso de haber un error. En otras palabras, la función de procesamiento debe dejar el disco tal como estaba al iniciarse.

VFS

Las imágenes COGS se manipulan de la siguiente manera:

  1. Al hacer gdal.Open se realiza una consulta al servidor donde esté almacenada, en la que se consulta la metadata de la imagen, obteniéndose el tamaño y demás.
  2. Al hacer .ReadAsArray se realizan consultas al servidor en las que se indica la porción a leer, obteniéndose sólo esa subset de píxeles.

Es necesario que se tengan instalados drivers de gdal de CURL, VSIS3 para poder utilizarse.

Corrección L1C

A grandes rasgos, el método consiste en obtener el pixel más oscuro de una pisada y restar ese valor a todas las bandas. Los pasos en concreto son:

  1. realizar histograma de la pisada de la banda 4
  2. obtener el valor de pixel que se repita 50 veces o menos
  3. realizar una corrección con una constante 0.008
  4. restar ese valor de todas las bandas

EL valor recibe el nombre de relative scatter y al ser de la banda 4 (roja), rs_red.

Puede pasar que la imagen tenga valores muy altos (imagen muy clara, saturada probablemente por nubes) y se omita la corrección.

ASGs

Los AutoScaling Groups agregan instancias a partir de imágenes (AMIs) y un script inicial. Como la única tarea que los ASGs ejecutan es la de procesar imágenes, sólo es necesario actualizarlos si esta función cambia.

AMIs

El servidor de virginia tiene un directorio en home ~/image_AWS_sentinel en el que se encuentra el repositorio. Las instancias de los ASGs corren sobre este directorio, por lo que debe tener el código que se quiera correr en los ASG. Tener duplicado el repositorio permite crear una AMI sin tener que modificar el directorio donde corren los workers de la instancia de virginia.

Launch templates

Son templates para levantar instancias. Algunas configuraciones se indican a nivel template como:

  • security groups
  • AMI
  • script inicial mientras que otras configuraciones se determinan a nivel de ASG.

En caso de querer crear uno, hay un botón que marca los campos del formulario como guía para ASGs

Los templates tienen versiones. Por lo que una vez creado, simplemente se pueden crear versiones con AMIs distintas.

Hay un launch template por cada ASG, ya que como se verá luego, cada ASG lleva configuraciones en su script inicial.

ASGs

Se crean indicando el template y otras configuraciones relacionadas con el escalamiento del grupo, como:

  • cantidad de instancias
  • tipo de instancias
  • spot o onDemand
  • vpc
  • otros...

Una vez indicado el template, se puede elegir la versión de 3 maneras:

  • Siempre la última versión
  • la versión default
  • una versión

Los ASGs de Sentinel están todos configurados para tomar la versión default, de manera que sólo cambiando la versión default en el launch template, se aplica el cambio sobre el ASG.

La cantidad de instancias se controla automáticamente (ver secciones siguientes), por lo que sólo importa que el mínimo y máximo de instancias estén dentro de valores razonables.

Los tipos de instancias se han ido determinando empíricamente. Los workers que procesan imágenes VFS necesitan más memoria y red, mientras que los de COGS consumen mucha CPU. Conviene especificar múltiples familias similares por si no hay disponibilidad.

Las instancias Spot son instancias que a AWS "le sobran" y le conviene tener funcionando. Por eso se subastan con un sistema de precios que fluctúa según la demanda. La desventaja es que AWS podrá terminar la instancia en cualquier momento, con un pre-aviso de 2 minutos. En auravant especificamos el 100% de instancias de ASGs como Spot. Cómo precio máximo a ofertar, colocamos el precio on-demand, de manera de no pagar más de lo que salen.

Script inicial

Al iniciar una instancia Spot, el script inicial simplemente debe iniciar el worker de Celery. Siendo que cada ASG tiene configuraciones distintas, como concurrencia del worker, el proveedor, las queues a consumir, etc. y para poder utilizar a misma AMI, el script inicial toma todas esas configuraciones como parámetro.

El script inicial corre el script run_celery (incluído en este repositorio: /features/control/run_celery) que se encuentra en el directorio home la instancia.

TODO: Debería ejecutarse dentro del repositorio para no correr el riesgo que alguien lo mueva.

Ejemplo de uso:

./home/ubuntu/run_celery 4 spotInstance_eu process_dwnl.mid,process_dwnl.high USE_VFS=FALSE

donde se indica:

  1. concurrencia del worker de Celery
  2. prefijo del nombre del worker de Celery, para poder identificarlo
  3. queues a consumir
  4. String a reemplazar en el .env, en la que se reemplaza el flag del proveedor.

Script de shutdown

Considerando que se utilizan instancias Spot y que pueden ser detenidas en cualquier momento, es necesario apagar los workers de Celery antes que esto suceda para que no se corten las tareas de procesamiento.

AWS disponibiliza un endpoint interno en cada instancia con información sobre el apagado automático. Por eso, se incluye un cron en la instancia (está configurado en la instancia de virginia y se copia con la AMI).

El cron es este archivo: /features/control/cron_shutdown y se coloca en /etc/cron.d/script_terminate_celery. El mismo ejecuta cada 30 segundos el script de shutdown /features/control/script_shutdown_workers, que se encuentra en el directorio home del servidor de virginia (de la misma manera que run_celery).

TODO: Este script también debería ejecutarse dentro del repositorio para no correr el riesgo que alguien lo mueva.

El script verifica el endpoint antes mencionado y en caso de recibir la señal de apagado, envía la señal de warm shutdown al worker de Celery (que permitirá que termine las tareas en proceso).

Para apagar sólo el worker que corre en la misma instancia (y no apagar cualquiera) se usa el hostname. Además el prefijo "spotInstance" es reemplazado por el prefijo indicado en run_celery.

Hay sospechas que esto no funciona correctamente, ya que suelen apagarse servidores con tareas corriendo.

Control

Instructivo para actualizar los ASGs

  1. Colocar en ~/image_AWS_sentinel del servidor de virginia el código tal como se quiere ejecutar, con las variables de .env correctas.
  2. Verificar que run_celery y script_shutdown_workers estén en el directorio home.
  3. En el listado de instancias, seleccionar el servidor de virginia y crear Imagen a partir de la instancia. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js ASEGURARSE DE MARCAR LA OPCIÓN PARA NO REINICIAR LA INSTANCIA Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Agregar descripción con hash del commit y numeración para poder identificarla. Dockerfile LICENSE README.md init.py api_run.py core docker-compose.yml docs features flowerconfig.py gunicorn_config.py ingest_sqs.py requirements.txt run.py run_rs.py workers_frankfurt.config.js workers_virginia.config.js Esperar
  4. En el listado de AMIs, una vez que esté lista para usar, seleccionar copiar y como destino indicar eu-central-1. Esto copiará la imagen a frankfurt, para luego usarla en los ASGs que corren allí.
  5. Tanto en virginia como frankfurt, en el listado de launch templates crear una nueva versión para cada uno, utilizando la nueva AMI. Incluir la descripción con la versión de la AMI para identificarla más fácil.
  6. Seleccionar la nueva versión como versión default. Esto aplicará para las próximas instancias que se lancen.
  7. Si no hay tareas ejecutándose, se puede forzar los ASG a 0 instancias. De esta manera, cuando el cron de control lance nuevas instancias lo hará con la nueva AMI .