Ana María Montaño Hernández

1. Descargar datos de precipitación global.

El Grupo de Riesgos Climáticos de precipitación infrarroja con datos de estación (CHIRPS) es un conjunto de datos de precipitación cuasi global de más de 35 años. Con un alcance de 50 ° S-50 ° N (y todas las longitudes) y desde 1981 hasta el presente, CHIRPS incorpora nuestra climatología interna, CHPclim, imágenes satelitales con resolución de 0.05 ° y datos de estaciones in situ para crear series de tiempo de lluvia cuadriculadas para análisis de tendencias y monitoreo estacional de sequías.

library(rgdal)
rgdal: version: 1.4-8, (SVN revision 845)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
 Path to GDAL shared files: C:/Users/user/Documents/R/win-library/3.6/rgdal/gdal
 GDAL binary built with GEOS: TRUE 
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: C:/Users/user/Documents/R/win-library/3.6/rgdal/proj
 Linking to sp version: 1.4-1 
library(raster)
library(sf)
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(tidyverse)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.0     v purrr   0.3.3
v tibble  2.1.3     v dplyr   0.8.4
v tidyr   1.0.2     v stringr 1.4.0
v readr   1.3.1     v forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x tidyr::extract() masks raster::extract()
x dplyr::filter()  masks stats::filter()
x dplyr::lag()     masks stats::lag()
x dplyr::select()  masks raster::select()
library(tmap)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(gstat)
library(sp)

2. Pre-procesamiento de los datos CHIRPS:

Primero hay que leer el archivo CHIRPS sin comprimir:

precip <- raster("C:/Users/user/Documents/Intro_to_R/chirps-v2.0.2020.04.6.tif")

Este archivo representa la lluvia acumulada de los últimos días de abril de 2020 (es decir, la precipitación del 26 al 30 de abril)

Observemos qué hay en el objeto precip:

precip
class      : RasterLayer 
dimensions : 2000, 7200, 14400000  (nrow, ncol, ncell)
resolution : 0.05, 0.05  (x, y)
extent     : -180, 180, -50, 50  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : C:/Users/user/Documents/Intro_to_R/chirps-v2.0.2020.04.6.tif 
names      : chirps.v2.0.2020.04.6 

Tenga en cuenta que este es un conjunto de datos con cobertura global. El CRS es el sistema de coordenadas geográficas. Ahora, se va a cargar un archivo shapefile que represente nuestra área de interés:

(aoi <- shapefile("C:/Users/user/Documents/Norte de Santander/54_NORTE DE SANTANDER/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 40 
extent      : -73.63379, -72.04761, 6.872201, 9.290847  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 9
names       : DPTO_CCDGO, MPIO_CCDGO,        MPIO_CNMBR,                          MPIO_CRSLC,    MPIO_NAREA, MPIO_NANO,         DPTO_CNMBR,     Shape_Leng,       Shape_Area 
min values  :         54,      54001,            ABREGO,                                1555,   44.94540102,      2017, NORTE DE SANTANDER, 0.455016349208, 0.00368621836307 
max values  :         54,      54874, VILLA DEL ROSARIO, Ordenanza 9 de Noviembre 25 de 1948, 2680.07859017,      2017, NORTE DE SANTANDER,  4.08629755008,   0.220098910874 

Hay que tener en cuenta y asegurarse que los sistemas de referencia de coordenadas para ambos conjuntos de datos sean los mismos. Ahora, se van a Recortar los datos de precipitación:

#Datos de precipitación de cultivos por extensión, del área de interés.
precip.crop <- raster::crop(precip, extent(aoi))

Recortar la capa Raster

precip.mask <- mask(x = precip.crop, mask = aoi)

Chequear la salida:

precip.mask
class      : RasterLayer 
dimensions : 49, 32, 1568  (nrow, ncol, ncell)
resolution : 0.05, 0.05  (x, y)
extent     : -73.65, -72.05, 6.849999, 9.299999  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : chirps.v2.0.2020.04.6 
values     : 2.060457, 38.14587  (min, max)

Luego, se plotea la capa Raster recortada:

png("C:/Users/user/Documents/Intro_to_R/precipitaciones1.png")
plot(precip.mask, main= "CHIRPS precipitaciones en Norte de Santander desde 26.04 hasta 30.04 de 2020 [mm]", cex.main= 0.8 )
plot(aoi, add=TRUE)

También, se puede realizar un mapa mejor usando la librería Leaflet y la función addRasterImage

library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(c("red","orange", "yellow", "blue", "darkblue"), values(precip.mask), na.color = "transparent")

leaflet() %>% addTiles() %>%
  addRasterImage(precip.mask, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(precip.mask),
            title = "CHIRPS precipitaciones en Norte de Santander desde 26.04 hasta 30.04 de 2020 [mm]")
ning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Inf

La conversión de Raster en puntos se puede realizar utilizando la función rasterToPoints de la librería raster:

precip.points <- rasterToPoints(precip.mask, spatial = TRUE)
precip.points
class       : SpatialPointsDataFrame 
features    : 721 
extent      : -73.575, -72.075, 6.924999, 9.274999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       : chirps.v2.0.2020.04.6 
min values  :      2.06045699119568 
max values  :      38.1458702087402 
names(precip.points) <- "Lluvia"
precip.points
class       : SpatialPointsDataFrame 
features    : 721 
extent      : -73.575, -72.075, 6.924999, 9.274999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       :           Lluvia 
min values  : 2.06045699119568 
max values  : 38.1458702087402 
str(precip.points)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 721 obs. of  1 variable:
  .. ..$ Lluvia: num [1:721] 21.53 13.99 16.87 16.75 8.82 ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:721, 1:2] -73 -73.1 -73.1 -73 -73.2 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : chr [1:2] "x" "y"
  ..@ bbox       : num [1:2, 1:2] -73.57 6.92 -72.07 9.27
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"

Ahora, se plotean los puntos:

png("C:/Users/user/Documents/Intro_to_R/puntos.png")
plot(precip.mask, main= "Datos CHIRPS de precipitaciones desde el 26 al 30.04.2020 [mm]", cex.main= 0.9)
plot(aoi, add=TRUE)
points(precip.points$x, precip.points$y, col = "darkblue", cex = 0.5)

Escribamos los objetos espaciales de puntos en un archivo de disco. Esto para evitar que algo salga mal. Se va a utilizar la librería rgdal

geojsonio::geojson_write(precip.points, file = "C:/Users/user/Documents/Intro_to_R/ppoints.geojson")
Success! File is at C:/Users/user/Documents/Intro_to_R/ppoints.geojson
<geojson-file>
  Path:       C:/Users/user/Documents/Intro_to_R/ppoints.geojson
  From class: SpatialPointsDataFrame

Se van a leer los puntos de precipitación. Hay que consultar la documentación de geojsonio para comprender qué parámetros deben pasarse a la función geojson_read.

precip.points <- geojsonio::geojson_read("C:/Users/user/Documents/Intro_to_R/ppoints.geojson", what= "sp")

Verifiquemos qué hay en el objeto precip.points:

precip.points
class       : SpatialPointsDataFrame 
features    : 721 
extent      : -73.575, -72.075, 6.924999, 9.274999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       :           Lluvia 
min values  : 2.06045699119568 
max values  : 38.1458702087402 

Pero, ¿Cuál es el punto de convertir los datos de precipitación ráster en datos de precipitación de puntos? Bueno, es porque hay pocas estaciones meteorológicas de la Organización Meteorológica Mundial (OMM) en nuestro país. Por lo tanto, CHIRPS puede ser una opción para obtener los datos de precipitación puntuales necesarios para obtener una superficie de precipitación continua.

Preparación adicional

En caso de que se pierda la conexión, podemos leer nuevamente el archivo de forma con el área de interés:

(aoi <- shapefile("C:/Users/user/Documents/Norte de Santander/54_NORTE DE SANTANDER/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 40 
extent      : -73.63379, -72.04761, 6.872201, 9.290847  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 9
names       : DPTO_CCDGO, MPIO_CCDGO,        MPIO_CNMBR,                          MPIO_CRSLC,    MPIO_NAREA, MPIO_NANO,         DPTO_CNMBR,     Shape_Leng,       Shape_Area 
min values  :         54,      54001,            ABREGO,                                1555,   44.94540102,      2017, NORTE DE SANTANDER, 0.455016349208, 0.00368621836307 
max values  :         54,      54874, VILLA DEL ROSARIO, Ordenanza 9 de Noviembre 25 de 1948, 2680.07859017,      2017, NORTE DE SANTANDER,  4.08629755008,   0.220098910874 

Ahora, es necesario convertirlo a una característica espacial.

NortedeSantander_sf <- sf::st_as_sf(aoi)

Disolver los límites internos:

(border_sf <- 
   NortedeSantander_sf %>%
   summarise(area = sum(MPIO_NAREA)))
Simple feature collection with 1 feature and 1 field
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -73.63379 ymin: 6.872201 xmax: -72.04761 ymax: 9.290847
CRS:            +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
      area                       geometry
1 21856.44 POLYGON ((-72.4556 7.553288...

Convertir de característica espacial a dataframe espacial:

(border <- as(border_sf, "Spatial"))
class       : SpatialPolygonsDataFrame 
features    : 1 
extent      : -73.63379, -72.04761, 6.872201, 9.290847  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs 
variables   : 1
names       :           area 
value       : 21856.43898003 

Otra conversión:

(NortedeSantander_sf <- st_as_sf(aoi) %>% mutate(MUNIC = MPIO_CNMBR, CODIGO = MPIO_CCDGO) %>% select(MUNIC, CODIGO))
Simple feature collection with 40 features and 2 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -73.63379 ymin: 6.872201 xmax: -72.04761 ymax: 9.290847
CRS:            +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
First 10 features:
        MUNIC CODIGO                       geometry
1     CÚCUTA  54001 MULTIPOLYGON (((-72.4778 8....
2      ABREGO  54003 MULTIPOLYGON (((-73.01687 8...
3   ARBOLEDAS  54051 MULTIPOLYGON (((-72.73134 7...
4   BOCHALEMA  54099 MULTIPOLYGON (((-72.60265 7...
5  BUCARASICA  54109 MULTIPOLYGON (((-72.95019 8...
6  CÃ\u0081COTA  54125 MULTIPOLYGON (((-72.62101 7...
7  CÃ\u0081CHIRA  54128 MULTIPOLYGON (((-73.04222 7...
8  CHINÃ\u0081COTA  54172 MULTIPOLYGON (((-72.58771 7...
9   CUCUTILLA  54223 MULTIPOLYGON (((-72.79776 7...
10    DURANIA  54239 MULTIPOLYGON (((-72.63625 7...

Ahora se usará la función st_intersection de la libreria sf

p.sf <- st_as_sf(precip.points)
# Intersecta polígonos con puntos, manteniendo la información de ambos
(precip.sf = st_intersection(NortedeSantander_sf, p.sf))
although coordinates are longitude/latitude, st_intersection assumes that they are planar
attribute variables are assumed to be spatially constant throughout all geometries
Simple feature collection with 721 features and 3 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -73.575 ymin: 6.924999 xmax: -72.075 ymax: 9.274999
CRS:            +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
First 10 features:
           MUNIC CODIGO    Lluvia                 geometry
36     EL CARMEN  54245 21.525385 POINT (-73.025 9.274999)
36.1   EL CARMEN  54245 13.994514 POINT (-73.125 9.224999)
36.2   EL CARMEN  54245 16.871891 POINT (-73.075 9.224999)
35   CONVENCIÓN  54206 16.749319 POINT (-73.025 9.224999)
36.3   EL CARMEN  54245  8.823729 POINT (-73.225 9.174999)
36.4   EL CARMEN  54245  9.523139 POINT (-73.175 9.174999)
36.5   EL CARMEN  54245 10.936153 POINT (-73.125 9.174999)
36.6   EL CARMEN  54245 12.797283 POINT (-73.075 9.174999)
35.1 CONVENCIÓN  54206 10.394583 POINT (-73.025 9.174999)
35.2 CONVENCIÓN  54206 10.106214 POINT (-72.975 9.174999)

Dos reproyecciones:

p.sf.magna <- st_transform(precip.sf, crs = 3116)
NortedeSantander.sf.magna <- st_transform(NortedeSantander_sf, crs =3116)
(precip2 <- as(p.sf.magna, "Spatial"))
class       : SpatialPointsDataFrame 
features    : 721 
extent      : 1055435, 1221276, 1257812, 1517605  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 3
names       :             MUNIC, CODIGO,           Lluvia 
min values  :            ABREGO,  54001, 2.06045699119568 
max values  : VILLA DEL ROSARIO,  54874, 38.1458702087402 
shapefile(precip2, filename = "C:/Users/user/Documents/Intro_to_R/precip2.shp", overwrite = TRUE)
precip2$precipitaciones <- round(precip2$Lluvia, 1)
precip2
class       : SpatialPointsDataFrame 
features    : 721 
extent      : 1055435, 1221276, 1257812, 1517605  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 4
names       :             MUNIC, CODIGO,           Lluvia, precipitaciones 
min values  :            ABREGO,  54001, 2.06045699119568,             2.1 
max values  : VILLA DEL ROSARIO,  54874, 38.1458702087402,            38.1 
(NortedeSantander2 <- as(NortedeSantander.sf.magna, "Spatial"))
class       : SpatialPolygonsDataFrame 
features    : 40 
extent      : 1048947, 1224322, 1252020, 1519363  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :             MUNIC, CODIGO 
min values  :            ABREGO,  54001 
max values  : VILLA DEL ROSARIO,  54874 
precip2@bbox <- NortedeSantander2@bbox

Plotear los datos con tmpap

tm_shape(NortedeSantander2) + tm_polygons()+ tm_shape(precip2) + tm_dots(col = "precipitaciones", palette = "Paired", midpoint = 3.0,                               title = "Precipitación muestreada (en mm)", size = 0.2)


tm_text("precipitaciones", just = "center", xmod = 0.6, size = 0.4) + tm_legend(legend.outside = TRUE))
Error: inesperado ')' in "tm_text("precipitaciones", just = "center", xmod = 0.6, size = 0.4) + tm_legend(legend.outside = TRUE))"

3. Interpolación de datos de precipitación

3.1 Polígonos Thiessen

Los polígonos de Thiessen (o interpolación de proximidad) se pueden crear utilizando la función dirichlet de spatstat.

th <- as(dirichlet(as.ppp(precip2)), "SpatialPolygons")

crs(th) <- crs(precip2)
crs(NortedeSantander2) <- crs(precip2)
crs(th)
CRS arguments:
 +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667
+k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80
+towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
crs(precip2)
CRS arguments:
 +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667
+k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80
+towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
th.z <- over(th, precip2, fn=mean)
th.spdf <- SpatialPolygonsDataFrame(th, th.z)

th.clp <- raster::intersect(NortedeSantander2, th.spdf)
tm_shape(th.clp) + tm_polygons(col= "Lluvia", palette= "RdYlBu", midpoint= 3.0,
                               title = "Polígonos Thiessen\n Precipitación predicha\n [en mm]") +
tm_legend(legend.outside= TRUE)

3.2 Interpolación usando una ponderación basada en el inverso de la distancia (IDW)

grd  <- as.data.frame(spsample(precip2, "regular", n= 100000))
names(grd)  <- c("X", "Y")
coordinates(grd) <- c("X", "Y")
gridded(grd)  <- TRUE
fullgrid(grd) <- TRUE


proj4string(grd)  <- proj4string(precip2)

P.idw <- gstat::idw(Lluvia ~ 1, precip2, newdata= grd, idp = 2.0)
[inverse distance weighted interpolation]
r  <- raster(P.idw)
r
class      : RasterLayer 
dimensions : 390, 256, 99840  (nrow, ncol, ncell)
resolution : 684.7279, 684.7279  (x, y)
extent     : 1049175, 1224466, 1252357, 1519401  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 2.085806, 37.93612  (min, max)
NortedeSantander2
class       : SpatialPolygonsDataFrame 
features    : 40 
extent      : 1048947, 1224322, 1252020, 1519363  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :             MUNIC, CODIGO 
min values  :            ABREGO,  54001 
max values  : VILLA DEL ROSARIO,  54874 
r.m <- raster::mask(r, NortedeSantander2)
r.m
class      : RasterLayer 
dimensions : 390, 256, 99840  (nrow, ncol, ncell)
resolution : 684.7279, 684.7279  (x, y)
extent     : 1049175, 1224466, 1252357, 1519401  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 2.085806, 37.93612  (min, max)

Ahora, se va a plotear:


tm_shape(r.m) + tm_raster(n=8, palette = "RdBu", auto.palette.mapping = FALSE,
                          title = "Distancia Inversa Ponderada\n Precipitación prevista [en mm]") + tm_shape(precip2) + tm_dots(size = 0.05) + tm_legend(legend.outside= TRUE)
The argument auto.palette.mapping is deprecated. Please use midpoint for numeric data and stretch.palette for categorical data to control the palette mapping.

Ahora, se obtendrá una mejor visualización de la superficie interpolada.

library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(c("red", "orange", "yellow", "blue", "darkblue"), values(precip.mask), 
                    na.color = "transparent")

leaflet() %>% addTiles() %>%
  addRasterImage(r.m, colors = pal, opacity = 0.6) %>% 
  addLegend(pal = pal, values = values(r.m),
            title = "Precipitación interpolada con IDW en Norte de Santander \ndel 26.04 al 30.04 del 2020 [mm] " )
ning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Inf

Afinando la interpolación.

Para ajustar la elección del parámetro de potencia, puede realizar una rutina de validación de omisión para medir el error en los valores interpolados.

precip2
class       : SpatialPointsDataFrame 
features    : 721 
extent      : 1048947, 1224322, 1252020, 1519363  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 4
names       :             MUNIC, CODIGO,           Lluvia, precipitaciones 
min values  :            ABREGO,  54001, 2.06045699119568,             2.1 
max values  : VILLA DEL ROSARIO,  54874, 38.1458702087402,            38.1 
P <- precip2
IDW.out <- vector(length = length(P))
for (i in 1:length(P)) {
  IDW.out[i] <- gstat::idw(Lluvia ~ 1, P[-i,], P[i,], idp= 2.0) $var1.pred
}

Plotear las diferencias


OP <- par(pty = "s", mar=c(4,3,0,0))
plot(IDW.out ~ P$Lluvia, asp=1, xlab= "Observado", ylab ="Predicho", pch= 16, 
     col=rgb(0,0,0,0.5))
abline(lm(IDW.out ~ P$Lluvia), col="red", lw=2, lty=2)
abline(0,1)

par(OP)

El error cuadrático medio (RMSE) se puede calcular desde IDW.out de la siguiente manera:

sqrt( sum((IDW.out - P$Lluvia)^2) / length(P))
[1] 2.393775

Revisar este valor, y arreglarlo porque el error está muy alto. Tal vez revisar el parámetro de potencia de idp = 2.0

Validación cruzada (Cross-validation)

Además de generar una superficie interpolada, se puede crear un mapa de intervalo de confianza del 95% del modelo de interpolación. Aquí se creará un mapa de IC del 95% a partir de una interpolación IDW que utiliza un parámetro de potencia de 2 (idp = 2.0)

3.3 Kriging

3.3.1 Ajustar el modelo de variograma

Primero, es necesario crear un modelo de variograma. Hay que tener en cuenta que el modelo de variograma se calcula sobre los datos de tendencia. Esto se implementa en el siguiente fragmento de código pasando el modelo de tendencia de primer orden (definido en un fragmento de código anterior como objeto de fórmula f.1) a la función variograma.

f.1 <- as.formula(precipitaciones ~ X + Y)
P$X <- coordinates(P)[,1]
P$Y <- coordinates(P)[,2]
var.smpl <- variogram(f.1, P, cloud = FALSE, cutoff = 100000, width = 8990)

dat.fit  <- fit.variogram(var.smpl, fit.ranges = TRUE, fit.sills = TRUE, 
                          vgm(psill = 3, model = "Mat", range = 150000, nugget = 0.2))
dat.fit

plot(var.smpl, dat.fit, xlim=c(0,110000))

Generar superficie Kriged Luego, use el modelo de variograma dat.fit para generar una superficie interpolada kriged. La función krige nos permite incluir el modelo de tendencia, lo que nos evita tener que reducir la tendencia de los datos, corregir los residuos y luego combinar los dos rásteres. En cambio, todo lo que tenemos que hacer es pasar krige la fórmula de tendencia f.1.

f.1 <- as.formula(Lluvia ~ X + Y)
dat.krg <- krige(f.1, P, grd, dat.fit)
[using universal kriging]
r <- raster(dat.krg)
r.m <- raster::mask(r, NortedeSantander2)
r.m
class      : RasterLayer 
dimensions : 390, 256, 99840  (nrow, ncol, ncell)
resolution : 684.7279, 684.7279  (x, y)
extent     : 1049175, 1224466, 1252357, 1519401  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 1.982649, 38.13942  (min, max)
tm_shape(r.m) + 
  tm_raster(n=10, palette="RdBu", auto.palette.mapping=FALSE, 
            title="Universal Kriging\nPrecipitación predicha \n(en mm)") +
  tm_shape(P) + tm_dots(size=0.1) +
  tm_legend(legend.outside=TRUE)
The argument auto.palette.mapping is deprecated. Please use midpoint for numeric data and stretch.palette for categorical data to control the palette mapping.

r   <- raster(dat.krg, layer="var1.var")
r.m <- raster::mask(r, NortedeSantander2)

tm_shape(r.m) + 
  tm_raster(n=7, palette ="Reds",
            title="Kriging Interpolation\nMapa de varianza \n(in squared mm)") +tm_shape(P) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)

Un mapa más fácil de interpretar es el mapa del intervalo de confianza del 95% que se puede generar a partir del objeto de varianza de la siguiente manera (los valores del mapa deben interpretarse como el número de mm por encima y por debajo de la cantidad de lluvia estimada).


r   <- sqrt(raster(dat.krg, layer="var1.var")) * 1.96
r.m <- raster::mask(r, NortedeSantander2)

tm_shape(r.m) + 
  tm_raster(n=7, palette ="Reds",
            title="Interpolación kriging\n Mapa de 95% IC\n(en mm)") +tm_shape(P) + tm_dots(size=0.1) +
  tm_legend(legend.outside=TRUE)

sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18363)

Matrix products: default

locale:
[1] LC_COLLATE=Spanish_Colombia.1252  LC_CTYPE=Spanish_Colombia.1252   
[3] LC_MONETARY=Spanish_Colombia.1252 LC_NUMERIC=C                     
[5] LC_TIME=Spanish_Colombia.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] spatstat_1.64-1     rpart_4.1-15        nlme_3.1-148       
 [4] spatstat.data_1.4-3 RColorBrewer_1.1-2  leaflet_2.0.3      
 [7] gstat_2.0-6         tmap_3.0            forcats_0.5.0      
[10] stringr_1.4.0       dplyr_0.8.4         purrr_0.3.3        
[13] readr_1.3.1         tidyr_1.0.2         tibble_2.1.3       
[16] ggplot2_3.3.0       tidyverse_1.3.0     sf_0.9-3           
[19] rgdal_1.4-8         raster_3.0-12       sp_1.4-1           

loaded via a namespace (and not attached):
  [1] leafem_0.1.1          colorspace_1.4-1      deldir_0.1-25        
  [4] class_7.3-15          rsconnect_0.8.16      base64enc_0.1-3      
  [7] fs_1.3.2              dichromat_2.0-0       httpcode_0.3.0       
 [10] rstudioapi_0.11       farver_2.0.3          fansi_0.4.1          
 [13] lubridate_1.7.4       xml2_1.2.5            splines_3.6.3        
 [16] codetools_0.2-16      knitr_1.28            polyclip_1.10-0      
 [19] jsonlite_1.6.1        tmaptools_3.0         broom_0.5.5          
 [22] dbplyr_1.4.2          png_0.1-7             rgeos_0.5-2          
 [25] shiny_1.4.0           compiler_3.6.3        httr_1.4.1           
 [28] backports_1.1.5       Matrix_1.2-18         assertthat_0.2.1     
 [31] fastmap_1.0.1         lazyeval_0.2.2        cli_2.0.2            
 [34] later_1.0.0           htmltools_0.4.0       tools_3.6.3          
 [37] gtable_0.3.0          glue_1.3.1            geojson_0.3.2        
 [40] V8_3.1.0              Rcpp_1.0.3            cellranger_1.1.0     
 [43] vctrs_0.2.3           crul_0.9.0            leafsync_0.1.0       
 [46] crosstalk_1.0.0       lwgeom_0.2-1          xfun_0.12            
 [49] rvest_0.3.5           mime_0.9              lifecycle_0.2.0      
 [52] goftest_1.2-2         XML_3.99-0.3          jqr_1.1.0            
 [55] zoo_1.8-7             scales_1.1.0          spatstat.utils_1.17-0
 [58] hms_0.5.3             promises_1.1.0        parallel_3.6.3       
 [61] yaml_2.2.1            curl_4.3              stringi_1.4.6        
 [64] maptools_0.9-9        e1071_1.7-3           intervals_0.15.2     
 [67] rlang_0.4.5           pkgconfig_2.0.3       evaluate_0.14        
 [70] lattice_0.20-38       tensor_1.5            htmlwidgets_1.5.1    
 [73] tidyselect_1.0.0      magrittr_1.5          R6_2.4.1             
 [76] geojsonio_0.9.2       generics_0.0.2        DBI_1.1.0            
 [79] mgcv_1.8-31           pillar_1.4.3          haven_2.2.0          
 [82] foreign_0.8-75        withr_2.1.2           units_0.6-5          
 [85] stars_0.4-1           xts_0.12-0            abind_1.4-5          
 [88] spacetime_1.2-3       modelr_0.1.6          crayon_1.3.4         
 [91] KernSmooth_2.23-16    rmarkdown_2.1         grid_3.6.3           
 [94] readxl_1.3.1          FNN_1.1.3             reprex_0.3.0         
 [97] digest_0.6.25         classInt_0.4-3        xtable_1.8-4         
[100] httpuv_1.5.2          munsell_0.5.0         viridisLite_0.3.0    
LS0tDQp0aXRsZTogIkRhdG9zIENISVJQUyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCkFuYSBNYXLDrWEgTW9udGHDsW8gSGVybsOhbmRleiANCg0KIyAxLiBEZXNjYXJnYXIgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gZ2xvYmFsLg0KRWwgR3J1cG8gZGUgUmllc2dvcyBDbGltw6F0aWNvcyBkZSBwcmVjaXBpdGFjacOzbiBpbmZyYXJyb2phIGNvbiBkYXRvcyBkZSBlc3RhY2nDs24gKENISVJQUykgZXMgdW4gY29uanVudG8gZGUgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gY3Vhc2kgZ2xvYmFsIGRlIG3DoXMgZGUgMzUgYcOxb3MuIENvbiB1biBhbGNhbmNlIGRlIDUwIMKwIFMtNTAgwrAgTiAoeSB0b2RhcyBsYXMgbG9uZ2l0dWRlcykgeSBkZXNkZSAxOTgxIGhhc3RhIGVsIHByZXNlbnRlLCBDSElSUFMgaW5jb3Jwb3JhIG51ZXN0cmEgY2xpbWF0b2xvZ8OtYSBpbnRlcm5hLCBDSFBjbGltLCBpbcOhZ2VuZXMgc2F0ZWxpdGFsZXMgY29uIHJlc29sdWNpw7NuIGRlIDAuMDUgwrAgeSBkYXRvcyBkZSBlc3RhY2lvbmVzIGluIHNpdHUgcGFyYSBjcmVhciBzZXJpZXMgZGUgdGllbXBvIGRlIGxsdXZpYSBjdWFkcmljdWxhZGFzIHBhcmEgYW7DoWxpc2lzIGRlIHRlbmRlbmNpYXMgeSBtb25pdG9yZW8gZXN0YWNpb25hbCBkZSBzZXF1w61hcy4NCg0KYGBge3J9DQpsaWJyYXJ5KHJnZGFsKQ0KbGlicmFyeShyYXN0ZXIpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KGdzdGF0KQ0KbGlicmFyeShzcCkNCmBgYA0KDQojIDIuIFByZS1wcm9jZXNhbWllbnRvIGRlIGxvcyBkYXRvcyBDSElSUFM6DQpQcmltZXJvIGhheSBxdWUgbGVlciBlbCBhcmNoaXZvIENISVJQUyBzaW4gY29tcHJpbWlyOg0KDQpgYGB7cn0NCnByZWNpcCA8LSByYXN0ZXIoIkM6L1VzZXJzL3VzZXIvRG9jdW1lbnRzL0ludHJvX3RvX1IvY2hpcnBzLXYyLjAuMjAyMC4wNC42LnRpZiIpDQpgYGANCg0KRXN0ZSBhcmNoaXZvIHJlcHJlc2VudGEgbGEgbGx1dmlhIGFjdW11bGFkYSBkZSBsb3Mgw7psdGltb3MgZMOtYXMgZGUgYWJyaWwgZGUgMjAyMCAoZXMgZGVjaXIsIGxhIHByZWNpcGl0YWNpw7NuIGRlbCAyNiBhbCAzMCBkZSBhYnJpbCkNCg0KT2JzZXJ2ZW1vcyBxdcOpIGhheSBlbiBlbCBvYmpldG8gcHJlY2lwOg0KYGBge3J9DQpwcmVjaXANCmBgYA0KDQpUZW5nYSBlbiBjdWVudGEgcXVlIGVzdGUgZXMgdW4gY29uanVudG8gZGUgZGF0b3MgY29uIGNvYmVydHVyYSBnbG9iYWwuIEVsIENSUyBlcyBlbCBzaXN0ZW1hIGRlIGNvb3JkZW5hZGFzIGdlb2dyw6FmaWNhcy4NCkFob3JhLCBzZSB2YSBhIGNhcmdhciB1biBhcmNoaXZvIHNoYXBlZmlsZSBxdWUgcmVwcmVzZW50ZSBudWVzdHJhIMOhcmVhIGRlIGludGVyw6lzOg0KDQpgYGB7cn0NCihhb2kgPC0gc2hhcGVmaWxlKCJDOi9Vc2Vycy91c2VyL0RvY3VtZW50cy9Ob3J0ZSBkZSBTYW50YW5kZXIvNTRfTk9SVEUgREUgU0FOVEFOREVSL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQoNCkhheSBxdWUgdGVuZXIgZW4gY3VlbnRhIHkgYXNlZ3VyYXJzZSBxdWUgbG9zIHNpc3RlbWFzIGRlIHJlZmVyZW5jaWEgZGUgY29vcmRlbmFkYXMgcGFyYSBhbWJvcyBjb25qdW50b3MgZGUgZGF0b3Mgc2VhbiBsb3MgbWlzbW9zLiANCkFob3JhLCBzZSB2YW4gYSAqKlJlY29ydGFyKiogbG9zIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuOg0KYGBge3J9DQojRGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gZGUgY3VsdGl2b3MgcG9yIGV4dGVuc2nDs24sIGRlbCDDoXJlYSBkZSBpbnRlcsOpcy4NCnByZWNpcC5jcm9wIDwtIHJhc3Rlcjo6Y3JvcChwcmVjaXAsIGV4dGVudChhb2kpKQ0KYGBgDQoNClJlY29ydGFyIGxhIGNhcGEgUmFzdGVyDQoNCmBgYHtyfQ0KcHJlY2lwLm1hc2sgPC0gbWFzayh4ID0gcHJlY2lwLmNyb3AsIG1hc2sgPSBhb2kpDQpgYGANCkNoZXF1ZWFyIGxhIHNhbGlkYToNCmBgYHtyfQ0KcHJlY2lwLm1hc2sNCmBgYA0KDQpMdWVnbywgc2UgcGxvdGVhIGxhIGNhcGEgUmFzdGVyIHJlY29ydGFkYToNCmBgYHtyfQ0KDQpwbG90KHByZWNpcC5tYXNrLCBtYWluPSAiQ0hJUlBTIHByZWNpcGl0YWNpb25lcyBlbiBOb3J0ZSBkZSBTYW50YW5kZXIgZGVzZGUgMjYuMDQgaGFzdGEgMzAuMDQgZGUgMjAyMCBbbW1dIiwgY2V4Lm1haW49IDAuOCApDQpwbG90KGFvaSwgYWRkPVRSVUUpDQpgYGANCg0KVGFtYmnDqW4sIHNlIHB1ZWRlIHJlYWxpemFyIHVuIG1hcGEgbWVqb3IgdXNhbmRvIGxhIGxpYnJlcsOtYSAqTGVhZmxldCogeSBsYSBmdW5jacOzbiAqKmFkZFJhc3RlckltYWdlKioNCg0KYGBge3J9DQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCnBhbCA8LSBjb2xvck51bWVyaWMoYygicmVkIiwib3JhbmdlIiwgInllbGxvdyIsICJibHVlIiwgImRhcmtibHVlIiksIHZhbHVlcyhwcmVjaXAubWFzayksIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JQ0KICBhZGRSYXN0ZXJJbWFnZShwcmVjaXAubWFzaywgY29sb3JzID0gcGFsLCBvcGFjaXR5ID0gMC42KSAlPiUNCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gdmFsdWVzKHByZWNpcC5tYXNrKSwNCiAgICAgICAgICAgIHRpdGxlID0gIkNISVJQUyBwcmVjaXBpdGFjaW9uZXMgZW4gTm9ydGUgZGUgU2FudGFuZGVyIGRlc2RlIDI2LjA0IGhhc3RhIDMwLjA0IGRlIDIwMjAgW21tXSIpDQpgYGANCg0KTGEgY29udmVyc2nDs24gZGUgUmFzdGVyIGVuIHB1bnRvcyBzZSBwdWVkZSByZWFsaXphciB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuICoqcmFzdGVyVG9Qb2ludHMqKiBkZSBsYSBsaWJyZXLDrWEgcmFzdGVyOg0KDQpgYGB7cn0NCnByZWNpcC5wb2ludHMgPC0gcmFzdGVyVG9Qb2ludHMocHJlY2lwLm1hc2ssIHNwYXRpYWwgPSBUUlVFKQ0KDQpgYGANCg0KYGBge3J9DQpwcmVjaXAucG9pbnRzDQpgYGANCg0KYGBge3J9DQpuYW1lcyhwcmVjaXAucG9pbnRzKSA8LSAiTGx1dmlhIg0KYGBgDQoNCmBgYHtyfQ0KcHJlY2lwLnBvaW50cw0KYGBgDQpgYGB7cn0NCnN0cihwcmVjaXAucG9pbnRzKQ0KYGBgDQoNCkFob3JhLCBzZSBwbG90ZWFuIGxvcyBwdW50b3M6DQpgYGB7cn0NCg0KcGxvdChwcmVjaXAubWFzaywgbWFpbj0gIkRhdG9zIENISVJQUyBkZSBwcmVjaXBpdGFjaW9uZXMgZGVzZGUgZWwgMjYgYWwgMzAuMDQuMjAyMCBbbW1dIiwgY2V4Lm1haW49IDAuOSkNCnBsb3QoYW9pLCBhZGQ9VFJVRSkNCnBvaW50cyhwcmVjaXAucG9pbnRzJHgsIHByZWNpcC5wb2ludHMkeSwgY29sID0gImRhcmtibHVlIiwgY2V4ID0gMC41KQ0KYGBgDQoNCkVzY3JpYmFtb3MgbG9zIG9iamV0b3MgZXNwYWNpYWxlcyBkZSBwdW50b3MgZW4gdW4gYXJjaGl2byBkZSBkaXNjby4gRXN0byBwYXJhIGV2aXRhciBxdWUgYWxnbyBzYWxnYSBtYWwuDQpTZSB2YSBhIHV0aWxpemFyIGxhIGxpYnJlcsOtYSAqcmdkYWwqDQpgYGB7cn0NCmdlb2pzb25pbzo6Z2VvanNvbl93cml0ZShwcmVjaXAucG9pbnRzLCBmaWxlID0gIkM6L1VzZXJzL3VzZXIvRG9jdW1lbnRzL0ludHJvX3RvX1IvcHBvaW50cy5nZW9qc29uIikNCmBgYA0KDQpTZSB2YW4gYSBsZWVyIGxvcyBwdW50b3MgZGUgcHJlY2lwaXRhY2nDs24uIEhheSBxdWUgY29uc3VsdGFyIGxhIGRvY3VtZW50YWNpw7NuIGRlICoqZ2VvanNvbmlvKiogcGFyYSBjb21wcmVuZGVyIHF1w6kgcGFyw6FtZXRyb3MgZGViZW4gcGFzYXJzZSBhIGxhIGZ1bmNpw7NuICoqZ2VvanNvbl9yZWFkKiouDQpgYGB7cn0NCnByZWNpcC5wb2ludHMgPC0gZ2VvanNvbmlvOjpnZW9qc29uX3JlYWQoIkM6L1VzZXJzL3VzZXIvRG9jdW1lbnRzL0ludHJvX3RvX1IvcHBvaW50cy5nZW9qc29uIiwgd2hhdD0gInNwIikNCmBgYA0KVmVyaWZpcXVlbW9zIHF1w6kgaGF5IGVuIGVsIG9iamV0byBwcmVjaXAucG9pbnRzOg0KYGBge3J9DQpwcmVjaXAucG9pbnRzDQpgYGANCg0KUGVybywgwr9DdcOhbCBlcyBlbCBwdW50byBkZSBjb252ZXJ0aXIgbG9zIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuIHLDoXN0ZXIgZW4gZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gZGUgcHVudG9zPw0KQnVlbm8sIGVzIHBvcnF1ZSBoYXkgcG9jYXMgZXN0YWNpb25lcyBtZXRlb3JvbMOzZ2ljYXMgZGUgbGEgT3JnYW5pemFjacOzbiBNZXRlb3JvbMOzZ2ljYSBNdW5kaWFsIChPTU0pIGVuIG51ZXN0cm8gcGHDrXMuIA0KUG9yIGxvIHRhbnRvLCBDSElSUFMgcHVlZGUgc2VyIHVuYSBvcGNpw7NuIHBhcmEgb2J0ZW5lciBsb3MgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gcHVudHVhbGVzIG5lY2VzYXJpb3MgcGFyYSBvYnRlbmVyIHVuYSBzdXBlcmZpY2llIGRlIHByZWNpcGl0YWNpw7NuIGNvbnRpbnVhLg0KDQojIFByZXBhcmFjacOzbiBhZGljaW9uYWwNCkVuIGNhc28gZGUgcXVlIHNlIHBpZXJkYSBsYSBjb25leGnDs24sIHBvZGVtb3MgbGVlciBudWV2YW1lbnRlIGVsIGFyY2hpdm8gZGUgZm9ybWEgY29uIGVsIMOhcmVhIGRlIGludGVyw6lzOg0KDQpgYGB7cn0NCihhb2kgPC0gc2hhcGVmaWxlKCJDOi9Vc2Vycy91c2VyL0RvY3VtZW50cy9Ob3J0ZSBkZSBTYW50YW5kZXIvNTRfTk9SVEUgREUgU0FOVEFOREVSL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQoNCkFob3JhLCBlcyBuZWNlc2FyaW8gY29udmVydGlybG8gYSB1bmEgY2FyYWN0ZXLDrXN0aWNhIGVzcGFjaWFsLg0KYGBge3J9DQpOb3J0ZWRlU2FudGFuZGVyX3NmIDwtIHNmOjpzdF9hc19zZihhb2kpDQpgYGANCg0KRGlzb2x2ZXIgbG9zIGzDrW1pdGVzIGludGVybm9zOg0KYGBge3J9DQooYm9yZGVyX3NmIDwtIA0KICAgTm9ydGVkZVNhbnRhbmRlcl9zZiAlPiUNCiAgIHN1bW1hcmlzZShhcmVhID0gc3VtKE1QSU9fTkFSRUEpKSkNCmBgYA0KDQpDb252ZXJ0aXIgZGUgY2FyYWN0ZXLDrXN0aWNhIGVzcGFjaWFsIGEgZGF0YWZyYW1lIGVzcGFjaWFsOg0KYGBge3J9DQooYm9yZGVyIDwtIGFzKGJvcmRlcl9zZiwgIlNwYXRpYWwiKSkNCmBgYA0KDQpPdHJhIGNvbnZlcnNpw7NuOg0KYGBge3J9DQooTm9ydGVkZVNhbnRhbmRlcl9zZiA8LSBzdF9hc19zZihhb2kpICU+JSBtdXRhdGUoTVVOSUMgPSBNUElPX0NOTUJSLCBDT0RJR08gPSBNUElPX0NDREdPKSAlPiUgc2VsZWN0KE1VTklDLCBDT0RJR08pKQ0KYGBgDQoNCkFob3JhIHNlIHVzYXLDoSBsYSBmdW5jacOzbiAqKnN0X2ludGVyc2VjdGlvbioqIGRlIGxhIGxpYnJlcmlhICoqc2YqKg0KDQpgYGB7cn0NCnAuc2YgPC0gc3RfYXNfc2YocHJlY2lwLnBvaW50cykNCmBgYA0KDQpgYGB7cn0NCiMgSW50ZXJzZWN0YSBwb2zDrWdvbm9zIGNvbiBwdW50b3MsIG1hbnRlbmllbmRvIGxhIGluZm9ybWFjacOzbiBkZSBhbWJvcw0KKHByZWNpcC5zZiA9IHN0X2ludGVyc2VjdGlvbihOb3J0ZWRlU2FudGFuZGVyX3NmLCBwLnNmKSkNCmBgYA0KDQpEb3MgcmVwcm95ZWNjaW9uZXM6DQpgYGB7cn0NCnAuc2YubWFnbmEgPC0gc3RfdHJhbnNmb3JtKHByZWNpcC5zZiwgY3JzID0gMzExNikNCmBgYA0KDQpgYGB7cn0NCk5vcnRlZGVTYW50YW5kZXIuc2YubWFnbmEgPC0gc3RfdHJhbnNmb3JtKE5vcnRlZGVTYW50YW5kZXJfc2YsIGNycyA9MzExNikNCmBgYA0KDQpgYGB7cn0NCihwcmVjaXAyIDwtIGFzKHAuc2YubWFnbmEsICJTcGF0aWFsIikpDQpgYGANCmBgYHtyfQ0Kc2hhcGVmaWxlKHByZWNpcDIsIGZpbGVuYW1lID0gIkM6L1VzZXJzL3VzZXIvRG9jdW1lbnRzL0ludHJvX3RvX1IvcHJlY2lwMi5zaHAiLCBvdmVyd3JpdGUgPSBUUlVFKQ0KYGBgDQpgYGB7cn0NCnByZWNpcDIkcHJlY2lwaXRhY2lvbmVzIDwtIHJvdW5kKHByZWNpcDIkTGx1dmlhLCAxKQ0KDQpgYGANCmBgYHtyfQ0KcHJlY2lwMg0KYGBgDQoNCmBgYHtyfQ0KKE5vcnRlZGVTYW50YW5kZXIyIDwtIGFzKE5vcnRlZGVTYW50YW5kZXIuc2YubWFnbmEsICJTcGF0aWFsIikpDQpgYGANCg0KYGBge3J9DQpwcmVjaXAyQGJib3ggPC0gTm9ydGVkZVNhbnRhbmRlcjJAYmJveA0KYGBgDQoNCiMgUGxvdGVhciBsb3MgZGF0b3MgY29uIHRtcGFwDQpgYGB7cn0NCnRtX3NoYXBlKE5vcnRlZGVTYW50YW5kZXIyKSArIHRtX3BvbHlnb25zKCkrIHRtX3NoYXBlKHByZWNpcDIpICsgdG1fZG90cyhjb2wgPSAicHJlY2lwaXRhY2lvbmVzIiwgcGFsZXR0ZSA9ICJQYWlyZWQiLCBtaWRwb2ludCA9IDMuMCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiUHJlY2lwaXRhY2nDs24gbXVlc3RyZWFkYSAoZW4gbW0pIiwgc2l6ZSA9IDAuMikNCg0KdG1fdGV4dCgicHJlY2lwaXRhY2lvbmVzIiwganVzdCA9ICJjZW50ZXIiLCB4bW9kID0gMC42LCBzaXplID0gMC40KSArIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZSA9IFRSVUUpKQ0KYGBgDQoNCg0KDQojIDMuIEludGVycG9sYWNpw7NuIGRlIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuDQoNCiMgMy4xIFBvbMOtZ29ub3MgVGhpZXNzZW4NCg0KTG9zIHBvbMOtZ29ub3MgZGUgVGhpZXNzZW4gKG8gaW50ZXJwb2xhY2nDs24gZGUgcHJveGltaWRhZCkgc2UgcHVlZGVuIGNyZWFyIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gZGlyaWNobGV0IGRlIHNwYXRzdGF0Lg0KDQpgYGB7cn0NCnRoIDwtIGFzKGRpcmljaGxldChhcy5wcHAocHJlY2lwMikpLCAiU3BhdGlhbFBvbHlnb25zIikNCg0KY3JzKHRoKSA8LSBjcnMocHJlY2lwMikNCmNycyhOb3J0ZWRlU2FudGFuZGVyMikgPC0gY3JzKHByZWNpcDIpDQpgYGANCg0KYGBge3J9DQpjcnModGgpDQpgYGANCmBgYHtyfQ0KY3JzKHByZWNpcDIpDQpgYGANCg0KYGBge3J9DQp0aC56IDwtIG92ZXIodGgsIHByZWNpcDIsIGZuPW1lYW4pDQp0aC5zcGRmIDwtIFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSh0aCwgdGgueikNCg0KdGguY2xwIDwtIHJhc3Rlcjo6aW50ZXJzZWN0KE5vcnRlZGVTYW50YW5kZXIyLCB0aC5zcGRmKQ0KYGBgDQoNCmBgYHtyfQ0KdG1fc2hhcGUodGguY2xwKSArIHRtX3BvbHlnb25zKGNvbD0gIkxsdXZpYSIsIHBhbGV0dGU9ICJSZFlsQnUiLCBtaWRwb2ludD0gMy4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlBvbMOtZ29ub3MgVGhpZXNzZW5cbiBQcmVjaXBpdGFjacOzbiBwcmVkaWNoYVxuIFtlbiBtbV0iKSArDQp0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9IFRSVUUpDQpgYGANCg0KIyAzLjIgSW50ZXJwb2xhY2nDs24gdXNhbmRvIHVuYSBwb25kZXJhY2nDs24gYmFzYWRhIGVuIGVsIGludmVyc28gZGUgbGEgZGlzdGFuY2lhIChJRFcpDQoNCmBgYHtyfQ0KZ3JkICA8LSBhcy5kYXRhLmZyYW1lKHNwc2FtcGxlKHByZWNpcDIsICJyZWd1bGFyIiwgbj0gMTAwMDAwKSkNCm5hbWVzKGdyZCkgIDwtIGMoIlgiLCAiWSIpDQpjb29yZGluYXRlcyhncmQpIDwtIGMoIlgiLCAiWSIpDQpncmlkZGVkKGdyZCkgIDwtIFRSVUUNCmZ1bGxncmlkKGdyZCkgPC0gVFJVRQ0KDQoNCnByb2o0c3RyaW5nKGdyZCkgIDwtIHByb2o0c3RyaW5nKHByZWNpcDIpDQoNClAuaWR3IDwtIGdzdGF0OjppZHcoTGx1dmlhIH4gMSwgcHJlY2lwMiwgbmV3ZGF0YT0gZ3JkLCBpZHAgPSAyLjApDQoNCnIgIDwtIHJhc3RlcihQLmlkdykNCmBgYA0KYGBge3J9DQpyDQpgYGANCg0KYGBge3J9DQpOb3J0ZWRlU2FudGFuZGVyMg0KYGBgDQoNCmBgYHtyfQ0Kci5tIDwtIHJhc3Rlcjo6bWFzayhyLCBOb3J0ZWRlU2FudGFuZGVyMikNCmBgYA0KDQpgYGB7cn0NCnIubQ0KYGBgDQoNCkFob3JhLCBzZSB2YSBhIHBsb3RlYXI6DQpgYGB7cn0NCg0KdG1fc2hhcGUoci5tKSArIHRtX3Jhc3RlcihuPTgsIHBhbGV0dGUgPSAiUmRCdSIsIGF1dG8ucGFsZXR0ZS5tYXBwaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkRpc3RhbmNpYSBJbnZlcnNhIFBvbmRlcmFkYVxuIFByZWNpcGl0YWNpw7NuIHByZXZpc3RhIFtlbiBtbV0iKSArIHRtX3NoYXBlKHByZWNpcDIpICsgdG1fZG90cyhzaXplID0gMC4wNSkgKyB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9IFRSVUUpDQoNCmBgYA0KDQpBaG9yYSwgc2Ugb2J0ZW5kcsOhIHVuYSBtZWpvciB2aXN1YWxpemFjacOzbiBkZSBsYSBzdXBlcmZpY2llIGludGVycG9sYWRhLg0KYGBge3J9DQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCnBhbCA8LSBjb2xvck51bWVyaWMoYygicmVkIiwgIm9yYW5nZSIsICJ5ZWxsb3ciLCAiYmx1ZSIsICJkYXJrYmx1ZSIpLCB2YWx1ZXMocHJlY2lwLm1hc2spLCANCiAgICAgICAgICAgICAgICAgICAgbmEuY29sb3IgPSAidHJhbnNwYXJlbnQiKQ0KDQpsZWFmbGV0KCkgJT4lIGFkZFRpbGVzKCkgJT4lDQogIGFkZFJhc3RlckltYWdlKHIubSwgY29sb3JzID0gcGFsLCBvcGFjaXR5ID0gMC42KSAlPiUgDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IHZhbHVlcyhyLm0pLA0KICAgICAgICAgICAgdGl0bGUgPSAiUHJlY2lwaXRhY2nDs24gaW50ZXJwb2xhZGEgY29uIElEVyBlbiBOb3J0ZSBkZSBTYW50YW5kZXIgXG5kZWwgMjYuMDQgYWwgMzAuMDQgZGVsIDIwMjAgW21tXSAiICkNCg0KYGBgDQoNCiMjIEFmaW5hbmRvIGxhIGludGVycG9sYWNpw7NuLg0KUGFyYSBhanVzdGFyIGxhIGVsZWNjacOzbiBkZWwgcGFyw6FtZXRybyBkZSBwb3RlbmNpYSwgcHVlZGUgcmVhbGl6YXIgdW5hIHJ1dGluYSBkZSB2YWxpZGFjacOzbiBkZSBvbWlzacOzbiBwYXJhIG1lZGlyIGVsIGVycm9yIGVuIGxvcyB2YWxvcmVzIGludGVycG9sYWRvcy4gDQoNCmBgYHtyfQ0KcHJlY2lwMg0KYGBgDQoNCmBgYHtyfQ0KUCA8LSBwcmVjaXAyDQpgYGANCg0KYGBge3J9DQpJRFcub3V0IDwtIHZlY3RvcihsZW5ndGggPSBsZW5ndGgoUCkpDQpgYGANCg0KYGBge3J9DQpmb3IgKGkgaW4gMTpsZW5ndGgoUCkpIHsNCiAgSURXLm91dFtpXSA8LSBnc3RhdDo6aWR3KExsdXZpYSB+IDEsIFBbLWksXSwgUFtpLF0sIGlkcD0gMi4wKSAkdmFyMS5wcmVkDQp9DQpgYGANCg0KUGxvdGVhciBsYXMgZGlmZXJlbmNpYXMgDQoNCmBgYHtyfQ0KDQpPUCA8LSBwYXIocHR5ID0gInMiLCBtYXI9Yyg0LDMsMCwwKSkNCnBsb3QoSURXLm91dCB+IFAkTGx1dmlhLCBhc3A9MSwgeGxhYj0gIk9ic2VydmFkbyIsIHlsYWIgPSJQcmVkaWNobyIsIHBjaD0gMTYsIA0KICAgICBjb2w9cmdiKDAsMCwwLDAuNSkpDQphYmxpbmUobG0oSURXLm91dCB+IFAkTGx1dmlhKSwgY29sPSJyZWQiLCBsdz0yLCBsdHk9MikNCmFibGluZSgwLDEpDQpgYGANCmBgYHtyfQ0KcGFyKE9QKQ0KYGBgDQoNCkVsIGVycm9yIGN1YWRyw6F0aWNvIG1lZGlvICoqKFJNU0UpKiogc2UgcHVlZGUgY2FsY3VsYXIgZGVzZGUgSURXLm91dCBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOg0KDQpgYGB7cn0NCnNxcnQoIHN1bSgoSURXLm91dCAtIFAkTGx1dmlhKV4yKSAvIGxlbmd0aChQKSkNCmBgYA0KDQpSZXZpc2FyIGVzdGUgdmFsb3IsIHkgYXJyZWdsYXJsbyBwb3JxdWUgZWwgZXJyb3IgZXN0w6EgbXV5IGFsdG8uIA0KVGFsIHZleiByZXZpc2FyIGVsIHBhcsOhbWV0cm8gZGUgcG90ZW5jaWEgZGUgaWRwID0gMi4wDQoNCiMjIFZhbGlkYWNpw7NuIGNydXphZGEgKENyb3NzLXZhbGlkYXRpb24pDQoNCkFkZW3DoXMgZGUgZ2VuZXJhciB1bmEgc3VwZXJmaWNpZSBpbnRlcnBvbGFkYSwgc2UgcHVlZGUgY3JlYXIgdW4gbWFwYSBkZSBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlbCA5NSUgZGVsIG1vZGVsbyBkZSBpbnRlcnBvbGFjacOzbi4gQXF1w60gc2UgY3JlYXLDoSB1biBtYXBhIGRlIElDIGRlbCA5NSUgYSBwYXJ0aXIgZGUgdW5hIGludGVycG9sYWNpw7NuIElEVyBxdWUgdXRpbGl6YSB1biBwYXLDoW1ldHJvIGRlIHBvdGVuY2lhIGRlIDIgKGlkcCA9IDIuMCkNCg0KDQojIDMuMyBLcmlnaW5nIA0KIyAzLjMuMSBBanVzdGFyIGVsIG1vZGVsbyBkZSB2YXJpb2dyYW1hDQoNClByaW1lcm8sIGVzIG5lY2VzYXJpbyBjcmVhciB1biBtb2RlbG8gZGUgdmFyaW9ncmFtYS4gSGF5IHF1ZSB0ZW5lciBlbiBjdWVudGEgcXVlIGVsIG1vZGVsbyBkZSB2YXJpb2dyYW1hIHNlIGNhbGN1bGEgc29icmUgbG9zIGRhdG9zIGRlIHRlbmRlbmNpYS4gRXN0byBzZSBpbXBsZW1lbnRhIGVuIGVsIHNpZ3VpZW50ZSBmcmFnbWVudG8gZGUgY8OzZGlnbyBwYXNhbmRvIGVsIG1vZGVsbyBkZSB0ZW5kZW5jaWEgZGUgcHJpbWVyIG9yZGVuIChkZWZpbmlkbyBlbiB1biBmcmFnbWVudG8gZGUgY8OzZGlnbyBhbnRlcmlvciBjb21vIG9iamV0byBkZSBmw7NybXVsYSBmLjEpIGEgbGEgZnVuY2nDs24gdmFyaW9ncmFtYS4NCg0KYGBge3J9DQpmLjEgPC0gYXMuZm9ybXVsYShwcmVjaXBpdGFjaW9uZXMgfiBYICsgWSkNClAkWCA8LSBjb29yZGluYXRlcyhQKVssMV0NClAkWSA8LSBjb29yZGluYXRlcyhQKVssMl0NCnZhci5zbXBsIDwtIHZhcmlvZ3JhbShmLjEsIFAsIGNsb3VkID0gRkFMU0UsIGN1dG9mZiA9IDEwMDAwMCwgd2lkdGggPSA4OTkwKQ0KDQpkYXQuZml0ICA8LSBmaXQudmFyaW9ncmFtKHZhci5zbXBsLCBmaXQucmFuZ2VzID0gVFJVRSwgZml0LnNpbGxzID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHZnbShwc2lsbCA9IDMsIG1vZGVsID0gIk1hdCIsIHJhbmdlID0gMTUwMDAwLCBudWdnZXQgPSAwLjIpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0LmZpdA0KYGBgDQoNCmBgYHtyfQ0KDQpwbG90KHZhci5zbXBsLCBkYXQuZml0LCB4bGltPWMoMCwxMTAwMDApKQ0KYGBgDQoNCkdlbmVyYXIgc3VwZXJmaWNpZSBLcmlnZWQNCkx1ZWdvLCB1c2UgZWwgbW9kZWxvIGRlIHZhcmlvZ3JhbWEgZGF0LmZpdCBwYXJhIGdlbmVyYXIgdW5hIHN1cGVyZmljaWUgaW50ZXJwb2xhZGEga3JpZ2VkLiBMYSBmdW5jacOzbiBrcmlnZSBub3MgcGVybWl0ZSBpbmNsdWlyIGVsIG1vZGVsbyBkZSB0ZW5kZW5jaWEsIGxvIHF1ZSBub3MgZXZpdGEgdGVuZXIgcXVlIHJlZHVjaXIgbGEgdGVuZGVuY2lhIGRlIGxvcyBkYXRvcywgY29ycmVnaXIgbG9zIHJlc2lkdW9zIHkgbHVlZ28gY29tYmluYXIgbG9zIGRvcyByw6FzdGVyZXMuIEVuIGNhbWJpbywgdG9kbyBsbyBxdWUgdGVuZW1vcyBxdWUgaGFjZXIgZXMgcGFzYXIga3JpZ2UgbGEgZsOzcm11bGEgZGUgdGVuZGVuY2lhIGYuMS4NCg0KYGBge3J9DQpmLjEgPC0gYXMuZm9ybXVsYShMbHV2aWEgfiBYICsgWSkNCmRhdC5rcmcgPC0ga3JpZ2UoZi4xLCBQLCBncmQsIGRhdC5maXQpDQpgYGANCmBgYHtyfQ0KciA8LSByYXN0ZXIoZGF0LmtyZykNCnIubSA8LSByYXN0ZXI6Om1hc2sociwgTm9ydGVkZVNhbnRhbmRlcjIpDQpgYGANCg0KYGBge3J9DQpyLm0NCmBgYA0KDQpgYGB7cn0NCnRtX3NoYXBlKHIubSkgKyANCiAgdG1fcmFzdGVyKG49MTAsIHBhbGV0dGU9IlJkQnUiLCBhdXRvLnBhbGV0dGUubWFwcGluZz1GQUxTRSwgDQogICAgICAgICAgICB0aXRsZT0iVW5pdmVyc2FsIEtyaWdpbmdcblByZWNpcGl0YWNpw7NuIHByZWRpY2hhIFxuKGVuIG1tKSIpICsNCiAgdG1fc2hhcGUoUCkgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQoNCg0KYGBge3J9DQpyICAgPC0gcmFzdGVyKGRhdC5rcmcsIGxheWVyPSJ2YXIxLnZhciIpDQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIE5vcnRlZGVTYW50YW5kZXIyKQ0KDQp0bV9zaGFwZShyLm0pICsgDQogIHRtX3Jhc3RlcihuPTcsIHBhbGV0dGUgPSJSZWRzIiwNCiAgICAgICAgICAgIHRpdGxlPSJLcmlnaW5nIEludGVycG9sYXRpb25cbk1hcGEgZGUgdmFyaWFuemEgXG4oaW4gc3F1YXJlZCBtbSkiKSArdG1fc2hhcGUoUCkgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQoNClVuIG1hcGEgbcOhcyBmw6FjaWwgZGUgaW50ZXJwcmV0YXIgZXMgZWwgbWFwYSBkZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBkZWwgOTUlIHF1ZSBzZSBwdWVkZSBnZW5lcmFyIGEgcGFydGlyIGRlbCBvYmpldG8gZGUgdmFyaWFuemEgZGUgbGEgc2lndWllbnRlIG1hbmVyYSAobG9zIHZhbG9yZXMgZGVsIG1hcGEgZGViZW4gaW50ZXJwcmV0YXJzZSBjb21vIGVsIG7Dum1lcm8gZGUgbW0gcG9yIGVuY2ltYSB5IHBvciBkZWJham8gZGUgbGEgY2FudGlkYWQgZGUgbGx1dmlhIGVzdGltYWRhKS4NCg0KYGBge3J9DQoNCnIgICA8LSBzcXJ0KHJhc3RlcihkYXQua3JnLCBsYXllcj0idmFyMS52YXIiKSkgKiAxLjk2DQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIE5vcnRlZGVTYW50YW5kZXIyKQ0KDQp0bV9zaGFwZShyLm0pICsgDQogIHRtX3Jhc3RlcihuPTcsIHBhbGV0dGUgPSJSZWRzIiwNCiAgICAgICAgICAgIHRpdGxlPSJJbnRlcnBvbGFjacOzbiBrcmlnaW5nXG4gTWFwYSBkZSA5NSUgSUNcbihlbiBtbSkiKSArdG1fc2hhcGUoUCkgKyB0bV9kb3RzKHNpemU9MC4xKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQoNCmBgYHtyfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQoNCg==