Open elgabbas opened 11 months ago
Here is a simplified version of your example that does not require an additional download.
library(terra)
url <- "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_gdd5_1981-2010_V.2.1.tif"
f <- basename(url)
if (!file.exists(f)) download.file(url, f, mode = "wb")
# Reference grid created with `as.character(GridR)`
GridR <- rast(ncols=469, nrows=404, nlyrs=1, xmin=2630000, xmax=7320000, ymin=1380000, ymax=5420000, names=c('Grid'), crs='PROJCRS[\"unknown\",BASEGEOGCRS[\"unknown\",DATUM[\"Unknown based on GRS80 ellipsoid\",ELLIPSOID[\"GRS 1980\",6378137,298.257222101004,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",7019]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433,ID[\"EPSG\",9122]]]],CONVERSION[\"Lambert Azimuthal Equal Area\",METHOD[\"Lambert Azimuthal Equal Area\",ID[\"EPSG\",9820]],PARAMETER[\"Latitude of natural origin\",52,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8801]],PARAMETER[\"Longitude of natural origin\",10,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8802]],PARAMETER[\"False easting\",4321000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8806]],PARAMETER[\"False northing\",3210000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8807]]],CS[Cartesian,2],AXIS[\"(E)\",east,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"(N)\",north,ORDER[2],LENGTHUNIT[\"metre\",1]]]')
And the projections
# bad
r1 <- rast(f)
r1_p <- project(r1, GridR, method = "average", threads = TRUE)
# good if first reading all values
r1a <- rast(f) * 1
r1a_p <- project(r1a, GridR, method = "average", threads = TRUE)
# good when coercing from a RasterLayer
r2 <- rast(raster::raster(f))
r2_p <- terra::project(r2, GridR, method = "average", threads = TRUE)
This is mysterious. Especially that it works when coercing from a RasterLayer! I will have a look.
fwiw, looks ok through 'GDALWarp()` api (with 'by_util'), also no need to download with the /vsicurl protocol
library(terra)
url <- "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_gdd5_1981-2010_V.2.1.tif"
f <- file.path("/vsicurl", url)
GridR <- rast(ncols=469, nrows=404, nlyrs=1, xmin=2630000, xmax=7320000, ymin=1380000, ymax=5420000, names=c('Grid'), crs='EPSG:3035')
r1 <- rast(f)
r1_p <- project(r1, GridR, method = "average", threads = TRUE, by_util = TRUE)
Thanks @mdsumner and @rhijmans for your feedback. This seems to be a temporary solution to avoid extremely high values shown in the above example.
However, there are value differences when coercing raster to spatraster vs using by_util = TRUE
.
# raster coerced to spatraster
R1 <- terra::rast(raster::raster(f)/10)
(R1_p <- terra::project(R1, GridR, method = "average", threads = TRUE))
# class : SpatRaster
# dimensions : 404, 469, 1 (nrow, ncol, nlyr)
# resolution : 10000, 10000 (x, y)
# extent : 2630000, 7320000, 1380000, 5420000 (xmin, xmax, ymin, ymax)
# coord. ref. : ETRS89-extended / LAEA Europe (EPSG:3035)
# source(s) : memory
# name : CHELSA_gdd5_1981.2010_V.2.1
# min value : 0.100
# max value : 6675.457
# read as spatraster, `by_util = TRUE`
R2 <- rast(f)
(R2_p <- terra::project(R2, GridR, method = "average", threads = TRUE, by_util = TRUE))
# class : SpatRaster
# dimensions : 404, 469, 1 (nrow, ncol, nlyr)
# resolution : 10000, 10000 (x, y)
# extent : 2630000, 7320000, 1380000, 5420000 (xmin, xmax, ymin, ymax)
# coord. ref. : ETRS89-extended / LAEA Europe (EPSG:3035)
# source(s) : memory
# name : CHELSA_gdd5_1981-2010_V.2.1
# min value : 0.0
# max value : 6707.1
The difference between both approaches:
R1_p - R2_p
# class : SpatRaster
# dimensions : 404, 469, 1 (nrow, ncol, nlyr)
# resolution : 10000, 10000 (x, y)
# extent : 2630000, 7320000, 1380000, 5420000 (xmin, xmax, ymin, ymax)
# coord. ref. : ETRS89-extended / LAEA Europe (EPSG:3035)
# source(s) : memory
# name : CHELSA_gdd5_1981.2010_V.2.1
# min value : -1230.521
# max value : 1370.416
Please note differences in the pattern of NA values (e.g. north Italy and Iceland) when using by_util = TRUE
and also the value range of both maps
plot(c(R1_p, R2_p, R1_p - R2_p), axes = F, colNA = "blue")
Any explanation/suggestion? Thanks..
This bug occurs because the input has a scale that is 0.1 (not 1). This is why if you first make a copy it works (that removes the scale). With a SpatRaster created from a RasterLayer, a copy is first made by project. That is why it works.
Thanks @rhijmans for your explanation.
For another CHELSA map (which also has a scale factor of 0.1), this problem did not occur.
library(terra)
url <- "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_bio12_1981-2010_V.2.1.tif"
f <- basename(url)
if (!file.exists(f)) download.file(url, f, mode = "wb")
# Reference grid created with `as.character(GridR)`
GridR <- rast(ncols=469, nrows=404, nlyrs=1, xmin=2630000, xmax=7320000, ymin=1380000, ymax=5420000, names=c('Grid'), crs='PROJCRS[\"unknown\",BASEGEOGCRS[\"unknown\",DATUM[\"Unknown based on GRS80 ellipsoid\",ELLIPSOID[\"GRS 1980\",6378137,298.257222101004,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",7019]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433,ID[\"EPSG\",9122]]]],CONVERSION[\"Lambert Azimuthal Equal Area\",METHOD[\"Lambert Azimuthal Equal Area\",ID[\"EPSG\",9820]],PARAMETER[\"Latitude of natural origin\",52,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8801]],PARAMETER[\"Longitude of natural origin\",10,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8802]],PARAMETER[\"False easting\",4321000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8806]],PARAMETER[\"False northing\",3210000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8807]]],CS[Cartesian,2],AXIS[\"(E)\",east,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"(N)\",north,ORDER[2],LENGTHUNIT[\"metre\",1]]]')
r1 <- rast(f)
r1_p <- project(r1, GridR, method = "average", threads = TRUE)
r1a <- rast(f) * 1
r1a_p <- project(r1a, GridR, method = "average", threads = TRUE)
r2 <- rast(raster::raster(f))
r2_p <- terra::project(r2, GridR, method = "average", threads = TRUE) * 0.1
plot(c(r1_p, r1a_p, r2_p))
The difference between both files is mainly in the NA value (using terra::describe()
). For the CHELSA_gdd5_1981-2010_V.2.1.tif
the NoData value is 2147483647
, while for the CHELSA_bio12_1981-2010_V.2.1.tif
the NoData value is -99999"
.
In the first example, the problematic Rstr2_proj
object has a maximum value of 214748364.8 which is very similar to the NoData value (after unscaling). Do you think that grid cells with NoData are considered in calculating the new values (i.e., NA cells were considered as 2147483647 in the calculation of the average)?
Among all current bio variables in CHLESA, extremely high values in projected maps existed in the following three maps (all having a NoData value of 2147483647)
https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_gdd5_1981-2010_V.2.1.tif
https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_gdd10_1981-2010_V.2.1.tif
https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_gsp_1981-2010_V.2.1.tif
Thanks
The following example suggests that the problem is how the NoData is treated.
library(terra)
library(stringr)
library(dplyr)
# download file
url <- "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_gdd5_1981-2010_V.2.1.tif"
f <- basename(url)
if (!file.exists(f)) download.file(url, f, mode = "wb")
# Reference grid
GridR <- rast(ncols=469, nrows=404, nlyrs=1, xmin=2630000, xmax=7320000, ymin=1380000, ymax=5420000, names=c('Grid'), crs='PROJCRS[\"unknown\",BASEGEOGCRS[\"unknown\",DATUM[\"Unknown based on GRS80 ellipsoid\",ELLIPSOID[\"GRS 1980\",6378137,298.257222101004,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",7019]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433,ID[\"EPSG\",9122]]]],CONVERSION[\"Lambert Azimuthal Equal Area\",METHOD[\"Lambert Azimuthal Equal Area\",ID[\"EPSG\",9820]],PARAMETER[\"Latitude of natural origin\",52,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8801]],PARAMETER[\"Longitude of natural origin\",10,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8802]],PARAMETER[\"False easting\",4321000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8806]],PARAMETER[\"False northing\",3210000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8807]]],CS[Cartesian,2],AXIS[\"(E)\",east,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"(N)\",north,ORDER[2],LENGTHUNIT[\"metre\",1]]]')
# read the tif file, then save it as a different name
f_Edited <- stringr::str_replace(f, ".tif", "_edited.tif")
f %>%
terra::rast() %>%
# write the raster as a tif file, keep scale = 0.1 and offset = 0
terra::writeRaster(
filename = f_Edited, NAflag = -99999, overwrite = TRUE, progress = TRUE, scale = 0.1, offset = 0)
# output file size is larger, but this is okay
Now, projecting the original and edited tiff file
# This is problematic as before
r1 <- rast(f)
r1_p <- project(r1, GridR, method = "average", threads = TRUE)
# This works as expected
r3 <- rast(f_Edited)
r3_p <- project(r3, GridR, method = "average", threads = TRUE)
plot(c(r1_p, r3_p))
Hello,
I would like to use
terra::project()
to project CHELSA data into a custom grid atEPSG:3035
projection. However, the values of some of the projected maps are not as expected. Here is an example:download the tif file
reference grid [attached]
reading as raster, then convert to spatraster
projecting to the reference grid
slow, but values are within the expected range
reading directly as spatraster
projecting to the reference grid
The output is not expected
It seems that the NA values in the original tif file [NoData Value=2147483647 for
CHELSA_gdd5_1981-2010_V.2.1.tif
] are considered in the calculation of new values.description of input files
Session info
reference grid
Thanks