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 { type SeedRate } from "./agri_seed_rate_types.ts";
/**
* Seed rate (kg/ha) = target plants/m² x TGW (g) / expected establishment (%).
*
* The TGW is taken to the centigram and the establishment is in basis points,
* so kg/ha is exactly plants x centigrams / basis points and is rounded once.
* Doing it in floats gets 100 x 1.15 / 100 = 1.1499999999999999, which rounds
* to 1.1 kg/ha instead of 1.2.
*/
export function seedRate(targetPlantsPerSquareMetre: number, thousandGrainWeightGrams: number, establishmentBasisPoints: number): SeedRate {
const plants = targetPlantsPerSquareMetre;
if (typeof plants !== "number" || !Number.isInteger(plants) || plants < 1 || plants > 100000) {
throw new RangeError(`targetPlantsPerSquareMetre must be a whole number from 1 to 100000, received ${plants}`);
}
const tgw = thousandGrainWeightGrams;
if (typeof tgw !== "number" || !Number.isFinite(tgw) || tgw <= 0 || tgw > 1000) {
throw new RangeError(`thousandGrainWeightGrams must be a finite number greater than 0 and at most 1000, received ${tgw}`);
}
const centigrams = Math.round(roundFloat(tgw, 2) * 100);
if (centigrams < 1) {
throw new RangeError(`thousandGrainWeightGrams must be at least 0.01 grams, received ${tgw}`);
}
const bp = establishmentBasisPoints;
if (typeof bp !== "number" || !Number.isInteger(bp) || bp < 1 || bp > 10000) {
throw new RangeError(`establishmentBasisPoints must be a whole number from 1 to 10000, received ${bp}`);
}
return {
kgPerHectare: roundDiv(plants * centigrams * 10, bp, "half-up") / 10,
seedsPerSquareMetre: roundDiv(plants * 100000, bp, "half-up") / 10,
};
}