WOFOST crop database¶
There is a GitHub repository containing calibtated parameters for a range of varieties of crops. These parameters were used, e.g., in the Hupselbrook test case provided with the SWAP model for potato variety. As these are reusable, it made sense to tap into that database to make creation of valid crop files for pySWAP easier.
In this notebook, we will create a .crp file for potato variety used in the hupselbrook test case.
import pyswap as psp
psp.setup_logging(level="INFO")
Exploring the database¶
pySWAP contains a simple wrapper around A. Wit's crop database. We can use built in classes to get an overview of available data. Then we can check which crop types are available in the database.
cropdb = psp.db.WOFOSTCropDB()
cropdb.croptypes
['barley', 'cassava', 'chickpea', 'cotton', 'cowpea', 'fababean', 'groundnut', 'maize', 'millet', 'mungbean', 'pigeonpea', 'potato', 'rapeseed', 'rice', 'sorghum', 'soybean', 'sugarbeet', 'sugarcane', 'sunflower', 'sweetpotato', 'tobacco', 'wheat', 'seed_onion']
When we call load_crop_file on the database object with the name of a specific crop type, we will get a WOFOSTCropFile object. We can then inspect that object to see the file's metadata, parameters in individual sections, available ecotypes and varieties.
cropfile = cropdb.load_crop_file("rice")
cropfile.metadata
{'Creator': 'Allard de Wit',
'Contributor': None,
'Contact': 'allard.dewit@wur.nl',
'Publisher': 'Wageningen Environmental Research',
'Title': 'Parameter sets for the WOFOST7.2/WOFOST8.0 model for simulating rice',
'Date': datetime.date(2022, 2, 13),
'Language': 'EN',
'Format': 'YAML',
'Subject': 'WOFOST parameters for rice',
'Description': 'This file provides parameters for several rice varieties. Mostly calibrated based on observations done at the International Rice Research Institute, but also based on observations from Europe and earlier work.',
'Identifier': None,
'Relation': None,
'Source': None,
'Type': None,
'Coverage': {'Region': 'Selected locations in Europe (France, Spain, Greece, Italy, Portugal), tropical regions'},
'Rights': 'European Union Public License (EUPL)',
'Keyword': 'rice; Oryza sativa'}
print(cropfile.ecotypes)
print(cropfile.varieties)
['rice_eu', 'rice_irri'] ['Rice_501', 'Rice_HYV_IR8', 'Rice_IR64616H_DS', 'Rice_IR64616H_WS', 'Rice_IR64', 'Rice_IR72', 'Rice_IR72_DS', 'Rice_IR72_WS', 'Rice_IR8A']
rice_501 = cropfile.get_variety("Rice_501")
The new object is CropVariety object. From here you can view the metadata of the particular variety or obtain just the parameters as a dictionary. Mind that at this stage, all tables are just arrays of numbers, the same way as it is formatted in the .yaml files. pySWAP automatically converts them in tables when they are used to populate the parameters of crop settings classes.
Using the CropVariety object to populate the crop settings class¶
The point of having this database integration is to enable populating some of the wofost crop parameters used by swap directly from the files. A lot of the parameters we still have to set manually, namely Preparation, ScheduledIrrigation, Interception, OxygenStress, DroughtStress, etc.
potato_prep = psp.components.crop.Preparation(
swprep=0,
swsow=0,
swgerm=2,
tsumemeopt=170.0,
tbasem=3.0,
teffmx=18.0,
hdrygerm=-500.0,
hwetgerm=-100.0,
zgerm=-10.0,
agerm=203.0,
dvsend=2.0,
swharv=0,
)
scheduled_irrigation = psp.components.irrigation.ScheduledIrrigation(schedule=0)
interception = psp.components.crop.Interception(swinter=1, cofab=0.25)
potato_ox_stress = psp.components.crop.OxygenStress(
swoxygen=1,
swwrtnonox=1,
aeratecrit=0.5,
hlim1=-10.0,
hlim2u=-25.0,
hlim2l=-25.0,
swrootradius=2,
root_radiuso2=0.00015,
)
potato_dr_stress = psp.components.crop.DroughtStress(
swdrought=1,
hlim3h=-300.0,
hlim3l=-500.0,
hlim4=-10000.0,
adcrh=0.5,
adcrl=0.1,
)
Then, we can load the potato_701 variety from the WOFOST database and create the CropDevelopmentSettings object like so:
db = psp.db.WOFOSTCropDB()
potato = db.load_crop_file("potato")
potato_params = potato.get_variety("Potato_701")
potato_cropdev_settings = psp.components.crop.CropDevelopmentSettingsWOFOST(
wofost_variety=potato_params,
swcf=2,
albedo=0.19,
laiem=0.0589,
ssa=0.0,
kdif=1.0,
rsc=207.0,
rsw=0.0,
kdir=0.75,
eff=0.45,
swrd=2,
rdc=50.0,
swdmi2rd=1,
)
# By calling the `update_from_wofost method`, the CropDevelopmentSettingsWOFOST object
# will be updated with the values from the WOFOST crop file and the model will be evaluated,
# to make sure that some of the required settings are not missing.
potato_cropdev_settings.update_from_wofost()
17:36:44 - WARNING - No matching array schema found for: ssatb
17:36:44 - WARNING - Failed to process parameter from WOFOST: ssatb, removing from update
17:36:44 - WARNING - No matching array schema found for: kdiftb
17:36:44 - WARNING - Failed to process parameter from WOFOST: kdiftb, removing from update
17:36:44 - WARNING - No matching array schema found for: efftb
17:36:44 - WARNING - Failed to process parameter from WOFOST: efftb, removing from update
17:36:44 - WARNING - No matching array schema found for: nmaxlv_tb
17:36:44 - WARNING - Failed to process parameter from WOFOST: nmaxlv_tb, removing from update
17:36:44 - WARNING - No matching array schema found for: pmaxlv_tb
17:36:44 - WARNING - Failed to process parameter from WOFOST: pmaxlv_tb, removing from update
17:36:44 - WARNING - No matching array schema found for: kmaxlv_tb
17:36:44 - WARNING - Failed to process parameter from WOFOST: kmaxlv_tb, removing from update
Additional tables defined in a yaml file (new since v0.2.9)¶
To complement the additional tables that are not normally found in the wofost database from another file, we can use update_from_yaml method passing the yaml path. The filr has to be in the following format:
Version: 1.0.0
Metadata: &meta
Creator:
Contributor:
# Any additional metadata fields you want
PredefinedArrays:
# DVS: &dws [0.0, 0.3, 0.5, 0.7, 1.0, 1.4, 2.0] <-- some arrays you want to reuse
CropParameters: # CropParameters and SWAPInput sections are essential.
SWAPInput:
# in contrast to the WOFOST database, here the columns are defined as a dictionary of lists. JSON resulting from this yaml structure looks like this: {CHTB: {DVS: [values...], CH: [values]}}
CHTB:
DVS: [0.0, 1.0, 2.0]
CH: [1.0, 40.0, 50.0]
RDCTB:
RRD: [0.0, 1.0]
RDENS: [1.0, 0.0]
from pyswap.testcase import get_path
# getting test dataset
potato_tables = get_path("hupselbrook", "potato_tables_yaml")
Further we proceed with creation of the CropFile object, which goes directly to the Model. You can observe the content of the crop file by calling CropFile.crp property.
potato_cropdev_settings.update_from_yaml(potato_tables)
Varify that the chtb and rdctb are added despite we did not define them in the code.
print(potato_cropdev_settings.chtb)
print(potato_cropdev_settings.rdctb)
DVS CH 0 0.0 1.0 1 1.0 40.0 2 2.0 50.0 RRD RDENS 0 0.0 1.0 1 1.0 0.0
crppotato = psp.components.crop.CropFile(
name="potatod",
prep=potato_prep,
cropdev_settings=potato_cropdev_settings,
oxygenstress=potato_ox_stress,
droughtstress=potato_dr_stress,
interception=interception,
scheduledirrigation=scheduled_irrigation,
)
print(crppotato.crp)
SWPREP = 0 SWSOW = 0 SWGERM = 2 SWHARV = 0 DVSEND = 2.0 TSUMEMEOPT = 170.0 TBASEM = 3.0 TEFFMX = 18.0 HDRYGERM = -500.0 HWETGERM = -100.0 ZGERM = -10.0 AGERM = 203.0 SWCF = 2 DVS CH 0.0 1.0 1.0 40.0 2.0 50.0 ALBEDO = 0.19 RSC = 207.00 RSW = 0.00 TSUMEA = 150.00 TSUMAM = 1550.00 TBASE = 2.00 KDIF = 1.00 KDIR = 0.75 SWRD = 2 RDI = 10.00 RRI = 1.20 RDC = 50.00 SWDMI2RD = 1 RDCTB = 0.0 1.0 1.0 0.0 IDSL = 0 DTSMTB = 0.0 0.0 2.0 0.0 13.0 11.0 30.0 28.0 VERNSAT = 70.0 VERNBASE = 14.0 VERNDVS = 0.3 VERNTB = -8.0 0.0 -4.0 0.0 3.0 1.0 10.0 1.0 17.0 0.0 20.0 0.0 TDWI = 75.0 LAIEM = 0.0589 RGRLAI = 0.012 SPA = 0.0 SSA = 0.0 SPAN = 37.0 SLATB = 0.0 0.0030 1.1 0.0030 2.0 0.0015 EFF = 0.45 AMAXTB = 0.00 30.0 1.57 30.0 2.00 0.0 TMPFTB = 0.0 0.01 3.0 0.01 10.0 0.75 15.0 1.00 20.0 1.00 26.0 0.75 33.0 0.01 TMNFTB = 0.0 0.0 3.0 1.0 CVO = 0.85 CVL = 0.72 CVR = 0.72 CVS = 0.69 Q10 = 2.0 RML = 0.03 RMO = 0.0045 RMR = 0.01 RMS = 0.015 RFSETB = 0.0 1.0 2.0 1.0 FRTB = 0.00 0.2 1.00 0.2 1.36 0.0 2.00 0.0 FLTB = 0.00 0.8 1.00 0.8 1.27 0.0 1.36 0.0 2.00 0.0 FSTB = 0.00 0.20 1.00 0.20 1.27 0.25 1.36 0.00 2.00 0.00 FOTB = 0.00 0.00 1.00 0.00 1.27 0.75 1.36 1.00 2.00 1.00 PERDL = 0.03 RDRRTB = 0.00 0.00 1.50 0.00 1.51 0.02 2.00 0.02 RDRSTB = 0.00 0.00 1.50 0.00 1.51 0.02 2.00 0.02 SWOXYGEN = 1 SWWRTNONOX = 1 AERATECRIT = 0.5 HLIM1 = -10.0 HLIM2U = -25.0 HLIM2L = -25.0 SWROOTRADIUS = 2 ROOT_RADIUSO2 = 0.00015 SWDROUGHT = 1 HLIM3H = -300.0 HLIM3L = -500.0 HLIM4 = -10000.0 ADCRH = 0.5 ADCRL = 0.1 SWSALINITY = 0 SWCOMPENSATE = 0 SWINTER = 1 COFAB = 0.25 SCHEDULE = 0
Changing the values (for example during model calibration)¶
The WOFOST database integration allows you draw calibrated settings from the database into pySWAP. If you wish to change some of the settings, you should do it by updating the base pySWAP classes (e.g., CropDevalopmentSettings), like so:
potato_cropdev_settings_tsum1_up = potato_cropdev_settings.update({"tsum1": 900})
crppotato_tsum1_up = crppotato.update(
{"cropdev_settings": potato_cropdev_settings_tsum1_up}
)
print(crppotato_tsum1_up.cropdev_settings.tsum1)
900.0