Sample data
set.seed(123)
df <- data.frame(day = 1:365, Precp = sample(1:30, 365, replace = T),
ETo = sample(1:10, 365, replace = T), top.FC = 23, CN = 61, DC = 0.4)
This data has day of the year, rainfall and evapotranspiration & some constants like top.FC, CN and DC.
For a given day i, the water.update
function calculates the Soil water for day i
water.update <- function(WAT0, RAIN.i, ETo.i, CN, DC, top.FC){
S = 25400/CN - 254; IA = 0.2*S
if (RAIN.i > IA) { RO = (RAIN.i - 0.2 * S)^2/(RAIN.i + 0.8 * S)
} else {
RO = 0
}
if (WAT0 + RAIN.i - RO > top.FC) {
DR = DC * (WAT0 + RAIN.i - RO - top.FC)
} else {
DR = 0
}
dWAT = RAIN.i - RO - DR - ETo.i
WAT1 = WAT0 + dWAT
WAT1 <- ifelse(WAT1 < 0, 0, WAT1)
return(list(WAT1,RO,DR))
}
The function water.model
applies the water.update
for all days. It's recursive i.e. each days soil water needs previous day's soil water. Hence the loop in the water.model
function.
water.model <- function(dat){
top.FC <- unique(dat$top.FC)
# I make a vector to store the results
dat$WAT <- -9999.9
dat$RO <- -9999.9
dat$DR <- -9999.9
# First day (day 1) has a default value
dat$WAT[1] <- top.FC/2 # assuming top soil water is half the content on day 1
dat$RO[1] <- NA
dat$DR[1] <- NA
# Now calculate water content for day 2 onwards
for(d in 1:(nrow(dat)-1)){
dat[d + 1,7:9] <- water.update(WAT0 = dat$WAT[d],
RAIN.i = dat$Precp[d + 1],
ETo.i = dat$ETo[d + 1],
CN = unique(dat$CN),
DC = unique(dat$DC),
top.FC = unique(dat$top.FC))
}
return(dat)
}
ptm <- proc.time()
result <- water.model(df)
proc.time() - ptm
user system elapsed
0.18 0.00 0.17
The for loop is inevitable in this case since it uses previous day's water content to determine the water content of the present day.
Is there faster way to write the above function? I am looking for speeding up this code. The reason is because my actual data is much bigger.