import {withDownload, fmt} from "../assets/js/dl.js"
final = FileAttachment("data/module2/final.csv").csv({typed: true})
gsim = FileAttachment("data/module2/growth_sim.csv").csv({typed: true})
gobs = FileAttachment("data/module2/growth_obs.csv").csv({typed: true})
stats = FileAttachment("data/module2/stats.csv").csv({typed: true})
carbon = FileAttachment("data/module2/carbon.csv").csv({typed: true})
cTot = FileAttachment("data/module2/carbon_totals.csv").csv({typed: true})
light = FileAttachment("data/module2/light.csv").csv({typed: true})
lightFit = FileAttachment("data/module2/light_fit.csv").csv({typed: true})
stress = FileAttachment("data/module2/stress.csv").csv({typed: true})
photo = FileAttachment("data/module2/photo_method.csv").csv({typed: true})
wSeason = FileAttachment("data/module2/weather_season.csv").csv({typed: true})
wMonthly = FileAttachment("data/module2/weather_monthly.csv").csv({typed: true})
wChecks = FileAttachment("data/module2/weather_checks.csv").csv({typed: true})
wTavAmp = FileAttachment("data/module2/weather_tavamp.csv").csv({typed: true})
wRound = FileAttachment("data/module2/weather_roundtrip.csv").csv({typed: true})
wSens = FileAttachment("data/module2/weather_sens.csv").csv({typed: true})
files = FileAttachment("data/module2/files.csv").csv({typed: true})
exps = FileAttachment("data/module2/experiments_per_crop.csv").csv({typed: true})
naming = FileAttachment("data/module2/naming.csv").csv()
// cultivar codes such as 990007 must stay text
cultivars = (await FileAttachment("data/module2/cultivars.csv").csv({typed: true})).map(d => ({...d, var: String(d.var)}))
mgPd = (await FileAttachment("data/module2/mg_pdate.csv").csv({typed: true})).map(d => ({...d, var: String(d.var)}))
daylength = FileAttachment("data/module2/daylength.csv").csv({typed: true})
sensCoef = FileAttachment("data/module2/sens_coef.csv").csv({typed: true})
sensCoefG = FileAttachment("data/module2/sens_coef_growth.csv").csv({typed: true})
mg7 = FileAttachment("data/module2/mg7_base.csv").csv({typed: true})
mgEx = (await FileAttachment("data/module2/mg_exercise.csv").csv({typed: true})).map(d => ({...d, var: String(d.var)}))
mgExG = (await FileAttachment("data/module2/mg_exercise_growth.csv").csv({typed: true})).map(d => ({...d, var: String(d.var)}))
grRaw = FileAttachment("data/module2/grgr_raw.csv").csv({typed: true})
grDaily = FileAttachment("data/module2/grgr_daily.csv").csv({typed: true})
grMonthly = FileAttachment("data/module2/grgr_monthly.csv").csv({typed: true})
grChecks = FileAttachment("data/module2/grgr_checks.csv").csv({typed: true})
grFiles = FileAttachment("data/module2/grgr_files.csv").csv({typed: true})
grStation = FileAttachment("data/module2/grgr_station.csv").csv({typed: true})
grMaize = FileAttachment("data/module2/grgr_maize.csv").csv({typed: true})
co2r = FileAttachment("data/module2/co2_response.csv").csv({typed: true})
coefModels = FileAttachment("data/module2/coefficients_by_model.csv").csv({typed: true})
runInfo = FileAttachment("data/module2/run_info.csv").csv()
dlLinks = html`<a href="${"../notebooks/module2" + ".ipynb"}" download>download .ipynb</a>, helper <a href="../notebooks/learnlib.py" download>learnlib.py</a>`
W = Math.min(width, 860)
trtName = new Map([[1, "irrigated"], [2, "rainfed"]])
bragg = cultivars.find(d => d.var === "IB0001")Module 2: growth processes, weather data, the DSSAT file system and cultivar coefficients
DSSAT training, module 2 of 6. Follows day 2 of the course, with code instead of the DSSAT shell
How to use this module. Read this page for the ideas; every chart comes from the module 2 notebook (), which runs the DSSAT engine and writes the small data files the charts read. The runs on this build were made on with model .
What you will learn
- How a crop model grows a crop each day: photosynthesis, respiration, and how the new mass is shared between leaves, stems, roots, pods and seeds.
- What a DSSAT weather file holds, how to check it, how to convert data from other units, and how much the simulated crop depends on each weather variable.
- Which files make up the minimum data set of a run and how DSSAT names them.
- The difference between species, ecotype and cultivar coefficients, and how day length and cultivar coefficients set when a soybean flowers and matures.
The example is a soybean experiment from Gainesville, Florida, in 1979 (UFGA7901, cultivar Bragg), shipped with DSSAT (DSSAT Foundation 2026). It has two treatments, irrigated and rainfed, both planted on 19 June. Soybean is simulated by CROPGRO, the grain legume model of DSSAT-CSM (Jones et al. 2003).
1. Growth processes
The run, checked against the field
Simulated seed yield is kg/ha irrigated and rainfed, against and measured. In both the field and the model the two treatments yield almost the same: in this season the irrigation added little.
The daily carbon balance
Each day CROPGRO computes gross photosynthesis, subtracts maintenance respiration (the cost of keeping existing tissue alive, part proportional to the plant’s mass and part to the day’s photosynthesis, RESPIR.for:54), and converts what is left into new tissue, losing growth respiration in the conversion. What is added to the crop that day is the crop growth rate:
\[ \frac{dW}{dt} = E\,(P_g - R_m), \qquad R_m = r_o\,W + r_p\,P_g \]
with \(W\) the crop’s dry weight, \(P_g\) gross photosynthesis, \(R_m\) maintenance respiration, \(E\) the conversion efficiency of carbohydrate into tissue (one minus the growth respiration share), and \(r_o\), \(r_p\) temperature-dependent coefficients (RO, RP in RESPIR.for).
Over the season the crop fixed g CH2O/m² and respired of it (maintenance , growth g/m²), while the daily crop growth adds up to g/m². Respiration is not a small correction: the crop respires almost as much as it grows.
The way gross photosynthesis is computed is a simulation option. This experiment uses PHOTO = L, an hourly leaf-level calculation done in the soil-plant-atmosphere module; with C CROPGRO uses a daily canopy equation instead (CROPGRO.for:748-758), which multiplies a light-limited rate by 0-1 factors for soil fertility (SLPF), temperature, leaf N, water and CO2 (PHOTO.for:225):
\[ \begin{aligned} P_g = {} & P_{max} \cdot SLPF \cdot f_{light} \cdot f_{T} \cdot f_{age,N} \\ & \cdot f_{SLW} \cdot f_{CO_2} \cdot f_{LFMAX} \cdot \min(SWFAC,\, f_{O_3}) \end{aligned} \]
(in the code PTSMAX, SLPF, PGFAC, TPGFAC, E_FAC, PGSLW, PRATIO, PGLFMX and the minimum of the water and ozone factors).
Where the new mass goes
Until flowering the new mass goes into leaves, stems (and roots, not shown). After the first pods set, a growing share goes to pods, and late in the season leaves fall and their mass is lost from the tops. The black dots are the field samples of total tops weight.
Compare any organ with the field samples:
Light interception
Photosynthesis starts with the light the canopy intercepts. With little leaf area most light reaches the ground; as leaf area grows, the canopy catches more and more of it, with diminishing returns. The usual summary is Beer’s law,
\[ LI = 1 - e^{-k \cdot LAI}, \]
with an extinction coefficient \(k\). The notebook fits k to the engine’s daily light interception (LI%D) and LAI by least squares: k = from days. Move the slider to see how k shapes the curve.
The engine does not use one fixed k: the hourly leaf method accounts for the sun’s angle and for direct and diffuse light, which is why the dots scatter around the fitted curve.
Water stress
PlantGro reports two water stress indices: on photosynthesis (WSPD) and on expansion, partitioning and development (WSGD). CROPGRO writes them as 1 minus the stress factor (Opgrow.for:277-278): 0 means no stress. In the rainfed run the expansion index peaks at , the photosynthesis index at : leaf expansion is the more sensitive process.
Rain bars show the weather file’s daily rain only (scaled by 1/40). Irrigation of the irrigated treatment is not drawn; it received mm in total.
The effect of CO2 on growth
Photosynthesis responds to the CO2 concentration of the air, and C3 crops (soybean) more than C4 crops (maize), whose photosynthesis already concentrates CO2 inside the leaf. The notebook runs the irrigated soybean of UFGA7901 and the irrigated, high-N maize of UFGA8201 at six fixed concentrations, set with the environmental modification column ECO2:
From 380 to 700 ppm the soybean yield rises by , the maize yield by .
2. Weather data
A DSSAT weather file has a station line (code, latitude, longitude, elevation, TAV the mean annual temperature and AMP the amplitude of the monthly mean temperatures) and one line per day with at least solar radiation (MJ/m²/day), maximum and minimum temperature (°C) and rain (mm). The DSSAT shell’s WeatherMan tool imports, checks and converts such data. In the notebook, pandas and xdssat’s src/wth.py do the same.
Checks before use
Bad weather data give wrong answers without an error message, so they are checked first. The notebook’s checks on the 1979 file:
TAV recomputed from the year’s own data agrees with the file; AMP does not. Both header values are the ones in the station’s long-term climate file, Weather/Climate/UFGA.CLI of dssat-csm-data (TAV 20.9, AMP 13.0, “calculated from daily data” for 49 years from 1958): the header carries the long-term climate, not the year’s own values. The engine reads both and uses them for the soil temperature; it only substitutes defaults (20 and 5 °C) when they are missing (weathr.for:215-224). Checks like the day-to-day change in Tmax list days to look at, not values to delete: a large jump can be real weather.
The WeatherMan exercise: weather from Griffin, Georgia
The course’s weather exercise hands out the daily records of an experiment station at Griffin, Georgia, as a spreadsheet, GRGR-Raw.xls. It has no header, and its units are not DSSAT’s: date as YYDDD, rain in inches, maximum and minimum temperature in °F, solar radiation in cal/cm² per day. The first rows:
In the DSSAT shell, WeatherMan reads the spreadsheet, is told what each column holds and in which unit, converts, checks and writes one weather file per year. The notebook does the same with pandas and wth.write_wth, with the station position the exercise gives (33°16’ N, 84°17’ W, 299 m). Try the conversions:
°C; mm; MJ/m²/day (°C = (°F - 32) × 5/9; 1 inch = 25.4 mm; 1 cal/cm² = 0.04184 MJ/m²).
The header of every file carries the station’s TAV = °C and AMP = °C, computed here from the whole 1992-1999 record.
Self test 1 of the exercise runs the first treatment of the maize experiment UFGA8201 with the new weather. The Griffin record covers 1992-1999, not 1982, so the notebook plants on 26 February of each year from 1992 to 1998 (the experiment’s other dates move with planting), next to Gainesville 1982:
At Griffin the crop takes to days to mature, against at Gainesville: Griffin is cooler over the season (mean Tmax °C against ). Yield swings from to kg/ha between years; hover the bars for the season’s rain.
Converting back and forth: an optional column matters
The notebook also converts the 1979 Gainesville file to those units and back, writes a new DSSAT weather file with wth.write_wth, and reruns the soybean experiment:
Rain differs by up to mm because the inches were rounded to two decimals. The more instructive result is the last pair of rows. The original file also has a PAR column (photosynthetically active radiation). When the conversion drops it, the engine estimates PAR from solar radiation instead, and irrigated seed yield changes from to kg/ha. An optional column can matter as much as a units error.
When there are no daily records: weather generators
A weather generator draws daily maximum and minimum temperature, solar radiation and rain that are statistically like a site’s climate. DSSAT has two: WGEN, which needs at least 5 years of daily data, and SIMMETEO, which works from monthly means (the course’s weather lecture). Their parameters sit in a climate file, one per site, named IIss.CLI (here UFGA.CLI). The WTHER option of the simulation controls chooses: M and G read the weather from a file, and S and W let the engine generate it itself from SIMMETEO or WGEN inputs (Weather/weathr.for:575-577). Generated weather fills gaps and lets one run many seasons where few were measured; it is how the seasonal analysis of module 5 and the rotations of module 6 get decades of weather. It is not a forecast: each generated season is one draw of the climate, not of a particular year.
What if the weather were different?
Each scenario edits the weather file and reruns both treatments.
For the crop, 20% less radiation costs of seed yield, and 4 °C warmer weather costs . Halving the rain costs the rainfed crop , the irrigated crop : its irrigation was a fixed schedule, not refilled as needed.
3. The minimum data set and the file system
A DSSAT run needs a minimum data set: the site and its soil, daily weather, the crop management, and the crop’s coefficients (Hunt and Boote 1998). The same reference sets out levels of data beyond that minimum: what is enough to run the model is not enough to calibrate it, and calibrating needs less than a full evaluation, which also needs measurements during the season.
The course’s lecture on the minimum data set put these as three levels, each adding to the one before:
| Level | Needed for | Data |
|---|---|---|
| 1 | Running the model | Daily weather (maximum and minimum temperature, rain, solar radiation); soil surface and profile (water limits, nitrogen, organic matter); management (crop, cultivar, planting date, spacing, irrigation, fertilizer, other operations) |
| 2 | Calibrating and evaluating it | Level 1, plus crop measurements (yield and its components, flowering and maturity dates, growth samples during the season) and soil measurements (water, nitrogen and carbon by depth over time) |
| 3 | Developing it | Levels 1 and 2, plus detailed experiments on the response to temperature, water, nitrogen and other factors |
Level 1 is what DSSAT, following IBSNAT, calls the minimum data set. Modules 1 and 2 run on it; module 3 (calibration) and module 4 (measurement files) need level 2.
Each part of the data lives in its own text file. The base run used these:
Experiment files are named IIssYYnn.ccX:
with A and T instead of X for the observed data; the weather file uses the same first eight characters and .WTH. DSSAT ships such experiment files in folders; the folders with most are:
4. Species, ecotype and cultivar coefficients
CROPGRO reads its crop parameters at three levels. The species file (SBGRO048.SPE) holds what all soybeans share, such as cardinal temperatures and the photosynthesis and respiration parameters. The ecotype file (SBGRO048.ECO) groups cultivars, here by maturity group. The cultivar file (SBGRO048.CUL) holds the coefficients that users estimate for each variety.
Day length and flowering
Soybean is a short-day plant: development toward flowering slows when days are longer than a critical day length CSDL. PPSEN is how fast it slows per hour beyond that. The engine computes the relative rate with an “inverse linear” curve (UTILS.for:378-383, called in PHENOL.for:243): rate 1 up to CSDL, then falling in a straight line to the ecotype’s minimum THVAR:
\[ \begin{gathered} f(DL) = \begin{cases} 1 & DL \le CSDL \\ 1 - (1 - THVAR)\,\dfrac{DL - CSDL}{CLDL - CSDL} & \text{in between} \\ THVAR & DL \ge CLDL \end{cases} \\[6pt] CLDL = CSDL + \frac{1 - THVAR}{PPSEN} \end{gathered} \]
with \(DL\) the day length in hours (Ipphenol.for:239-240). THVAR is for every soybean ecotype in the file, so development stops entirely at that day length.
The shaded band is the range of day length at Gainesville from April to November 1979 (from the engine’s weather output). Dashed: the cultivar you started from. In the generic maturity groups of the cultivar file, CSDL falls from h (group 000) to h (group 10). A cultivar whose CSDL is above the longest Gainesville day is not slowed at all; Bragg, with h, is slowed for much of the summer.
Coefficients across the crop models
Every crop model has its own cultivar coefficients. CERES models describe a cultivar mainly by thermal time to stages and by grain number and size; CROPGRO models by photothermal days between reproductive stages and by leaf, pod and seed traits. The definitions below are read from the comment block of each model’s cultivar file in the engine:
CERES-Rice’s TCLDF, the temperature below which cold makes spikelets sterile, is the coefficient the rice case study raises for the cool highlands of Java.
The course exercise: maturity groups 3, 5 and 7
The irrigated treatment of UFGA7901 with the generic maturity group 3, 5 and 7 cultivars, everything else as in the experiment. The self test asks for the days to flowering and to maturity, the time between them and the seed yield:
Maturity group 7 flowers days later than group 3 and takes days from flower to maturity instead of . With the longer season its seed yield is kg/ha against . The day-length response below shows why the later groups wait longer in Florida’s June days.
Maturity group and planting date
Generic maturity groups 3, 5 and 7, and Bragg, each planted every three weeks from 10 April, under potential production (water and N switched off), all in one FileX:
Maturity group 7 flowers days after a May planting but only days after the August one. The day length at planting is h in late May and h in mid August, and falling: a late crop spends the weeks before flowering in ever shorter days, which slow it less. Its season is also shorter (maturity after days against for the April planting), and for every maturity group the yield falls with each planting after early May.
One coefficient at a time: the course’s values
Exercise 3 of the course changes one coefficient of the maturity group 7 cultivar (990007) at a time, to the values the course gives, in the irrigated treatment. Every value is a separate cultivar in a copy of the cultivar file (learnlib.write_cultivar_variants), so the whole sweep is one FileX and one engine call. Exercise 4 adds a new cultivar, DS0001: maturity group 7 with PODUR = 7.
Across the course’s values (including the standard MG 7), each coefficient moves these outputs by:
EM-FL, CSDL and PPSEN move the dates, which is why calibration (module 3) sets them first, from observed flowering and maturity. SFDUR leaves the dates alone and changes how long each pod cohort fills, so seed yield follows it. WTPSD is the exercise’s puzzle: from to g the seeds grow from to mg, but the seed number falls from to per m² and the yield hardly changes. The new cultivar DS0001 gives kg/ha with seeds per m², the same as the PODUR = 7 run ( kg/ha): the exercise’s self test, that a cultivar entry with a changed coefficient behaves like the sensitivity run with that coefficient.
From one field to a grid: xdssat
Module 2 wrote weather files for one station. For a region, xdssat writes one weather file per 0.1° cell, from the gridded AgERA5 data set, derived from the ERA5 reanalysis (Copernicus Climate Change Service 2019), and the same checks and conversions apply to every cell. The season weather of irrigated wet-season rice in the rice case study, averaged over 1991-2020:
Across cells this variable ranges from to . Hover a cell for its value.
Self-test
- Respiration took about 40% of gross photosynthesis. Would you expect that share to be higher or lower in a hotter climate, and why?
- Why do the irrigated and rainfed treatments of UFGA7901 yield almost the same?
- Your weather data lack PAR. Is that an error? What does the engine do, and how large was the effect here?
- Bragg (CSDL 12.33 h) is grown in Java, at about 7° S, where day length changes little over the year. Use the day-length chart to predict its time to flowering compared with Gainesville in June, then test it in the notebook.
- Which observation would you use to estimate
WTPSD, and why not seed yield?
Where this goes next
Module 3 estimates cultivar coefficients from observations with GLUE, builds soil profiles, and turns the water balance on. The plan for all six modules is on the training overview.
References
Copernicus Climate Change Service. 2019. Agrometeorological Indicators from 1979 up to 2019 Derived from Reanalysis (AgERA5). ECMWF. https://doi.org/10.24381/cds.6c68c9bb.
DSSAT Foundation. 2026. DSSAT-CSM Example Data (Dssat-Csm-Data), Commit 99c95b3. https://github.com/DSSAT/dssat-csm-data.
Hunt, L. A., and K. J. Boote. 1998. “Data for Model Operation, Calibration, and Evaluation.” In Understanding Options for Agricultural Production. Springer Netherlands. https://doi.org/10.1007/978-94-017-3624-4_2.
Jones, J. W., G. Hoogenboom, C. H. Porter, et al. 2003. “The DSSAT Cropping System Model.” European Journal of Agronomy 18 (3–4): 235–65. https://doi.org/10.1016/S1161-0301(02)00107-7.