max_intake_shareexcess is now redirected via an availability-aware chain that preserves supply conservation. When an item violates a Livestock_cat'smax_intake_share, the reduced DM is carried over to substitute items in this order:- Grassland (unlimited fallback) if not capped for the Livestock_cat.
- Otherwise, non-Grassland items from
items_fullin the main-pipeline priority order (Lactation / High_quality → Low_quality → Residues → Grass), skipping items capped for this Livestock_cat. Each substitute is bounded byavail$avail_remainingand decrements it (prov avail preferred, nat used if prov insufficient), keeping supply conservation intact. - If all non-Grassland substitutes are exhausted (capped or
avail-depleted) and excess remains, the remainder is pushed to
Grassland regardless of its cap, with a warning — per user request
("chaining to grass if not enough other substitutes"). Previously the
redirect emitted synthetic intake rows with
avail_id = NA, silently violating supply conservation for any non-Grassland substitute.
- Final
arrange()now deterministic on all tiebreakers (item_cbs,original_Provinceappended) so two runs producing the same allocation can't differ in row order. compute_scaling()no longer collapses intendedNA_real_results (demand = 0, intake > 0) to0; aligns with the priorcase_whensemantics.- Removed dead
can_receive_prioritycolumn computed twice and never referenced. - Removed dead first call of
compute_scaling()that was always overwritten by the final pass. allocate_grassland()no longer manually zeroesdemand$remaining—add_alloc()already decrements by the actually-allocated amount, and the manual zero could drift from the true intake if the cap ever bound.
- Replaced
stats::aggregate()in the priority-pool inner loop withrowsum()(same pattern asadd_alloc(); lower per-call overhead). - Pre-bucketed demand row indices by
(Year, Territory)at preprocessing so the priority-pool and surplus loops subset in O(1) instead of filtering the full demand table once per bucket. - Converted
allocate_cartesian()andallocate_grouped()(the two primary-level join-heavy helpers, called 12+ times per run) to data.table.data.tablemoved fromSuggeststoImports. - Net result on the 25 k-demand reference fixture: baseline 2.62 s → current 1.38 s (1.9× speedup) with the new chained-redirect behavior absorbing the complexity.
- Zoot_fixed cap is now per-Livestock_cat. Each demand row's intake is
bounded by
zoot_fixed_max_multiplier * Avail_MgDMindependently of other Livestock_cats competing for the same(Year, Territory, Province, item_cbs)pool. Previously the cap applied to the group sum, so an individual Livestock_cat could be scaled down because of another's demand. - New parameter
prioritize_monogastric(defaultTRUE). WhenFALSE, monogastric and ruminant demand are allocated in a single combined pass through the primary hierarchy, so monogastrics no longer get first pick on scarce high-priority feed.
- Determinism: stabilised the per-group cap inside
add_alloc()so that two runs with identical inputs produce bit-identical outputs. Previously thecumsum()cap depended on arbitrary row order from upstream joins. - Fixed a local-cache bug in the priority-pool inner loop where multiple
allocations to the same
demand_idwithin one(Year, Territory)batch were silently dropped by index overwrite, allowing minor over-allocation. - Trade allocations (release pass,
allow_trade = TRUE) now correctly record the sourcing province inoriginal_Province. They previously carried the demand's own province. - Removed dead code (no-op weight refresh in
distribute_surplus(); a duplicateensure_item_metadata()call insideallocate_grouped()). - Added structural-invariant tests: determinism, supply conservation per source province, scaling-factor consistency, Zoot_fixed cap, and inter-provincial trade province tracking.
- Speed: replaced join-based updates in
add_alloc()with indexed writes (composite-key map), vectorisedreroute_excess_grass(), vectorised finalscaling_factorcomputation, short-circuiteddiag_snapshot()whenverbose = FALSE, and replaced the monogastric/ruminant%in% target_idsfilter with a pre-computed logical mask. Together these deliver ~2× speedup on the reference fixture (inst/bench/bench_redistribute_feed.R: 2.62s → 1.26s).
-
BNF functions module (
R/bnf_functions.R): 5 exported functions for biological nitrogen fixation —calc_crop_bnf(),calc_weed_bnf(),calc_nonsymbiotic_bnf(),calc_bnf(), andsummarize_bnf()— with literature-based environmental modifiers for temperature, water stress, soil organic matter, pH, and clay content. -
IPCC biomass coefficients: 6 new sheets in
Biomass_coefs.xlsxwith crop residue, root, and mapping coefficients verified against IPCC 2006 Vol.4 Ch.11 Table 11.2. -
Data-driven NPP model: NPP model coefficients extracted to Excel (
NPP_model_coefssheet).calculate_potential_npp()now reads coefficients from the data table instead of hardcoded literals. -
Simple mode for crop NPP functions:
calculate_crop_npp(),calculate_crop_residues(),calculate_crop_roots(), andcalculate_npp_dm_c_n()gain amodeparameter ("full"/"simple") that auto-detects available columns and adjusts calculations accordingly. -
Crop-group-specific residue/root helper data: new lookup tables for residue shares, weed NPP scaling, fallow cover, and root-shoot N response.
-
Feed distribution:
redistribute_feed()function for multi-level feed allocation with diagnostics, plusmax_intake_shareloaded fromLivestock_coefs.xlsx.
- Fixed crop-specific irrigation residue factor and reduced rice
HI_gap_factor. - Fixed N-input root-shoot adjustment:
calculate_crop_roots()now uses theN_input_RS_adjdata table viafindInterval()instead of ignoring it. - Added
DescToolsandzooto package dependencies (previously undeclared). - Fixed
stats::quantile()call incalculate_footprints()draught share calculation (was missing namespace prefix). - Replaced non-ASCII box-drawing characters in
redistribute_feed()diagnostics with ASCII equivalents for portable package compliance. - Fixed
%!in%operator documentation to avoid invalid Rd\namefield. - Moved unused
data.tableandreadxlfrom Imports to Suggests. - Added comprehensive
globalVariables()declarations for all NSE column names across the package (eliminates R CMD check NOTEs).
- Expanded
DATA_REFERENCE.mdto 80+ objects with IPCC and NPP sections. - Complete roxygen2 rewrite for
calculate_potential_npp()and NPP model coefficient documentation. - Added
Names_BNF,Pure_legs,NPP_model_coefs, andmax_intake_shareto pkgdown reference index.
- Removed
Filling,FillingProxy,fill_na_with_sum(migrated towhep). - Cross-repo dependency fixes and code audit.
- Added
redistribute_feed()function. - Aligned
calculate_footprints()with General reference data.