Crop Production¶
Overview¶
The crop production module translates GAEZ yield potentials and land availability into production constraints for the optimization model. Each crop can be grown in multiple regions, on different resource classes, and potentially with either rainfed or irrigated water supply.
Crop Coverage¶
The default configuration includes over 60 crops spanning major food categories:
- Cereals
Wheat, dryland rice, wetland rice, maize
Barley, oat, rye, sorghum
Buckwheat, foxtail millet, pearl millet
- Legumes and Pulses
Soybean, dry pea, chickpea
Cowpea, gram, phaseolus bean, pigeonpea
- Roots and Tubers
White potato, sweet potato, cassava, yam
- Vegetables
Tomato, carrot, onion, cabbage
- Fruits
Banana, watermelon, mango, citrus, coconut
- Oil Crops
Sunflower, rapeseed, groundnut
Sesame, oil palm, olive
- Sugar Crops
Sugarcane, sugarbeet
- Fiber Crops
Cotton (ginned to produce cotton lint, cottonseed oil, and oilseed meal)
- Fodder Crops
Alfalfa, biomass sorghum
The complete crop list is configured in config/default.yaml under the crops key.
Note
Managed grassland is also modelled, but yields derived from the LPJmL mode; see Grassland Yields
GAEZ Yield Data¶
Yield potentials come from the FAO/IIASA Global Agro-Ecological Zones (GAEZ) v5 dataset, which provides spatially-explicit crop suitability and attainable yields under various scenarios. The GAEZ documentation can be found here. Module II gives more details on biomass and yield calculations (including links to appendices with detailed calculations and parameter choices); subsequent modules apply climatic and technical constraints to arrive at potential yields in Module V.
All RES05 yield rasters used here are provided on a 0.083333° (~5 arc-minute, ≈9 km at the equator) latitude–longitude grid, which sets the native spatial resolution before aggregation to optimization regions.
GAEZ Configuration¶
Key GAEZ parameters in config/default.yaml:
data:
gaez:
# GAEZ v5 parameters
# Note: RES05 (yields/suitability) has ENSEMBLE, but RES02 (growing season) only has individual GCMs
climate_model: "GFDL-ESM4" # Specific GCMs: "GFDL-ESM4", "IPSL-CM6A-LR", "MPI-ESM1-2-HR", "MRI-ESM2-0", "UKESM1-0-LL"
period: "FP2140" # Future: "FP2140" (2021-2040), "FP4160" (2041-2060), "FP6180" (2061-2080), "FP8100" (2081-2100); Historical: "HP0120" (2001-2020), "HP8100" (1981-2000)
climate_scenario: "SSP126" # "SSP126" (low emissions), "SSP370" (medium, ~RCP4.5), "SSP585" (high), "HIST" (historical)
input_level: "H" # "H" (High), "L" (Low)
# Variable codes for GAEZ v5
yield_var: "RES05-YCX" # Average attainable yield, current cropland
water_requirement_var: "RES05-WDC" # Water deficit/net irrigation requirement during crop cycle, current cropland
suitability_var: "RES05-SX1" # Share of grid cell assessed as VS or S (very suitable or suitable)
usda:
# When false, the build uses the bundled data/curated/nutrition.csv. When
# true, nutrition data is fetched from USDA FoodData Central (relevant after
# adding a food) and a USDA API key is required, via USDA_API_KEY or
# config/secrets.yaml (see config/secrets.yaml.example).
retrieve_nutrition: false
# Nutrient mapping: internal name -> USDA FoodData Central name
# USDA names must match nutrient names in FoodData Central exactly
nutrients:
protein: "Protein"
carb: "Carbohydrate, by difference"
fat: "Total lipid (fat)"
cal: "Energy"
mirror:
# GLADE input-data mirror on Zenodo (CC-BY-4.0): one record holding the
# land-cover extract and the FAOSTAT bulk zips, so builds fetch pinned
# data vintages with no API keys. Refresh with tools/mirror_land_cover.py
# / tools/mirror_faostat.py and point this at the new record id (see
# docs/data_sources.rst). A new FAOSTAT vintage requires recalibration.
zenodo_record: "21694233" # https://doi.org/10.5281/zenodo.21694233
land_cover:
# Copernicus ESA CCI land cover version mirrored for `baseline_year`.
version: "v2_1_1"
faostat:
qcl_production_element_code: 5510 # "Production" in tonnes (QCL dataset, covers crops and livestock)
fbs_food_supply_element_code: 645 # "Food supply quantity (kg/capita/yr)" in FBS dataset
fbs_food_kcal_element_code: 664 # "Food supply (kcal/capita/day)" in FBS dataset
fbs_other_uses_element_code: 5154 # "Other uses (non-food)" in 1000 tonnes (FBS dataset)
fbs_production_element_code: 5511 # "Production" in 1000 tonnes (FBS dataset)
soilgrids:
target_resolution_m: 10000 # Target resolution in meters (10000m = 10km)
Climate Models: Individual global circulation models (GCMs): GFDL-ESM4, IPSL-CM6A-LR, MPI-ESM1-2-HR, MRI-ESM2-0, UKESM1-0-LL; or multi-model ENSEMBLE
- Periods:
Historical: HP8100 (1981-2000), HP0120 (2001-2020)
Future: FP2140 (2021-2040), FP4160 (2041-2060), FP6180 (2061-2080), FP8100 (2081-2100)
Scenarios: SSP126 (low emissions), SSP370 (medium), SSP585 (high), HIST (historical)
- Input Levels:
“H” (high): Modern agricultural inputs (fertilizer, irrigation, pest management)
“L” (low): Subsistence farming practices
GAEZ Variables¶
The model uses several GAEZ raster products for each crop:
YCX (RES05): Attainable yield on current cropland (kg/ha or other units)
SX1 (RES05): Suitability index (fraction of gridcell suitable for cultivation)
WDC (RES05): Net irrigation water requirement during crop cycle (mm)
Growing season start (RES02): Julian day when growing season begins
Growing season length (RES02): Number of days in growing cycle
Note
RES05 (yields/suitability) supports ENSEMBLE, but RES02 (growing season) only has individual GCM outputs.
The following figures show yield potential maps for three major crops, illustrating the spatial variation in productivity that drives the optimization:
Wheat rainfed yield potential (tonnes/hectare) from GAEZ v5. Higher yields are shown in darker green. Black lines indicate region boundaries. Wheat performs best in temperate zones with adequate rainfall.¶
Wetland rice rainfed yield potential (tonnes/hectare) from GAEZ v5. Rice shows high productivity in tropical and subtropical regions with suitable water availability, particularly in Asia.¶
Maize rainfed yield potential (tonnes/hectare) from GAEZ v5. Maize is adaptable across diverse climates, with strong yields in the Americas, parts of Africa, and temperate zones.¶
Yield Aggregation¶
Yields are aggregated from the input resolution gridcells to (region, resource_class, water_supply) combinations by workflow/scripts/build_crop_yields.py. Exact region-to-cell coverage fractions are computed once per configuration by workflow/scripts/build_region_class_cell_mapping.py and reused for every crop-yield and harvested-area raster.
Aggregation Process¶
Load the cell mapping: Read the reusable region, resource-class, cell, and exact coverage arrays derived from the class raster (see Land Use & Resource Classes)
Load crop-specific rasters:
Yield potential (kg/ha, converted to t/ha)
Suitability fraction (0-1)
Water requirement (mm, converted to m³/ha)
Growing season timing (start day, length)
Unit conversions: Apply crop-specific conversion factors
Potential runs: GAEZ RES05 “yield” rasters are in kg/ha, so the default multiplier is
0.001(kg → tonne). This is the behaviour in the standard (non-validation) configuration.Validation runs: When
validation.use_actual_yields: truethe pipeline swaps to the GAEZ “actual yield” rasters, which are already in tonnes per hectare. In this mode the default multiplier is1.0so we do not double scale the data.Sugar & oil crops:
data/curated/yield_unit_conversions.csvstores overrides for sugarcane, sugarbeet, and oil-palm because GAEZ reports processed outputs (sugar or oil). The factors are interpreted relative to the historical kg/ha baseline, so they continue to work for both scenarios (we convert them into a scenario-agnostic multiplier insidebuild_crop_yields.py).
Mask by suitability: Only aggregate over suitable land (SX1 > 0)
Compute class averages: Within each (region, resource_class) combination:
Mean yield (t/ha) weighted by suitable area
Mean water requirement (m³/ha)
Modal growing season start and length
Output: CSV file (
processing/{name}/crop_yields/{crop}_{water_supply}.csv) with tidy columns:region– Optimization region IDresource_class– Class numbervariable– One ofyield,suitable_area,water_requirement_m3_per_ha,growing_season_start_day,growing_season_length_daysunit– Physical unit for the variable (t/ha,ha,m³/ha,day-of-year,days)value– Numeric value for the (region, class, variable) triplet
Resource Class Yields¶
Because resource classes are defined by yield quantiles (see Land Use & Resource Classes), yields generally increase with class number. For example, in a particular region with quantiles [0.25, 0.5, 0.75], we might see the following average yields by resource class:
Class 0: 1.5 t/ha (bottom quartile land)
Class 1: 2.8 t/ha (second quartile)
Class 2: 4.2 t/ha (third quartile)
Class 3: 6.5 t/ha (top quartile)
This allows the optimizer to preferentially allocate crops to high-quality land or expand onto marginal land as needed.
The following figure illustrates this variation, comparing rainfed wheat yields between resource classes 1 and 2 across all regions:
Comparison of wheat rainfed yields (tonnes/hectare) between resource class 1 (left) and resource class 2 (right). Resource class 2 represents higher-quality land and generally shows higher yields across most regions, demonstrating how the resource class stratification captures land quality variation.¶
Note
Yields for individual crops need not always be better in a high resource class. This is because resource classes are determined “globally” for all crops at once, so that each grid cell is assigned a resource class independent of any crop. So while resource class 2 has better average yields than resource class 1 in every region, that might not be true for some individual crops (e.g. rainfed wheat in the Western USA region in the above example.)
GAEZ-Proxy Yield Calibration¶
A handful of model crops do not have a dedicated GAEZ yield raster and
must therefore borrow a related crop’s raster as a proxy. Without
correction, country-level production under
validation.use_actual_yields: true then systematically
under- or over-shoots the FBS-corrected FAOSTAT total for those crops.
The yield_calibration section of config/default.yaml lists the
affected crops and provides a per-country multiplicative correction
that rescales every per-cell yield in a country so that the model’s
country-level production matches FAOSTAT by construction, while
preserving the GAEZ within-country spatial pattern.
For each crop \(f\) listed under yield_calibration.crops the
multiplier for country \(c\) is
with both sides on a fresh-weight basis (the dry-matter-to-fresh
conversion cancels in the ratio, but is applied explicitly so that the
intermediate diagnostics in the build log are interpretable). Clip
bounds default to [0.5, 3.0]; a value outside this range is logged
and clipped rather than silently absorbed.
Initial entries (subject to change as upstream data evolves):
plantain — GAEZ has no plantain output, so the build pipeline uses the GAEZ banana raster as the proxy. FAOSTAT plantain yields run ~30 % higher than GAEZ-banana yields in African producers, giving a global plantain under-production of about 24 % before calibration.
coffee — GAEZ COC yields are systematically below FAOSTAT in the major producers (BRA, VNM, COL), giving ~26 % global under-production before calibration.
tea — GAEZ TEA yields overshoot in CHN; without rescaling the model produces about 30 % more dried tea than the FAOSTAT fresh-leaf statistics imply (after the standard 4:1 fresh-to-dry conversion).
The output schema matches fodder_yield_corrections.csv
(country, crop, yield_correction_factor) so the
build_model.crops module applies both corrections through the same
per-cell yield-rescaling mechanism; where they overlap they compose
multiplicatively. The mechanism is intentionally inert in
optimisation mode: the calibration is only applied when
validation.use_actual_yields: true, since the GAEZ potential
yields under the standard configuration are meant to reflect agronomic
potential rather than current realised output and so cannot be
anchored to historical FAOSTAT totals.
Rule: build_yield_calibration in workflow/rules/crops.smk.
Script: workflow/scripts/build_yield_calibration.py.
Seed Reservation¶
Per growing cycle, a fraction of harvested mass is reserved as seed for the next planting and never reaches the crop bus. The model deducts this on the production side as a yield haircut:
Sowing rates are looked up per crop in data/curated/seed_rates.csv and combined with the per-(country, region, class, water) yield. This makes the seed share country-specific by construction: low-yield countries reserve a larger fraction of the harvest. The deduction is applied uniformly to single-crop and multi-crop links (workflow/scripts/build_model/crops.py).
The seed share is separate from food-loss-and-waste accounting; FLW only handles supply-chain and consumer-side losses applied at the food bus. Coverage of every configured crop is enforced by workflow.validation.seed_rates so a missing row triggers a startup error rather than a silent zero.
Annualisation conventions encoded in the table:
Multi-year crops (alfalfa, sugarcane): the establishment-year sowing rate is divided by typical stand life so that a fixed annual deduction does not over-count seed.
Vegetatively propagated crops (cassava, sweet-potato, banana): zero, because cuttings come from above-ground biomass that FAOSTAT does not book under the Seed element.
Perennials (oil-palm, olive, mango, citrus, coconut, cocoa, coffee, tea): zero, no annual seed reservation.
Sowing rates are drawn from agronomy literature; one row (biomass-sorghum) is explicitly marked ASSUMED because no global review was found at the time of compilation. The full table is reproduced below for spot-checking; each row carries its source description and (where available) a URL.
Mango uses its own GAEZ v5 RES05 yield, suitability, and water-deficit rasters,
but GAEZ v5 does not currently provide mango RES02 growing-season start/length
rasters. The workflow therefore uses citrus as an explicit RES02 calendar
fallback via data/curated/gaez_crop_code_mapping.csv while keeping mango’s
own output filenames and downstream crop identity.
Show seed_rates.csv (per-crop sowing rates and citations)
# SPDX-FileCopyrightText: 2026 Koen van Greevenbroek
#
# SPDX-License-Identifier: CC-BY-4.0
#
# Per-crop sowing rates (kg of seed planted per hectare per growing cycle).
# Values are in *fresh / as-planted* mass to match the source citations
# (e.g. seed tubers for potato, seed setts for sugarcane). build_model.py
# converts them to dry matter via (1 - moisture_fraction) before computing
# the seed share against the DM yield basis used elsewhere in the model.
# Used in build_model/crops.py to deduct a "seed share" from crop_production
# link efficiency: post-seed yield = yield * (1 - seed_kg_dm_per_ha/1000 / yield_t_dm_per_ha).
# Country-specific yields therefore generate country-specific seed shares
# (low-yield countries reserve a higher fraction). The deduction is
# intentionally separate from FLW / consumption-side accounting.
#
# Validation: workflow/validation/seed_rates.py requires every crop in
# config["crops"] to have a row here. There is no fallback default in
# build_model.
#
# Conventions:
# - Annual rate: for multi-year crops (alfalfa, sugarcane) the value is
# AMORTIZED over typical stand life so it can be deducted yearly without
# over-counting (alfalfa: 22 kg/ha establishment / ~5 yr stand ~= 4;
# sugarcane: 6000 kg/ha fresh planting / ~4 yr ratoon cycle ~= 1500).
# - Vegetatively propagated crops (cassava, sweet-potato, banana) record 0:
# FAOSTAT does not book the planting material as Seed because cuttings
# come from above-ground biomass, not harvested production.
# - Perennials with no annual seed reservation (oil-palm, olive, mango,
# citrus, coconut, cocoa, coffee, tea) record 0.
# - 'gram' is identical to 'chickpea' (same crop in Indian English).
# - Where no credible citation could be found the source begins with
# "ASSUMED" and explains the analogy used; the url column is empty.
#
crop,seed_kg_per_ha,source,url
wheat,140,"UMN Extension small grains seeding rate; range 100-200 chose median.",https://extension.umn.edu/planting-small-grains/seeding-rate-small-grains
dryland-rice,70,"IRRI Rice Knowledge Bank Direct Seeded Rice; range 60-80 kg/ha.",http://www.knowledgebank.irri.org/decision-tools/rice-doctor/rice-doctor-fact-sheets/item/direct-seeded-rice
wetland-rice,40,"IRRI Rice Knowledge Bank Transplanting; nursery seed for transplanted paddy 35-50 kg/ha.",http://www.knowledgebank.irri.org/step-by-step-production/growth/planting/transplanting
maize,22,"TNAU Crop Production Guide 126 (Maize); hybrid grain ~70-80k seeds/ha at TKW 250-300 g.",https://tnagriculture.in/dashboard/CPG/02_%20Maize.pdf
barley,110,"NDSU Extension Fertilizing Malting and Feed Barley; range 90-130.",https://www.ndsu.edu/agriculture/extension/publications/fertilizing-malting-and-feed-barley
oat,100,"Iowa State Extension Fine-tune Oat Seeding Rate; range 85-115 kg/ha.",https://crops.extension.iastate.edu/cropnews/2016/03/fine-tune-oat-seeding-rate-spring
rye,110,"USDA-ARS Brennan et al. Agron. J. 101:47; range 80-130.",https://www.ars.usda.gov/ARSUserFiles/21904/BrennanPeerRevPdfs/Agron%20J%20101p47.pdf
sorghum,10,"Sorghum Checkoff Sorghum Seeding Rates; range 7-12.",https://www.sorghumcheckoff.com/agronomy-insights/sorghum-seeding-rates/
buckwheat,55,"University of Missouri Extension G4163 Growing Buckwheat for Grain or Cover Crop; drilled 50-65 kg/ha.",https://extension.missouri.edu/publications/g4163
foxtail-millet,10,"ICAR-IIMR Foxtail Millet brochure; line-sown 8-10 broadcast up to 15.",https://www.millets.res.in/technologies/brochures/Foxtail_Millet_Brochure.pdf
pearl-millet,4,"ICRISAT Pearl Millet Crop Manual; direct-seeded 4-5 kg/ha.",https://oar.icrisat.org/4060/1/158_07_Pearl_Millet_Manual.pdf
soybean,75,"Purdue Extension AY-217-W Plant Populations and Seeding Rates for Soybeans; ~370k seeds/ha at TKW 150-180 g.",https://www.extension.purdue.edu/extmedia/ay/ay-217-w.pdf
dry-pea,200,"Saskatchewan Pulse Growers seeding-rate guide; large seed (TKW 200-250 g) range 100-230.",https://saskpulse.com/resources/calculating-seeding-rates/
chickpea,80,"Tropical Legumes Hub Chickpea Seed Production Manual; range 75-100 (kabuli higher).",https://tropicallegumeshub.com/wp-content/uploads/2020/07/ChickpeaManual_full.pdf
cowpea,20,"ARC South Africa Production guidelines for Cowpeas; range 12-25.",https://www.arc.agric.za/arc-gci/Fact%20Sheets%20Library/Cowpea%20-%20Production%20guidelines%20for%20cowpea.pdf
gram,80,"Same as chickpea (gram = Bengal gram = chickpea in Indian English; both map to QCL Chick peas dry).",https://tropicallegumeshub.com/wp-content/uploads/2020/07/ChickpeaManual_full.pdf
phaseolus-bean,65,"CIAT improved bean varieties guide (Kholophethe & Kabalabala); range 50-80.",http://ciat-library.ciat.cgiar.org/articulos_ciat/Kholophethe%20and%20Kabalabala.pdf
pigeonpea,8,"ICRISAT Pigeonpea Botany and Production Practices; standard direct-sown rate at 90x75 cm spacing.",https://oar.icrisat.org/2422/1/Pigeonpea-Botany-Production-Practices.pdf
white-potato,2200,"AGRICURA Production guidelines for 1 ha of potatoes; range 2000-2500 (4 tubers/m^2 x ~55 g).",https://agricura.co.zw/wp-content/uploads/2017/11/AGRICURA-1HA-POTATOES-2017.pdf
sweet-potato,0,"Vegetatively propagated from stem cuttings (slips); FAOSTAT does not book Seed for sweet potato.",
cassava,0,"Vegetatively propagated from stem cuttings; FAOSTAT does not book Seed for cassava.",
yam,850,"Cornet et al. 2025 PLANTS PEOPLE PLANET 10.1002/ppp3.10446 (851 kg/ha minisett system at ~17k plants/ha); traditional whole-tuber systems can reach 2000-10000 kg/ha.",https://nph.onlinelibrary.wiley.com/doi/full/10.1002/ppp3.10446
tomato,0.4,"AVRDC Raising Healthy Tomato Seedlings; 400 g/ha for nursery-transplant (dominant global practice).",https://avrdc.org/download/publications/from_the_field/technol/Tomato-Seedlings_web.pdf
carrot,4,"Stark Ayres Carrot Production Guideline; direct-sown 3-5 kg/ha.",https://www.starkeayres.com/uploads/files/Carrot-Production-Guideline-2019.pdf
onion,6,"NHRDF Onion Agro Techniques; direct-sown 5-8 kg/ha; nursery raise ~3.",http://www.nhrdf.org/pAgroTechniques_o.php
cabbage,0.5,"Stark Ayres Cabbage Production Guideline; 250-400 g/ha for nursery-transplant.",https://www.starkeayres.com/uploads/files/Cabbage-Production-Guideline-2019.pdf
banana,0,"Vegetatively propagated (suckers/tissue-culture); not booked annually as Seed.",
watermelon,2,"Texas A&M seeded watermelon crop guide; 1-3 lb/acre seeding rate converted to ~1.1-3.4 kg/ha, chose midpoint.",https://aggie-horticulture.tamu.edu/vegetable/watermelon/seeded-watermelon-crop-guide/
mango,0,"Perennial tree crop; no annual seed reservation booked in FAOSTAT.",
citrus,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
apple,0,"Perennial tree crop (grafted onto rootstock); no annual seed reservation booked in FAOSTAT.",
coconut,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
sunflower,4,"Nuseed Sunflower Seeding Rates; hybrid oilseed 3.3-4.4 kg/ha.",https://nuseed.com/us/planting-seeding-rates/
rapeseed,6,"Canola Council of Canada Seeding Rate; range 4-8 kg/ha.",https://www.canolacouncil.org/canola-encyclopedia/plant-establishment/seeding-rate/
groundnut,130,"ARC-GCI Groundnut Production: A Concise Guide (Cilliers); kernel 80-110 -> in-shell ~130 (shelling % ~0.7).",https://www.arc.agric.za/arc-gci/Fact%20Sheets%20Library/Groundnut%20Production.pdf
sesame,5,"ICAR-IIOR Sesame PoP; drilled 4-6 kg/ha.",https://icar-iior.org.in/sites/default/files/iiorcontent/pops/sesame.pdf
oil-palm,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
olive,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
sugarcane,1500,"TNAU eAgri AGR301 Lec15 Sugarcane; 6 t/ha per fresh planting amortized over ~4-yr ratoon cycle ~= 1500 kg/ha/yr.",http://eagri.org/eagri50/AGRO301/lec15.html
sugarbeet,3,"NDSU 2022 Sugarbeet Production Guide A1698; modern monogerm pelleted 1-3 kg/ha; chose top of range as bag-mass.",https://www.ndsu.edu/agriculture/sites/default/files/2022-01/a1698.pdf
cocoa,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
coffee,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
tea,0,"Perennial; no annual seed reservation booked in FAOSTAT.",
alfalfa,4,"Wisconsin Extension Determining the Optimum Alfalfa Seeding Rate; 22 kg/ha establishment amortized over ~5-yr stand life ~= 4 kg/ha/yr.",https://fyi.extension.wisc.edu/forage/determining-the-optimum-alfalfa-seeding-rate/
cotton,22,"TNAU Irrigated Cotton Crop Geometry & Seed Rate; fuzzy-seed 20-25 kg/ha (delinted seed lower 3-7).",http://www.agritech.tnau.ac.in/agriculture/agri_cotton_Crop%20geometry_Seed%20Rate.html
biomass-sorghum,12,"ASSUMED 20% above grain sorghum by analogy (forage/biomass cultivars seeded heavier for thinner-stand uniformity); only one trial paper found, no solid global review.",
silage-maize,25,"UMN Extension Strategies to Optimize Corn Silage Production; silage corn target population ~83-88k plants/ha (10-15% above grain maize at same TKW).",https://extension.umn.edu/corn-planting/strategies-optimize-corn-silage-production
plantain,0,"Vegetatively propagated from corms or suckers; not booked annually as Seed (analogous to banana).",
Production Constraints¶
In the PyPSA model (workflow/scripts/build_model.py), crop production is represented as multi-bus links:
- Inputs:
Land (from land bus for the region/class/water combination)
Water (for irrigated crops only)
Fertilizer (for all crops, with configurable N-P-K requirements)
- Outputs:
Crop product (to crop bus)
Emissions (CH₄ from wetland rice, N₂O from un-collectable residue decomposition)
Net (feed-usable) crop residue, if any
- Efficiency Parameters:
efficiency(bus0→bus1): Yield in t/ha (already net of the seed reservation described above and the per-country supply-chain loss multiplier)efficiency2(bus2, negative): Water requirement in m³/ha (irrigated rows only)efficiency3(bus3, negative): Fertilizer N requirement in Mt N per Mhaefficiency4(bus4, positive): Wetland-rice CH₄ emissions in t CH₄ per Mha (zero for non-rice rows)efficiency5(bus5, positive): Net residue yield in t DM per ha — gross at-harvest biomass scaled by the per-feed-item field utilisation efficiency (FUE, per GLEAM 3.0 Supplement S1). Routed toresidue:{item}:{country}and from there into feed-conversion or optionalresidue_incorporation. Loss multipliers are not applied: residues stay in the field and do not share the grain’s storage/transport/processing loss path.efficiency6(bus6 =emission:n2o, positive): Mandatory soil N₂O in t N₂O per Mha from the(1 - FUE)gross residue share that cannot be physically collected from the field. Equalsgross_residue_per_ha * (1 - FUE) * n2o_eff_per_t_DM. Wired here (rather than on the residue bus) so the LP cannot avoid the un-collectable-residue N₂O by re-routing dispatch through the feed link — a plainefficiency<1on a residue→feed link silently destroys the (1 - FUE) fraction at the conversion step instead of routing it to soil. See Environmental Impacts for the N₂O coefficient formula.
When crops are converted into foods, the model first rescales the dry-matter crop bus to fresh edible mass using FAO edible portion coefficients and moisture shares drawn from data/curated/crop_moisture_content.csv. The scaling factor edible_portion_coefficient / (1 - moisture_fraction) is applied before product-specific extraction factors in data/curated/foods.csv. Crops listed in data/curated/yield_unit_conversions.csv are the cases where GAEZ reports processed outputs (sugar or oil); the table converts those back to dry matter so that subsequent processing logic is uniform.
Crop-specific exceptions: For certain crops, FAO’s edible portion coefficients do not match the model’s yield units, requiring special handling in workflow/scripts/prepare_fao_edible_portion.py:
Grains (rice, barley, oat, buckwheat): FAO coefficients reflect milled/hulled conversion, but we track whole grain. Coefficient forced to 1.0; milling handled separately.
Sugar crops (sugarcane, sugarbeet), oil-palm, and rapeseed: sugar and palm yields are converted back to whole-crop dry matter via
data/curated/yield_unit_conversions.csv; rapeseed uses FAO edible-portion type-2 coefficients that already encode processing extraction. In all three cases, edible portion coefficients are forced to 1.0 so that extraction losses are handled exactly once indata/curated/foods.csv.
Note
When validation.use_actual_yields is enabled, the GAEZ “actual” rasters already reflect whole-crop fresh mass for sugarcane, sugarbeet, and oil palm, so the workflow bypasses the conversion overrides above and relies directly on data/curated/crop_moisture_content.csv to compute dry-matter production. This keeps validation-era sugarcane output near observed fresh cane harvests instead of re-scaling the processed sugar or oil mass.
The model constrains:
Total land used per (region, class, water) ≤ available land
Total water used per region ≤ blue water availability (see water constraints)
Total fertilizer used globally ≤ global fertilizer limit
Production Costs¶
Crop production incurs economic costs that are included in the optimization objective. Costs are derived from FAOSTAT producer prices and yields, scaled by a configurable non-endogenous cost share, producing per-(crop, country) estimates.
Crop costs are applied as marginal costs on production links. For multiple cropping systems, costs are summed across all crops in the combination.
Cost structure:
Included: All non-endogenous production costs (approximated as a share of revenue)
Excluded: Fertilizer (modeled endogenously), land rent (opportunity cost in optimization), irrigation water (resource constraint)
For comprehensive details on crop production cost data sources, processing methodology, and model application, see:
Production Costs - Complete documentation of all production costs (crops, livestock, and grazing)
Quick reference for crop cost workflow:
prepare_faostat_crop_costs: Computes per-(crop, country) costs from FAOSTAT PP prices and QCL yieldsOutput:
processing/{name}/faostat_crop_costs.csvwith columns:crop: Crop namecountry: ISO3 country codecost_usd_{base_year}_per_ha: Production cost estimate (USD/ha)n_years: Number of years with valid datais_fallback: Whether the value is a global median fallback
Water Constraints¶
For irrigated crops, water availability is a key constraint. Water is a primary
resource in its own right: the crop-production link consumes the crop’s net
irrigation requirement \(E\) (GAEZ RES05-WDC, m3/ha) from a per-region
field bus, which a calibrated efficiency link feeds from the regional
consumption pool. The pool, the AWARE scarcity characterisation, the groundwater
bands, the three water quantities (net requirement, consumption, withdrawal) and
the solve-time pricing/capping levers are documented in the dedicated
Water resources chapter.
Annual renewable water availability by optimization region (mm), area-normalized. The default AWARE source combines WaterGAP-derived irrigation surface and renewable groundwater availability with AWARE basin scarcity factors. The map shows the regional pool summed over the year; the LP applies the corresponding water constraint per period.¶
Irrigated Land Availability¶
Only a fraction of agricultural land is equipped with irrigation infrastructure. The model uses GAEZ v5’s “land equipped for irrigation” dataset (LR-IRR) to determine which land can support irrigated crops.
Key features:
Spatial variation: Irrigated land fraction varies by location based on infrastructure, water access, and historical development
Land competition: Rainfed and irrigated production compete for the same physical land
Water coupling: Irrigated land must have both irrigation infrastructure and sufficient blue water availability
The following figure shows the global distribution of land equipped for irrigation:
Fraction of land equipped for irrigation from GAEZ v5. Higher values (darker colors) indicate areas with more extensive irrigation infrastructure. Many agricultural regions show low irrigation fractions, limiting irrigated crop production even when water is available.¶
Interaction with rainfed cropland:
Within each optimization region and resource class, the model maintains separate variables for rainfed and irrigated land use. However, these share the same physical land base:
Rainfed land limit: Total suitable cropland minus irrigated share
Irrigated land limit: Total suitable cropland times irrigated share
Constraint: Rainfed area + irrigated area ≤ total suitable cropland
This means that in regions with limited irrigation infrastructure, the model may:
Prioritize irrigated production on the best land (higher resource classes) when water is available
Fall back to rainfed production when irrigation infrastructure or water is limiting
Trade off between high-yield irrigated crops (requiring both infrastructure and water) and lower-yield rainfed crops (requiring neither)
The irrigation infrastructure constraint is particularly important in regions where water is abundant but irrigation systems are not widely deployed, preventing the model from unrealistically converting all suitable land to high-yield irrigated production.
Fertilizer¶
Crop production requires nitrogen (N), phosphorus (P), and potassium (K) fertilizers. The model includes:
Global fertilizer limit: Total synthetic nitrogen available (
fertilizer.limitin config, specified in kg-N and converted to Mt-N internally)Global marginal cost: Blanket fertilizer price in USD per tonne-N (
fertilizer.marginal_cost_usd_per_tonne) converted to bnUSD/Mt-N and applied to the global fertilizer generatorCrop-specific requirements: Fertilizer needed per tonne of production (from
data/crops.csv)Emissions factors: N₂O emissions from nitrogen application
All fertilizer quantities in the model (limits, costs, crop coefficients, emissions factors) refer to the mass of nitrogen nutrient (t-N or Mt-N). The fertilizer constraint is typically set at a realistic global scale (e.g., 200 Mt-N/year) to prevent unrealistic intensification.
At present only nitrogen nutrient flows are modeled explicitly; phosphorus and potassium application (and their GHG emissions) remain out of scope and are tracked implicitly in future work.
Growing Seasons¶
Temporal overlap of growing seasons within a region affects:
Water availability: Multiple crops may compete for water during the same months
Land use: Double-cropping potential if growing seasons don’t overlap
Currently, the model uses annual time resolution, so it implicitly assumes:
Each land parcel produces one crop per year
Water constraints apply to the full growing season
Multiple Cropping¶
Many production systems plant two or more sequential crops on the same parcel.
Multiple cropping is anchored to an observed reference-year baseline derived
from MIRCA-OS v2 (see Data Sources), so the model starts from observed
double-cropped area – notably India’s rice-wheat and rice-rice systems – rather
than treating every extra cropping cycle as unanchored potential. The MIRCA
release closest to baseline_year is used; the workflow supports 2010, 2015,
and 2020, ties select the earlier year, and a warning is emitted when the match
is not exact.
Observed-baseline derivation. The ordinary, config-specific Snakemake rule
derive_mirca_multicropping (workflow/scripts/derive_mirca_multicropping.py)
attributes MIRCA’s extra-cycle harvested area – annual harvested area minus the
AEI-capped physical footprint – independently for irrigated and rainfed land.
It considers only the fixed candidate sequences in
data/curated/mirca_os_multicropping_combinations.yaml. The catalog is tied to
the MIRCA-OS v2 crop taxonomy and records widely documented rotations and
repeated-rice systems that both datasets can represent; catalog membership is a
candidate attribution, not evidence that a rotation occurs in every cell.
The rule aggregates directly to the active config’s regions and resource
classes. It writes baseline_area.csv, a diagnostic
residual_multicrop.tif, and attribution_stats.csv under
processing/{name}/multi_cropping/. Keeping these products config-specific
is necessary because the aggregation and GAEZ multiple-cropping-zone gate
depend on the config’s spatial and climate inputs. Extra-cycle area that cannot
be assigned to a catalog sequence remains unattributed and is handled by the
bulk land correction.
A combination is a candidate in a cell where every crop is observed in MIRCA
in that water supply and the GAEZ multiple-cropping zone permits the cycle count.
sequence_feasible on GAEZ growing-season windows is deliberately not used as
a feasibility gate: GAEZ attainable season lengths overshoot the farmed cycle and
would reject nearly all observed irrigated double-cropping. MIRCA’s observation is
the feasibility evidence; beyond the zone gate, GAEZ enters only for
suitability, yields and water requirements.
Within each cell and water supply, all candidate sequences receive a common proportional fill rate subject to the extra-cycle magnitude, physical footprint, each constituent crop’s observed harvested-area budget, and each sequence’s MIRCA/GAEZ support. The shared crop budgets prevent the same observed wheat, maize, or other crop area from being attributed independently to several overlapping rotations. Any area that cannot be assigned under all budgets stays in the residual.
Potential derivation. The preprocessing rule
build_multi_cropping reads the GAEZ rasters for every crop in each
(combination, water supply) pair and, over pixels where the zone permits the cycle
count and every crop has suitability, positive yield and (irrigated) a water
requirement, computes the eligible potential area and per-cycle yields. The
three tables in processing/{name}/multi_cropping/ are
eligible_area.csv (potential area plus the summed irrigated water
requirement water_requirement_m3_per_ha; zero for rainfed variants),
cycle_yields.csv (per-cycle t/ha), and baseline_area.csv (observed
anchor area per region/class/water supply).
Catalog combinations are included automatically when all their crops are
modeled. The multiple_cropping config section may set a catalog name to
null to disable it or add a uniquely named greenfield sequence. Greenfield
sequences have an implicit zero baseline and expose only GAEZ-constrained
optimization potential; catalog entries cannot be redefined in config.
Seasonal water split. When the model resolves intra-year water periods
(water.temporal_resolution > 1), each irrigated cycle’s net requirement is
placed into the periods by that crop’s observed MIRCA-OS irrigated calendar for
the cell’s region, rather than smeared evenly across the year – so a dry-season
cycle (rabi wheat, boro rice) lands its demand in the scarce period. Where a
region has no observed calendar for the crop, the cycle falls back to its own
GAEZ growing season; repeated same-crop cycles, for which GAEZ gives a single
window, are staggered at equal 365/n-day offsets in that fallback so the
second cycle does not double the monsoon window.
The RES01 classes report the agro-climatic zone the pixel belongs to. We interpret the numeric codes as:
0 – masked (ocean/undefined)
1 – no cropping (too cold/dry)
2 – single cropping
3 – limited double cropping (GAEZ permits relay; we conservatively treat it as sequential double cropping with at most one wetland rice cycle)
4 – double cropping (no wetland rice sequentially)
5 – double cropping with up to one wetland rice crop
6 – double rice cropping (limited triple in the documentation is ignored here)
7 – triple cropping (≤2 wetland rice crops)
8 – triple rice cropping (up to three wetland rice crops)
Relay cropping opportunities mentioned for the C/F zones are not modeled; we only construct sequential crop chains. This limitation is also noted in the configuration and model framework documentation.
During build_model each (combination, region, resource class) creates a single
rainfed or irrigated multi-output link (carrier crop_production_multi) that:
draws physical land from the matching cropland bus (
_ror_i),emits one crop bus per cycle with efficiencies equal to the per-cycle yield,
charges marginal cost using the sum of crop prices across cycles,
deducts the combined fertilizer rate (kg N per ha summed over the crops), and
(irrigated only) withdraws the summed water requirement on the region water bus.
The link is anchored at its MIRCA baseline via baseline_area_mha with
p_nom_max = max(GAEZ potential, baseline) and stays extendable, so it is
subject to the same production-stability penalty as single-crop links and the
model can add or drop a complete sequence. Every configured cycle must have a
valid yield; partial bundles are never built. If an observed local anchor lacks
a complete GAEZ row, it is relocated within the same combination, country, and
water supply. If that group has no valid full-sequence target under the active
GAEZ inputs, no partial bundle is created: the harvested-area budget remains on
the constituent single-crop baselines.
Single-crop crop_production baselines are FAOSTAT harvested area and
already count every cycle. The harvested cycles carried by multi links are
therefore subtracted from the corresponding single-crop baselines
(m_k times the multi anchor for crop k). Where joint MIRCA bundle
requirements exceed a constituent crop’s national FAOSTAT budget, all affected
bundle anchors are scaled by the most restrictive crop ratio. Any cycle
subtraction that cannot be made locally is taken from other single-crop links
only within the same crop, country, and water supply. The build then asserts
that single plus multiplicity-weighted multi baselines exactly reproduce every
incoming FAOSTAT budget. The crop-agnostic
multi_cropping_land_correction generator absorbs only residual,
unattributed extra-cycle area.
Rain-fed perspective: top panel shows RES01-MCR classes from GAEZ v5. Bottom panel reports the share of each optimisation region where the climate supports sequential multi-cropping (zones 3–8). The model treats the relay-permitting zone 3 as sequential multi-cropping.¶
Irrigated perspective: top panel shows RES01-MCI classes. Bottom panel reports the share of each optimisation region where irrigated climate conditions allow sequential multi-cropping (zones 3–8); the model interprets relay-permitting zone 3 as a sequential crop chain.¶
Crop-Specific Data Files¶
- data/crops.csv
Long-form crop parameter table (mock starter data). Each row represents a
(crop, param)pair:crop: Crop identifier matching entries used in configs and raster filenamesparam: Parameter key (currentlyfertilizer,co2, orch4)unit: Unit string forvalue(e.g.,kg/t)value: Numeric parameter value interpreted according toparamdescription: Free-text explanation of the assumption
Add new parameters by appending rows; comment lines starting with
#are ignored by loaders.- data/curated/gaez_crop_code_mapping.csv
Lookup table aligning GLADE crop identifiers with GAEZ resource codes. Columns:
crop_name,description, and the RES02/RES05/RES06 codes used to locate raster layers.- data/curated/yield_unit_conversions.csv
Optional per-crop overrides for converting raw GAEZ yields to tonnes of dry matter per hectare. Columns:
code(crop identifier),factor_to_t_per_ha(multiplier applied to raster values), andnotefor context. Only sugar crops and oil-palm currently require overrides; all other crops use the default0.001factor (kg → tonne).- data/curated/crop_moisture_content.csv
Moisture fractions (0-1) for each modelled crop, primarily sourced from the GAEZ v5 Module VII documentation with explicit notes where assumptions were required. Combined with edible portion coefficients to convert dry matter yields into fresh edible mass.
Workflow Rules¶
Crop yield processing is handled by the build_crop_yields rule:
Input: Resource classes, GAEZ rasters (yield, suitability, water, growing season), regions, unit conversions
Wildcards:
{crop}(crop name),{water_supply}(“r” or “i”)Output:
processing/{name}/crop_yields/{crop}_{water_supply}.csvScript:
workflow/scripts/build_crop_yields.py
Run for a specific crop with:
tools/smk -j1 processing/{name}/crop_yields/wheat_r.csv
Or for all crops automatically via dependencies of the build_model rule.
Visualization¶
Once a scenario has been solved, several plotting rules in
workflow/rules/plotting.smk produce diagnostic figures for the crop
sector. All outputs land under
results/{name}/plots/scen-{scenario}/.
Dominant-crop-group map — gridcell-level map of cropland intensity coloured by the locally dominant crop group:
tools/smk -- results/{name}/plots/scen-{scenario}/crop_production_map.pdf
Produced by rule plot_crop_production_map
(workflow/scripts/plotting/plot_crop_production_map.py). Feed crops
(pasture, forage) dominate area everywhere and are excluded from the
raster so they do not overwhelm the other groups; they remain visible in
the accompanying bar chart.
Crop-use breakdown — stacked bar chart of global crop production allocated to food, animal feed, and other uses, with separate irrigated and rainfed totals:
tools/smk -- results/{name}/plots/scen-{scenario}/crop_use_breakdown.pdf
Produced by rule plot_crop_use_breakdown
(workflow/scripts/plotting/plot_crop_use_breakdown.py). The companion
CSV (crop_use_breakdown.csv) carries the same numbers in tabular
form for downstream notebooks.
Crop-trade map — same gridcell map as above, overlaid with the largest hub-to-hub trade flows (arrow colour by commodity group, width by volume):
tools/smk -- results/{name}/plots/scen-{scenario}/crop_trade_map.pdf
Produced by rule plot_crop_trade_map
(workflow/scripts/plotting/plot_crop_trade_map.py).