KiwiFert turns published New Zealand fertiliser practice into a recommendation for one point on a map. This note sets out exactly how — what comes from a workbook, what comes from a soil map, what the application itself contributes, and where each of those is likely to be wrong. Nothing here is hidden inside the code: if you disagree with a coefficient, it is on the Parameters tab and you can change it.
1What this is, and what it is not
The application answers one question: given this block, this crop and this rotation, what would typical New Zealand practice put on, and what mass of each element does that amount to? It is a structured lookup with site adjustment, not a mechanistic model. There is no soil chemistry solver, no plant growth model, no leaching simulation and no economics.
Three claims it does make, and can defend:
- The published practice is reproduced faithfully. Where the source workbook gives an application event, KiwiFert re-derives every nutrient in it from the product analysis and the product rate. Across all 466 events and 855 nutrient figures, the largest discrepancy between the re-derivation and the workbook is 0.05 kg/ha — rounding, nothing more. You can run this check yourself: open the calculator, open the browser console, and type
KF.selfTest(). - Every co-delivered nutrient is counted. Superphosphate applied for phosphorus also delivers sulphur and calcium; DAP applied for phosphorus also delivers nitrogen; muriate of potash applied for potassium also delivers 46 % chloride. A budget that counts only the nutrient you were aiming at will over-apply the others, and that is precisely the error the source workbook was built to prevent.
- Every number carries its provenance. Each site variable is labelled KiwiMap, entered, estimated or soil test; each coefficient names the sheet, the regulation or the fact that KiwiFert invented it.
This is not a fertiliser recommendation. The source workbooks describe typical commercial practice, not what any particular block needs. A real recommendation comes from a soil test, a herbage or leaf test, and a nutrient budget for that block, interpreted by someone who has stood on it. The Fertiliser Association of New Zealand Code of Practice for Nutrient Management is the governing document. Treat KiwiFert as a way of seeing the arithmetic quickly and consistently, and of asking better questions of a real adviser.
2The data the model rests on
Four sources, three of them workbooks compiled from published New Zealand industry guidance, one of them a spatial data application.
| Source | What it supplies | Rows |
|---|---|---|
| NZ fertilisation and liming schedules | Nutrient rates by plant type; one row per fertiliser application event, keyed to rotation and phase; the liming schedule; fertiliser product analyses; soil order adjustments; trace elements | 51 plant types, 466 events, 27 liming rows, 43 products, 15 soil orders, 10 trace elements |
| NZ agricultural and forestry rotations | Rotations and their phases — species, timing, duration, expected yield, and the link to the plant nutrient database | 45 rotations, 175 phases |
| NZ plant nutrient database | Yield ranges, dry matter content, harvest index, and nutrient concentration on two bases — removed in harvest, and whole above-ground plant | 194 plant types × 19 elements × 2 bases |
| KiwiMap | Soil order and subgroup, pH, cation exchange capacity, carbon, drainage, texture, depth, bypass flow, land use, land cover, ecological district, nine climate variables, 65-element soil geochemistry | Read at a point, from national rasters on a 100 m grid |
The workbooks are converted to JavaScript by scripts/extract.py, which writes the files in data/. Nothing in data/ is hand-edited: if a figure is wrong, the spreadsheet is corrected and the script is re-run. The join keys are exact string matches and all of them resolve — 175 of 175 phase links land on a plant database row, 51 of 51 rate rows land on a plant database row, and 32 of 33 named products in the schedule land on a product row (the thirty-third is the sentinel “No fertiliser applied”).
Units, and why they are the ones they are. Macronutrient concentrations in the plant database are g kg−1 of dry matter, which is numerically identical to kg per tonne of dry matter and to ten times the percentage. That identity is why removal falls straight out of a multiplication with no conversion factor: a pasture at 40 g N kg−1 DM cut at 15 t DM ha−1 removes 600 kg N ha−1. Micronutrients are mg kg−1 (= ppm), so the same multiplication gives g ha−1. Phosphorus and potassium are elemental throughout, following New Zealand soil test convention, not the P2O5 and K2O of fertiliser labels; the oxide equivalents are shown alongside on the budget tab (P × 2.291, K × 1.205).
3Reading the site from KiwiMap
A click on the map projects the latitude and longitude to NZTM2000 (EPSG:2193) and reads one full-resolution pixel from each of nineteen national rasters plus sixteen geochemistry bands, using HTTP Range requests against Cloud-Optimized GeoTIFFs. KiwiFert does not reimplement any of this: it loads KiwiMap's own libraries and its cog-layer.js, and calls KiwiMap's CogRenderer.readValue(). If KiwiMap's pipeline is re-run with better data, KiwiFert reads the better data with no change.
Provenance, and the order of precedence
Every site variable resolves through one function, and the order never varies:
- A laboratory soil test, where one has been entered. A measured pH replaces the modelled pH everywhere in the calculation.
- A value typed into the Site table, which overrides the map for that variable only.
- The value KiwiMap read at the point.
- Nothing — in which case the calculation that needed it is not performed, and says so, rather than substituting a national average.
The soil order join
KiwiMap's legend labels the raster “Brown Soils”, “Podzols”, “Allophanic Soils”; the workbook keys on “Brown”, “Podzol”, “Allophanic”. The mapping is an explicit table in js/lookup.js (SOIL_ORDER_FROM_MAP), not a string transformation, so a legend change breaks loudly rather than silently. Six map units carry no soil at all — lake, estuary, river bed, quarry, permanent ice, urban area — and the application says so and makes no soil-order adjustment.
Rainfall: the one estimated variable
KiwiMap carries wet days, not rainfall depth. Two parts of the calculation need annual rainfall — the sulphur leaching term and the lime longevity formula — so where no rainfall has been entered, KiwiFert estimates it as
rainfall (mm) = wet days (≥1 mm) × rainfallPerWetDay (default 9.5 mm)
This is a crude proxy. Mean wet-day intensity in New Zealand varies from about 6 mm in inland Otago to well over 15 mm on the West Coast, so a single national coefficient will be wrong by tens of percent in both directions. The estimate is labelled estimated everywhere it appears and raises a note on the Recommendation tab. If either the sulphur rate or the lime interval matters to you, type the real annual rainfall from the nearest climate station. Extending KiwiMap with a rainfall surface would remove this weakness entirely and is the single largest available improvement to the model.
Geochemistry is evidence, not a rate
Fourteen elements from the national geochemical survey are read and shown: B, Co, Cu, Mn, Mo, Se, Zn, P, S, K, Ca, Mg, Na and Fe, as total soil concentration in mg kg−1. Total concentration is not plant availability — a soil can carry 1300 mg kg−1 of total phosphorus and still have an Olsen P of 8. These values never enter a rate calculation. They are there to support or contradict a deficiency flag, and to give a sense of the geochemical setting.
4The baseline nutrient rate
The Nutrient rates by plant type sheet gives, for each of 51 land uses, a low–high range of typical New Zealand practice for N, P, K, S, Ca and Mg, and a typical single-application rate for the trace elements. The basis differs by crop and is stated on the row: per year for perennials and pasture, per crop for annuals, per rotation for forestry.
KiwiFert positions itself within that range with a single dial:
basee = lowe + (highe − lowe) × ratePosition (default 0.5)
A position of 0 applies the low end of every range, which suits an extensive block, a low yield target, or a nitrogen-sensitive catchment. A position of 1 applies the high end, which suits an irrigated high-production system. The default of 0.5 is the midpoint and carries no more authority than that.
Where a range starts at zero, zero is a real answer. Pulses need no nitrogen, and a well-clovered sheep and beef pasture may need none either. Crops in the workbook's Legume and Pulse groups have their nitrogen zeroed outright unless nApplyToLegumes is turned on. Note that this test is on the crop group, not the crop name: a ryegrass/white clover pasture has “clover” in its name and is emphatically not a legume stand — it is the most nitrogen-fertilised land use in the country.
5Soil and climate adjustment
The published rate is a national figure. Four multiplicative factors move it towards the site. Each is computed once and then used in both calculation modes — multiplying the annual target in one, and multiplying the product rate of each application event in the other.
Phosphorus: anion storage capacity
fP = MASC(soil order)
Straight from the Soil order adjustments sheet, with Pallic as the reference at 1.0. Allophanic and Oxidic soils are 1.6; Granular and Podzol 1.4; Ultic 1.3; Pumice 1.2; Brown 1.1. The physical basis is phosphate retention: it takes about 11 kg P ha−1 to lift Olsen P by one unit on an Allophanic soil against about 5 kg on a Pallic one, because allophane and ferrihydrite adsorb phosphate on the same sites that make those soils well-structured. Set pSoilOrderMultiplier to 0 to switch this off.
The compensation. A high-ASC soil holds a large slow-release reserve. Withhold P from a well-supplied Allophanic soil and production holds for at least five years; withhold it from a Pallic soil and pasture production declines immediately. The multiplier is about the cost of building the reserve, not the cost of maintaining production.
Potassium: weatherable reserve
fK = CK(soil order K reserve class)
The workbook states the reserve as a word — very low, low, moderate, moderate to high, high — and KiwiFert turns that word into a number using four editable factors (kReserveVeryLow 1.30, kReserveLow 1.15, kReserveModerate 1.00, kReserveHigh 0.85). A compound class such as “moderate to high” is read as the mean of its two neighbours rather than needing a parameter of its own. These four numbers are KiwiFert's, not the workbook's, and are the sort of thing to argue with.
Cation exchange capacity from KiwiMap enters separately, and only as a splitting rule: below kCecSplitThreshold (12 cmol(+) kg−1) the threshold at which a potassium dressing is split in two is halved, because a soil with little exchange capacity cannot hold a large dressing against leaching.
Sulphur: leaching class and water through the profile
fS = CS(leaching class) × [1 + sRainfallSlope × (R + I − sRainfallRef) / 100] for R + I > sRainfallRef
where R is annual rainfall and I applied irrigation. The class factors run from 0.85 (low — Allophanic, Oxidic and Granular soils, which retain sulphate on the same sites that hold phosphate) to 1.30 (very high — Podzol and Raw). The rainfall term adds three percent per 100 mm above 1000 mm, the threshold the workbook itself uses when it describes sulphur leaching as a problem “in >1000 mm rainfall”. Both the class factors and the slope are KiwiFert's.
The factor raises the rate. It does not choose the product, and on a high-leaching soil the product choice matters more: sulphate-S is immediately available and immediately leachable, while elemental sulphur must be oxidised by Thiobacillus over three to nine months before a plant can use it. Elemental sulphur cannot rescue a deficiency that is showing now; sulphate-S can. A high-leaching site wants both forms, and that decision is left to the user.
Nitrogen: growth potential from temperature
fN = clamp(1 + nTempSlope × (T − nTempOptimum), 1 ± nTempClamp)
T is the mean annual air temperature at the point. The reference of 13 °C is roughly the mean annual temperature of the Waikato and coastal Canterbury dairy country the published rates were written for; the slope is 3 % per degree, bounded at ±20 %. This is a first-order growth-potential scaler and nothing more.
It is applied to pasture, herb, forage and legume rows only. An arable or horticultural nitrogen rate is set by the yield target and by growth-stage timing — urea split at Zadoks GS30 and GS32–37, side-dressing at maize V6–V8 — and scaling those by a site mean temperature would be a fiction. Set nTempSlope to 0 to disable the term entirely.
After adjustment, nitrogen on pastoral land is capped at nCapPastoral (190 kg N ha−1 yr−1). That is a regulatory ceiling, not an agronomic one — see section 11.
What is deliberately not adjusted. Calcium and magnesium from fertiliser carry no site factor: calcium is dominated by lime, which is calculated separately and properly, and magnesium is a soil-test and animal-health decision the workbook does not model spatially. Drainage, texture, depth, bypass flow, carbon, solar radiation, humidity, wind and frost days are read, reported and used to raise cautions, but do not scale any rate. Inventing a coefficient for each of them would add precision without accuracy.
6Capital phosphorus
Maintenance phosphorus replaces what the crop removes and what the soil fixes. Capital phosphorus is different: it is the investment that moves a block from below its target Olsen P into the target range. The two are budgeted separately because they behave differently — maintenance is an annual cost, capital is a one-off with a multi-year payback.
Capital P is calculated only when an Olsen P has been entered. Without a soil test the application gives maintenance only and says so, because there is no honest way to guess where a block sits.
target = bandlo + (bandhi − bandlo) × p
deficit = target − measured Olsen P
capital P (kg ha−1) = deficit × KOlsen(soil order)
years = ⌈ capital P / pCapitalMaxPerYear ⌉
The band is the workbook's Olsen P target for that soil order, chosen by land use: the pastoral column for dairy, sheep and beef and deer, the cropping and horticulture column otherwise. KOlsen is the workbook's kilograms of P per Olsen unit for that order — 5 on Pallic and Recent, 7 on Brown and Pumice, 11 on Allophanic and Oxidic, 12 on Organic.
The position p within the band is olsenTargetPosition (default 0.5), except on a soil the workbook classes as low or very low P retention, where it is olsenTargetPositionLowASC (default 0.25). That distinction is the workbook's own note 6: low-ASC soils — Pallic, Recent, Raw, Semiarid — are where applied phosphorus is most likely to reach water, so the advice on them is to target the lower end of the range, not the upper.
Worked. A Waikato Allophanic block growing potatoes, measured Olsen P 22. The cropping band for Allophanic soils is 30–45, so the target at position 0.5 is 37.5. The deficit is 15.5 Olsen units. At 11 kg P per unit that is 171 kg P ha−1 — which at the 60 kg default limit is spread over three years at 57 kg P ha−1 yr−1, on top of maintenance. On a Pallic soil the same 15.5-unit deficit would cost 78 kg P ha−1. That difference — the same soil test result implying a fertiliser bill more than twice as large — is the single most important thing the soil order does in this model.
7Lime, and the acidity the fertiliser itself creates
Liming is calculated from the Liming schedule sheet, which gives a target pH band, a trigger pH, capital and maintenance rates, an interval, a timing and an incorporation note for each of 27 land uses. Where no liming row covers a crop, the crop's own target pH from the Nutrient rates sheet is used with the generic soil-order arithmetic.
Crops that must not be limed
Three land uses are flagged calcifuge and never receive lime — blueberries, plantation forestry, and manuka. Blueberries want pH 4.5–5.5; liming a blueberry block is one of the most expensive and slowest-to-reverse mistakes in New Zealand horticulture. Radiata pine is well adapted to acid soils and liming a stand can induce boron, zinc and manganese deficiency and disturb the mycorrhizal association. For blueberries above pH 5.5 the application calculates an acidification requirement in elemental sulphur instead, at roughly 1 t ha−1 of the 90 % product per pH unit.
Capital lime
Capital lime is calculated only when the current pH is below the trigger:
target pH = bandlo + (bandhi − bandlo) × limeTargetPosition
ΔpH = target pH − current pH
lime (t ha−1) = ΔpH × Torder × (d / limeReferenceDepth) × (limeReferenceNV / limeProductNV)
Torder is the workbook's tonnes of lime to raise pH one unit on that soil order, taken from the Soil order adjustments sheet: 9–10 t ha−1 on Pallic, 10–11 on Brown, 13–15 on Allophanic, and 7–17 on Organic. Using that column directly is preferable to the more familiar rule of thumb (1 t ha−1 of good lime lifts pH by 0.1 in the top 75 mm), because the column already carries the buffering differences between orders that the rule of thumb averages away.
Two corrections follow:
- Depth. The published rates act over the top 75 mm, the depth the target pH is quoted at. Some crops need the pH corrected deeper — lucerne wants 6.2–6.4 through 150 mm, asparagus is incorporated to 250–300 mm — so more lime is needed. The depth is parsed out of the liming row's own text, so it cannot drift away from the source. The correction is bounded at
limeDepthFactorMax(default ×2). Scaling linearly with depth assumes the subsoil is as acid and as strongly buffered as the topsoil, which it usually is not, and which the published capital rates flatly contradict: a straight-line reading would put asparagus at 3.7 times the surface rate against a published pre-plant range of 4–6 t ha−1. When the bound bites, the recommendation says so and reports the unbounded figure alongside. - Grade. New Zealand agricultural limestone runs 60–90 % CaCO3 by region. A low-grade rock needs proportionally more tonnage for the same pH effect, and the rate is scaled by the ratio of the reference neutralising value to the one you will actually buy.
The result is split into applications of at most limeMaxPerApplication (5 t ha−1), except on Organic soils where the workbook's own peat capital range applies and is much larger. Where the calculated figure falls outside the published capital range for that land use, the application says so — that is a prompt to confirm the pH with a laboratory test before spending the money, not a sign that the arithmetic is wrong.
How long a dressing lasts
life (yr) = a(rate) − limeLifeRainfallCoef × (R + I)
with a = 7 for a 1.25 t ha−1 dressing, 9 for 2.5, and 11 for 5.0, and the coefficient 0.0012 yr per mm. This is the liming sheet's own note 2. At 1200 mm a 2.5 t ha−1 dressing lasts about 7.6 years.
Maintenance, and the acidity the programme creates
Nitrogen fertiliser acidifies. The Fertiliser products sheet gives the lime needed to neutralise each kilogram of nitrogen applied: about 1.8 kg for urea and the urea-based and ammonium phosphate products, about 5.4 kg for ammonium sulphate, and effectively zero for calcium ammonium nitrate. KiwiFert computes
acidification (t ha−1 yr−1) = N target × acid coefficient / 1000
and reports the larger of that figure and the published maintenance rate as the maintenance lime requirement. The two are not added: the published maintenance rate is typical practice on land already carrying a typical nitrogen programme, so adding them would double-count. Maintenance is an annual figure and is deliberately kept out of the one-off capital requirement.
A long-running ammonium sulphate programme carries a lime bill that is easy to overlook: at 5.4 kg lime per kg N, a 150 kg N ha−1 programme needs 810 kg lime ha−1 yr−1 just to stand still. The same nitrogen as urea needs 270 kg.
8Targets into products
There are two ways to get from a nutrient target to a bag of fertiliser, and KiwiFert uses whichever the selection implies.
8a. Rotation mode — the workbook's own events
With a rotation chosen, the programme is the Schedule by rotation phase sheet filtered to that rotation: real application events, in the months and at the growth stages New Zealand practice actually uses. Each event is scaled as follows.
- Identify the nutrient the product was bought for. A phosphate-group product is bought for P, a nitrogen-group product for N, a trace-element carrier for whichever trace element it carries at the highest analysis, and so on. The mapping is a table in
js/lookup.js. - Scale the product rate by the site factor for that nutrient. Superphosphate on an Allophanic soil is scaled by fP = 1.6, so 389 kg ha−1 becomes 622 kg ha−1.
- Recompute every nutrient from the scaled product rate and the product analysis. That 622 kg of superphosphate delivers 56.0 kg P, 68.5 kg S and 124.5 kg Ca. The sulphur and calcium rise with the phosphorus because that is what physically happens when you spread more of the same product — and this is exactly the arithmetic the workbook used to derive its own co-delivered nutrient columns, which is why at a scale factor of 1.000 the recomputation reproduces the sheet to the decimal place.
- Count the repeats. The sheet's Applies within the phase column distinguishes a one-off establishment dressing from one that repeats every year of a multi-year phase, and marks alternative crop options that are not additive. An annual dressing in an eight-year pasture phase is one row carrying ×8, not eight rows; alternative options are excluded from the totals unless
includeAlternativesis turned on.
One place the source contradicts itself
The mid-rotation forestry nitrogen dressings are marked “every year of the phase”, while the note on the same row says nitrogen is “applied once or at most a few times in a 25–30 year rotation” and the Forest Owners Association source gives an estate-wide average of about 8 kg N ha−1 yr−1. Read literally, Douglas fir's 25-year growth phase would carry 3750 kg N ha−1.
KiwiFert resolves this in favour of the note: in the Forestry sector, a nitrogen product marked “every year of the phase” is counted forestryNitrogenApplications times (default 1), the affected row says so on hover, and the parameter restores the literal reading if you disagree. It applies to nitrogen products only, and only in that sector: the annual superphosphate and selenium prill in the silvopastoral rotation are the pasture programme running underneath the trees and are genuinely annual. With the default, radiata pine comes to 650 kg N ha−1 over a 28-year rotation (23 kg ha−1 yr−1), which is three dressings — “a few times”.
The general safeguard against this class of error is a cross-check between the two sheets. After the programme is built, the whole-cycle total for nitrogen, phosphorus and potassium is compared against the published envelope for the selected plant type, scaled to the cycle length. A disagreement of more than a factor of two raises a flag. The two sheets are independent compilations of the same practice, so a gross mismatch means one of them is being read wrongly — or, just as often, that the rotation spends most of its cycle growing something other than the plant type you selected.
One event in the rotation programme is not from the workbook: where a soil test shows the block below its Olsen P target, the capital phosphorus programme is added at the front of the rotation, labelled as KiwiFert's addition. The event schedule describes typical practice and cannot contain a soil-test answer, so without this the capital requirement would appear in the target table and never reach the programme, the totals or the budget.
The rotation programme will not match the annual target table exactly, and should not. The targets come from the annual rate sheet for one land use; the programme comes from the event schedule across every phase of the rotation, including the phases growing something else entirely. They are two views of the same practice. A large gap between them is a question worth asking, not an error to fix.
8b. Annual mode — a solved product basket
Without a rotation, KiwiFert solves a basket against the adjusted targets, sequentially, in the order P, K, S, Mg, N:
residuale = targete − already suppliede
product rate = residuale / (analysise / 100)
supplied += rate × analysis / 100, for every element in the product
The order is not arbitrary. Co-delivery runs one way: superphosphate brings sulphur and calcium with the phosphorus, DAP brings nitrogen with the phosphorus, sulphate of potash brings sulphur with the potassium. Solving phosphorus first means the sulphur step only has to supply what is left; solving nitrogen first would over-apply everything downstream of it. Where a step's target is already met by co-delivery, the application says so explicitly rather than leaving a blank row.
The product for each step is read from the crop's own row — “Triple super pre-plant plus DAP starter”, “Sulphate of potash, incorporated pre-plant” — by matching the prose against the product table, longest and most specific alias first. Where the prose names no stocked product (“Up to 30 kg K/ha down the spout”), a sensible default is substituted and the substitution is reported. For a chloride-sensitive crop the potassium default is sulphate of potash rather than muriate.
Dressings are then split: nitrogen at nMaxSingleDressing (50 kg N ha−1), potassium at kSplitAboveKg (50 kg K ha−1, halved on a low-CEC soil). Splitting is why the timing summary on the crop row matters: the number of dressings is arithmetic, but when they go on is agronomy.
Trace elements
Trace elements listed on the crop's own row are delivered from the carriers named in the Trace elements sheet — granular borate for boron, sodium selenate prill for selenium, cobalt sulphate for cobalt, sodium molybdate for molybdenum.
Trace elements that the soil order is flagged for, but the crop row does not list, are shown as advice and are never added to the programme or the totals. The workbook's flag is a possibility, not a prescription: Allophanic soils are flagged “Mo (clover), occasionally B and Cu”, and Gley soils are flagged for manganese and iron excess rather than deficiency. Adding 2 kg B ha−1 to a dairy pasture on the strength of the word “occasionally” would be both wrong and, for boron, unsafe. The flag is surfaced with the workbook's own wording, the critical test value and the caution, and the decision is left where it belongs.
9Total mass applied per hectare
Every application event carries a product rate and a product analysis, so the mass of each element follows directly:
macronutrient (kg ha−1) = product rate (kg ha−1) × analysis (%) / 100
trace element (g ha−1) = product rate × analysis / 100 × 1000
These are summed over the whole programme, with each event multiplied by its repeat count, to give the mass per rotation cycle. Dividing by the cycle length gives the annual figure. Sixteen elements are tracked — N, P, K, S, Ca, Mg, Na and Cl in kg ha−1; B, Zn, Cu, Mo, Se, Co, Mn and Fe in g ha−1 — and oxide equivalents are shown alongside for the elements whose labels use them.
Lime is reported separately, in three places. Its calcium load dwarfs everything else — a 5 t ha−1 dressing of agricultural lime delivers 1900 kg Ca ha−1, against perhaps 200 kg ha−1 from a year of superphosphate — so folding it into one column would make every other calcium figure invisible. The annual maintenance lime is included in the combined annual total; the one-off capital dressing is shown in its own column, because averaging a one-off over a rotation would misrepresent both.
Read the chloride row. Muriate of potash at 150 kg K ha−1 also delivers about 276 kg Cl ha−1; sulphate of potash delivers none. That is the whole argument for using the more expensive product on potatoes, onions and berries, and it is only visible if you count the chloride.
10Removal and the balance
The other half of a nutrient budget is what leaves. This comes from the plant nutrient database, and the units make the arithmetic trivial:
harvested DM (t ha−1) = yield × (dry matter basis ? 1 : DM% / 100)
removal (kg ha−1) = concentration (g kg−1 DM) × harvested DM (t ha−1)
removal (g ha−1) = concentration (mg kg−1 DM) × harvested DM (t ha−1)
The database quotes pasture, forage crops and forestry as dry matter and everything else as fresh weight as harvested, and says which on every row, so the conversion is never guessed.
Two concentration bases, and when to use which
Each plant row carries concentrations on two bases. Removed in harvest is the concentration in the fraction that physically leaves — grain, tuber, bulb, fruit, seed, cut herbage, stemwood plus bark. Whole above-ground plant includes the residues left in situ: straw, stover, tops, prunings, leaf fall.
KiwiFert uses the removed basis when residueRetained is 1, and the whole-plant basis applied to total above-ground biomass when it is 0. The difference is largest for potassium, which is overwhelmingly returned in cereal straw rather than exported in grain: baling the straw off a wheat crop turns a small potassium export into a large one, and that single switch is worth more to a potassium budget than any coefficient in section 5.
Grazing returns: uptake is not export
For grazed pasture, herbage uptake is not farm export. Grazing animals return roughly 70–95 % of what they eat to the same paddock in dung and urine — redistributed unevenly, and concentrated in camps and laneways. Net export is the small fraction retained in liveweight, milk, wool and velvet, plus leaching, runoff and gaseous loss. KiwiFert applies
net exporte = uptakee × (1 − grazingReturnFraction) (default 0.85)
to every element, macro and trace, on rows the database marks as grazed. The source database quotes the return range for nitrogen, phosphorus, potassium and sulphur; the same fraction is used for calcium, magnesium, sodium, chloride and the trace elements, which animals also excrete far more of than they retain. It is a single coefficient, so it is rougher for calcium, which a milking herd retains more of than the others. Cut-and-carry silage and hay are listed as separate rows in the database and do remove the full herbage load — which is why a silage paddock and a grazed paddock on the same farm need different potassium budgets.
Removal through a rotation
With a rotation selected, removal is computed phase by phase: each phase's own species, its own published yield, its own duration. A yield quoted per year applies for every year of the phase; a yield quoted per phase is the whole phase already. The phase totals are summed to give whole-cycle export, and divided by the cycle length for the annual figure.
Why this matters more than it looks. The rotations workbook makes the point directly: a fertilisation calculator built on annual averages will systematically mis-set inputs in any rotation carrying a legume or pasture phase. The pasture phase in a Canterbury mixed-cropping rotation banks nitrogen that the following wheat crop spends. Fertilise that wheat as though the pasture never happened and you will over-apply by 100–150 kg N ha−1 and leach the difference. KiwiFert does not model the nitrogen carry-over — no simple model can — but by presenting the phases in sequence with their own removal it at least makes the omission visible rather than burying it in an average.
The balance
balancee = appliede + maintenance limee − removede
A positive balance builds soil reserves, or is lost to water and air. A negative balance mines them. Neither is automatically wrong: a capital phosphorus programme is deliberately positive, and a well-supplied Allophanic soil can run a negative phosphorus balance for five years with no production penalty at all. What matters is that the sign is the one you intended, and that you know how long you can hold it.
11Ceilings and cautions
Three limits are hard, in the sense that exceeding them is a regulatory or toxicological problem rather than an agronomic judgement.
| Limit | Value | Basis |
|---|---|---|
| Synthetic nitrogen on pastoral land | 190 kg N ha−1 yr−1 | Resource Management (National Environmental Standards for Freshwater) Regulations 2020. Applies both to each individual hectare of pasture and to the average across all pastoral land use on the farm. Dairy farmers report annually by 31 July for the year to 30 June. |
| Selenium | 20 g Se ha−1 | Narrowest margin between deficiency and toxicity of anything applied to New Zealand pasture. Double-dosing through both fertiliser and animal treatment is the usual way it is exceeded. |
| Boron ahead of a cereal | 3 kg B ha−1 | A corrective 3 kg B ha−1 is safe for a brassica; 6 kg will damage a cereal following in the same rotation. |
The selenium ceiling is enforced in the calculation, not merely reported: a target above it is clamped. The other two raise flags.
Softer cautions are raised for: chloride on a chloride-sensitive crop; low anion storage capacity with phosphorus applied, where loss to water is most likely; poorly drained soil, where drainage is the first fertiliser decision and denitrification removes nitrogen before the crop sees it; molybdenum applied without copper, since herbage Mo above about 3 mg kg−1 DM induces secondary copper deficiency in cattle and deer; high pH on a Melanic soil, where over-liming rather than acidity is the risk; a calculated lime rate outside the published capital range; and any element delivered far past its own target by co-delivery.
Data-quality flags are raised for a missing soil order, a missing pH, an estimated rainfall, and the absence of a soil test. These are not decoration. An answer computed without a soil test is a different kind of object from one computed with one, and the application should say so every time.
12Where the model is weakest
In rough order of how much damage each could do:
- The soil test is usually missing. Without an Olsen P there is no capital phosphorus calculation at all, and the maintenance rate is a national typical figure rather than anything about this block. This dominates every other source of error.
- KiwiMap's pH is modelled, not measured. The layer is a quantile regression forest prediction on a 100 m grid. Lime is the most pH-sensitive output in the whole application — a 0.2 pH unit error on an Allophanic soil is 2.8 t ha−1 of lime — so a laboratory pH on a real sample changes the answer more than any coefficient here.
- Rainfall is estimated from wet days. See section 3. Affects the sulphur rate and the lime interval.
- The K, S and N adjustment factors are KiwiFert's, not the workbook's. The workbook states these as classes; turning a class into a number is an interpolation this application makes. They are the coefficients most worth challenging, and they are all on the Parameters tab.
- Tissue concentrations are central estimates. They vary with cultivar, growth stage at harvest, season, soil supply and fertiliser history. Luxury uptake of potassium alone can double the tabulated value on a high-K soil. Silicon, aluminium and chloride are the weakest columns in the database and should be treated as indicative only.
- Rotations are modal, not prescriptive. Real farms vary the sequence with soil type, irrigation, contract availability and season.
- Nothing carries nitrogen over between phases. The pasture-to-wheat nitrogen credit, the pulse-to-cereal credit and the residual value of an effluent block are all real and all absent. This is the largest structural omission in the model.
- No economics. The economically optimal rate is almost always below the agronomically maximal one, and it moves with both the product price and the commodity price.
13Parameter reference
Every coefficient the model uses, its default, and where the default comes from. A source of KiwiFert means the application introduced that number: it is an interpretation, not a published figure, and it is the kind you should feel free to change. All of these are editable on the Parameters tab, and a saved scenario records only the ones you changed — so a scenario saved today picks up a corrected default tomorrow.
| Parameter | Default | Unit | Source |
|---|---|---|---|
The table is built from the same file the application reads (js/params.js), so it cannot drift out of step with the code. If it has not appeared, JavaScript is disabled — the same list is on the calculator's Parameters tab. | |||
14A worked example
A Waikato dairy block at 37.43997 °S, 175.78125 °E, growing the default rotation D1 (permanent ryegrass/white clover pasture with periodic renewal, 10-year cycle), with every parameter at its default and no soil test entered.
Step 1 — the site, read from KiwiMap
| Variable | Value | Variable | Value |
|---|---|---|---|
| Soil order | Allophanic | Mean annual air temperature | 14.0 °C |
| Soil pH (0–10 cm) | 5.37 | Wet days | 143 yr−1 |
| Cation exchange capacity | 25.9 cmol(+) kg−1 | Rainfall (estimated) | 1359 mm |
| Soil carbon | 3.00 % | PED | 80 mm |
| Drainage / texture / depth | Well drained / silty / deep | Land use (2020) | Grassland – high producing |
Step 2 — the factors
fP = 1.600 (Allophanic, very high P retention). fK = 0.925 (K reserve “moderate to high”, read as the mean of the moderate and high factors). fS = 0.850 × 1.108 = 0.941 (low leaching class, then +10.8 % for 359 mm of rainfall above the 1000 mm reference). fN = 1.030 (14.0 °C against the 13 °C reference, at 3 % per degree).
Step 3 — the targets
| Element | Published range | Base at position 0.5 | Factor | Target |
|---|---|---|---|---|
| N | 100–190 | 145.0 | ×1.030 | 149.4 |
| P | 30–45 | 37.5 | ×1.600 | 60.0 |
| K | 0–80 | 40.0 | ×0.925 | 37.0 |
| S | 30–50 | 40.0 | ×0.941 | 37.7 |
| Ca | 60–100 | 80.0 | ×1.000 | 80.0 |
| Mg | 0–30 | 15.0 | ×1.000 | 15.0 |
All in kg ha−1 yr−1. Nitrogen at 149.4 sits below the 190 cap, so no clamping. Selenium comes through from the crop row at 10 g ha−1. Boron, copper and molybdenum are flagged as possible deficiencies on Allophanic soils and appear as advice only.
Step 4 — lime
The liming row for permanent ryegrass/white clover pasture gives a target band of 5.8–6.0 and a trigger of 5.6. At position 0.5 the target is pH 5.90, and the current 5.37 is below the trigger, so capital lime is due: ΔpH = 0.53, at 14 t ha−1 per pH unit on Allophanic soil, with no depth or grade correction, gives 7.41 t ha−1 — split into two dressings of 3.70 t ha−1, each lasting about 7.4 years at 1359 mm of rainfall. That is above the published capital range of 2.5–5.0 t ha−1, so the application flags it: confirm the pH with a real sample before spending it.
Maintenance is the larger of the published 400–625 kg ha−1 yr−1 (midpoint 513) and the acidification the nitrogen programme creates (149.4 kg N × 1.8 kg lime kg N−1 = 269), so 513 kg ha−1 yr−1.
Step 5 — the programme
Fifteen application events across the three phases of D1. The annual maintenance dressing of single superphosphate is the one to watch: the workbook's 389 kg ha−1 is scaled by fP = 1.6 to 622 kg ha−1, delivering 56.0 kg P, 68.5 kg S and 124.5 kg Ca — and the sulphur and calcium come with it whether they were wanted or not.
Step 6 — totals and balance
| Element | Applied, kg ha−1 yr−1 | From maintenance lime | Net export | Balance |
|---|---|---|---|---|
| N | 121.3 | – | 86.3 | +35.0 |
| P | 53.6 | – | 8.2 | +45.4 |
| K | 37.0 | – | 65.3 | −28.3 |
| S | 60.9 | – | 7.3 | +53.6 |
| Ca | 205.2 | 194.8 | 11.5 | +388.5 |
| Mg | 20.2 | – | 4.5 | +15.7 |
| Cl | 34.0 | – | 26.4 | +7.6 |
Three things in that table are worth a postgraduate's attention.
The nitrogen balance of +35 is not a soil accumulation. Grazed pasture returns most ingested nitrogen to the paddock as urine, and urine patches are the dominant nitrate leaching pathway in New Zealand pastoral systems — so a modest positive balance on paper can coexist with substantial loss to water. The balance is a mass-conservation statement, not an environmental one.
The potassium balance of −28 is real and is what the workbook predicts: the published potassium range starts at zero and rises only where silage is cut, so a maintenance-only programme on a grazed platform runs a potassium deficit that the soil reserve absorbs. On an Allophanic soil with moderate-to-high reserve that is sustainable for some years; on a Pumice soil, with essentially no weatherable potassium, it is not.
The sulphur balance of +54 is co-delivery. Nobody chose to apply 61 kg S ha−1; it arrived inside the superphosphate bought for phosphorus. On a low-leaching Allophanic soil most of it stays put, which is fine; on a Podzol it would be gone by spring, which is why the same programme on the West Coast wants an elemental sulphur component instead.
15For whoever maintains this
The application is plain HTML, CSS and JavaScript — no framework, no build step, no external requests, no dependencies beyond KiwiMap's vendored libraries. It will still work in ten years.
| File | What lives there |
|---|---|
scripts/extract.py | Reads the three .xlsx workbooks and writes data/*.js. Re-run it after any spreadsheet change: python3 scripts/extract.py (needs openpyxl). |
data/*.js | Generated. Never hand-edited. Each file extends one global, KF_DATA. |
js/params.js | Every coefficient, with its default, unit, help text and source. Adding a parameter here makes it appear on the Parameters tab and in the table in section 13 automatically. |
js/lookup.js | Indexes and joins, plus the two mapping tables that are not in the workbooks: KiwiMap soil-order label → workbook soil order, and plant type → liming row. |
js/model.js | The calculation. Touches no DOM; can be driven from the console. Its nine sections correspond one-to-one with sections 3 to 11 of this document. |
js/kiwimap.js | The KiwiMap picker map. Reading the point is done by the site's shared reader, ../ks-kiwimap.js, which loads KiwiMap's libraries and manifest, re-bases its paths and reads the point for every tool on the site. |
js/scenario.js | Scenario JSON: format, versioning, save, load, autosave. |
js/contaminants.js | Cadmium, uranium and fluorine added with phosphate fertiliser, and the years to each threshold (section 16). Touches no DOM. |
js/app.js | Everything that touches the DOM. One renderer per tab. |
scripts/check_contaminants_vs_tutor.js | Checks section 16's arithmetic against the Numerical Tutor's cadmium question: node kiwifert/scripts/check_contaminants_vs_tutor.js from the site root. |
../scripts/kiwiscience_server.py | The site's local server, with HTTP Range support, serving the whole KiwiScience folder so KiwiFert can see the KiwiMap folder and the shared site files. Open KiwiScience.command wraps it for Finder, and Open KiwiFert.command hands over to it with KiwiFert already open. |
To change a coefficient, edit js/params.js. Do not type a constant into js/model.js: the Parameters tab, the scenario file and section 13 of this document are all generated from the parameter list, and a hard-coded number is invisible to all three.
To add a site variable, add it to QUERY_PLAN in ../ks-kiwimap.js, read it in Model.deriveSite(), and add it to SITE_FIELDS in js/app.js so it becomes editable.
To check the model against the workbook, open the calculator and run KF.selfTest() in the browser console. It re-derives every nutrient figure in all 466 application events from the product analyses and reports the largest discrepancy. Anything above about 0.1 kg ha−1 means a product analysis has changed and the arithmetic no longer reconciles.
16Contaminants in phosphate fertiliser
Phosphate rock carries cadmium, uranium and fluorine, and they come onto the block with the phosphorus. The Contaminants tab works out how much the programme adds each year, what the soil holds now, and how many years of the same programme it takes to reach each threshold that applies. The arithmetic lives in js/contaminants.js.
The phosphorus that carries them
Only phosphorus from products made from phosphate rock is counted: the superphosphates, the ammonium phosphates, reactive phosphate rock, the potash supers and the compound blends. It is summed over the programme as in section 9 and divided by the cycle length. Organic P sources (blood and bone, compost, effluent) are left out. They carry their own contaminants, which a mg-per-kg-P figure for rock phosphate does not describe.
The mass balance
This is the calculation the Numerical Tutor teaches in Cadmium: years to a threshold, line for line, so that a student who works the question by hand gets the number the tool prints:
added (g ha−1 yr−1) = P applied (kg ha−1 yr−1) × content (mg kg−1 P) / 1000
soil mass (t ha−1) = 10 000 m2 × depth (m) × bulk density (t m−3)
now (g ha−1) = soil mass × current concentration (mg kg−1 = g t−1)
at the threshold (g ha−1) = soil mass × threshold (mg kg−1)
years = (at the threshold − now) / added, rounded up
The result is rounded up because the threshold is first exceeded during that year. scripts/check_contaminants_vs_tutor.js draws problems from the tutor's own generator and confirms the two give the same answer. At its last run, all 5 000 matched, with no difference in the unrounded years. Run it after changing either file.
It is a straight accumulation. Everything added stays in the layer: nothing leaves by plant offtake, leaching or erosion, and nothing arrives from lime, biosolids or the atmosphere. Offtake and leaching remove a little cadmium each year, so the years shown are the shortest plausible time, not a forecast. That is the right side to err on for a screening figure, and it is what the tutor teaches.
The inputs, and where their defaults come from
| Input | Default | Source |
|---|---|---|
| Cd in the fertiliser | 280 mg Cd/kg P | The New Zealand fertiliser industry's voluntary upper limit, which is also the figure in the tutor's Unit 4 slides. It gives the fastest accumulation a compliant product allows. Enter the supplier's declared figure for the product actually used. |
| U and F in the fertiliser | none (0 = not entered) | Neither KiwiFert nor KiwiChem holds a figure. Without one, uranium and fluorine are not accumulated. For scale, superphosphate is often quoted at 1.5–2 % F, about 170 000–220 000 mg F/kg P at 9 % P. |
| Accumulation depth | 75 mm pastoral; 150 mm cultivated | The Tiered Fertiliser Management System's sampling depths: 0–75 mm screening samples for pasture, where unploughed soil keeps fertiliser cadmium near the surface, and 0–150 mm definitive samples for cultivated soil. Whether the block is pastoral follows the plant type. |
| Bulk density | 1.0 t/m3 | KiwiFert's choice for a pasture topsoil. Allophanic and pumice soils run nearer 0.7 t/m3 (less soil, so each threshold is reached sooner). Enter a measured value. |
The soil now is, in order of preference: a value typed into the tab; the KiwiMap geochemistry at the point read on the Site tab; KiwiChem's New Zealand background median (0.08 mg Cd kg−1 nationally). The KiwiMap value is the GNS Geochemical Atlas interpolated from 676 samples over 2–20 cm. That is a regional estimate rather than a paddock measurement, and a deeper layer than the 75 mm pasture sample. Fertiliser cadmium concentrates at the surface, so on long-fertilised pasture a soil test of the top 75 mm is likely to read higher, and it should be entered when there is one.
The thresholds
| Element | Threshold | mg/kg | Where it comes from |
|---|---|---|---|
| Cd | TFMS Tier 1 | 0.6 | Tiered Fertiliser Management System, NZ Cadmium Management Strategy. Each tier restricts the choice and rate of phosphate fertiliser further; at Tier 4 no further accumulation is allowed without a site-specific investigation. Held in js/contaminants.js, because these are industry triggers, not soil guideline values, and KiwiChem does not carry them. |
| TFMS Tier 2 | 1.0 | ||
| TFMS Tier 3 | 1.4 | ||
| TFMS Tier 4 | 1.8 | ||
| Rural residential / lifestyle block | 0.8 | KiwiChem soil guideline values: the MfE Soil Contaminant Standards (rural residential, 25 % home-grown produce; residential, 10 %) and the Eco-SGV for agricultural land. Read from KiwiChem's API when the tab opens. The residential values are there because farmland is subdivided, and a soil that passes as pasture can fail as a house section with a vegetable garden. | |
| Eco-SGV, agricultural land | 1.5 | ||
| Residential | 3 | ||
| U | CCME agricultural (Canada) | 23 | KiwiChem holds no New Zealand value for uranium; the Canadian agricultural guideline is the nearest it has. |
| F | none | KiwiChem holds neither a soil guideline value nor a New Zealand background for fluorine, so the tab shows the annual addition only. | |
A worked example
This uses the tutor's slide figures: pasture receiving 50 kg P ha−1 a year at 280 mg Cd kg−1 P, onto 75 mm of soil at 1.0 t m−3 that starts at the national background of 0.08 mg kg−1. That adds 50 × 280 / 1000 = 14 g Cd ha−1 yr−1 to 10 000 × 0.075 × 1.0 = 750 t of soil, which holds 750 × 0.08 = 60 g now.
| Threshold | mg/kg | g/ha at the threshold | (threshold − now) / added | Years |
|---|---|---|---|---|
| TFMS Tier 1 | 0.6 | 450 | (450 − 60) / 14 = 27.86 | 28 |
| Rural residential | 0.8 | 600 | (600 − 60) / 14 = 38.57 | 39 |
| TFMS Tier 2 | 1.0 | 750 | (750 − 60) / 14 = 49.29 | 50 |
| TFMS Tier 3 | 1.4 | 1050 | (1050 − 60) / 14 = 70.71 | 71 |
| Eco-SGV, agricultural | 1.5 | 1125 | (1125 − 60) / 14 = 76.07 | 77 |
| TFMS Tier 4 | 1.8 | 1350 | (1350 − 60) / 14 = 92.14 | 93 |
| Residential | 3 | 2250 | (2250 − 60) / 14 = 156.43 | 157 |
The depth matters as much as the rate. Mixed through 150 mm instead of 75 mm, the same programme takes twice as long to reach every threshold.
Sources for the Tiered Fertiliser Management System tiers and sampling depths: Abraham (2018), New Zealand Journal of Agricultural Research; Sneath (2020) and Stafford (2014), Fertiliser and Lime Research Centre workshop papers, Massey University; the Cadmium Management Group's guidance published by MPI.
Prepared for KiwiScience postgraduate students. The three source workbooks were compiled in August 2026 from published New Zealand industry guidance; see Data sources & terms for the full reference list and for the limits on what any of this may be used for.