Using 'disaggregate' with GCM data - r

I have data from various Global Circulation Models (GCM) that I need in at a finer resolution to perturb climate observations that are 0.5 degree pixel. I saw that I could use disaggregate because this function won't change pixels values, as 'resample' does using, e.g., the bilinear method. But still, the output doesn't match my fine-res-grids.
Here an example with the dimensions of the files I'm dealing with:
r = raster(ncols=720, nrows=360) #fine resolution grid
r[] = runif(1:100)
> r
class : RasterLayer
dimensions : 360, 720, 259200 (nrow, ncol, ncell)
resolution : 0.5, 0.5 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : layer
values : 0.0159161, 0.9876637 (min, max)
s = raster(ncols=192, nrows=145) #dimensions of one of the GCM
s[] = runif(1:10)
> s
class : RasterLayer
dimensions : 145, 192, 27840 (nrow, ncol, ncell)
resolution : 1.875, 1.241379 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : layer
values : 0.03861309, 0.9744665 (min, max)
d=disaggregate(s, fact=c(3.75,2.482759)) #fact equals r/s for cols and rows
> d
class : RasterLayer
dimensions : 290, 768, 222720 (nrow, ncol, ncell)
resolution : 0.46875, 0.6206897 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : layer
values : 0.03861309, 0.9744665 (min, max)
The dimensions of 'd' are not equal to the dimensions of 'r', so I can't do operations with the 2 grids. And I'm not meant to be interpolating the pixel values. So, what's the best method to achieve the disaggregation with GCM data?
Thanks in advance.

The code below should help- it uses aggregate to the closest integer scaling possible then resample to match the other raster's spatial characteristics exactly:
r = raster(ncols=720, nrows=360) #fine resolution grid
r[] = runif(1:100)
s = raster(ncols=192, nrows=145) #dimensions of one of the GCM
s[] = runif(1:10)
d=disaggregate(s, fact=c(round(dim(r)[1]/dim(s)[1]),round(dim(r)[2]/dim(s)[2])), method='') #fact equals r/s for cols and rows
e=resample(d, r, method="ngb")
But there a few caveats/ warnings: If you want to have the same values as the original raster, use disaggregate with method='' or else it will interpolate. But most important looking at the aspect ratio between your r and s rasters, they are not the same: dim(r)[1]/dim(s)[1] != dim(r)[2]/dim(s)[2]). I would double check the original data because if there is a difference in resolution, projection, or extent you will not get what you want from the steps above.

Related

Merge (mosaic) of rasters changes resolution

I'm merging two MODIS DSR tiles using a R script that I developed, these are the products:
https://drive.google.com/drive/folders/1RG3JkXlbaotBax-h5lEMT7lEn-ObwWsD?usp=sharing
So, I open both products (tile h15v05 and tile h16v05) from same date (2019180), then I open each SDS and merge them together (00h from h15v05 with 00h from h16v05 and so on...)
Visualisation on Panoply (using the merge option) of the two products:
Purple square is the location of the division line that separates the two tiles.
With my code I obtain a plot with pixels with different resolution (and different min/max values) and I don't understand why:
I suspect that the results obtained are due to:
1- Changing from Sinusoidal CRS to longlat WGS84 CRS;
2- Using resample (method ngb) to work with mosaic.
My code is extensive, but here are some parts of it:
# Open scientific dataset as raster
SDSs <- sds(HDFfile)
SDS <- SDSs[SDSnumber]
crs(SDS) <- crs("+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs")
SDSreprojected <- project(SDS, DesiredCRS)
SDSasRaster <- as(SDSreprojected, "Raster")
# Resample SDS based on a reference SDS (SDS GMT_1200_DSR of a first product), I need to do this to be able to use mosaic
SDSresampled <- resample(SDSasRaster,ResampleReference_Raster,method='ngb')
# Create mosaic of same SDS, but first convert stack to list to use mosaic
ListWith_SameSDS_OfGroupFiles <- as.list(StackWith_SameSDS_OfGroupFiles)
ListWith_SameSDS_OfGroupFiles.mosaicargs <- ListWith_SameSDS_OfGroupFiles
ListWith_SameSDS_OfGroupFiles.mosaicargs$fun <- mean
SDSmosaic <- do.call(mosaic, ListWith_SameSDS_OfGroupFiles.mosaicargs)
# Save SDSs mosaic stack to netCDF
writeRaster(StackWith_AllMosaicSDSs_OfGroupFiles, NetCDFpath, overwrite=TRUE, format="CDF", varname= "DSR", varunit="w/m2", longname="Downward Shortwave Radiation", xname="Longitude", yname="Latitude", zname="TimeGMT", zunit="GMT")
Does anyone have an idea of what could be the cause of this mismatch between results?
print(ResampleReference_Raster)
class : RasterLayer
dimensions : 1441, 897, 1292577 (nrow, ncol, ncell)
resolution : 0.01791556, 0.006942043 (x, y)
extent : -39.16222, -23.09196, 29.99652, 40 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : MCD18A1.A2019180.h15v05.061.2020343034815
values : 227.5543, 970.2346 (min, max)
print(SDSasRaster)
class : RasterLayer
dimensions : 1399, 961, 1344439 (nrow, ncol, ncell)
resolution : 0.01515284, 0.007149989 (x, y)
extent : -26.10815, -11.54627, 29.99717, 40 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : MCD18A1.A2019180.h16v05.061.2020343040755
values : 0, 0 (min, max)
print(SDSmosaic)
class : RasterLayer
dimensions : 1441, 897, 1292577 (nrow, ncol, ncell)
resolution : 0.01791556, 0.006942043 (x, y)
extent : -39.16222, -23.09196, 29.99652, 40 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : layer
values : 0, 62.7663 (min, max)
Also, some of the islands were ignored by the script (bottom right)...
sorry I didn't reply earlier. So I think you're right that this issue is extent to which you are resampling. I think you might be able to get around this by creating a dummy raster that has the extent of the raster you want to resample, but has the resolution of the raster you want to mosaic to.Try:
dummy<-raster(ext = SDSasRaster#extent, resolution=ResampledReference_Raster#res, crs=SDSasRaster#crs)
SDS2<-resample(SDSasRaster, dummy, method="ngb")
Final<-moasic(SDS2, ResampledReference_Raster, fun=mean)

Converting .adf files into NetCDF

I have a set of .adf files which contain spatially distributed data. The files look like this:
dblbnd.adf
hdr.adf
metadata.xml
prj.adf
sta.adf
w001001.adf
w001001x.adf
I can read in the large file (w001001.adf) into R as a raster. This is the raster characteristics:
class : RasterLayer
dimensions : 1692, 3611, 6109812 (nrow, ncol, ncell)
resolution : 6, 6 (x, y)
extent : -10833.68, 10832.32, -4713.677, 5438.323 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : C:/Users/ahsa361/Documents/CEDS_Data/gridding-preprocessing/input/Corbett/w001001.adf
names : w001001
values : 0, 5637.337 (min, max)
I would like to convert this to NetCDF with dimensions of 180 deg lat. x 360 deg lon. at 0.5 deg resolution. How do I go about doing this?
You have an extent that does not match your coordinate reference system
#extent : -10833.68, 10832.32, -4713.677, 5438.323 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
Without more information it not really possible to help you much. Most likely the crs is wrong and you need to replace it with the correct one. Did you set it to the wrong value? (that is the most common cause of this problem). If you know what it should be, you can set it like this
crs(x) <- "correct crs definition"
It is also possible that the extent is wrong, and you could also set that to the right value. But based on the what you say, you do not know, so you need to figure these things out before we can help with how to fix your problem.
To get a global extent, and a resolution close to 0.1 degrees, you can do
extent(x) <- c(-180,180,-90,90)
Given the number of rows and columns you have, that would get you:
library(raster)
raster(nrow=1692, ncol=3611)
#class : RasterLayer
#dimensions : 1692, 3611, 6109812 (nrow, ncol, ncell)
#resolution : 0.09969538, 0.106383 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs

Make raster stack with different extent

I am in trouble making raster stack which have slightly different extent. The answer (1st one) given here is useful but did not help in my case. For example, I want to make a raster stack using bio2 raster for Australia and this Australian raster. The second raster comes for Australia only and the first one is global. So I cropped the global bio2 raster to the same extent of Australian raster using crop() function, but the resultant raster extent (i.e., bio2.au) is slightly different (therefore, I cannot make raster using the cropped raster and the Australian raster, awc). Sample code is below:
library(raster)
awc <- raster("path to Australian raster")
bio2.g <- raster("path to Bio2 global raster")
# crop bio2.g to the same extent of awc
bio2.au <- crop(bio2.g, extent(awc))
# make a raster stack
st <- stack(awc, bio2.au)
Error in compareRaster(x) : different extent
I have also tried using quick=TRUE within the stack() function. But in this case the cell values in awc is lost. Note: the size of awc raster is 4gb.
# first make a list of rasters saved in the computer
li <- list.files("path to file", pattern = ".tif$", full.names = TRUE)
st <- stack(li, quick=TRUE)
st[[1]] # no cell values for awc
Your suggestions will be highly appreciated. My ultimate goal is to crop several bioclim rasters to the same extent of Australian raster awc and stack them together so that raster cell values are not lost.
Edit (after comment of #Cobin):
Below is the attribute of each raster
# global raster (bigger raster)
> r
class : RasterLayer
dimensions : 21600, 43200, 933120000 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\Worldclim2_Bioclim\wc2.0_bio_30s_02.tif
names : wc2.0_bio_30s_02
values : 0, 37.06667 (min, max)
# Australian raster (smaller raster)
> r1
class : RasterLayer
dimensions : 43201, 49359, 2132358159 (nrow, ncol, ncell)
resolution : 0.0008333333, 0.0008333333 (x, y)
extent : 112.8921, 154.0246, -44.00042, -7.999583 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\SoilAWC5cm.EV1.tif
names : SoilAWC5cm.EV1
values : 2.997789, 27.86114 (min, max)
# new raster, after crop() function is applied
> r2 <- crop(r,extent(r1))
> r2
class : RasterLayer
dimensions : 4320, 4936, 21323520 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : 112.8917, 154.025, -44, -8 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\Anwar\AppData\Local\Temp\Rtmpmg9fyF\raster\r_tmp_2018-11-23_164300_11308_65747.grd
names : wc2.0_bio_30s_02
values : 1.933333, 18.15833 (min, max)
# rebuild r2 to match r1
> r22 <- raster(vals=values(r2),ext=extent(r1), nrows=dim(r1)[1],ncols=dim(r1)[2])
Error in setValues(r, vals) :
length(values) is not equal to ncell(x), or to 1
I suppose that the extent of two raster are differet though the raster masked by crop function.You
should check the both of awc and bio.au extent base on same reolution, rows and columns. Because I couldn't download data from
hyperlink, I give an example of my own data.
r <- raster('/big_raster')
r1 <- raster('/small_raster')
r2 <- crop(r,extent(r1))
r1
class : RasterLayer
dimensions : 74, 157, 11618 (nrow, ncol, ncell)
resolution : 0.0833333, 0.0833333 (x, y)
extent : 89.2185, 102.3018, 30.96238, 37.12905 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\D\temp\Rtest\modis8km.tif
names : modis8km
values : -32768, 32767 (min, max)
r2
class : RasterLayer
dimensions : 74, 157, 11618 (nrow, ncol, ncell)
resolution : 0.08333333, 0.08333333 (x, y)
extent : 89.25, 102.3333, 31, 37.16667 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : g201401a
values : -32768, 7789 (min, max)
Though r1 and r1 with same resolution and dimension, the extent have tiny offset. It cause stack error.
stack(r1,r2)
Error in compareRaster(x) : different extent
So, you should rebuid the r2 to match r1:
r22 <- raster(vals=values(r2),ext=extent(r1),crs=crs(r1),
nrows=dim(r1)[1],ncols=dim(r1)[2])
Now stack(r22,r1) will be successful.

How can I get the cell number of a raster using extent information?

I have a raster and I am using the raster package.
class : RasterLayer
dimensions : 103, 118, 12154 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -83.075, -82.09167, 34.95833, 35.81667 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\fb.tif
names : fdr_fb
values : 1, 128 (min, max)
I know how to subset and all. But how can I find the cellnumber (preferred) or cellvalue by using the Lat-Long value?
For example, I can find cell value using lat/long:
extract(ras,SpatialPoints(cbind(-82.8,35.2)))
But I want to find the cell number (row,col) corresponding to (Say) Long= -82.1 and Lat= 35.0
Raster: https://www.dropbox.com/s/8nhfirxr2hm3l4v/fdr_fb.tif?dl=0
To get the cell number from a point, you can do:
cellFromXY(ras, cbind(-82.8, 35.2))
If you have an Extent object e you can do:
cellsFromExtent(ras, e)

Calculating area of occupancy from a binary unprojected raster

I have a series of binary raster layers (ascii file) showing presence/absence of a species in Europe and Africa. The file is based on unprojected lat/long (WGS84) data. My aim is to calculate the area of presence using R (I don't have access to ArcGIS).
I know that the raster package has a function for calculating area, but I'm worried that this won't be accurate for unprojected data. I have also looked at the cellStats function in the raster package, and can use this to "sum" the number of cells occupied, but I feel this has the same problem.
jan<-raster("/filelocation/file.asc")
jan
class : RasterLayer
dimensions : 13800, 9600, 132480000 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -20, 60, -40, 75 (xmin, xmax, ymin, ymax)
coord. ref. : NA
data source : "/filelocation"
names : file.asc
values : -2147483648, 2147483647 (min, max)
area(jan)
class : RasterLayer
dimensions : 13800, 9600, 132480000 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -20, 60, -40, 75 (xmin, xmax, ymin, ymax)
coord. ref. : NA
names : layer
values : 6.944444e-05, 6.944444e-05 (min, max)
Warning messages:
1: In .local(x, ...) :
This function is only useful for Raster* objects with a longitude/latitude coordinates
2: In .rasterFromRasterFile(grdfile, band = band, objecttype, ...) :
size of values file does not match the number of cells (given the data type)
cellStats(jan,"sum")
[1] 3559779
Anybody know of a way to calculate the presence area accurately, accounting for the earth curvature?
Thanks!
I do not know what is going in with your file (why you get warning #2). But is here is a work around
r <- raster(nrow=13800, ncol=9600, xmn=-20, xmx=60, ymn=-40, ymx=75)
# equivalent to r <- raster(jan)
x = area(r)
x
class : RasterLayer
dimensions : 13800, 9600, 132480000 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -20, 60, -40, 75 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84
data source : c:\temp\R_raster_Robert\2015-01-26_213612_1208_85354.grd
names : layer
values : 0.2227891, 0.8605576 (min, max)
Now you have the area of each cell in km2. By multiplying these values with Raster objects with presence/absence values and then using cellStats( , 'sum') you can obtain the total area with presence.

Resources