R workflow to generate SWATfarmR input
Abstract
This repository provides an automated R workflow to combine field-scale crop-rotation data with crop-specific and generic management schedules. Output of this workflow is the file farmR_input.csv, which can be directly used within the SWATfarmR package to generate SWAT+ management files (`management.sch`, `plant.ini`). Download and unpack `SWATfarmR_input.zip`, adapt all required input files and run the workflow as described in the README. The procedure is described in much more detail in Chapter 4 of the OPTAIN SWAT+ Modelling Protocol (Schürz et al., 2022).
Full text
R Workflow for Generating the SWATfarmR Input File This repository provides an automated R workflow to combine field-scale crop-rotation data with crop-specific and generic management schedules. Output of this workflow is the file farmR_input.csv , which can be directly used within the SWATfarmR (https://chrisschuerz.github.io/SWATfarmR/) package to generate SWAT+ management files ( management.sch , plant.ini ). The procedure is described in more detail in Chapter 4 of the OPTAIN SWAT+ Modelling Protocol (Schürz et al., 2022; DOI: 10.5281/zenodo.7463395 (https://doi.org/10.5281/zenodo.7463395)). Download and unpack SWATfarmR_input.zip , adapt all required input files and run the workflow as described in the following. Required Input Files All input files should be placed in the ./input_data/ directory. File naming can be customized in the main R script ( write_SWATfarmR_input.R ). (1) Land-use Crop Map A polygon shapefile ( my_lu_crops.shp ) representing all field-scale HRUs (Hydrologic Response Units) that include cropland and non-cropland land uses. Required attributes: Column Description lu Unique land-use or field identifier. y_2012 … y_2020 Crop or land-use name for each year (as in management tables). Additional fields (optional) May include subbasin IDs, area, or HRU names. Requirements: Field HRUs should have a consistent prefix (e.g. field_ ) defined in the script as hru_crops <- 'field' . Each crop name used in the year columns must exactly match entries in my_mgt_crops.csv . Non-cropland areas (e.g. pasture, forest) should use names matching the my_mgt_generic.csv table. (2) Crop-specific Management Schedules A table ( my_mgt_crops.csv ) describing single-year representative management schedules for each crop. Each row represents one operation (e.g., tillage, sowing, fertilizer, harvest). Typical structure: crop_mgt mon_1 day_1 mon_2 day_2 operation op_data1 op_data2 op_data3 wwht 9 15 10 7 fertilizer elem_p broadcast 25 wwht 9 16 10 8 tillage cultiv25 wwht 9 24 10 9 tillage harrow7 wwht 9 25 10 10 plnt wwht wwht skip wwht 3 3 3 17 fertilizer elem_n broadcast 78 wwht 4 23 5 7 fertilizer elem_n broadcast 50 wwht 5 25 6 8 fertilizer elem_n broadcast 15
crop_mgt mon_1 day_1 mon_2 day_2 operation op_data1 op_data2 op_data3 wwht 7 25 8 17 harvest_only wwht grain wwht 7 25 8 17 kill_only wwht wwht 7 26 8 19 tillage fldcul10 Rules and constraints: Each schedule must contain at least one plant and one kill_only operation. Use harvest_only (not harvest_kill ) when a crop should survive harvest (important for model verification in SWATdoctR (https://git.ufz.de/schuerz/swatdoctr/) package). Include one skip line to mark the end of each year. The skip line must not be the last entry. Operations must be chronologically ordered (by month/day within the year). Multi-year crops: For crops that persist multiple years (e.g. grassland), create multiple schedules: grass_1yr , grass_2yr , grass_3yr , … up to grass_maxyr . If a summer crop follows a perennial (e.g., barley after grass), provide a half-year version of the summer crop schedule (e.g. barl_0.5yr ) to represent spring-only management (and no autumn tillage). (3) Generic Land-use Management A table ( my_mgt_generic.csv ) defining representative schedules for non-cropland land uses such as pasture, meadow, or forest. These are treated separately because they do not require crop-rotation logic and will be repeated in each simulation year. Typical structure: crop_mgt mon_1 day_1 mon_2 day_2 operation op_data1 op_data2 op_data3 past initial_plant fesc 1, 1000, 0, 0, 1, 1000 past 3 1 3 31 fertilizer elem_n broadcast 60 past 3 1 3 31 fertilizer elem_p broadcast 25 past 5 25 6 5 harvest_only fesc hay_cut_low past 6 7 6 15 fertilizer elem_n broadcast 40 past 8 10 8 25 harvest_only fesc hay_cut_low Notes: No skip lines are used in these tables. The first operation must be initial_plant , defining vegetation parameters for SWAT+ plant.ini . op_data1 = plant community name (from plants.plt ) op_data2 = comma-separated initialization parameters: lai_init, bm_init, phu_init, plnt_pop, yrs_init, rsd_init Operations can include grazing , fertilizer , irrigation , or harvest_only as applicable. Running the Workflow Open SWATfarmR_input.proj in RStudio Load write_SWATfarmR_input.R : This is the main user script — edit only input paths and settings, then run it line by line. functions_write_SWATfarmR_input.R is sourced at the beginning. It contains helper functions for building and checking the schedules.
# Load functions and packages ------------------------------------------------------- source('./functions_write_SWATfarmR_input.R') foo1(c("sf" , "tidyverse" , "lubridate", "reshape2", "remotes", "dplyr", "data.table")) foo2("HighFreq") # Define input files----------------------------------------------------------------- lu_shp <- './input_data/my_lu_crops.shp' # land-use crop map shapefile mgt_csv <- './input_data/my_mgt_crops.csv' # crop management .csv table lu_generic_csv <- './input_data/my_mgt_generic.csv' # generic land use management .csv table # Define variables------------------------------------------------------------------- ## Simulation period start_y <- 2009 #starting year (consider at least 3 years for warm-up!) end_y <- 2020 #ending year ## Prefix of cropland hrus (all names of hrus with a crop rotation must begin ## with this prefix in column 'lu' of your land use map) hru_crops <- 'field' ## Multi-year farmland grass ## Did you define any multi-year farmland grass schedules? 'y' (yes), 'n' (no) m_yr_sch_existing <- 'y' ## If yes, define also the following variables. If not, skip next four lines crop_myr <- 'akgs' # prefix of multi-year schedules in management file # multiple entries should have the same number of characters, e.g.: crop_myr <- c('akgs', 'bsv g') max_yr <- 5 # maximum number of years farmland grass can grow before it is killed (should be <8) ## Do your multi-year farmland grass schedules consider the type of the following crop (summer o r winter crop)? ## (e.g., a '_1.5yr' schedule with a kill op in spring allows for planting a summer crop immedia tely afterwards) ## If yes, you must define your summer crops crop_s <- c('sgbt','csil','barl') ## Do your summer crop schedules usually start with an operation in autumn (e.g. tillage)? ## To combine them with farmland grass, it is necessary that you provide 'half-year-schedules' ## ('half-year-schedules' are additional summer crop schedules without operations in autumn) ## The adapted schedules should be added to the crop management table with suffix '_0.5yr' (e.g. 'csil_0.5yr') ## If additional 'half-year-schedules' are not needed, because your normal summer crop schedules ## do not start in autumn, type 'n' additional_h_yr_sch_existing <- 'y' # 'y' (yes), 'n' (no) # Read input data ---------------------------------------------------------------- ## Read land-use crop map shapefile and drop geometry lu <- st_drop_geometry(read_sf(lu_shp)) ## Read crop management .csv table ## Make sure it includes all crops of your lu map mgt_crop <- read.csv(mgt_csv, as.is=T) ## Read generic land use management .csv table ## Make sure it includes all non-cropland classes with a vegetation cover mgt_generic <- read.csv(lu_generic_csv, as.is=T) # Check for correct positioning of 'skip' line ------------------------------------ check_skip <- check_skip_position() # Check for date conflicts within single crop schedules ------------------------------- check_date_conflicts1()
# Build schedules for crop sequences ---------------------------------------------- rota_schedules <- build_rotation_schedules() # Check for date conflicts in combined (rotation) schedule -------------------------- check_date_conflicts2() # Solve minor date conflicts (where only a few days/weeks are overlapping)--------- rota_schedules <- solve_date_conflicts() ## check again for date conflicts ------------------------------------------------- check_date_conflicts2() ## write the SWAT farmR input table ----------------------------------------------- write_farmR_input() Diagnostic files check_skip.csv — lists crops with missing or misplaced skip lines crop_comb_conflict.csv — identifies overlapping crop combinations mgt_conflict.csv — details specific date conflicts between operations Output file farmR_input.csv — this file can be used directly with the SWATfarmR function: SWATfarmR::write_management_sch("farmR_input.csv") to produce the final SWAT+ management.sch and plant.ini files. Notes and Good Practices Always review the diagnostic files before proceeding to SWAT+. Regenerate farmR_input.csv for each simulation period. Customize the filter and cond fields in the CSV for location-specific management rules - details can be found in the description of the SWATfarmR (https://chrisschuerz.github.io/SWATfarmR/) package. Maintain chronological operation order; the script assumes increasing day-of-year order. Keep helper functions unchanged unless debugging. Citation This workflow is described in more detail in: Schürz C., et al. (2022). SWAT+ Modelling Protocol for the Assessment of Water and Nutrient Retention Measures in Small Agricultural Catchments. Zenodo. DOI: 10.5281/zenodo.7463395