Saltar a contenido

Análisis

Nueve tablas en la app mangroove_analisis: los perfiles de umbrales, la corrida con sus fechas e insumos fijados, y los resultados que la API publica.

La corrida es la unidad de verdad del sistema. Todo lo que un visitante ve pertenece a exactamente una corrida, y una corrida pertenece a exactamente una región, una madurez y una versión de perfil. Los resultados se escriben una vez, al terminar el cálculo, y no se tocan más (RN-14).

Requerimientos cubiertos

Diagrama

---
config:
  elk:
    nodePlacementStrategy: NETWORK_SIMPLEX
  fontFamily: monospace
  layout: elk
---
classDiagram
    class PerfilUmbrales {
        +uuid id
        +varchar(50) codigo
        +smallint version
        +varchar(100) nombre
        +real ow_hh_db
        +real ow_hv_db
        +real iv_hh_db
        +real iv_ratio_db
        +real otros_21_umbrales
    }
    class Corrida {
        +uuid id
        +uuid region_id
        +varchar(20) version
        +uuid perfil_id
        +varchar(12) madurez
        +varchar(50) modelo_marea
        +varchar(50) fuente_lluvia
        +varchar(5) orbita
        +smallint[] tracks
        +date desde
        +date hasta
        +varchar(40) codigo_version
        +integer semilla
        +varchar(12) estado
        +boolean vigente
        +smallint n_fechas
        +uuid solicitada_por_id
        +uuid publicada_por_id
        +timestamptz publicada_at
        +timestamptz retirada_at
        +text motivo_retiro
        +timestamptz purgar_despues_de
        +text error
    }
    class CorridaFecha {
        +uuid id
        +uuid corrida_id
        +uuid adquisicion_id
        +smallint orden
        +varchar(20) fecha_codigo
        +real desfase_db
        +real marea_m
        +varchar(12) marea_nivel
        +real lluvia_3d_mm
        +boolean usada_en_if_alta
    }
    class CorridaInsumo {
        +uuid id
        +uuid corrida_id
        +uuid insumo_id
    }
    class ResultadoCelda {
        +uuid id
        +uuid corrida_id
        +uuid celda_id
        +varchar(2) pais
        +boolean en_mascara
        +boolean humedal
        +smallint[] hh
        +smallint[] hv
        +smallint[] coherencia
        +smallint[] clases
        +smallint clase_tipica
        +real if_total
        +real if_alta
        +smallint n_fechas
        +smallint n_fechas_alta
        +boolean datos_suficientes
        +boolean desconectada
        +real p_error
        +real if_esperada
        +smallint cambio_orden
        +real cambio_confianza
        +real cambio_delta_hv_db
    }
    class ResumenPais
    class ResumenFecha
    class PruebaHipotesis
    class ResultadoEstanque
    PerfilUmbrales "1" --> "*" Corrida
    Corrida "1" --> "1..*" CorridaFecha
    Corrida "1" --> "*" CorridaInsumo
    Corrida "1" --> "*" ResultadoCelda
    Corrida "1" --> "*" ResumenPais
    CorridaFecha "1" --> "*" ResumenFecha
    Corrida "1" --> "*" PruebaHipotesis
    Corrida "1" --> "*" ResultadoEstanque

PerfilUmbrales

Una versión de un conjunto con nombre de todos los umbrales del método. Editar un perfil es crear su versión siguiente.

Columnas

Los valores predeterminados son los del perfil predeterminado versión 1, tomados del método de la sección 6.4 del manual de NISAR y ajustados con la escena sintética de prueba.

Campo Tipo Predeterminado Descripción
codigo varchar(50) estricto, predeterminado, permisivo...
version smallint derivada Siguiente versión del mismo código
nombre varchar(100)
ow_hh_db, ow_hv_db real -16.5, -22 Agua abierta: HH y HV por debajo de estos valores
iv_hh_db real -6.5 Vegetación inundada: HH por encima de este valor
iv_ratio_db real 5 Vegetación inundada: HH − HV por encima de este valor
cambio_hh_db, cambio_hv_db real 3, 1.5 Cambio respecto al promedio del track que mueve una celda de clase
nc_hh_db, nc_hv_db real -1, -7 Por encima: fuera del modelo (NC)
usar_coherencia boolean true Corregir OW a NI si la coherencia es alta
coherencia_min real 0.40
marea_alta_m real 0.55 Desde esta altura, la fecha es de marea alta
marea_baja_m real -0.55 Hasta esta altura, la fecha es de marea baja
lluvia_max_mm real 60 Lluvia de tres días desde la que una fecha no cuenta para if_alta
if_alta_desconectada real 0.20 Bajo este if_alta, desconectada
min_fechas_alta smallint 3 Fechas de marea alta mínimas, por RN-10
mayoria boolean true Voto de mayoría 3 × 3 sobre la desconexión
usar_elevacion boolean true Exigir inundación esperada por cota, si hay DEM
if_esperada_min real 0.5
sigma_db real 0.9 Ruido de speckle para p_error
cusum_b smallint 120 Permutaciones del bootstrap
cusum_confianza real 0.95 Confianza mínima de un cambio publicado
cusum_perdida_db real 1.5 Caída mínima de HV de un cambio publicado
cv_estanque real 0.45 Desde este CV, el estanque es activo
cv_banda varchar(2) 'hv' hh / hv
mascara_modo varchar(10) 'estricta' Modo de la máscara GCOV al agregar
creado_por_id uuid Nulo en los perfiles sembrados por migración

Ningún campo es nulo salvo creado_por_id.

Constraints

CONSTRAINT chk_perfilumbrales_mareas
CHECK (marea_baja_m < marea_alta_m)

CONSTRAINT chk_perfilumbrales_fracciones
CHECK (
  coherencia_min BETWEEN 0 AND 1 AND if_alta_desconectada BETWEEN 0 AND 1
  AND if_esperada_min BETWEEN 0 AND 1 AND cusum_confianza BETWEEN 0 AND 1
)

CONSTRAINT chk_perfilumbrales_cusum
CHECK (cusum_b BETWEEN 20 AND 1000 AND cusum_perdida_db > 0)

CONSTRAINT chk_perfilumbrales_clases
CHECK (ow_hh_db < iv_hh_db AND sigma_db > 0 AND min_fechas_alta >= 1)
Nombre Definición
unq_perfilumbrales_codigo_version (codigo, version)

Los mismos rangos, más amplios que estos CHECK, acotan los umbrales que acepta una exploración pública (RF-C-12).


Corrida

Un análisis de una región con una madurez, un perfil y un conjunto de fechas e insumos fijados.

Columnas

Campo Tipo Nulo Predeterminado Descripción
region_id uuid no
version varchar(20) no Semver de los datos, por RN-15
perfil_id uuid no Versión exacta del perfil
madurez varchar(12) no Única madurez admitida, por RN-01
modelo_marea varchar(50) no Modelo de EstimacionMarea a usar
fuente_lluvia varchar(50) no '' Fuente de LluviaDiaria; '' = sin lluvia
orbita varchar(5) no 'ambas' ambas / asc / desc
tracks smallint[] no '{}' '{}' = todos los tracks
desde, hasta date sí Rango de fechas UTC; nulo = sin límite
codigo_version varchar(40) no Commit del código que ejecutó el cálculo
semilla integer no 12345 Semilla del bootstrap, por D-14
estado varchar(12) no 'pendiente' pendiente / en_proceso / completada / fallida / publicada / retirada
vigente boolean no false La publicada que ve el público
n_fechas smallint no Fechas fijadas; largo de cada serie
solicitada_por_id uuid sí Cuenta que la lanzó; nulo si la encoló una sincronización
publicada_por_id uuid sí Cuenta que la publicó; firma los ApiMedia de sus artefactos
iniciada_at, terminada_at timestamptz sí
publicada_at timestamptz sí
retirada_at timestamptz sí
motivo_retiro text no ''
purgar_despues_de timestamptz sí retirada_at + 30 días
error text no '' Motivo de la falla; '' = ninguna

Constraints

CONSTRAINT chk_corrida_version
CHECK (version ~ '^\d+\.\d+\.\d+$')

CONSTRAINT chk_corrida_estado
CHECK (estado IN ('pendiente', 'en_proceso', 'completada', 'fallida', 'publicada', 'retirada'))

CONSTRAINT chk_corrida_madurez
CHECK (madurez IN ('provisional', 'validado'))

CONSTRAINT chk_corrida_vigente_publicada
CHECK (NOT vigente OR estado = 'publicada')

CONSTRAINT chk_corrida_publicacion
CHECK ((estado IN ('publicada', 'retirada')) = (publicada_at IS NOT NULL AND publicada_por_id IS NOT NULL))

CONSTRAINT chk_corrida_retiro
CHECK ((estado = 'retirada') = (retirada_at IS NOT NULL AND motivo_retiro <> '' AND purgar_despues_de IS NOT NULL))

CONSTRAINT chk_corrida_falla
CHECK ((estado = 'fallida') = (error <> ''))

beta no está entre las madurezas admitidas: los productos beta no están calibrados y la guía de NISAR desaconseja usarlos para análisis.

Unicidad e índices

Nombre Definición Propósito
unq_corrida_region_version (region_id, version) RN-15
unq_corrida_region_vigente (region_id) WHERE vigente Una vigente por región
idx_corrida_cola (created_at) WHERE estado = 'pendiente' Cola del trabajador
idx_corrida_purga (purgar_despues_de) WHERE estado = 'retirada' Barrido de la purga

Triggers

Nombre Evento Momento Nivel Regla Origen
trg_corrida_transicion_valida UPDATE OF estado BEFORE ROW pendiente → en_proceso → completada \| fallida; completada → publicada; publicada → retirada RN-14
trg_readonly_corrida UPDATE OF region_id, version, perfil_id, madurez, modelo_marea, fuente_lluvia, orbita, tracks, desde, hasta, semilla, n_fechas BEFORE ROW Lo que define la corrida no cambia después de crearla RN-14
trg_corrida_relevo_vigente UPDATE OF vigente, estado BEFORE ROW Al marcar una vigente, desmarca la anterior de la región; al retirar la vigente, marca la publicada más reciente RF-O-13
trg_corrida_retiro_deja_vigente UPDATE OF estado BEFORE ROW Rechaza retirar la vigente si no hay otra publicada en la región, salvo que la región esté inactiva RF-O-13

CorridaFecha

Una adquisición dentro de una corrida, con lo que de ella depende del perfil: desfase, nivel de marea y si cuenta para if_alta. Es la entrada fechas del manifiesto.

Campo Tipo Nulo Predeterminado Descripción
corrida_id uuid no
adquisicion_id uuid no
orden smallint no Posición en las series de ResultadoCelda, desde 0, en orden temporal
fecha_codigo varchar(20) no copiada Copia de la adquisición; es el fecha_id del contrato
desfase_db real no Calibración relativa restada, por RF-M-10
marea_m real sí Del modelo de la corrida; nulo = sin estimación
marea_nivel varchar(12) no alta / media / baja / desconocida, por RN-08
lluvia_3d_mm real sí Nulo si falta alguno de los tres días
usada_en_if_alta boolean no Marea alta y lluvia bajo el umbral, por RN-09
CONSTRAINT chk_corridafecha_nivel
CHECK ((marea_m IS NULL) = (marea_nivel = 'desconocida'))

CONSTRAINT chk_corridafecha_if_alta
CHECK (NOT usada_en_if_alta OR marea_nivel = 'alta')
Nombre Definición
unq_corridafecha_corrida_orden (corrida_id, orden)
unq_corridafecha_corrida_adquisicion (corrida_id, adquisicion_id)
Nombre Evento Momento Nivel Regla Origen
trg_corridafecha_madurez_coherente INSERT BEFORE ROW La adquisición es de la región y de la madurez de la corrida, y no está reemplazada ni excluida RN-01
trg_corridafecha_derivar_codigo INSERT BEFORE ROW Sobrescribe fecha_codigo con el de la adquisición RN-18
trg_resultado_solo_insercion UPDATE, DELETE BEFORE ROW Rechaza toda actualización; admite el borrado solo durante la purga RN-14

CorridaInsumo

Qué versión de cada tipo de insumo usó la corrida.

Nombre Definición
unq_corridainsumo_corrida_insumo (corrida_id, insumo_id)

trg_corridainsumo_coherente (BEFORE INSERT) exige que el insumo sea de la región de la corrida y que no haya otro del mismo tipo en ella.


ResultadoCelda

Todo lo que la corrida sabe de una celda: su serie, sus clases y sus métricas. Es la fila que lee el inspector.

Columnas

Campo Tipo Nulo Predeterminado Descripción
corrida_id uuid no
celda_id uuid no
pais varchar(2) no '' Del insumo paises; '' = sin asignar
en_mascara boolean no Dentro de la máscara de manglar
humedal boolean no Dentro del humedal: cota y pendiente bajas, fuera de zonas excluidas
hh, hv smallint[] no dB × 100 calibrados, uno por fecha; -32768 = sin dato
coherencia smallint[] no '{}' × 1000, uno por fecha; '{}' = la corrida no tiene coherencia
clases smallint[] no Códigos de clase, uno por fecha
clase_tipica smallint no Clase del promedio multitemporal
if_total real sí if del contrato; nulo fuera de la máscara
if_alta real sí Nulo fuera de la máscara o sin datos suficientes
n_fechas, n_fechas_alta smallint no Fechas que respaldan cada fracción
datos_suficientes boolean no Por RN-10
desconectada boolean no Por RN-11, después del voto de mayoría
p_error real sí Nulo fuera de la máscara
if_esperada real sí Inundación esperada por cota; nulo sin DEM o fuera de la máscara
cambio_orden smallint sí orden de la primera fecha después del cambio; nulo = sin cambio
cambio_confianza real sí
cambio_delta_hv_db real sí HV medio después menos antes
perdida_copa boolean no generada Almacenada. cambio_orden IS NOT NULL AND cambio_delta_hv_db < 0

if es palabra reservada en Python; la columna se llama if_total y la API la publica como if.

Constraints

CONSTRAINT chk_resultadocelda_series_alineadas
CHECK (
  cardinality(hh) = cardinality(hv) AND cardinality(hh) = cardinality(clases)
  AND (cardinality(coherencia) = 0 OR cardinality(coherencia) = cardinality(hh))
)

CONSTRAINT chk_resultadocelda_clases
CHECK (clases <@ ARRAY[0, 1, 2, 3, 4]::smallint[] AND clase_tipica BETWEEN 0 AND 4)

CONSTRAINT chk_resultadocelda_fracciones
CHECK (
  (if_total IS NULL OR if_total BETWEEN 0 AND 1)
  AND (if_alta IS NULL OR if_alta BETWEEN 0 AND 1)
  AND (p_error IS NULL OR p_error BETWEEN 0 AND 1)
  AND (if_esperada IS NULL OR if_esperada BETWEEN 0 AND 1)
  AND (cambio_confianza IS NULL OR cambio_confianza BETWEEN 0 AND 1)
)

CONSTRAINT chk_resultadocelda_fuera_mascara
CHECK (
  en_mascara OR (
    if_total IS NULL AND if_alta IS NULL AND p_error IS NULL
    AND if_esperada IS NULL AND cambio_orden IS NULL
    AND NOT desconectada AND NOT datos_suficientes
  )
)

CONSTRAINT chk_resultadocelda_mascara_metricas
CHECK (NOT en_mascara OR (if_total IS NOT NULL AND p_error IS NOT NULL))

CONSTRAINT chk_resultadocelda_ifalta_suficiente
CHECK (datos_suficientes = (if_alta IS NOT NULL))

CONSTRAINT chk_resultadocelda_desconexion
CHECK (NOT desconectada OR (en_mascara AND datos_suficientes))

CONSTRAINT chk_resultadocelda_cambio_completo
CHECK (
  (cambio_orden IS NULL) = (cambio_confianza IS NULL)
  AND (cambio_orden IS NULL) = (cambio_delta_hv_db IS NULL)
)

chk_resultadocelda_desconexion no exige if_alta bajo el umbral: después del voto de mayoría, una celda puede quedar desconectada por sus vecinas con un if_alta algo mayor. Lo que sí garantiza es que nunca se declare desconectada una celda sin máscara o sin datos.

Unicidad

Nombre Definición Propósito
unq_resultadocelda_corrida_celda (corrida_id, celda_id) Lectura de una celda por llave, por RNF-02

Triggers

Nombre Evento Momento Nivel Regla Origen
trg_resultadocelda_largo_serie INSERT BEFORE ROW El largo de las series es el n_fechas de la corrida y la celda es de su región D-04
trg_resultado_solo_insercion UPDATE, DELETE BEFORE ROW Igual que en CorridaFecha RN-14

Resúmenes y pruebas

Cuatro tablas pequeñas, todas en régimen de resultado de corrida, que la API sirve sin recalcular.

ResumenPais

Una fila por país y una con pais = '' para la región completa.

Campo Tipo Descripción
corrida_id, pais Únicos juntos: unq_resumenpais_corrida_pais
ha_manglar real Celdas en máscara
ha_desconectada, ha_insuficiente, ha_perdida_copa real
ha_iv_tipica, ha_ow_tipica, ha_ni_tipica real Por clase típica
n_celdas integer

ResumenFecha

Hectáreas de cada clase por fecha y país, para la línea de tiempo y el CSV.

Campo Tipo Descripción
corrida_fecha_id, pais Únicos juntos: unq_resumenfecha_corridafecha_pais
ha_iv, ha_ow, ha_ni, ha_nc, ha_nd real Solo celdas en máscara de manglar

PruebaHipotesis

Campo Tipo Nulo Descripción
corrida_id, codigo no H1 / H2 / H3; únicos juntos
grupo_a, grupo_b varchar(100) no Descripción de cada grupo: «junto a bordas»...
evaluable boolean no
motivo text no Por qué no fue evaluable; '' si lo fue
n_a, n_b integer no
mediana_a, mediana_b real sí
estadistico_u, z, p_valor, efecto_r real sí Mann-Whitney; nulos si no fue evaluable
CONSTRAINT chk_pruebahipotesis_evaluable
CHECK (evaluable = (p_valor IS NOT NULL) AND evaluable = (motivo = ''))

ResultadoEstanque

Campo Tipo Nulo Descripción
corrida_id, estanque_id no Únicos juntos
cv_hh, cv_hv, cv real no CV por banda, promedio de los tracks; cv según cv_banda
activo boolean no cv >= cv_estanque
dist_canal_km real no Al agua abierta típica más cercana
if_vecino real sí if medio del manglar a tres celdas; nulo si no hay manglar
puntaje real sí Solo en abandonados
CONSTRAINT chk_resultadoestanque_puntaje
CHECK (activo = (puntaje IS NULL))