Extent and crs of rasters not written by writeCDF - raster

When writing rasters in netCDF files, I always get the warning message: "[rast] unknown extent". Indeed, the extent is not written in the external file. Neither is the crs.
library(terra)
#terra version 1.0.2
r <- rast(ncol=2, nrow=2, vals=c(5.3, 7.1, 3, 1.2))
crs(r)<-"epsg:27572"
ext(r)
#SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
t<-writeCDF(r,"test.ncdf",overwrite=TRUE)
#Warning message:
#[rast] unknown extent
ext(t) # extension is not correct
#SpatExtent : 0, 1, 0, 1 (xmin, xmax, ymin, ymax)
crs(t) # crs is not correct
#[1] "GEOGCRS[\"unknown\",\n DATUM[\"World Geodetic System 1984\",\n ...
Perhaps there is a peculiar syntax to use here. I explored ?writeCDF, but could not find any clue.

This points at an issue with GDAL --- depending on whether you think that .ncdf is a common filename extension for netCDF files.
library(terra)
#terra version 1.0.3
r <- rast(ncol=2, nrow=2, vals=c(5.3, 7.1, 3, 1.2))
Note the different file extensions, .nc, .cdf, .ncdf or missing.
# ok
x <- writeCDF(r, "test1.nc", overwrite=TRUE)
y <- writeCDF(r, "test2.cdf", overwrite=TRUE)
# not ok
z <- writeCDF(r, "test3.ncdf", overwrite=TRUE)
#Warning message:
#[rast] unknown extent
a <- writeCDF(r, "test4", overwrite=TRUE)
#Warning message:
#[rast] unknown extent
GDALinfo shows:
describe("test1.nc")[1]
#[1] "Driver: netCDF/Network Common Data Format"
describe("test3.ncdf")[1]
#[1] "Driver: HDF5Image/HDF5 Dataset"
It looks like GDAL first tries the netCDF driver when the extension is .nc or .cdf, but that it first tries the HDF5 driver when it is .ncdf or missing --- and since this does not fail (the warning comes from terra, not from GDAL), that is what it uses.
This is the GDAL version on windows.
gdal()
#[1] "3.0.4"
I see the same behavior with GDAL 2.2.3 on linux and 3.2.0 on mac.
You can work around that by not using .ncdf or by specifying the driver when opening the file:
rast('NETCDF:"test3.ncdf"')
#class : SpatRaster
#dimensions : 2, 2, 1 (nrow, ncol, nlyr)
#resolution : 180, 90 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +datum=WGS84 +no_defs
#source : NETCDF:test1.ncdf
#varname : test1
#name : test1
I do not think there is anything wrong with the CRS (it is the same as crs(r)). However, I should note that terra writes the proj4 and wkt strings to a ncdf file, and does not follow the ncdf standard in that respect.
(You are asking a question about a method that is only available in the development version of terra. I appreciated that very much, but raising an issue on the terra github site would be more appropriate in this case. I will make writeCDF give a warning when the file extension is not .nc or .cdf)

Related

Projecting a raster in terra fails

I have a single simple raster in EPSG:7532 that I am trying to project to EPSG:4326 but is failing
The source data is a Lidar point clould that I am able to process using the lidR package. The data source is in the link below
https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/WI_BrownRusk_2020_B20/WI_Brown_2_2020/LAZ/USGS_LPC_WI_BrownRusk_2020_B20_02531702.laz
l1 = readLAS("USGS_LPC_WI_BrownRusk_2020_B20_02531702.laz")
> l1
class : LAS (v1.4 format 6)
memory : 2.5 Gb
extent : 25349, 26849, 170258, 171758 (xmin, xmax, ymin, ymax)
coord. ref. : NAD83(2011) / WISCRS Brown (m) + NAVD88 height - Geoid18 (m)
area : 2.25 km²
points : 35.57 million points
density : 15.79 points/m²
density : 12.89 pulses/m²
convert to a spatRaster:
dsm <- rasterize_canopy(l1, res = 1.0, pitfree(c(0,2,5,10,15), c(0, 1.5)))
> dsm
class : SpatRaster
dimensions : 1500, 1501, 1 (nrow, ncol, nlyr)
resolution : 1, 1 (x, y)
extent : 25349, 26850, 170258, 171758 (xmin, xmax, ymin, ymax)
coord. ref. : NAD83(2011) / WISCRS Brown (m) (EPSG:7532)
source : memory
name : Z
min value : 185.836
max value : 333.709
The point of failure is the attempt to project to geographic format:
dsm_test <- terra::project(dsm, "EPSG:4326", method="bilinear")
> dsm_test <- terra::project(dsm, "EPSG:4326", method="bilinear")
Error: [project] cannot get output boundaries
In addition: Warning messages:
1: In x#ptr$warp(SpatRaster$new(), y, method, mask, FALSE, opt) :
GDAL Error 1: PROJ: vgridshift: could not find required grid(s).
2: In x#ptr$warp(SpatRaster$new(), y, method, mask, FALSE, opt) :
GDAL Error 1: PROJ: pipeline: Pipeline: Bad step definition: proj=vgridshift (File not found or invalid)
3: In x#ptr$warp(SpatRaster$new(), y, method, mask, FALSE, opt) :
GDAL Error 1: Too many points (961 out of 961) failed to transform, unable to compute output bounds.
A similar topic here, but seems different.
https://stackoverflow.com/questions/72404897/what-is-causing-this-raster-reprojection-error
This issue is not resulting from reprojection from EPSG:7532 to EPSG:4326 per se, but seems rather connected to the fact, that your SpatRaster object created via rasterize_canopy() comes with a vertical datum, apparently causing problems downstream:
VERTCRS["NAVD88 height - Geoid18 (m)",
VDATUM["North American Vertical Datum 1988"],
CS[vertical,1],
AXIS["up",up,
LENGTHUNIT["meter",1]],
GEOIDMODEL["GEOID18"],
ID["EPSG",5703]]]
The quick & dirty solution would be to simply override crs definition by EPSG:7532 and dropping references in Z dimension, although this does not feel 100 % right. On the other hand, I'm not sure how terra handles vertical crs information and if it is possible to keep this information at all.
library(lidR)
library(terra)
#> terra 1.6.49
l1 = readLAS("USGS_LPC_WI_BrownRusk_2020_B20_02531702.laz")
#> Warning: There are 53206 points flagged 'withheld'.
dsm <- rasterize_canopy(l1, res = 1.0, pitfree(c(0,2,5,10,15), c(0, 1.5)))
crs(dsm) <- "epsg:7532"
dsm_4326 <- project(dsm, "epsg:4326", method="bilinear")
dsm_4326
#> class : SpatRaster
#> dimensions : 1235, 1727, 1 (nrow, ncol, nlyr)
#> resolution : 1.093727e-05, 1.093727e-05 (x, y)
#> extent : -88.0786, -88.05972, 44.49092, 44.50443 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
#> source(s) : memory
#> name : Z
#> min value : 185.8360
#> max value : 295.1357
From my personal point of view, it would be better to have both crs (xy, z) listed in the SpatRaster summary with reproject() being able to address z-transformations separately (or have e.g. terra::transform()), e.g. when you wanted to just transform your heights but still keep EPSG:7532 as your xy reference system.
coord. ref. xy: NAD83(2011) / WISCRS Brown (m) (EPSG:7532)
coord. ref. z: NAVD88 height - Geoid18 (m) (EPSG:5703)

Save raster to USGS DEM Format in R

Similar to this question:
I would like to know how to do the reverse and save an .img raster image into a USGS DEM format.
Based on GDAL docs, it seems like it would be possible but when I run rgdal::getGDALDriverNames() in R I get the following:
name long_name create copy isRaster
139 USGSDEM USGS Optional ASCII DEM (and CDED) FALSE TRUE TRUE
which seems to imply that it won't create these files?
I was hoping to do something like:
library(raster)
# read
img <- raster("Raster_100ft_2022_10_18.img")
# convert to DEM
writeRaster(img, 'test.dem')
But raster doesn't seem to recognize that output format.
Is there some other method to save as USGS DEM files?
Thanks
For me it works with terra. If that's proper "USGSDEM" file, that's another question. From gdal reference it should save the file as well: https://gdal.org/drivers/raster/usgsdem.html
f <- system.file("ex/elev.tif", package="terra")
r <- terra::rast(f)
terra::writeRaster(r, filename = "test.dem", filetype = "USGSDEM", overwrite = TRUE)
raster::raster("test.dem")
#> class : RasterLayer
#> dimensions : 90, 95, 8550 (nrow, ncol, ncell)
#> resolution : 0.008333333, 0.008333333 (x, y)
#> extent : 5.741667, 6.533333, 49.44167, 50.19167 (xmin, xmax, ymin, ymax)
#> crs : +proj=longlat +datum=WGS84 +no_defs
#> source : test.dem
#> names : elevation
#> values : 141, 547 (min, max)
Created on 2022-10-20 with reprex v2.0.2

Trouble reading a netcdf file and convert it into a SpatRaster

I am struggling to open a NetCDF file and convert it into a raster using R. The
data is supposed to be on a regular grid of 25 km by 25 km. It contains sea
ice concentration in the Arctic.
library(terra)
#> terra 1.5.21
library(ncdf4)
file <- "~/Downloads/data_sat_Phil_changt_grid/SIC_SMMR_month_2015.nc"
I am getting a warning about the extent not found.
r <- rast(file)
#> Error in R_nc4_open: No such file or directory
#> Warning: [rast] GDAL did not find an extent. Cells not equally spaced?
We can see that there is a problem with the coordinates/extent.
r
#> class : SpatRaster
#> dimensions : 448, 304, 12 (nrow, ncol, nlyr)
#> resolution : 0.003289474, 0.002232143 (x, y)
#> extent : 0, 1, 0, 1 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
#> source : SIC_SMMR_month_2015.nc:sic
#> varname : sic
#> names : sic_1, sic_2, sic_3, sic_4, sic_5, sic_6, ...
I can open the nc file with nc_open() and I see that the coordinates are present.
nc <- nc_open(file)
names(nc$var)
#> [1] "lat" "lon" "sic"
lat <- ncvar_get(nc, "lat")
lon <- ncvar_get(nc, "lon")
dim(lat)
#> [1] 304 448
dim(lon)
#> [1] 304 448
dim(r)
#> [1] 448 304 12
Is it possible to assemble this data (the SIC values and the coordinates) to create a SpatRaster?
The nc file can be downloaded here: https://easyupload.io/pfth0s
Created on 2022-05-20 by the reprex package (v2.0.1)
The data are gridded, but the file does not specify the coordinates, nor the coordinate reference system. The file specifies the lon/lat values associated with the cells, but does not help us much, as these are clearly not on a regular grid. That is easy to see from plot(r)
NAflag(r) = -9999
plot(r,1)
And also from
p = cbind(as.vector(lon), as.vector(lat))
plot(p, cex=.1, xlab="lon", ylab="lat")
So what you need to find out, is which coordinate reference system (crs) is used, clearly some kind of polar crs. And what the extent of the data set is.
From the website you point to, I take it we can use:
crs(r) = "+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +a=6378273 +b=6356889.449 +units=m +no_defs"
ext(r) = c(-3850000, 3750000, -5350000, 5850000)
r
#class : SpatRaster
#dimensions : 448, 304, 12 (nrow, ncol, nlyr)
#resolution : 25000, 25000 (x, y)
#extent : -3850000, 3750000, -5350000, 5850000 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +x_0=0 +y_0=0 +a=6378273 +b=6356889.449 +units=m +no_defs
#source : SIC_SMMR_month_2015.nc:sic
#varname : sic
#names : sic_1, sic_2, sic_3, sic_4, sic_5, sic_6, ...
The results look good:
g = geodata::gadm("Greenland", level=0, path=".")
gg = project(g, crs(r))
plot(r,1)
lines(gg)
But this is of course not a good way to do such things; the ncdf file should have contained all the metadata required.

Error in shapefile(dataFolder, "file.shp")) : could not find function "shapefile"

I am getting an error, saying could not find the function "shapefile".
I also tried all the possible solutions.
I did the shp, .shx and .dbf files in the same folder and many more but it doesn't work, any help, please?
library(raster)
setwd("filename of the folder ")
S <-shapefile(datafolder,"file.shp"))
then error
Error in shapefile(dataFolder, "file.shp")) : could not find function "shapefile"
Here I show that/how raster::shapefile works.
library(raster)
filename <- system.file("external/lux.shp", package="raster")
filename
#[1] "C:/soft/R/R-4.1.1/library/raster/external/lux.shp"
p <- shapefile(filename)
p
#class : SpatialPolygonsDataFrame
#features : 12
#extent : 5.74414, 6.528252, 49.44781, 50.18162 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
#variables : 5
#names : ID_1, NAME_1, ID_2, NAME_2, AREA
#min values : 1, Diekirch, 1, Capellen, 76
#max values : 3, Luxembourg, 12, Wiltz, 312
Your
S <-shapefile(datafolder,"file.shp"))
is not proper R syntax (parenthesis do not match). Perhaps you want
S <- shapefile("file.shp")
or
S <- shapefile(file.path(datafolder,"file.shp"))
in which case you do not need to set the working directory

Extracting all individual layers from a Raster Brick File

I have stacked 28 layers to a brick in R
brik
class : RasterBrick
dimensions : 720, 1440, 1036800, 28 (nrow, ncol, ncell, nlayers)
resolution : 0.25, 0.25 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
source : C:/Users/Ujjal Baruah/AppData/Local/Temp/Rtmp0GaiPO/raster/r_tmp_2020-01-03_030159_46788_10398.grd
names : Data.Fiel//tNO2Trop.1, Data.Fiel//tNO2Trop.2, Data.Fiel//tNO2Trop.3, Data.Fiel//tNO2Trop.4, Data.Fiel//tNO2Trop.5, Data.Fiel//tNO2Trop.6, Data.Fiel//tNO2Trop.7, Data.Fiel//tNO2Trop.8, Data.Fiel//tNO2Trop.9, Data.Fiel//NO2Trop.10, Data.Fiel//NO2Trop.11, Data.Fiel//NO2Trop.12, Data.Fiel//NO2Trop.13, Data.Fiel//NO2Trop.14, Data.Fiel//NO2Trop.15, ...
Now, i want to save this individual layers in Geotiff using
writeRaster(brik, file.path('/output/filepath/', names(brik)), bylayer=TRUE, format('GTiff'))
Unfortunately, i get just one file instead of multiple layers in geotiff.
Any solution would be appreciated.
Thanks
writeRaster seems to strip off the dot-number before creating a raster file. Hence it tries to write your layers all to Data.Fiel//tNO2Trop.tif.
> writeRaster(r, "./test.2", format="GTiff")
> dir(".")
[1] "test.tif"
(Note for some reason your code has format("GTiff") for format="GTiff". This works by the fluke that format is a function and returns the string "GTiff" and writeRaster is expecting the format string here)
I don't know why and I don't know if this is documented or a bug. You can work round by using dashes instead of dots:
> writeRaster(r, "./test-2", format="GTiff")
> dir(".")
[1] "test-2.tif" "test.tif"
and if dots are important to you then do a file.rename afterwards.
Edit: If you add the .tif to the file names then all is well:
> writeRaster(s, names(s), bylayer=TRUE, format="GTiff")
Error in .getGDALtransient(x, filename = filename, options = options, :
filename exists; use overwrite=TRUE
fails on the second layer because dot-number is stripped:
> dir()
[1] "layer.tif"
add .tif to the names:
> writeRaster(s, paste0(names(s),".tif"), bylayer=TRUE, format="GTiff")
shazam:
> dir()
[1] "layer.1.tif" "layer.2.tif" "layer.3.tif" "layer.tif"

Resources