02 — Livestock nutrition, energy and herd review of cleaned v0.7.0

Reviewer role: ruminant nutrition / livestock systems (adversarial). Source: CIAT/cleaned @ 800d53a (read-only). How I checked it: I sourced R/feed_quality.R and R/energy_requirement.R into Rscript and ran them on inst/extdata/example_input.json. The example needed two patches before it would run (both are findings: C-01 and M-01). I reproduced the livestock-N block of R/ghg_emission.R by hand and compared it with IPCC 2006/2019 Tier 2. Scripts are in the session scratchpad (run2.R, run3.R). I did not change the source.

Verdict

The feed-demand engine has a basic unit error. It adds up IPCC net energy requirements (NEm, NEa, NEg, NEl, NEp) and divides them by the feed's metabolisable energy density. There is no km/kl/kg or REM/REG conversion anywhere. This makes energy-driven DMI about 35–50% too low for cattle, and too low by a larger margin for growth and for small ruminants. The error carries through to land requirement, enteric CH4, VS and N excretion. In the example the bias is hidden because DMI is taken as max(DMI_energy, DMI_CP) with no intake cap. For low-CP tropical diets this gives physically impossible intakes: 4.4% of body weight for a 600 kg cow on a 5.3 MJ ME/kg DM ration. In the IPCC N-excretion block, retention is in kg N/day but the code uses it as a fraction. For dairy cows it is also divided by 365 twice. So N excretion comes out 30–45% too high and N retention is effectively zero. Neither shipped example dataset runs end-to-end: the column names, the DM units and the livestock labels don't match the code. Herd dynamics (mortality, replacement, offtake) are not modelled at all. As it stands, I would not trust absolute DMI, land, CH4 or N outputs from this model. Scenario differences inherit the same biases, but less severely.

Findings table

ID Sev Verdict Location Issue
C-01 Critical CONFIRMED R/energy_requirement.R:79-128,140,170 NE requirements are divided by ME density with no NE→ME (km/kl/kg or IPCC REM/REG) conversion, so energy DMI is 50–63% of IPCC.
C-02 Critical CONFIRMED R/ghg_emission.R:226,233 N retention (kg N/d) is used as a fraction in n_intake*(1-n_retained), and dairy retention is divided by 365 twice. Nex is 31–46% too high.
H-01 High CONFIRMED R/energy_requirement.R:174,180 DMI = max(energy DMI, CP DMI) with no fill or BW cap. CP-limited diets inflate DMI, ME intake, CH4, manure and land (example cow: 26.6 kg DM/d = 4.4% BW).
H-02 High CONFIRMED R/energy_requirement.R:96-101,109; lkp_livetype Small-ruminant growth and lactation use IPCC eq 10.7/10.10 with body_weight_weaning/body_weight_year_one, which default to 0. NEg falls to a only (3–10× too low) and ewe/doe NEl falls to 0.
H-03 High CONFIRMED R/energy_requirement.R:106; R/land_productivity.R:60; example_input.json The code needs fat_milkcontent, cp_lys_pregnancy, cp_lys_growth, lw_gain_piglets, proportion_growth_piglets_milk and n_manure_content. The example, the DB and the input mappings supply fat_content, cp_pregnancy and so on, so energy_requirement() errors on the shipped example.
H-04 High CONFIRMED R/ghg_emission.R:226 Growth N retention divides NEg (MJ/d) by WG in kg/yr (not kg/d). The 7.03·NEg/WG term shrinks about 365×, so protein in gain is about 268 g/kg instead of about 185 g/kg.
H-05 High CONFIRMED R/energy_requirement.R:198-212 vs R/ghg_emission.R:233 There are two independent manure-N pathways. N balance uses manure DM × 0.029 (with manure DM = 0.365 × DMI); GHG uses the IPCC Nex. For the example cow the N balance gets 0 kg collected manure N while GHG gets 89 kg N/yr.
M-01 Medium CONFIRMED R/feed_quality.R:44; example_input.json; data/mufindi.rda The example lacks crop_name, so unnest() errors. The example DM is a fraction (0.3) where the DB/contract use % (87). Concentrate dm_content = 0 removes it from the diet. mufindi labels ("Cows (high productive)") don't match the class vectors, so Cfi comes out NA.
M-02 Medium CONFIRMED lkp_livetype (cleaned.sqlite) me_* columns The DB carries an ME-based requirement system (me_maintenance 60.6 MJ/d for a 600 kg cow, me_lactmilk 5.5, me_growth 50 MJ/kg). The code ignores it, and hard-codes pig growth at 45 and pig pregnancy at 171.
M-03 Medium CONFIRMED R/ghg_emission.R:206-229 n_intake is herd total (from herd-level GE); n_retained is per animal. They are mixed whenever herd_composition > 1.
M-04 Medium CONFIRMED R/land_productivity.R:55-56 Meat = herd LWG × carcass fraction. Growth of retained replacements counts as meat; culled adults, mortality and offtake are ignored. There is no herd model.
M-05 Medium CONFIRMED R/energy_requirement.R:133,142-144 Ewe/doe CP: cp_lactation (2 × cp_maint × lactation length) is added and annual_milk × cp_lactmilk, so lactation protein is counted twice when milk is recorded.
M-06 Medium CONFIRMED lkp_feeditem (cleaned.sqlite) Implausible feed library values: Brachiaria CP = ME (7.25/7.25), oat straw CP 0, lupin ME 19 and groundnut kernel ME 21.2 MJ/kg DM (de_fraction > 1), maize stover ME 9.13, sweet-potato tuber (fresh) DM 59%.
M-07 Medium CONFIRMED ../cleaned/data/ilri_feed_db.xlsx sheet ilri_feed_db 995 rows (3.1% of ME rows) have ME > 16 alongside IVDMD < 20, so the ME and IVDMD columns are swapped. DM is on a lab (air-dry) basis, median 91%.
M-08 Medium PLAUSIBLE R/energy_requirement.R:92,110,134,141 Pig "CP" fields in the DB look like lysine-scale values (sow cp_maintenance 0.030 kg/d) but are compared against feed CP%. The pig growth value of 45 MJ/kg gain looks like a total ME:gain that already includes maintenance.
M-09 Medium CONFIRMED R/energy_requirement.R:146-185 Requirements are spread pro rata over seasons, and the feed basket is always assumed to meet them. There is no availability check, no deficit or liveweight loss, and no seasonal milk variation.
L-01 Low CONFIRMED R/energy_requirement.R:190-191 sum(x, na.omit=TRUE) is not na.rm: it adds 1 to each total and does not drop NAs (verified: dmi_cp_total = dmi_tot + 1).
L-02 Low CONFIRMED R/energy_requirement.R:94 "Steers/heifers" and "Calves" use C = 1.0 (castrate). Heifers should use 0.8, so NEg is about 15% low for heifers.
L-03 Low CONFIRMED R/energy_requirement.R:117 Pregnancy uses Cpregnancy = 0.10 for all non-pig classes. IPCC gives sheep/goats 0.077 (single) and 0.126 (twins).
L-04 Low PLAUSIBLE R/energy_requirement.R:84,86,100 Sheep Ca for housed ewes is 0.0096 (IPCC 2006 Table 10.5: 0.0090). Goat grazing uses 0.019 and lambs use a = 2.3, b = 0.4; I could not match either to IPCC.
L-05 Low CONFIRMED R/energy_requirement.R:109 Eq 10.10 uses the weaning weight, where IPCC uses the lamb's gain from birth to weaning (about 15–25% high). Litter size is ignored.
L-06 Low CONFIRMED R/land_productivity.R:60-62 Milk protein and energy are applied to FPCM rather than raw milk (+5.8% in the example). The cow FPCM formula is applied to goat and sheep milk too. The merge_outputs.R:457 fallback uses per-animal milk.
L-07 Low CONFIRMED R/merge_outputs.R:530 vs R/differences.R:196 Adult-male-equivalent days are computed with 2500 kcal in one file and 2100 kcal in the other.
L-08 Low CONFIRMED R/energy_requirement.R:33,167 Season shares use a fixed 365 days, so they are not normalised when season lengths don't sum to 365. season_length() handles only 2 seasons, has an off-by-one, and is unused.

Counts: Critical 2, High 5, Medium 9, Low 8.

Detailed findings

C-01 NE requirements met with ME (no efficiency conversion). Critical, CONFIRMED

C-02 IPCC N retention used as a fraction and double-annualised. Critical, CONFIRMED

H-01 DMI = max(energy DMI, CP DMI), uncapped. High, CONFIRMED

H-02 Small-ruminant growth and lactation silently collapse with default weights. High, CONFIRMED

H-03 Column contract broken between the code and every data source. High, CONFIRMED

H-04 Growth N retention unit error. High, CONFIRMED

H-05 Two inconsistent manure-N estimates. High, CONFIRMED

M-01 Shipped examples are not runnable, and their units are inconsistent. Medium, CONFIRMED

M-02 ME requirement data in the DB bypassed. Medium, CONFIRMED

M-03 Herd vs per-animal mixing in N. Medium, CONFIRMED

M-04 No herd dynamics; meat from LWG. Medium, CONFIRMED

M-05 Small-ruminant lactation CP double-counted. Medium, CONFIRMED

M-06 Feed library (cleaned.sqlite lkp_feeditem) plausibility. Medium, CONFIRMED

M-07 ILRI and ERA libraries (parent repo data/). Medium, CONFIRMED

M-08 Pig protein and growth basis. Medium, PLAUSIBLE

M-09 No seasonal feed balance. Medium, CONFIRMED (design)

Low items (brief)

Done well

Open questions for authors

  1. Was the NE-divided-by-ME approach deliberate (e.g. inherited from the CLEANED Excel tool), and was it ever benchmarked (auxilary_info/CLEANED_benchmark_RGQ.xlsx)?
  2. Is feed_basket.allocation meant to be % as fed or % DM? The code treats it as as-fed (fraction_as_fed). App users usually think in DM.
  3. Is annual_milk offtake milk or total yield? Suckling calves' milk intake isn't credited in the calves' energy balance.
  4. Where do the pig 45 MJ/kg and 171 MJ values, the goat Ca of 0.019, and the lamb a = 2.3, b = 0.4 come from?
  5. Are the pig cp_* fields CP or lysine?
  6. Which renaming layer (app side?) maps fat_content → fat_milkcontent and similar, and why does the package ship an example that fails?
  7. Should there be a DMI cap and explicit deficit reporting instead of max(E, CP)?

Comments

Comments are GitHub Discussions on peetmate/cleaned-review; sign in with GitHub to post.