
Split a national crop total across the units of its container
Source:R/spatialize_levels.R
build_level_crop_targets.RdThe first half of allocate_level_crops(), exposed on its own because
the reconciliation diagnostics read it: it turns national totals plus
resolved admin shares into one target per (year, container, unit, item), and says on every row which regime produced it.
Usage
build_level_crop_targets(
country_areas,
unit_weights,
admin_shares = NULL,
tolerance_relative = 0.1,
tolerance_absolute = 1000
)Arguments
- country_areas
National crop areas keyed on the container; see
allocate_level_crops().- unit_weights
Per-unit pattern weights, from
.alloc_unit_weights():year,area_code,level_polity_code,item_prod_code,weight_rainfed,weight_irrigated,cropland_rainfed_ha,cropland_irrigated_ha,n_cells.Resolved admin shares, or
NULL.- tolerance_relative
Relative discrepancy above which a complete-coverage group is refused,
0.10by decision T31(d).- tolerance_absolute
Absolute discrepancy, in hectares, above which the same group is refused,
1000by decision T31(d). BOTH must be breached.
Value
A list of two tibbles, targets and coverage; see
allocate_level_crops() for their columns.
How the denominator is chosen
Per (year, area_code, item_prod_code), writing D for the
denominator each unit's reported value is divided by:
"pattern"No unit reports. Every unit's share is its own pattern weight over the group's,
method_crop_alloc = "pattern_implied"– or"pattern_national"where the container is at level 0 and is therefore its own single unit."admin_sum"Every unit of the layer reports a value: complete coverage, so
D = admin_sumand the reported units rescale proportionally onto the national total. The leftover is a diagnostic; it is refused only when it breaks BOTH tolerances (decision T31(d))."residual"Some units report a value:
D = max(admin_sum, national), so a reported value binds in absolute hectares whileadmin_sumis below the national total, and rescales down when it is above. The residual,1 - admin_sum / Dof the total, is split across the units that reported NO absolute area, and never touches a unit that did (decision T31(a)). Those units' pattern weights split it – unless every one of them declares a share, in which case the declared shares do, because that is what a declared share states."share_normalised"The rows carry a
shareand novalue, which is whatbackcast_admin_shares()produces: the shares already sum to 1 over the units they cover, so they are used as they stand and a unit outside them gets zero.method_crop_alloc = "admin_backcast_luh2".
method_crop_alloc therefore takes one of "pattern_national" (a
container the layer holds at level 0, which is its own single unit),
"pattern_implied", "admin_area_shares", "admin_backcast_luh2",
"admin_residual" (a unit carrying its share of the residual on the
weights that split it – whether because it reported nothing, or because
it declared a share the split did not run on) and "unallocated" (a unit
whose target is 0: the shares do not cover it and no residual reaches it,
or the group had neither pattern weight nor cropland for anything to be
split on, coverage$weight_basis == "none"). The column names what placed
the hectares, so a unit whose declared share was displaced by the pattern
weights is "admin_residual" and not "admin_area_shares", and a group
the pattern never ran on is "unallocated" and not "pattern_implied".
A group whose reported values are all zero while the national total is
positive cannot set a shape. Under complete coverage every share is 0,
the hectares are counted in coverage$dropped_ha, and the T31(d)
refusal fires on any group where that matters (the discrepancy is then
100% of the national total). Where that leaves NO positive target at all,
allocate_level_crops() returns the empty allocation beside this
coverage rather than calling an engine with nothing to place.
An admin-share row carrying no level_polity_code names no unit – that
is what resolve_admin_units() leaves on a unit it could not resolve –
and is dropped, counted and named before the split. NA is the layer's
own value for "this container is at level 0 and IS its own unit", so such
a row would otherwise bind the container's own row and publish one
unresolved province as the country's complete subnational evidence.
What counts as a report
One predicate. A unit reports when it carries a value, a share, or
both, and coverage$n_units_reporting counts exactly the units that then
bind. reports_value – an ABSOLUTE area – is a narrower question, and
it decides two things only: which denominator the group uses, and which
units the residual is spread over. So a unit declaring a share and no
value is a reporter, and it takes a slice of the residual the valued
units left. What sizes that slice is a property of the candidate SET,
not of the unit: where every residual candidate declares a share, those
shares split the residual (coverage$weight_basis is then
"declared") and the declared share binds; where only some do, the
pattern weights split it, because a declared fraction and a hectare of
potential are not the same quantity. In that second case the unit is
allocated exactly as a silent one is, and method_crop_alloc says so.
A negative reported value, a negative declared share and a negative
derived target are all refused (classes whep_alloc_negative_value and
whep_alloc_negative_target); allocate_level_crops() refuses a
negative national total ahead of both, as
whep_alloc_negative_national. A negative target is dropped by the
engine's positivity filter, after which the remaining units divide the
whole national total between them: the container over-allocates and
nothing downstream can see the row that is not there.
Irrigation
The unit's irrigated target is the national irrigated area split by the
engine's own ir_potential aggregated per unit, so the two steps
compose; where a group has no irrigated potential the split falls to the
units' irrigated cropland, and where there is none of that either the
irrigated area is unplaceable and is reported as such, because the
engine would drop it too. The rainfed target is the remainder, and the
irrigated target is clipped at the unit's area target so the remainder
is never negative – the engine computes harvested - irrigated with no
clipping and lets a negative row through its output filter. Clipped
hectares are reported per unit in irrigation_clipped_ha and are NOT
redistributed to units with room: that would be an allocation rule
nothing has decided.
Examples
weights <- tibble::tibble(
year = 2000L,
area_code = 1L,
level_polity_code = c("A1", "A2"),
item_prod_code = 15L,
weight_rainfed = c(400, 600),
weight_irrigated = 0,
cropland_rainfed_ha = c(800, 1200),
cropland_irrigated_ha = 0,
n_cells = 1L
)
national <- tibble::tibble(
year = 2000L, area_code = 1L, item_prod_code = 15L,
harvested_area_ha = 1000
)
build_level_crop_targets(national, weights)$targets
#> # A tibble: 2 × 12
#> year area_code level_polity_code item_prod_code share target_ha
#> <int> <int> <chr> <int> <dbl> <dbl>
#> 1 2000 1 A1 15 0.4 400
#> 2 2000 1 A2 15 0.6 600
#> # ℹ 6 more variables: irrigated_target_ha <dbl>, rainfed_target_ha <dbl>,
#> # irrigation_clipped_ha <dbl>, method_crop_alloc <chr>,
#> # national_total_ha <dbl>, n_cells <int>