Skip to content

Commit 9583b24

Browse files
committed
Added update_template.R, msr bug fixes
1 parent 154126d commit 9583b24

5 files changed

Lines changed: 177 additions & 28 deletions

File tree

R/CreateFlownet.R

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
#'
33
#' Creates the flow networkd table used by RHESSys
44
#' @param flownet_name The name of the flow network file to be created. Will be coerced to have ".flow" extension if not already present.
5-
#' @param readin readin indicates which maps to be used. If CreateFlowmet.R is run it's own, this should point to the template. Otherwise,
6-
#' if run inside of RHESSysPreprocess, readin will use the map data from world_gen.R, Streams map, and other optional maps, still need to
7-
#' be specified.
5+
#' @param readin readin indicates the maps to be used. If CreateFlowmet.R is run it's own, this should point to the template which references the maps(or values)
6+
#' used for the various levels and statevars. Otherwise, if run inside of RHESSysPreprocess, readin will use the map data from world_gen.R,
7+
#' Streams map, and other optional maps, still need to be specified.
88
#' @param type Input file type to be used. Default is raster. "Raster" type will use rasters
99
#' in GeoTiff or equivalent format (see Raster package), with file names matching those indicated in the template.
1010
#' ASCII is supported, but 0's cannot be used as values for data. "GRASS" will attempt to autodetect the version of
@@ -69,13 +69,13 @@ CreateFlownet = function(flownet_name,
6969
# Check for streams map, menu allows input of stream map
7070
if (is.null(streams) & (cfmaps[cfmaps[,1] == "streams",2] == "none" | is.na(cfmaps[cfmaps[,1] == "streams",2]))) {
7171
t = menu(c("Specify map","Abort function"),
72-
title = "Missing stream map. Specify one now, or abort function and edit cf_maps file?")
72+
title = "Missing stream map. Specify one now, or abort function and edit cf_maps file/readin input?")
7373
if (t == 2) {stop("Function aborted")}
7474
if (t == 1) {
7575
streams = readline("Stream map:")
7676
}
7777
}
78-
# only add stream map to cfmaps if it's not there already
78+
# add stream map to cfmaps if it's not there already
7979
if ((cfmaps[cfmaps[,1] == "streams",2] == "none" | is.na(cfmaps[cfmaps[,1] == "streams",2]))) {
8080
cfmaps[cfmaps[,1] == "streams",2] = streams
8181
}
@@ -88,32 +88,57 @@ CreateFlownet = function(flownet_name,
8888
if (!is.null(impervious)) {cfmaps[cfmaps[,1] == "impervious",2] = impervious}
8989
if (!is.null(roofs)) {cfmaps[cfmaps[,1] == "roofs",2] = roofs}
9090

91-
maps_in = unique(cfmaps[cfmaps[,2] != "none" & cfmaps[,1] != "cell_length",2])
91+
# remove tif and tiff extensions for simplicity
92+
if ( any(endsWith(cfmaps[,2],".tif") | endsWith(cfmaps[,2],".tiff")) ) {
93+
cfmaps[,2] = gsub(".tif$","",cfmaps[,2])
94+
cfmaps[,2] = gsub(".tiff$","",cfmaps[,2])
95+
}
96+
97+
# check inpputs are maps or values
98+
notamap = cfmaps[suppressWarnings( which(!is.na(as.numeric(cfmaps[,2])))),1]
99+
maps_in = unique(cfmaps[cfmaps[,2] != "none" & !cfmaps[,1] %in% notamap,2])
92100

93101
# ------------------------------ Use GIS_read to get maps ------------------------------
94102
readmap = GIS_read(maps_in, type, typepars, map_info = cfmaps)
103+
104+
# going to get rid of this
95105
map_ar_clean = as.array(readmap)
96106
dimnames(map_ar_clean)[[3]] = colnames(readmap@data)
97107

98-
raw_patch_data = map_ar_clean[, , cfmaps[cfmaps[, 1] == "patch", 2]]
99-
raw_patch_elevation_data = map_ar_clean[, , unique(cfmaps[cfmaps[, 1] == "z", 2])]
100-
raw_hill_data = map_ar_clean[, , cfmaps[cfmaps[, 1] == "hillslope", 2]]
101-
raw_basin_data = map_ar_clean[, , cfmaps[cfmaps[, 1] == "basin", 2]]
102-
raw_zone_data = map_ar_clean[, , cfmaps[cfmaps[, 1] == "zone", 2]]
103-
raw_slope_data = map_ar_clean[, , unique(cfmaps[cfmaps[, 1] == "slope", 2])]
104-
raw_stream_data = map_ar_clean[, , cfmaps[cfmaps[, 1] == "streams", 2]]
108+
# this is better
109+
map_list = lapply(readmap@data, matrix, nrow = readmap@grid@cells.dim[1], ncol = readmap@grid@cells.dim[2])
110+
111+
raw_patch_data = map_list[[cfmaps[cfmaps[, 1] == "patch", 2]]]
112+
raw_hill_data = map_list[[cfmaps[cfmaps[, 1] == "hillslope", 2]]]
113+
raw_basin_data = map_list[[cfmaps[cfmaps[, 1] == "basin", 2]]]
114+
raw_zone_data = map_list[[cfmaps[cfmaps[, 1] == "zone", 2]]]
115+
raw_stream_data = map_list[[cfmaps[cfmaps[, 1] == "streams", 2]]]
116+
117+
if ("slope" %in% notamap) {
118+
raw_slope_data = raw_patch_data
119+
raw_slope_data[!is.na(raw_slope_data)] = as.numeric(cfmaps[cfmaps[,1] == "slope",2])
120+
} else {
121+
raw_slope_data = map_list[[unique(cfmaps[cfmaps[, 1] == "slope", 2])]]
122+
}
123+
if ("z" %in% notamap) {
124+
raw_patch_elevation_data = raw_patch_data
125+
raw_patch_elevation_data[!is.na(raw_patch_elevation_data)] = as.numeric(cfmaps[cfmaps[,1] == "z",2])
126+
} else {
127+
raw_patch_elevation_data = map_list[[unique(cfmaps[cfmaps[, 1] == "z", 2])]]
128+
}
129+
105130
cell_length = readmap@grid@cellsize[1]
106131

107132
# Roads
108133
raw_road_data = NULL
109-
if (!is.null(roads)) {raw_road_data = map_ar_clean[, ,cfmaps[cfmaps[,1] == "roads",2]]}
134+
if (!is.null(roads)) {raw_road_data = map_list[[cfmaps[cfmaps[,1] == "roads",2]]]}
110135

111136
# Roofs and impervious is not yet implemented - placeholders for now -----
112137
if (!is.null(roofs) | !is.null(impervious)) {print("Roofs and impervious are not yet working",quote = FALSE)}
113138
raw_roof_data = NULL
114-
if (!is.null(roofs)) {raw_roof_data = map_ar_clean[, ,cfmaps[cfmaps[,1] == "roofs",2]]}
139+
if (!is.null(roofs)) {raw_roof_data = map_list[[cfmaps[cfmaps[,1] == "roofs",2]]]}
115140
raw_impervious_data = NULL
116-
if (!is.null(impervious)) {raw_impervious_data = map_ar_clean[, ,cfmaps[cfmaps[,1] == "impervious",2]]}
141+
if (!is.null(impervious)) {raw_impervious_data = map_list[[cfmaps[cfmaps[,1] == "impervious",2]]]}
117142

118143
# ----- SMOOTH FLAG STILL NEEDS TO BE LOOKED AT AGAIN -----
119144
smooth_flag = FALSE
@@ -138,7 +163,12 @@ CreateFlownet = function(flownet_name,
138163

139164
# ------------------------------ Multiscale routing/aspatial patches ------------------------------
140165
if (!is.null(asp_list)) {
141-
CF1 = multiscale_flow(CF1 = CF1, map_ar_clean = map_ar_clean, cfmaps = cfmaps, asp_list = asp_list)
166+
if ("asp_rule" %in% notamap) {
167+
map_list[["asp_rule"]] = raw_basin_data
168+
map_list[["asp_rule"]][!is.na(map_list[["asp_rule"]])] = as.numeric(cfmaps[cfmaps[,1] == "asp_rule",2])
169+
}
170+
171+
CF1 = multiscale_flow(CF1 = CF1, map_list = map_list, cfmaps = cfmaps, asp_list = asp_list)
142172
}
143173

144174
# ---------- Flownet list to flow table file ----------

R/multiscale_flow.R

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@
22
# function that transforms flowtable into multiscale flow table
33
# Will Burke 1/16/19
44

5-
multiscale_flow = function(CF1, map_ar_clean, cfmaps, asp_list){
5+
multiscale_flow = function(CF1, map_list, cfmaps, asp_list){
66

77
# Inputs: exisiting flow table (list), map arrays, map list, aspatial/multiscale rule list
88

99
# ----- Variable setup -----
10-
asp_map = map_ar_clean[, ,cfmaps[cfmaps[,1] == "asp_rule",2]] # matrix of aspatial rules
10+
asp_map = map_list[["asp_rule"]] # matrix of aspatial rules
11+
1112
patch_ID = unlist(lapply(CF1, "[[",9)) # patch IDs from cf1
1213
numbers = unlist(lapply(CF1, "[[",1)) # flow list numbers
13-
raw_patch_data = map_ar_clean[, , cfmaps[cfmaps[, 1] == "patch", 2]] # get patch matrix inside the function
14+
raw_patch_data = map_list[[cfmaps[cfmaps[, 1] == "patch", 2]]] # get patch matrix inside the function
1415
rulevars = asp_list # get rules - state variable overrides
1516
CF2 = list() # empty list for new flow list
1617

1718
# ----- iterate through (spatial) patches -----
18-
for (p in raw_patch_data[!is.na(raw_patch_data)]) {
19+
#for (p in raw_patch_data[!is.na(raw_patch_data)]) {
20+
for (p in patch_ID) {
1921
id = unique(asp_map[which(raw_patch_data == p)]) # get unique rule ID for patch p
22+
id = paste0("rule_",id)
2023

2124
if (length(id) > 1) {stop(paste("multiple aspatial rules for patch",p))} # if multiple rules for a single patch
2225
asp_count = ncol(rulevars[[id]]$patch_level_vars[1,]) - 1 # get number of aspatial patches for current patch
@@ -60,12 +63,13 @@ multiscale_flow = function(CF1, map_ar_clean, cfmaps, asp_list){
6063
CF2[[length(CF2)]]$Slopes = new_slope
6164
CF2[[length(CF2)]]$Boarder = new_boarder
6265

63-
for(i in 1:length(CF2[[length(CF2)]])){
64-
if(is.na(CF2[[length(CF2)]])[[i]]) {stop("shouldn't have NAs")}
65-
if(length(CF2[[length(CF2)]][[i]])==0) {stop("shouldn't have numeric(0)'s")}
66+
if (length(CF2) != 1 & unique(sapply(CF2, "[[", "PatchFamilyID")) != 1) {
67+
for (i in 1:length(CF2[[length(CF2)]])) {
68+
if(is.na(CF2[[length(CF2)]])[[i]]) {stop("shouldn't have NAs")}
69+
if(length(CF2[[length(CF2)]][[i]])==0) {stop("shouldn't have numeric(0)'s")}
70+
}
6671
}
6772

68-
6973
} # end aspatial patch loop
7074
} # end spatial patch loop
7175

R/patch_data_analysis.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ patch_data_analysis <- function(raw_patch_data,
396396

397397
# -------------------- Single Patch World --------------------
398398
# If there's only 1 patch, build list manually and return
399-
if (length(raw_patch_data) == 1) {
399+
if (length(raw_patch_data) == 1 | length(flw_struct$Number) == 1) {
400400
lst[[1]]$Slopes = 0
401401
lst[[1]]$TotalG = flw_struct$Area
402402
return(lst)

R/update_template.R

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#' update_template
2+
#'
3+
#' Read and modify an existing template
4+
#' @param template Name and path of templatefile to be created.
5+
#' @param out_file Destination file to write new template
6+
#' @param vars State variable(s) to be modified
7+
#' @param operator Operator to be (optionally) replaced. If not included the existing operator (e.g. 'value') will be left.
8+
#' @param values Values to replace for `vars`. N args must equal that of vars or be 1 (will be used for all vars).
9+
#' @param level_names Not implamented yet - for rare cases where you only want to replace 1 occurance of a state var (e.g. 'z' at zone but not patch ele)
10+
#' @param overwrite TRUE/FALSE if input file should be overwriten
11+
#' @author Will Burke
12+
#' @export
13+
14+
update_template = function(template, out_file, vars, values, operator = NULL, level_names = NULL, overwrite = FALSE) {
15+
16+
# NOTES
17+
# - vdouble check all the list options work and check var lengths/numbers when needed
18+
19+
# ---------- Check Aguments ----------
20+
if (is.null(out_file) & !overwrite) {stop(noquote("No destination file set by 'out_file' and 'overwrite' is FALSE"))}
21+
if ( file.exists(out_file) & overwrite == FALSE) {stop(noquote(paste0("File '",out_file,"' already exists and 'overwrite' argument is FALSE")))}
22+
if (length(vars) != length(values) & length(values) != 1) { stop(noquote(paste0("Vars and values have different lengths"))) }
23+
24+
25+
if (!is.character(values)) {
26+
values = as.character(values)
27+
}
28+
29+
30+
# for (i in length(vars)) {
31+
# if (level_names[i] == "all") {level_names[i] = c("world", "basin", "hillslope", "zone", "patch", "canopy_strata")}
32+
# }
33+
34+
# ---------- Parse templatefile ----------
35+
options(scipen = 999)
36+
# parsing the values as characters to retain the exact value/precision
37+
read_template = readLines(template)
38+
template = strsplit(trimws(read_template), "\\s+")
39+
40+
#template = data.frame(matrix(unlist(template), nrow=length(template), byrow=T),stringsAsFactors = FALSE)
41+
#names(template) = c("values","vars")
42+
43+
# ---------- Find Levels----------
44+
template_vars = sapply(template,"[[",1)
45+
index_all = which(template_vars == "_world" | template_vars == "_basin" | template_vars == "_hillslope" |
46+
template_vars == "_zone" | template_vars == "_patch" | template_vars == "_canopy_strata")
47+
index_names = gsub("^_", "", x = template_vars[index_all])
48+
index_max = c(index_all[2:length(index_all)]-1, length(read_template))
49+
template_levels = unname(unlist(mapply(rep,index_names, (index_max - index_all) + 1 )))
50+
51+
# ---------- Find and Replace Vars ----------
52+
for (i in length(vars)){
53+
54+
if (!is.null(level_names[i])) {
55+
find_index = template_levels == level_names[i]
56+
} else {
57+
find_index = rep(TRUE,length(template_levels))
58+
}
59+
60+
replace_index = which(template_vars == vars[i] & find_index)
61+
62+
# if unique values for every instance of var to be replaces were given, do nothing, otherwise repeat to get enough replacement values
63+
if (length(replace_index) > 1) {stop(noquote("Too many things to replace havet coded this yet"))}
64+
65+
if (template_levels[replace_index] == "canopy_strata") {
66+
current_value = template[[replace_index]][c(length(template[[replace_index]]) - 1, length(template[[replace_index]]))]
67+
} else {
68+
current_value = template[[replace_index]][length(template[[replace_index]])]
69+
}
70+
71+
if (length(values[i]) != length(replace_index)) {
72+
new_value = rep(values[i], length(replace_index)/length(values[i]))
73+
} else {
74+
new_value = values[i]
75+
}
76+
77+
if (any(startsWith(new_value,"*"))) {
78+
new_value = as.numeric(trimws(substr(new_value[startsWith(new_value,"*")],2,nchar(new_value[startsWith(new_value,"*")]))))
79+
new_value = new_value * as.numeric(current_value)
80+
} else {
81+
new_value = as.numeric(trimws(new_value))
82+
}
83+
84+
# generic sub/gsub
85+
#sub(paste0("[[:blank:]]",current_value,"$"), paste0("\t",new_value), read_template[replace_index])
86+
87+
read_template[replace_index] = unname(mapply(sub,paste0("[[:blank:]]",current_value,"$"), paste0("\t",new_value),read_template[replace_index]))
88+
89+
}
90+
91+
# ---------- Write file ----------
92+
writeLines(text = read_template,out_file)
93+
94+
print(noquote(paste("Successfully wrote updated template to",out_file)))
95+
96+
97+
}

R/world_gen.R

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,15 +295,20 @@ world_gen = function(template,
295295
if (asp_check) {
296296
patches = unique(levels[levels[,4] == z & levels[,3] == h & levels[,2] == b, 5])
297297
asp_ct = sapply(rulevars, FUN = function(x) ncol(x[[1]]) - 1)
298-
total_patches = sum(asp_ct[levels[levels[,5] == patches & levels[,4] == z & levels[,3] == h & levels[,2] == b, 7]])
298+
if (length(patches) == 1 & length(asp_ct) == 1){
299+
total_patches = length(patches) * asp_ct
300+
} else {
301+
total_patches = sum(asp_ct[levels[levels[,5] == patches & levels[,4] == z & levels[,3] == h & levels[,2] == b, 7]])
302+
}
299303

300304
writeChar(paste("\t\t\t",total_patches,"\t\t\t","num_patches\n",sep = ""),con = wcon,eos = NULL)
301305

302306
# ----- Patches (spatial) -----
303307
for (p in patches) {
304308
ruleid = unique(levels[(levels[,5] == p & levels[,4] == z & levels[,3] == h & levels[,2] == b),7])
309+
ruleid = paste0("rule_",ruleid)
305310
if (length(ruleid) != 1) {stop("something's wrong with the ruleid")}
306-
asp_index = 1:(length(rulevars[[ruleid]]$patch_level_vars[1,]) - 1)
311+
asp_index = 1:(length(rulevars[[(ruleid)]]$patch_level_vars[1,]) - 1)
307312

308313
# ----- Patches (non-spatial) -----
309314
for (asp in asp_index) {
@@ -443,6 +448,19 @@ world_gen = function(template,
443448
c("cell_length",cell_len),
444449
c("streams","none"), c("roads","none"), c("impervious","none"),c("roofs","none"))
445450

451+
if (any(!map_info[,1] == "slope")) {
452+
slope = NULL
453+
for (i in 1:length(which(var_names == "slope"))) {
454+
slope = c(slope, template_clean[[which(var_names == "slope")[i]]][3])
455+
}
456+
cfmaps = rbind(cfmaps, c("slope", mean(as.numeric(slope))))
457+
}
458+
if (asp_check) {
459+
if (!"asp_rule" %in% cfmaps[,1]) {
460+
cfmaps = rbind(cfmaps, c("asp_rule", mean(as.numeric(template_clean[[which(var_names == "asp_rule")]][3]))))
461+
}
462+
}
463+
446464
world_gen_out = list(cfmaps,rulevars)
447465

448466
return(world_gen_out)

0 commit comments

Comments
 (0)