luh2impact turns raw land use data into the parameters read by IFPRI's
IMPACT model and its LUMEN land use downscaler. It holds two independent
pipelines that share a country definition — the IMPACT regions shapefile and
Sets.xlsx — but nothing else:
- a pixel pipeline that builds a 0.25° gridded baseline (areas, spatial weights, protected area, suitability) and writes the LUMEN input GDX; and
- a country pipeline that fits FAOSTAT land use elasticities against
cropland and GDP per capita and writes
LAND00,LANDELAS,LANDPA00andBII_COEFFfor IMPACT.
Both use the same six land pools: crop, past, natfor (naturally
regenerating forest), plant (planted forest), other and urban.
Protected area is deliberately not a pool — it overlays natfor, past
and other — and is carried as a separate area floor.
From the IFPRI r-universe:
install.packages(
"luh2impact",
repos = c("https://ifpri.r-universe.dev", "https://cloud.r-project.org")
)Or straight from GitHub:
# install.packages("remotes")
remotes::install_github("IFPRI/luh2impact")The package depends on DOORMAT for reading GDX files, which is installed from GitHub rather than CRAN.
Every function that reads or writes a GDX file needs gamstransfer, which
ships with GAMS rather than CRAN, so it is only a Suggests. Install it from
your GAMS system directory:
install.packages("<GAMS_DIR>/apifiles/R/gamstransfer", repos = NULL, type = "source")Without it, the package still installs and loads; the GDX entry points will not run.
library(luh2impact)
# One-off: rasterize WDPA protected areas onto the LUH2 grid (slow)
wdpa_process(
gdb_path = "data/WDPA/WDPA_Jul2026_Public.gdb",
static_nc = "data/LUH2/staticData_quarterdeg.nc",
output_tif = "data/WDPA/pa_area_km2.tif",
year = 2021
)
luh2gdx(
states_nc = "data/LUH2/states.nc",
static_nc = "data/LUH2/staticData_quarterdeg.nc",
planted_tif = "data/SDPT/sdpt_global.tif",
cty_shp = "data/IMPACT/impact_regions.shp",
impact_gdx = "data/IMPACT/solution.gdx",
output_gdx = "outputs/lumen_input.gdx",
year = 2021,
pa_tif = "data/WDPA/pa_area_km2.tif"
)luh2gdx() chains luh2_load(), luh2_pool_trend(), luh2_extract_year(),
luh2_merge_planted(), luh2_suitability(), luh2_build_pixels() and
luh2_export_gdx(). Every one of them is exported, so the pipeline can be
run step by step when only part of it needs redoing.
Pixel areas are reconciled to the IMPACT country totals by iterative proportional fitting, and the allocation weights combine each pool's historical trend with a long-run suitability index.
After LUMEN solves:
luh2_write_tifs("outputs/CHM/solution_lu.gdx", "outputs/CHM")
luh2_plot_results("outputs/CHM", "data/IMPACT/impact_regions.shp")
luh2_plot_bii("outputs/CHM", "data/IMPACT/impact_regions.shp")luh2_landuse_elasticities(
fao_land_csv = "data/FAOSTAT/Inputs_LandUse_E_All_Data_(Normalized).csv",
sets_xlsx = "data/IMPACT/Sets.xlsx",
ssp_gdx = "data/SSP/ssp.gdx",
fao_country_map_csv = "data/FAOSTAT/country_codes.csv",
wb_gdppc_csv = "data/WorldBank/API_NY.GDP.PCAP.PP.CD.csv",
output_gdx = "outputs/landuse.gdx",
states_nc = "data/LUH2/states.nc", # adds urban land
static_nc = "data/LUH2/staticData_quarterdeg.nc",
cty_shp = "data/IMPACT/impact_regions.shp",
pa_tif = "data/WDPA/pa_area_km2.tif" # adds LANDPA00
)The elasticity core (luh2_load_faoland() → luh2_compute_gdppc() →
luh2_fit_elasticities() → luh2_export_elasticities_gdx()) always runs;
urban land and protected area are added only when their inputs are supplied.
BII coefficients are always written, either blended from FAOSTAT primary
forest shares (luh2_bii_coeff_cty()) or read from the pixel-derived tables
shipped with the package (luh2_bii_coeff_cty_pixel()).
The fitted model, per country and per non-cropland pool, is
dln_use ~ dln_crop + dln_gdppc
on first-differenced logs of annual FAOSTAT areas. The coefficients are
descriptive associations within a country's own history, estimated without
controls or instruments; they are not causal effects. Countries that cannot
be fitted are kept and flagged rather than dropped, and only ok rows reach
the LANDELAS parameter the model solves with.
Nothing ships with the package except the pre-computed pixel BII tables under
inst/extdata; every entry point takes file paths.
| Input | Used by | Source |
|---|---|---|
states.nc, staticData_quarterdeg.nc |
both | LUH2 |
| Planted forest GeoTIFF | pixel | e.g. SDPT |
| WDPA geodatabase | both | UNEP-WCMC / IUCN |
IMPACT regions shapefile (NEW_REGION field) |
both | IMPACT |
Sets.xlsx (Regions sheet) |
country | IMPACT |
IMPACT solution GDX (LANDX0) |
pixel | IMPACT |
Inputs_LandUse_E_All_Data_(Normalized).csv |
country | FAOSTAT |
SSP scenario GDX (OECD_GDP, POP) |
country | SSP database |
NY.GDP.PCAP.PP.CD CSV |
country | World Bank |
wdpa_process()caches its latitude bands in a hard-coded directory (C:/Local/Work/IFPRI/Landuse/WDPA/Processed Polygons) and merges every.tifit finds there. Change the year or the WDPA release and the cache has to be cleared by hand. The WDPA layer name is hard-coded too.- Country-level protected area only counts pixels inside the IMPACT regions shapefile, so totals sit below published global figures.
luh2_build_pixels()reconciles to IMPACT totals for 2021 specifically, and drops South Sudan;luh2_merge_planted()exempts South Africa from the forest/non-forest split.- Several BII coefficients in
luh2_bii_coeff_cty()are visual reads off a published figure rather than digitized values — see?luh2_bii_coeff_cty. luh2_suitability()assumes a LUH2 file that starts in 850.
?luh2impact gives the package overview; every exported function has its own
help page, and the two pipelines are cross-linked through the
pixel pipeline functions and country pipeline functions families.
CC BY 4.0. See LICENSE.md.