2020# ' ecological zones (Canadian Ecozones), are "larg-ish", more "blobby" (low fractal dimension)
2121# ' than other ecological zonation in mountains (which tend to follow elevation
2222# ' contours), and are each buffered (default 20km).
23- # ' @param nationalForestPolygon A polygon layer (`SpatVector` or `sf`) that maps the
24- # ' national forests of Canada . If missing, it will try to use
23+ # ' @param x A polygon layer (`SpatVector` or `sf`) or gridded layer (`SpatRaster`)
24+ # ' that maps the entire area of interest for the ELFs . If missing, it will try to use
2525# ' `scfmutils::prepInputsFireRegimePolys(type = "FRU")` if `scfmutils` is installed.
2626# ' Currently, only options with a column called `FRU` will work.
2727# ' @param desiredBuffer The distance in `m` that the buffers should be. Default is `20000`.
4040# ' and lat0 = ymin and lat1 = ymax of the individual ELF. This will create ELFs
4141# ' with the least amount of pixel deformation.
4242# ' @export
43- makeELFs <- function (nationalForestPolygon , desiredBuffer = 20000 ,
43+ makeELFs <- function (x , desiredBuffer = 20000 ,
4444 maxArea = 2.4e+11 , destinationPath = " ." , singleSpatVector = FALSE ,
4545 useCache = TRUE ) {
46- if (missing(nationalForestPolygon )) {
46+ if (missing(x )) {
4747 if (! requireNamespace(" scfmutils" )) stop(" Please install PredictiveEcology/scfmutils " ,
48- " or supply a nationalForestPolygon " )
49- nationalForestPolygon <-
48+ " or supply a x " )
49+ x <-
5050 scfmutils :: prepInputsFireRegimePolys(type = " FRU" , destinationPath = destinationPath )
5151 }
52- digNFP <- reproducible :: .robustDigest(nationalForestPolygon )
53- dv <- terra :: vect(nationalForestPolygon ) | >
54- reproducible :: Cache(omitArgs = " x" , .cacheExtra = digNFP ,
55- useCache = useCache )
52+ digNFP <- reproducible :: .robustDigest(x )
53+ if (is(x , " sf" )) {
54+ dv <- terra :: vect(x ) | >
55+ reproducible :: Cache(omitArgs = " x" , .cacheExtra = digNFP ,
56+ useCache = useCache )
57+ } else if (is(x , " SpatRaster" )) {
58+ dv <- {
59+ `>=`(x , 0 ) | >
60+ terra :: as.polygons() | >
61+ terra :: buffer(4 * res(x )[1 ]) | >
62+ terra :: buffer(- 4 * res(x )[1 ]) } | >
63+ Cache(.cacheExtra = digNFP , omitArgs = " x" ,
64+ .functionName = " Create polygon from input SpatRaster" )
65+ }
5666 ecoNames <- c(
5767 " zone" , " region" ,
5868 " province"
@@ -66,16 +76,23 @@ makeELFs <- function(nationalForestPolygon, desiredBuffer = 20000,
6676 ecosLCC <- Map(nam = ecoNames , url = urls , function (nam , url ) {
6777 reproducible :: prepInputs(url = url ,
6878 destinationPath = destinationPath ,
69- projectTo = nationalForestPolygon ,
79+ projectTo = x ,
7080 useCache = useCache ) | >
7181 reproducible :: Cache(omitArgs = " projectTo" ,
72- .cacheExtra = list (nationalForestPolygon = digNFP ),
73- useCache = useCache )
82+ .cacheExtra = list (x = digNFP ),
83+ useCache = useCache , .functionName = paste0( " prepInputs_ " , nam ) )
7484 })
7585 tmpl <- terra :: rast(ecosLCC [[1 ]], res = 5000 )
76- hf <- terra :: rasterize(nationalForestPolygon , tmpl , field = " FRU" ) | >
77- reproducible :: Cache(omitArgs = " x" , .cacheExtra = digNFP ,
78- useCache = useCache )
86+ if (is(x , " SpatRaster" )) {
87+ hf <- terra :: project(x , tmpl )
88+ } else {
89+ hf <- terra :: rasterize(x , tmpl , field = " FRU" ) | >
90+ reproducible :: Cache(omitArgs = " x" , .cacheExtra = digNFP ,
91+ useCache = useCache )
92+ }
93+
94+ hf <- terra :: trim(hf )
95+
7996 ecosR <- Map(ecoLCC = ecosLCC , nam = names(ecosLCC ),
8097 function (ecoLCC , nam ) {
8198 terra :: rasterize(ecoLCC , tmpl , field = toupper(paste0(" eco" , substr(nam , 1 , 7 )))) | >
@@ -97,27 +114,37 @@ makeELFs <- function(nationalForestPolygon, desiredBuffer = 20000,
97114
98115 # plotStack(ecopRseg)
99116 message(" Starting to buffer ELFs" )
100- out <- bufferOut(dv , desiredBuffer = desiredBuffer ,
101- useCache = useCache ) | >
102- reproducible :: Cache(omitArgs = " v" , .cacheExtra = digNFP ,
103- useCache = useCache )
117+ # out <- bufferOut(dv, desiredBuffer = desiredBuffer, # spatRas = x ,
118+ # useCache = useCache) |>
119+ # reproducible::Cache(omitArgs = "v", .cacheExtra = digNFP,
120+ # useCache = useCache)
104121 out2 <- mergeAndSplitRas(ecopRseg , ecosLCC $ province , maxArea = maxArea ,
105- useCache = useCache ) | >
106- Cache(useCache = useCache )
122+ useCache = useCache , destinationPath = destinationPath ) | >
123+ reproducible :: Cache(omitArgs = " ecopRseg " , .cacheExtra = attr( ecosR , " tags " ) )
107124
108125 out3 <- lapply(out2 , function (x ) as.list(segregateKeepNames(x , omitClasses = 0 ))) | >
109126 unlist(recursive = FALSE )
110127 names(out3 ) <- sapply(out3 , names )
111128
112- ELFs <- bufferOut(spatRasSeg = out3 , mask = out $ rasWhole [[ 1 ]] ,
129+ ELFs <- bufferOut(spatRasSeg = out3 , mask = hf ,
113130 desiredBuffer = desiredBuffer ,
114131 useCache = useCache ) | >
115132 reproducible :: Cache(omitArgs = c(" spatRasSeg" , " mask" ),
116- .cacheExtra = list (nationalForestPolygon = digNFP ,
117- attr(out2 , " tags" ),
118- attr(out , " tags" )
133+ .cacheExtra = list (x = digNFP ,
134+ attr(out2 , " tags" )# ,
135+ # attr(out, "tags")
119136 ),
120137 useCache = useCache )
138+
139+ # ELFs <- bufferOut(spatRasSeg = out3, mask = out$rasWhole[[1]],
140+ # desiredBuffer = desiredBuffer,
141+ # useCache = useCache) |>
142+ # reproducible::Cache(omitArgs = c("spatRasSeg", "mask"),
143+ # .cacheExtra = list(x = digNFP,
144+ # attr(out2, "tags"),
145+ # attr(out, "tags")
146+ # ),
147+ # useCache = useCache)
121148 if (isTRUE(singleSpatVector )) {
122149
123150 ELFs <- makeELFs(destinationPath = " inputs" )
@@ -152,6 +179,8 @@ bufferOut <- function(v, spatRasSeg, spatRas, mask, field = "FRU", desiredBuffer
152179 terra :: rasterize(v , y = _, field = " FRU" , touches = TRUE )} | >
153180 reproducible :: Cache(omitArgs = " x" ,
154181 useCache = useCache )
182+ }
183+ if (missing(spatRasSeg )) {
155184 spatRasSeg <- terra :: segregate(spatRas )
156185 }
157186
@@ -237,37 +266,53 @@ bufferOut <- function(v, spatRasSeg, spatRas, mask, field = "FRU", desiredBuffer
237266
238267 # need to mask 2x maybe
239268 r [[i ]] <- reproducible :: maskTo(r [[i ]], mask , verbose = FALSE , touches = FALSE )
240- ca [[i ]] <- reproducible :: maskTo(ca [[i ]], mask , verbose = FALSE , touches = FALSE )
241-
242- patchs <- terra :: patches(r [[i ]], allowGaps = FALSE , values = FALSE , directions = 8 )
243- tab <- terra :: freq(patchs )
244-
245- if (NROW(tab ) > 1 ) {
246- tooSmall <- tab $ count < 500
247- if (any(tooSmall )) {
248-
249- r [[i ]][patchs [] %in% tab $ value [tooSmall ]] <- NA
250- r [[i ]] <- terra :: trim(r [[i ]])
251- a <- ca [[i ]]
252- a [ca [[i ]] == 0 ] <- NA
253- patchsCA <- terra :: patches(a , allowGaps = FALSE , values = FALSE , directions = 8 )
254- # patchsCA <- terra::patches(ca[[i]] > 0, allowGaps = FALSE, values = FALSE, directions = 8)
255- tab <- terra :: freq(patchsCA )
256- tooSmall <- tab $ count < 500
257- wh <- which(patchsCA [] %in% tab $ value [tooSmall ])
258- dtLost <- data.table(pixelID = wh , value = terra :: values(ca [[i ]])[wh ])
269+ if (NROW(terra :: freq(is.na(r [[i ]]))) > 1 ) {
270+ ca [[i ]] <- reproducible :: maskTo(ca [[i ]], mask , verbose = FALSE , touches = FALSE )
259271
260- lostPixels [[i ]] <- dtLost
261- ca [[i ]][wh ] <- 0
272+ patchs <- terra :: patches(r [[i ]], allowGaps = FALSE , values = FALSE , directions = 8 )
273+ tab <- terra :: freq(patchs )
274+
275+ if (NROW(tab ) > 1 ) {
276+ tooSmall <- tab $ count < 500
277+ if (! all(tooSmall )) {
278+ if (any(tooSmall )) {
279+
280+ r [[i ]][patchs [] %in% tab $ value [tooSmall ]] <- NA
281+ r [[i ]] <- terra :: trim(r [[i ]])
282+ a <- ca [[i ]]
283+ a [ca [[i ]] == 0 ] <- NA
284+ patchsCA <- terra :: patches(a , allowGaps = FALSE , values = FALSE , directions = 8 )
285+ # patchsCA <- terra::patches(ca[[i]] > 0, allowGaps = FALSE, values = FALSE, directions = 8)
286+ tab <- terra :: freq(patchsCA )
287+ tooSmall <- tab $ count < 500
288+ wh <- which(patchsCA [] %in% tab $ value [tooSmall ])
289+ dtLost <- data.table(pixelID = wh , value = terra :: values(ca [[i ]])[wh ])
290+
291+ lostPixels [[i ]] <- dtLost
292+ ca [[i ]][wh ] <- 0
293+ }
294+ }
262295 }
296+ # r[[i]] <- maskTo(r[[i]], mask, verbose = FALSE, touches = FALSE)
297+ # ca[[i]] <- maskTo(ca[[i]], mask, verbose = FALSE, touches = FALSE)
263298 }
264- # r[[i]] <- maskTo(r[[i]], mask, verbose = FALSE, touches = FALSE)
265- # ca[[i]] <- maskTo(ca[[i]], mask, verbose = FALSE, touches = FALSE)
266-
267299 print(paste0(" Done " , i ))
268300 }
269301
270302 ll <- moveSliversToOtherELFs(lostPixels , lp , ca , i , r )
303+ ll3 <- ll
304+ destinationPath <- unique(dirname(Filenames(spatRasSeg )))
305+ ELFpath <- file.path(destinationPath , " ELFs_final" )
306+ unlink(ELFpath , recursive = TRUE )
307+ dir.create(ELFpath , recursive = TRUE , showWarnings = FALSE )
308+ message(" Writing ELF rasters to disk" )
309+ for (i in seq_along(ll )) {
310+ for (j in seq_along(i )) {
311+ fn <- file.path(ELFpath , paste0(names(ll [[i ]][[j ]]), " .tif" ))
312+ unlink(fn )
313+ ll [[i ]][[j ]] <- terra :: writeRaster(ll [[i ]][[j ]], filename = fn , overwrite = TRUE )
314+ }
315+ }
271316
272317 list (rasCentered = ll $ r , rasWhole = ll $ ca )
273318}
@@ -278,6 +323,7 @@ segregateKeepNames <- function(ecopR, omitClasses, classes = NULL) {
278323 classes <- setdiff(uniquVals , omitClasses )
279324 }
280325 if (length(setdiff(uniquVals , 0 )) > 1 ) {
326+ origFilenames <- Filenames(ecopR )
281327 ecopRseg <- terra :: segregate(ecopR , classes = classes )
282328 if (is.factor(ecopR )) {
283329 names(ecopRseg ) <- cats(ecopR )[[1 ]][match(as.numeric(names(ecopRseg )), cats(ecopR )[[1 ]]$ ID ), 2 ]
@@ -291,6 +337,10 @@ segregateKeepNames <- function(ecopR, omitClasses, classes = NULL) {
291337 data.table :: setorder(dt , " num" )
292338 ecopR <- ecopRseg [[match(dt $ nam , names(ecopRseg ))]]
293339 }
340+ if (terra :: inMemory(ecopR ))
341+ ecopR <- writeRaster(ecopR , overwrite = TRUE ,
342+ filename = file.path(dirname(origFilenames ),
343+ paste0(paste(names(ecopR ), collapse = " _" ), " .tif" )))
294344 ecopR
295345
296346}
@@ -323,7 +373,8 @@ split_poly <- function(sf_poly, n_areas) {
323373}
324374
325375mergeAndSplitRas <- function (ecopRseg , ecopLCC , maxArea = 2.4e+11 ,
326- field = " ECOPROVINC" , useCache = TRUE ) { # FRU 27 ... or FRU 26 is 4.02075e+11
376+ field = " ECOPROVINC" , useCache = TRUE ,
377+ destinationPath ) { # FRU 27 ... or FRU 26 is 4.02075e+11
327378 # Require::Require(c(sf, dismo))
328379 prov1 <- as.character(sort(as.numeric(unique(names(ecopRseg )))))
329380 out <- Map(prov = prov1 , function (prov ) {
@@ -356,11 +407,15 @@ mergeAndSplitRas <- function(ecopRseg, ecopLCC, maxArea = 2.4e+11,
356407 tmpRas <- try(terra :: rasterize(tmp , ecopRseg [[provChar ]], field = field , touches = TRUE ))
357408 whChange <- tmpRas [] > 0
358409 a <- ecopRseg [[provChar ]]
410+ # Next line doesn't work --> it pulls it into memory
411+ # set.values(a, cells = which(whChange %in% 1), values(tmpRas, mat = FALSE)[whChange %in% 1])
359412 a [whChange ] <- tmpRas [whChange ]
360- tmp <- a
361413 } else {
362- tmp <- ecopRseg [[provChar ]]
414+ a <- ecopRseg [[provChar ]]
363415 }
416+ # Need to write it explicitly because it keeps the original "fullRaster" as its .tif
417+ tmp <- writeRaster(a , filename = file.path(destinationPath , paste0(provChar , " .tif" )),
418+ overwrite = TRUE )
364419 message(" Done " , prov )
365420 tmp
366421 })
@@ -401,11 +456,20 @@ moveSliversToOtherELFs <- function(lostPixels, lp, ca, i, r) {
401456 sums <- list ()
402457 for (addToInd in addTo ) {
403458 curPixelVal <- ca [[addToInd ]][] != 2
404- a [[addToInd ]] <- ca [[addToInd ]]
459+ arr <- try(a [[addToInd ]] <- ca [[addToInd ]])
460+ if (is(arr , " try-error" )) browser()
405461 a [[addToInd ]][lostPixels [[lp ]]$ pixelID ] <- pmax(terra :: values(a [[addToInd ]])[lostPixels [[lp ]]$ pixelID ], lostPixels [[lp ]]$ value , na.rm = TRUE )
406462 theA <- terra :: freq(a [[addToInd ]])
407463 # theA <- lapply(a, function(x) if (!is.null(x)) terra::freq(x))
408- sums [[addToInd ]] <- sum(theA [- 1 ,] - terra :: freq(ca [[addToInd ]])[- 1 ,])
464+ ar1 <- theA [- 1 , ]
465+ br1 <- terra :: freq(ca [[addToInd ]])[- 1 ,]
466+ if (NROW(ar1 ) != NROW(br1 )) {
467+ missings <- setdiff(br1 $ value , ar1 $ value )
468+ a2 <- data.frame (layer = ar1 $ layer [1 ], value = missings , count = br1 $ count [br1 $ value %in% missings ])
469+ ar1 <- rbind(ar1 , a2 )
470+ ar1 <- ar1 [order(ar1 $ value ),]
471+ }
472+ sums [[addToInd ]] <- sum(ar1 - br1 )
409473 }
410474 addTo <- which.min(unlist(lapply(sums , function (ss ) if (is.null(ss )) 1e7 else ss )))
411475 if (hasNames )
@@ -420,6 +484,7 @@ moveSliversToOtherELFs <- function(lostPixels, lp, ca, i, r) {
420484 a [lostPixels [[lp ]]$ pixelID ] <- newVals
421485 # a[a[] == 0] <- NA
422486 a <- terra :: trim(a )
487+ # if (is(a, "try-error")) browser()
423488 a <- terra :: project(a , terra :: crs(r [[addTo ]]), method = " near" )
424489 bb <- terra :: resample(a , r [[addTo ]], method = " near" )
425490 whVals <- which(terra :: values(bb ) > 0 )
0 commit comments