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…