
Build the full nitrogen balance: inputs, outputs, losses and NUE.
Source:R/n_balance.R
build_nitrogen_balance.RdAssembles build_n_inputs()'s long-format nitrogen inputs into the
aggregate N_input_* sums, adds the output side (crop production,
residue use/burning, grazed weeds, soil organic-matter sequestration),
runs the nitrogen-loss cascade (calculate_nh3(), calculate_soil_n2o(),
calculate_n_leaching(), calculate_indirect_n2o_nh3()), closes the
balance (N_input_full - N_output_full), applies the N-limitation cap on
SOM sequestration, and derives nutrient-use-efficiency (NUE) indicators
plus a GWP/CO2e indicator for the nitrous-oxide streams. Ported from
Spain_Hist's Balance_parameters()/N_Figs.R equations.
Arguments
- methods
A named list of method choices:
nh3(forwarded tocalculate_nh3(), default"manner"),n2o(forwarded tocalculate_soil_n2o(), default"ipcc2019", the globally applicable IPCC 2019 Tier 1 method) andleaching(forwarded tocalculate_n_leaching(), default"meisinger_drainage").- resolution
"grid"(default) or"polity", as inbuild_n_inputs();"polity"sums every term (and re-derives every indicator) over cells.- polity_validity
What to do with a row whose
(area_code, year)resolves to a polity that did not exist in that year (the cell-polity crosswalk has no year dimension, so an early-20th-century cell is labelled with its present-day territory)."keep"(default) keeps every row, which is the historical behaviour, and warns naming the rows, years and area codes involved."flag"keeps them and adds the per-row logicalreporting_polity_out_of_span, marking exactly which rows are stand-ins."drop"removes them. All three warn; only"drop"changes the numbers. Seepolity_coverage_gaps(), which reports the same rows for an already-built table.- data
Named list of pre-loaded upstream inputs.
n_inputs(build_n_inputs()'s output) is used directly when supplied, elsebuild_n_inputs()is called with this SAMEdatalist (so its nested readers, e.g.bnf_input/npp_n_input/livestock_intake, propagate through). Also required:npp_n_input: shared withbuild_n_inputs()'s"recycling"term (seecalculate_npp_carbon_nitrogen()); used here forprod_n_t.ag_land_support: thebuild_ag_land_support()table, supplyingarea_ha(the per-hectare boundary denominator) on a physical-land basis. Derived natively when absent and derivable, and shared withbuild_n_inputs()so both see one table; when neither supplied nor derivable,area_hafalls back to the harvested area the NPP input carries.residue_destiny_input:calculate_residue_destinies()'s required input (item_prod_code,residue_dm_t, plus whatever the chosenresidue_destiny_methodneeds), forused_residue_n_t/burnt_residue_n_t.residue_destiny_methodselects the method (default"krausmann_regional").livestock_intake: shared withbuild_n_inputs()'s manure term; its"grass"feed_qualityrows drivegrazed_weeds_n_t.carbon_balance: shared withbuild_n_inputs()'s"som_ mineralization"term; itsson_change_kgn_hadrivessom_ sequestration_n_t.n_balance_drivers: additional per-(key, fert_type)driver columnscalculate_nh3()/calculate_soil_n2o()/calculate_indirect_n2o_nh3()need beyondn_input_t/fert_type(climate,irrig_type, plus every MANNER driver column whenmethods$nh3 == "manner"), joined by the balance key ANDfert_type(the Title-case vocabulary fromcalculate_nh3()'s own documentation, e.g."Synthetic","Solid","Excreta_other"; see the file-level "fert_type vocabulary bridge" note for the exact mapping frombuild_n_inputs()'s lowercase values). A second set of balance-key-only driver columns (fert_type,climate,irrig_cat,tillage,som_share,cn_input,land_use) forcalculate_n_leaching()is read fromn_balance_leaching_drivers, which must hold at most one row per balance key (a many-to-one join aborts on duplicate keys rather than fanning the rows out and misaligningdrainage_mm). Missing required drivers abort inside the calledcalculate_*()function, naming the exact column.drainage_mm: annual drainage (mm) forcalculate_n_leaching(), as a numeric vector aligned to the balance-key rows, or already present as adrainage_mmcolumn vian_balance_leaching_drivers.
- gwp
100-year global warming potential standard for N2O,
"ar6"(default),"ar5"or"ar4", matchingbuild_crop_soil_n2o_extension().- example
If
TRUE, return a small fixture instead of assembling real data. Defaults toFALSE.
Value
A tibble keyed by year/area_code/item_cbs_code (plus
lon/lat at resolution = "grid") with area_ha (each crop's
harvested hectares in the cell, summed over cells at
resolution = "polity"; used downstream to convert tonnes N to a
per-hectare rate), the input aggregates
(n_input_full_t, n_input_full_nosom_t, n_input_std_t,
n_input_som_t, n_input_for_n2o_t), the output aggregates
(n_output_residues_t, n_output_som_t, n_output_useful_t,
n_output_std_t, n_output_full_t), the loss terms (nh3_n_t,
n2o_direct_n_t, no3_n_t, denitrification_n_t,
n2o_indirect_no3_n_t, n2o_indirect_nh3_n_t), the (post-cap)
som_sequestration_n_t, n_balance_t, surplus_t, surplus_share,
the five NUE ratios (nue_std, nue_residues, nue_som,
nue_useful, nue_full), total_gwp_co2e_kg, and the method_nh3/
method_soil_n2o/method_leaching provenance columns, plus the polity
columns below. When the supplied n_inputs carry them, the
method_recycling_n, method_synthetic and method_deposition_scope
stamps from build_n_inputs() are carried through as well, so a balance
names the input conventions that produced it. Gains
reporting_polity_out_of_span when polity_validity = "flag".
Details
polity_validity is forwarded to build_n_inputs() – which forwards it in
turn to build_ag_land_support(), build_n_deposition(), build_urban_n()
and spatialize_country_n_to_crops() – and then applied to the balance rows
themselves, so one choice governs the whole build (whep#727). A
data$n_inputs table supplied directly is left alone: it was built by its
own call with its own choice, and the balance rows derived from it still get
this argument's fate at the tail.
Polity columns
Every area-keyed output carries the polity its area_code resolves to in
that row's year:
polity_area_code: The numeric key rows are AGGREGATED on, for the matrix workflows. It is a bucket, not an identity: usereporting_polity_codeto say which territory a row belongs to.reporting_polity_code: The polity itself, e.g.ESP-1846-1914. It is year-aware, so the samearea_coderesolves to different polities in different years, which is the point of the crosswalk.reporting_polity_name: Its name. It can differ from the area's own name where the area folds into an aggregate.reporting_polity_has_geometry: Whether the polity has a polygon in the WHEP polity database, for callers that need to map or intersect it.FALSEis a documented gap upstream, not an error.
Rows whose area_code resolves to no polity keep the columns with NA
rather than being dropped, so a gap is visible instead of silent.
Rows before the back-cast anchor year resolve to the polity live in that
anchor year rather than to the polity live in the row's own year, because
WHEP's pre-anchor series are back-cast onto the anchor-year territory. See
add_polity_code() for the reasoning. Where that polity is not live in the
row's own year – 41.5% of the pre-1961 (area, year) cells –
add_polity_code() says so as mapping_status == "backcast_anchor", and
polity_coverage_gaps() reports it as gap_kind == "backcast_anchor".
These columns do not say so either way.
A row whose year no mapped period covers is resolved to the NEAREST period of
the same area instead, so reporting_polity_code can name a polity that did
not exist in that row's year – FAOSTAT bucket 206 "Sudan (former)" keeps
reporting after SUD-1956-2011 ends, and its post-2011 rows carry that code.
These columns do not say so: add_polity_code() reports such a row as
mapping_status == "out_of_span", and that column is dropped here so that
adding it does not change the schema of every area-keyed output at once.
polity_coverage_gaps() reports the stand-in rows of a built table, and
options(whep.polity_mapping_status = "flag") (or "status") carries the
signal on the outputs themselves. Both are opt-in; the default is no extra
column.
Examples
build_nitrogen_balance(example = TRUE)
#> # A tibble: 1 × 41
#> year area_code polity_area_code reporting_polity_code reporting_polity_name
#> <int> <int> <int> <chr> <chr>
#> 1 2020 10 10 AUS-1901-2025 Australia
#> # ℹ 36 more variables: reporting_polity_has_geometry <lgl>,
#> # item_cbs_code <int>, area_ha <dbl>, n_input_full_t <dbl>,
#> # n_input_full_nosom_t <dbl>, n_input_std_t <dbl>, n_input_som_t <dbl>,
#> # n_input_for_n2o_t <dbl>, prod_n_t <dbl>, used_residue_n_t <dbl>,
#> # burnt_residue_n_t <dbl>, grazed_weeds_n_t <dbl>,
#> # som_sequestration_n_t <dbl>, n_output_residues_t <dbl>,
#> # n_output_som_t <dbl>, n_output_useful_t <dbl>, n_output_std_t <dbl>, …