install.packages("INLA",repos=c(getOption("repos"),INLA="https://inla.r-inla-download.org/R/stable"), dep=TRUE)
library(sf)
library(sp)
library(INLA)
library(raster)
library(spatstat)
library(dplyr)
library(terra)
#This data needs be changed if the study area changes
explosions <- st_read("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Tile_Effects\\exp_model_V4.shp") # Reads in Explosions Point Shapefile
## Reading layer `exp_model_V4' from data source
## `D:\Ukraine_GradProject\Explosion_Model\Explosion_Model\Tile_Effects\exp_model_V4.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 84324 features and 44 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 31.3517 ymin: 45.3854 xmax: 39.5732 ymax: 50.6984
## Geodetic CRS: WGS 84
boundary <- st_read("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Tile_Effects\\explosiontiles.shp") # Reads in Boundary Shapefile
## Reading layer `explosiontiles' from data source
## `D:\Ukraine_GradProject\Explosion_Model\Explosion_Model\Tile_Effects\explosiontiles.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 26 features and 2 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 1586587 ymin: 2026501 xmax: 2096973 ymax: 2661127
## Projected CRS: Europe_Lambert_Conformal_Conic
# Coordinate System in Use: Europe_Lambert_Conformal_Conic (Meters)
explosions <- st_transform(explosions, st_crs(boundary)) # Coverts the CRS into the same CRS as the Boundary file
# Extract Coordinates and Covariates
coords <- st_coordinates(explosions) # Extract the Coordinates from the Explosions
# Create a Dataframe with all the Coordinates and Covariate Information
# Covariate Information needs to have distance to all the covariates, and the population number of the closest city to the explosion point
data <- explosions %>%
mutate(x = coords[, 1], y = coords[, 2]) %>%
select(x, y, DIST_ROAD, DIST_FL, DIST_RAILS, DIST_HOS, DIST_PP, RASTERVALU)
# Create Spatial Mesh
mesh <- inla.mesh.2d(loc = coords,
max.edge = c(10000,100000),
cutoff = 5000)
plot(mesh)
# Stochastic Partial Differential Equation (SPDE) Model
# Creates the Matern Covariance Function for the Spatial Random Effect
spde <- inla.spde2.pcmatern(mesh = mesh, alpha = 2,
prior.range = c(5000, 0.07),
prior.sigma = c(1, 0.1))
# The Prior Range is larger than 5 km with a 7% Probability it is smaller
# Prior Range includes the distance (5000 m or 5 km) at which spatial correlation drops
# Prior Sigma is that standard deviation is larger than 1 with a probability of 1% (Low Variability in the Spatial Field)
grid_res <- 250 # Cell Size Resolution of 1000 meters
boundary_extent <- st_bbox(boundary)
x_seq <- seq(boundary_extent["xmin"], boundary_extent["xmax"], by = grid_res)
y_seq <- seq(boundary_extent["ymin"], boundary_extent["ymax"], by = grid_res)
grid_coords <- expand.grid(x = x_seq, y = y_seq)
# Convert to sf object and clip to boundary
# Used in creating final raster image
grid_sf <- st_as_sf(grid_coords, coords = c("x", "y"), crs = st_crs(boundary))
grid_sf <- st_intersection(grid_sf, boundary)
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
# Convert to matrix for INLA
grid_mat <- st_coordinates(grid_sf)
# Drops the Geometry of the Data
data_no_geom <- st_drop_geometry(data)
# Drops the X, Y geometry from the dataframe
covariates_obs <- data_no_geom %>%
select(-x, -y)
# Covariate Values were in Kilometers (Still were too big for INLA to Run). All are divided by the Mean of each covariate besides Population(log+1)
covariates_obs$DIST_ROAD <- (covariates_obs$DIST_ROAD) / mean(covariates_obs$DIST_ROAD)
covariates_obs$DIST_FL <- (covariates_obs$DIST_FL) / mean(covariates_obs$DIST_FL)
covariates_obs$Population <- log(covariates_obs$RASTERVALU + 1)
covariates_obs$DIST_RAILS <- (covariates_obs$DIST_RAILS) / mean(covariates_obs$DIST_RAILS)
covariates_obs$DIST_HOS <- (covariates_obs$DIST_HOS) / mean(covariates_obs$DIST_HOS)
covariates_obs$DIST_PP <- (covariates_obs$DIST_PP) / mean(covariates_obs$DIST_PP)
A_obs <- inla.spde.make.A(mesh = mesh, loc = coords) # Projects the Spatial Random Effect onto the observations
# Index for the spatial random field
spde_index <- inla.spde.make.index(name = "spatial_field", n.spde = spde$n.spde)
# Build observation stack
stack_obs <- inla.stack(
data = list(y = rep(1, nrow(covariates_obs))), # Measures Count Data; y=1 for each observation point
A = list(A_obs, 1), # Projects the Spatial Random Effect onto the observations
effects = list(
spatial_field = spde_index$spatial_field, # Links the Spatial Random Effect from the SPDE to the observations
covariates = covariates_obs # Fixed Effects
),
tag = "obs"
)
A_pred <- inla.spde.make.A(mesh = mesh, loc = grid_mat)
# This data needs be changed if the study area changes
# These raster layers were created in ArcGIS Pro using the Euclidean Distance tool for the distances and WorldPop data for the Population.
DIST_ROAD <- rast("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Covariates\\roads_ukr_250m.tif")
DIST_FL <- rast("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Covariates\\frontline_ukr_250m.tif")
DIST_RAILS <- rast("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Covariates\\rails_ukr_250m.tif")
DIST_HOS <- rast("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Covariates\\hos_ukr_250m.tif")
DIST_PP <- rast("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Covariates\\pp_ukr_250m.tif")
Population <- rast("D:\\Ukraine_GradProject\\Explosion_Model\\Explosion_Model\\Covariates\\new_pop_v2_250.tif")
# grid_mat is a matrix with columns x and y
coords_pred_vect <- vect(grid_mat, type = "points", crs = crs(DIST_ROAD))
# Extract raster values at prediction points
DIST_ROAD_vals <- raster::extract(DIST_ROAD, coords_pred_vect)[,2]
DIST_FL_vals <- raster::extract(DIST_FL, coords_pred_vect)[,2]
DIST_RAILS_vals <- raster::extract(DIST_RAILS, coords_pred_vect)[,2]
DIST_HOS_vals <- raster::extract(DIST_HOS, coords_pred_vect)[,2]
DIST_PP_vals <- raster::extract(DIST_PP, coords_pred_vect)[,2]
Population_vals <- raster::extract(Population, coords_pred_vect)[,2]
#Covariate Dataframe
covariate_df <- data.frame(
DIST_ROAD = DIST_ROAD_vals,
DIST_FL = DIST_FL_vals,
DIST_RAILS = DIST_RAILS_vals,
DIST_HOS = DIST_HOS_vals,
DIST_PP = DIST_PP_vals,
Population = Population_vals
)
stack_pred <- inla.stack(
data = list(y = NA), # NA tells INLA that we are predicting here
A = list(A_pred, 1), # Projects the Spatial Random Field(on the mesh) to the Prediction Locations
effects = list(
spatial_field = spde_index$spatial_field, # Links the Spatial Random Effect from the SPDE to the Predictions
covariates = covariate_df # Covariate dataframe that has all the prediction values in it
),
tag = "pred"
)
stack_full <- inla.stack(stack_obs, stack_pred)
formula <- y ~ DIST_ROAD + DIST_FL + DIST_RAILS + DIST_HOS + DIST_PP + Population + f(spatial_field, model = spde) # No Intercept is Used; All of the Covariates are used and the Spatial Random Effect from SPDE is added
# Model Formula
formula <- y ~ DIST_ROAD + DIST_FL + DIST_RAILS + DIST_HOS + DIST_PP + Population +
f(spatial_field, model = spde)
# Running INLA
result3 <- inla(
formula,
family = "poisson",
data = inla.stack.data(stack_full),
control.predictor = list(
A = inla.stack.A(stack_full),
compute = TRUE
),
control.inla = list(int.strategy = "eb", h = 0.01),
control.compute = list(dic = TRUE, cpo = TRUE, waic = TRUE),
verbose = TRUE
)
## Warning in inla.core(formula = formula, family = family, contrasts = contrasts, : The A-matrix in the predictor (see ?control.predictor) is specified
## but an intercept is in the formula. This will likely result
## in the intercept being applied multiple times in the model, and is likely
## not what you want. See ?inla.stack for more information.
## You can remove the intercept adding ``-1'' to the formula.
result3$summary.fixed # Shows the results of the fixed covariates
## mean sd 0.025quant 0.5quant 0.975quant
## (Intercept) 1.279111e-06 0.006339425 -0.012423766 1.279111e-06 0.012426324
## DIST_ROAD -9.270921e-06 0.003651255 -0.007165599 -9.270921e-06 0.007147057
## DIST_FL -6.484392e-06 0.003265063 -0.006405890 -6.484392e-06 0.006392921
## DIST_RAILS -1.040186e-05 0.003483589 -0.006838112 -1.040186e-05 0.006817308
## DIST_HOS -1.259424e-06 0.005299950 -0.010388971 -1.259424e-06 0.010386452
## DIST_PP -1.946742e-05 0.006509315 -0.012777490 -1.946742e-05 0.012738555
## Population -7.252358e-07 0.001674852 -0.003283375 -7.252358e-07 0.003281924
## mode kld
## (Intercept) 1.279111e-06 0
## DIST_ROAD -9.270921e-06 0
## DIST_FL -6.484392e-06 0
## DIST_RAILS -1.040186e-05 0
## DIST_HOS -1.259424e-06 0
## DIST_PP -1.946742e-05 0
## Population -7.252358e-07 0
result3$summary.hyperpar # Shows the results of the priors from the SPDE
## mean sd 0.025quant 0.5quant
## Range for spatial_field 4.457203e+04 1.137068e+05 2.171664e+03 1.724062e+04
## Stdev for spatial_field 3.376556e-03 2.549372e-03 4.620959e-04 2.706415e-03
## 0.975quant mode
## Range for spatial_field 2.622710e+05 5.055867e+03
## Stdev for spatial_field 9.902459e-03 1.358932e-03
## Creating Predictions from the Posterior Distribution (Mean)
index_pred <- inla.stack.index(stack_full, "pred")$data
predictions <- result3$summary.fitted.values[index_pred, "mean"]
# Create Column for Predictions
grid_sf$predictions <- predictions
# Exponentiation of the Explosion Count Intensity
grid_sf$predictions_exp <- exp(grid_sf$predictions)
## Creating the Raster Image
r_pred_exp <- raster(extent(boundary), res = grid_res, crs = st_crs(boundary)$proj4string)
r_pred_exp <- rasterize(grid_sf, r_pred_exp, field = "predictions_exp", fun = mean, na.rm = TRUE)
## Plot the Predicted Explosion Count Intensity Plot
plot(r_pred_exp, main = "Predicted Explosion Intensity Count", col = terrain.colors(100))
plot(st_geometry(boundary), add = TRUE, border = "black", lwd = 2)