Functional Weave
Code in TypeScript

agri.stocking-rate

Stocking rate: livestock units and LU per hectare from animal numbers, by a published LU coefficient table.

1.0.1 · published 2026-10-03 by charlie · Anterra

Pinned by 17 tests, run in TypeScript, Python and Rust.

What it does

Livestock units (LU) and the stocking rate in LU per hectare, from head counts by category and a published table of livestock unit coefficients. `stockingRate("eurostat", [{category: "dairy-cows", count: 100}, {category: "bovine-1-to-2-years", count: 80}], 120)` is 156 LU, 1.3 LU/ha.

## Two tables, deliberately separate

For example

  • stockingRate(eurostat, animals ×2, 120) → livestock units 156, units per hectare 1.3, lines ×2 Eurostat: 100 dairy cows and 80 yearlings on 120 ha is 156 LU, 1.3 LU/ha
  • stockingRate(uk-countryside-stewardship, animals ×2, 40) → livestock units 56, units per hectare 1.4, lines ×2 Countryside Stewardship: 300 lowland ewes with lambs and 20 suckler cows on 40 ha
  • stockingRate(eurostat, animals ×1, 3) → livestock units 224, units per hectare 74.67, lines ×1 16,000 laying hens on 3 ha is 224 LU, 74.67 LU/ha

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

export function stockingRate(scheme: string, animals: readonly LivestockCount[], areaHectares: number): StockingRate
schemestringeurostat or uk-countryside-stewardship
animalsLivestockCount[]head counts by category of that scheme; may be empty
areaHectaresfloatthe land they are kept on, taken to 0.0001 ha (1 m²)
returnsStockingRate

The types it declares, generated into your project

/** How many animals of one category. */
export interface LivestockCount {
  /** a category code of the scheme, e.g. dairy-cows, lowland-ewe-and-lamb */
  readonly category: string;
  /** head, 0 or more */
  readonly count: number;
}

/** One category's contribution. */
export interface LivestockUnitLine {
  readonly category: string;
  readonly count: number;
  /** livestock units per head, from the table */
  readonly coefficient: number;
  /** count x coefficient, exact (to 0.001 LU) */
  readonly livestockUnits: number;
}

/** Total livestock units and the rate per hectare. */
export interface StockingRate {
  /** total, exact (to 0.001 LU) */
  readonly livestockUnits: number;
  /** total / area, rounded half up to 0.01 LU/ha */
  readonly unitsPerHectare: number;
  /** one per animals entry, in order */
  readonly lines: readonly LivestockUnitLine[];
}

Your code names it in one line, in the file that uses it

import { stockingRate } from "#fune/agri.stocking-rate@^1";
impl/typescript.ts · 40 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { roundDiv } from "./math_round_div.ts";  ← from math.round-div ^1.0.0 · built alongside by fune
import { roundFloat } from "./math_round_float.ts";  ← from math.round-float ^1.0.0 · built alongside by fune
import { LIVESTOCK_UNITS } from "./agri_stocking_rate_data.ts";  ← this capability’s own data, compiled from data/livestock-units.json into the same file by fune build
import { type LivestockCount, type LivestockUnitLine, type StockingRate } from "./agri_stocking_rate_types.ts";

const MAX_COUNT = 10000000;

/**
 * Livestock units and the stocking rate per hectare.
 *
 * Coefficients are held in thousandths of a livestock unit, so a herd's total
 * is an exact integer and only the rate per hectare is rounded. Adding float
 * coefficients drifts: 3 x 0.7 is 2.0999999999999996, which puts 3 yearlings
 * on 12 ha at 0.17 LU/ha instead of 0.18 (0.175 rounded half up).
 */
export function stockingRate(scheme: string, animals: readonly LivestockCount[], areaHectares: number): StockingRate {
  const table = LIVESTOCK_UNITS.filter((row) => row.scheme === scheme);
  if (table.length === 0) {
    throw new RangeError(`unknown scheme "${scheme}": use eurostat or uk-countryside-stewardship`);
  }
  if (typeof areaHectares !== "number" || !Number.isFinite(areaHectares) || areaHectares <= 0 || areaHectares > 1000000) {
    throw new RangeError(`areaHectares must be a finite number greater than 0 and at most 1000000, received ${areaHectares}`);
  }
  const area = Math.round(roundFloat(areaHectares, 4) * 10000);
  if (area < 1) throw new RangeError(`areaHectares must be at least 0.0001 hectares, received ${areaHectares}`);

  let total = 0;
  const lines: LivestockUnitLine[] = animals.map((animal, i) => {
    const row = table.find((r) => r.category === animal.category);
    if (!row) throw new RangeError(`unknown category "${animal.category}" in scheme ${scheme}`);
    if (typeof animal.count !== "number" || !Number.isInteger(animal.count) || animal.count < 0 || animal.count > MAX_COUNT) {
      throw new RangeError(`animal ${i + 1}: count must be a whole number from 0 to 10000000, received ${animal.count}`);
    }
    const thousandths = animal.count * row.thousandths;
    total += thousandths;
    return { category: animal.category, count: animal.count, coefficient: row.thousandths / 1000, livestockUnits: thousandths / 1000 };
  });
  // LU/ha in hundredths = (total / 1000) / (area / 10000) x 100.
  return { livestockUnits: total / 1000, unitsPerHectare: roundDiv(total * 1000, area, "half-up") / 100, lines };
}

Install

fune build

With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:

fune add agri.stocking-rate
Download for TypeScript agri.stocking-rate-1.0.1-typescript.fune · 22,416 bytes sha256 590d18dd7d931e5c680956368d15f1239e66d97cc5fcacefb9e2cf8a3dfd5c85

The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./agri.stocking-rate-1.0.1-typescript.fune, or fetch it from a terminal with fune pull agri.stocking-rate@1.0.1:typescript.

The whole function, every language, is one file too: agri.stocking-rate-1.0.1.fune, 29,126 bytes, sha256 8445c31ba2f5ec6cb65840b2379f4ef85f0522b532fb24eeb6e45dd5e6b37c21. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before agri.stocking-rate

after — your function gets the result and the arguments, and returns the final result.

// fune: after agri.stocking-rate

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

// fune: replace math.round-div in agri.stocking-rate
// fune: replace math.round-float in agri.stocking-rate

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show agri.stocking-rate --steps.

// fune: step agri.stocking-rate after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
Eurostat: 100 dairy cows and 80 yearlings on 120 ha is 156 LU, 1.3 LU/ha eurostat, animals ×2, 120 → livestock units 156, units per hectare 1.3, lines ×2
Countryside Stewardship: 300 lowland ewes with lambs and 20 suckler cows on 40 ha uk-countryside-stewardship, animals ×2, 40 → livestock units 56, units per hectare 1.4, lines ×2
16,000 laying hens on 3 ha is 224 LU, 74.67 LU/ha eurostat, animals ×1, 3 → livestock units 224, units per hectare 74.67, lines ×1
piglets at 0.027 LU each eurostat, animals ×1, 10 → livestock units 27, units per hectare 2.7, lines ×1
3 yearlings on 12 ha is 0.175, rounded up to 0.18, where float coefficients say 0.17 eurostat, animals ×1, 12 → livestock units 2.1, units per hectare 0.18, lines ×1
horses and ponies under Countryside Stewardship uk-countryside-stewardship, animals ×2, 5.5 → livestock units 4.4, units per hectare 0.8, lines ×2
the two tables differ: a goat is 0.1 LU in Eurostat, 0.12 in Countryside Stewardship eurostat, animals ×1, 10 → livestock units 5, units per hectare 0.5, lines ×1
hill ewes on rough grazing, a rate below 0.005 rounds to zero uk-countryside-stewardship, animals ×1, 100 → livestock units 0.4, units per hectare 0, lines ×1
no animals is zero eurostat, , 10 → livestock units 0, units per hectare 0, lines
a count of zero keeps its line eurostat, animals ×1, 1 → livestock units 0, units per hectare 0, lines ×1
Show the other 7 tests
CaseArgumentsExpected
the smallest area, one square metre eurostat, animals ×1, 0 → livestock units 0.1, units per hectare 1,000, lines ×1
an unknown scheme is an error defra, , 10 → error: unknown scheme "defra"
a category from the other table is an error eurostat, animals ×1, 10 → error: unknown category "lowland-ewe-and-lamb" in scheme eurostat
a negative count is an error eurostat, animals ×1, 10 → error: animal 1: count must be a whole number from 0 to 10000000
a fractional count is an error eurostat, animals ×1, 10 → error: animal 1: count must be a whole number from 0 to 10000000
zero area is an error eurostat, , 0 → error: areaHectares must be a finite number greater than 0
an area below a square metre is an error eurostat, , 0 → error: areaHectares must be at least 0.0001 hectares

More from the author

A livestock unit is a convention, not a measurement, and the published tables disagree (a goat is 0.1 LU to Eurostat and 0.12 LU to Countryside Stewardship), so the caller names the scheme and each category belongs to one:

- `eurostat`: the EU livestock unit (LSU) coefficients used in farm statistics, from the reference of a dairy cow = 1 LSU. 21 categories: bovine animals by age and type, sheep, goats, equidae, pigs, poultry, breeding rabbits. - `uk-countryside-stewardship`: the grazing livestock unit table Defra and the RPA use to set and check stocking in England's Countryside Stewardship agreements: cattle over 2 years 1.0, 6 months to 2 years 0.6, lowland ewe and lamb or ram 0.12, hill ewe and lamb, store lamb or hogg/teg 0.08, horse 1.0, pony or donkey 0.8, goat 0.12. Cattle under 6 months are not in the table, so there is no category for them.

Category codes are listed in `data/livestock-units.json`, with each row's full name and source. The data has no `effective` dates: these are reference conventions rather than rules with commencement dates, and a revised table will be published as a new version of this capability.

## Exactness

Coefficients are held in thousandths of an LU, so each line and the total are exact (0.027 LU piglets included) and only the rate per hectare is rounded, once, half up to 0.01 LU/ha. The area is taken to 0.0001 ha (1 m²). Adding float coefficients drifts: 3 x 0.7 is 2.0999999999999996, which puts three yearlings on 12 ha at 0.17 LU/ha rather than 0.18.

It does not judge whether a rate is too high: limits differ by scheme option, land type and season.

## Limits

Counts are whole numbers from 0 to 10,000,000; area more than 0 and at most 1,000,000 ha, and at least 0.0001 ha after rounding. An empty list is 0 LU.

## Sources

- Eurostat, "Glossary: Livestock unit (LSU)", https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Glossary:Livestock_unit_(LSU) (coefficients checked against the page, September 2026). - Defra and Rural Payments Agency, "Countryside Stewardship Higher Tier manual for agreements starting on 1 January 2023", Annex 8C "Convert livestock numbers into Livestock Units", https://www.gov.uk/government/publications/countryside-stewardship-higher-tier-manual-for-agreements-starting-on-1-january-2023/annex-8c-convert-livestock-numbers-into-livestock-units (the same table is Annex 6C of the Mid Tier manual).

## Notices

Contains public sector information licensed under the Open Government Licence v3.0 (https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).

Source: Eurostat; Defra and the Rural Payments Agency.

1.0.1 adds its attribution notices (NOTICE). The code and the tests are unchanged.

Files

PathBytes
NOTICE237
README.md3,102
data/livestock-units.json6,901
impl/python.py2,603
impl/rust.rs3,873
impl/typescript.ts2,336
vectors.json4,674