Repository for ecohydrological modeling analysis of maize yield variability and tradeoffs between yield and crop failure. See article by Krell et al. (2021) "Consequences of dryland maize planting decisions under increased seasonal rainfall variability" in Water Resources Research.
Create fork of maize-Toff and git clone to local machine.
cd maize-Toffconda env create -f environment.yml -n maize-Toffconda activate maize-Toffjupyter notebook
Note: To update dependecies in an existing environment, use conda env update --file environment.yml after step four.
- where models are stored
- contains CETRAD rainfall data, maize variety info
- exported figures, results
- contains notebook that generates figures from the manuscript
The soil object contains all the necessary parameters to specify soil hydraulic properties and texture. The easiest
way to generate a soil instance is to use one of the standard USDA soil texture types: Sand, Loamy Sand, Sandy Loam, Silt Loam, Loam, Sandy Clay Loam,
Clay Loam, Sandy Clay, Silty Clay, Clay, and Sandy Silty Loamy Clay. Just kidding. That last one is totally not a soil type.
# Creates a sand soil object:
soil = Soil('sand') You can also specify your own parameters:
param_dict = {
'b': 11.4,
'Psi_S_cm': 40.5, # saturated water tension, cm
'Psi_l_cm': 24.3, # leakage water tension, cm
'n': 0.482, # porosity, cm^3/cm^3 (is Psi_S) in C&H,
'Ks': 0.0077, # saturated hydraulic conductivity, cm/min
'S': 0.268 # sorptivity, cm/min^1/2
}
custom_soil = Soil(params=param_dict)Of the parameters, only b, Psi_S_cm, Psi_l_cm, n, and Ks are required. The model doesn't use S right now.
The climate object has information on maximum evapotranspiration, as well as a time series of rainfall.
The rainfall timeseries is generated stochastically using
the parameters of storm depth, frequency, and the length of the season. The storm depth (alpha_r) specifies the average daily storm depth, assuming that daily storm depths are drawn from an exponential distribution. The frequency (lambda_r) is best described as the daily probability of rainfall. The length of the season ends up setting the timescale of the simulation in days.
There are several keyword arguments available:
alpha_rAverage storm depth [mm]lambda_rFrequency of storms [day^-1]t_seasLength of rainy season [days]ET_maxMaximum evapotranspiration [mm/day]
Keyword arguments can be specified when instantiating the object, or the following are the resonable defaults values:
climate = Climate(
alpha_r=10.0,
lambda_r=0.3,
t_seas=180,
ET_max=6.5)The plant object requires the most parameters to generate, and some of these parameters depend on the soil in which the plant is growing. In addition, the plant object can be subclassed into specific plant types to allow for varying structures and function. In this simulation, we are using the Crop subclass, which is initialized with the minimum following parameters:
kc_maxThe maximum crop coefficient [dimensionless], which is a scale factor applied toET_maxto determine the maximum rate of plant transpiration,T_max.LAI_maxThe maximum crop leaf area [m^2/m^2].T_maxThe maximum rate of crop water use in [mm/day]soilA soil object that specifies the soil that this crop is growing in.
crop = Crop(kc_max=1.2, LAI_max=2.0, T_max=4.0, soil=soil)Additional parameters that should be specified are:
ZrPlant rooting depth [mm]. Default is 500mm.sw_MPaPlant wilting point [MPa]. Default is -1.5MPas_star_MPaWater potential of maximum water use [MPa]. Default is -0.2 MPa.
If these parameters are not provided, default values are inherited from the Plant class.
Combining the prior three steps, we can create a model instance and run the model:
# Import the necessary objects:
from farm.climate import Climate
from farm.soil import Soil
from farm.plant import Crop
from farm.model import CropModel
# Make the things
climate = Climate() # uses default climate values
soil = Soil('sand')
crop = Crop(kc_max=1.2, LAI_max=2.0, T_max=4.0, soil=soil)
# Create the model
model = CropModel(crop=crop,soil=soil,climate=climate)
# RUN IT.
model.run() # TADA!
model.output()The model.output() function returns all the simulation output structured as a single pandas DataFrame. The frame has the following columns:
kcTime series of daily crop coefficients.LAITime series of crop LAIRTime series of daily rainfall [mm]sTime series of daily relative soil moisture [0-1]ITime series of daily interception [mm]ETime series of daily soil evaporation [mm]TTime series of daily plant transpiration [mm]LTime series of soil leakage loss [mm]QTime series of surface runoff [mm]dsdtTime series of changing relative soil moisture
To plot any of this data, simply use the .plot() command:
output = model.output()
# Plots a time series of simulated evapotranspiration:
output['ET'].plot()
# Plots a time series of simulated relative soil moisture
output['s'].plot()From the root of the directory, run the following in the command line to put farm into your python path in editable mode.
pip install -e .
After that, run tests from the subdirectory farm/tests, for example:
nosetests -vv test_sand
Update the coverage for the model before pushing new commits, or in advance of a pull request. You can update the coverage using the following command:
nosetests -vv ./farm/tests --with-coverage --cover-package=farm --cover-html --cover-html-dir=coverage_html_report/