The output.hru file is one of the most important output files of the SWAT (Soil and Water Assessment Tool) simulation model. It contains daily or monthly (depending on how you configured your simulation) time series of about 70 variables that are computed within the HRUs (hydrologic response units) of your simulation. The HRUs are the basic simulation units of SWAT, so the output.hru file is about the most detailed output you can get from the model.
The output.hru file tends to be a huge text table, hard formatted with fixed columns (i.e., Fortran style). It mixes monthly and annual values of the output variables, and it is sometimes a pain to read. I wrote a little R function for reading SWAT output.hru files, and I thought it could be useful for somebody. It can be easily adapted to other SWAT output files or versions (I am still using SWAT 2005 here).
Usage: swat_readOutputhru(file,col=NULL,hru=NULL,year=NULL,lulc=NULL,ver=2012)
Arguments:
| file | Character. Direction of the output.hru file. |
| col | Optional. Vector of column names or column numbers to be read from the output.hru file. |
| hru | Optional. Numeric, id of the HRU to be read. It can also be a vector of numeric ids. |
| year | Optional. Numeric, year to be read. It can also be a vector of years. |
| lulc | Optional. Character, id of a specific land use / land cover (LULC). |
| ver | Optional. Numeric, version of SWAT being used. Defaults to 2012. |
Result: a list object with monthly values stored as mon and annual values in anu.
Here’s the function:
swat_readOutputhru <- function(file,col=NULL,hru=NULL,year=NULL,lulc=NULL,ver=2012) {
# format of the .hru file (SWAT 2012)
fmt=list(var=c('LULC','HRU','GIS','SUB','MGT','MON','AREA','PRECIP','SNOFALL','SNOMELT','IRR',
'PET','ET','SW_INIT','SW_END','PERC','GW_RCHG','DA_RCHG','REVAP','SA_IRR','DA_IRR','SA_ST',
'DA_ST','SURQ_GEN','SURQ_CNT','TLOSS','LATQ','GW_Q','WYLD','DAILYCN','TMP_AV','TMP_MX',
'TMP_MN','SOL_TMP','SOLAR','SYLD','USLE','N_APP','P_APP','NAUTO','PAUTO','NGRZ','PGRZ',
'NCFRT','PCFRT','NRAIN','NFIX','F-MN','A-MN','A-SN','F-MP','AO-LP','L-AP','A-SP','DNIT',
'NUP','PUP','ORGN','ORGP','SEDP','NSURQ','NLATQ','NO3L','NO3GW','SOLP','P_GW','W_STRS',
'TMP_STRS','N_STRS','P_STRS','BIOM','LAI','YLD','BACTP','BACTLP',
'WTAB','WTABELO','SNO_HRU','CMUP_KGH','CMTOT_KGH','QTILE','TNO3','LNO3','GW_Q_D','LATQ_CNT'),
col=c(4,5,9,5,5,5,rep(10,79)))
if (ver==2009) {
fmt$var <- fmt$var[1:80]
fmt$col <- fmt$col[1:80]
}
if (ver==2005) {
fmt$var <- fmt$var[1:75]
fmt$col <- fmt$col[1:75]
}
if (class(w)=='numeric') {
col <- fmt$var[w]
}
# select columns
if (!is.null(col)) {
if (!('MON' %in% col)) {
col <- c('MON',col)
}
if (!('LULC' %in% col)) {
col <- c('LULC',col)
}
if (!('HRU' %in% col)) {
col <- c('HRU',col)
}
w <- fmt$var %in% col
fmt$var <- fmt$var[w]
fmt$col <- ifelse(w,fmt$col,-fmt$col)
}
# read file, rearrange table
res <- read.fwf(file,fmt$col,
head=F,skip=9,encoding='latin1',
strip.white=TRUE,nrow=-1,buffersize=20000)
colnames(res) <- fmt$var
res <- res[order(res$HRU),]
# select hrus by number or by lulc
if (!is.null(hru)) {
res <- res[res$HRU>=min(hru) & res$HRU<=max(hru),]
}
if (!is.null(lulc)) {
res <- res[res$LULC==lulc,]
}
# monthly and annual tables
mon <- res[res$MON<=12,]
anu <- res[res$MON>12,]
colnames(anu) <- sub('MON','YEA',colnames(anu))
w <- which(mon$HRU==mon$HRU[1] & mon$MON==mon$MON[1])
ww <- c((w-1)[-1],nrow(mon))
years <- min(anu$YEA):max(anu$YEA)
mon$YEA <- NA
for (i in 1:length(w)) {
mon[w[i]:ww[i],][,'YEA'] <- years[i]
}
# select years
if (!is.null(year)) {
mon <- mon[mon$YEA>=min(year) & mon$YEA<=max(year),]
anu <- anu[anu$YEA>=min(year) & anu$YEA<=max(year),]
}
# rearrange
rownames(mon) <- rownames(anu) <- NULL
w <- which(colnames(mon)=='MON')
ww <- which(colnames(mon)=='YEA')
mon <- mon[,c(colnames(mon)[c(1:w)],'YEA',colnames(mon)[-c(1:w,ww)])]
# go
return(list(mon=mon,anu=anu))
}
Example:
file <- './Scenarios/Default/TxtInOut/output.hru'
w <- c('PRECIP','SNOFALL','SNOMELT','IRR','ET',
'SW_END','SA_ST','DA_ST','WYLD','REVAP')
# the following also works:
# w <- c(1,2,6,8,9,10,11,13,15,22,23,25,26,27,28,29)
# read the whole file
r <- swat_readOutputhru(file,col=w)
# read just one hru and one year
r <- swat_readOutputhru(file,col=w,hru=14,year=2009)
r$mon
r$anu
What would you add to the code and where, if you are running a multi-year simulation on a daily time step with more than 50 sub-basins and 500 HRUs to summarize outputs to monthly and annual values? Gracias!
Hi Johan. I incorporated this code into higher-level functions to read and process SWAT output files, but they very much depend on i) which version of the model you’re using, and; ii) how did you configure the daily outputs. I will however upload these functions just in case they are of help to someone, if I find time for it…