From a9acf198d1da07d671ccc6a5819925dfd56dca32 Mon Sep 17 00:00:00 2001 From: Sven Verweij <37927107+SvenVw@users.noreply.github.com> Date: Wed, 17 Sep 2025 10:40:35 +0200 Subject: [PATCH 1/4] fix: dividing by 0 error at nitrogen balance calculation when b_lu_hi is undefined or 0 --- .changeset/pink-readers-serve.md | 5 ++ .../emission/ammonia/residues.test.ts | 54 +++++++++++++++++++ .../nitrogen/emission/ammonia/residues.ts | 8 +++ .../balance/nitrogen/removal/residue.test.ts | 36 +++++++++++++ .../src/balance/nitrogen/removal/residue.ts | 8 +++ 5 files changed, 111 insertions(+) create mode 100644 .changeset/pink-readers-serve.md diff --git a/.changeset/pink-readers-serve.md b/.changeset/pink-readers-serve.md new file mode 100644 index 000000000..9f478a798 --- /dev/null +++ b/.changeset/pink-readers-serve.md @@ -0,0 +1,5 @@ +--- +"@svenvw/fdm-calculator": patch +--- + +Fix dividing by 0 error at nitrogen balance calculation when b_lu_hi is undefined or 0 diff --git a/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts b/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts index c8e356235..81f9247db 100644 --- a/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts +++ b/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts @@ -258,4 +258,58 @@ describe("calculateNitrogenEmissionViaAmmoniaByResidues", () => { { id: "cultivation1", value: expect.any(Decimal) }, ]) }) + + it("should return 0 when b_lu_hi is 0", () => { + const cultivations: FieldInput["cultivations"] = [ + { + b_lu: "cultivation1", + b_lu_catalogue: "catalogue1", + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), + m_cropresidue: true, + }, + ] + const harvests: FieldInput["harvests"] = [ + { + b_id_harvesting: "harvest1", + b_lu: "cultivation1", + b_lu_harvest_date: new Date(), + harvestable: { + b_id_harvestable: "harvestable1", + harvestable_analyses: [ + { + b_lu_yield: 1000, + b_lu_n_harvestable: 20, + }, + ], + }, + }, + ] + const cultivationDetailsMap = new Map([ + [ + "catalogue1", + { + b_lu_catalogue: "catalogue1", + b_lu_croprotation: "cereal", + b_lu_yield: 1000, + b_lu_n_harvestable: 20, + b_lu_hi: 0, + b_lu_n_residue: 14, + b_n_fixation: 0, + }, + ], + ]) + + const result = calculateNitrogenEmissionViaAmmoniaByResidues( + cultivations, + harvests, + cultivationDetailsMap, + ) + + //Check for approximation due to floating point + expect(result.total.toNumber()).toBeCloseTo(0, 2) + expect(result.cultivations).toEqual([ + { id: "cultivation1", value: expect.any(Decimal) }, + ]) + }) }) diff --git a/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.ts b/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.ts index 243c58718..190480573 100644 --- a/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.ts +++ b/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.ts @@ -97,6 +97,14 @@ export function calculateNitrogenEmissionViaAmmoniaByResidues( const b_lu_hi = new Decimal(cultivationDetail.b_lu_hi ?? 0) const b_lu_hi_res = new Decimal(1).minus(b_lu_hi) + // If cultivation has no residues possible return 0 + if (b_lu_hi.isZero()) { + return { + id: cultivation.b_lu, + value: new Decimal(0), + } + } + // Get the Nitrogen content of the crop residues const b_lu_n_residue = new Decimal( cultivationDetail.b_lu_n_residue ?? 0, diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts index 5159ba4a5..8b1f9732c 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts @@ -17,6 +17,18 @@ describe("calculateNitrogenRemovalByResidue", () => { b_n_fixation: 0, }, ], + [ + "catalogue2", + { + b_lu_catalogue: "catalogue1", + b_lu_croprotation: "quinoa", + b_lu_yield: 1000, + b_lu_n_harvestable: 20, + b_lu_hi: 0, + b_lu_n_residue: 2, + b_n_fixation: 0, + }, + ], ]) it("should return 0 if no crop residues are left", () => { @@ -216,4 +228,28 @@ describe("calculateNitrogenRemovalByResidue", () => { expect(result.total.toNumber()).toBeCloseTo(-3) //Approximation due to floating point expect(result.cultivations[0].value.toNumber()).toBeCloseTo(-3) //Approximation due to floating point }) + + it("should return 0 if b_lu_hi is 0", () => { + const cultivations: FieldInput["cultivations"] = [ + { + b_lu: "cultivation1", + b_lu_catalogue: "catalogue2", + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), + m_cropresidue: true, + }, + ] + const harvests: FieldInput["harvests"] = [] + + const result = calculateNitrogenRemovalByResidue( + cultivations, + harvests, + cultivationDetailsMap, + ) + + expect(result).toEqual({ + total: new Decimal(0), + cultivations: [{ id: "cultivation1", value: new Decimal(0) }], + }) + }) }) diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.ts index 1784dad53..17dc5f8eb 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.ts @@ -101,6 +101,14 @@ export function calculateNitrogenRemovalByResidue( cultivationDetail.b_lu_n_residue ?? 0, ) + // If cultivation has no residues possible return 0 + if (b_lu_hi.isZero()) { + return { + id: cultivation.b_lu, + value: new Decimal(0), + } + } + // Calculate the amount of Nitrogen removed by crop residues of this cultivation const removal = b_lu_yield .dividedBy(b_lu_hi) From 0ab0e17c47a25c790ffa35b17493f6055b258745 Mon Sep 17 00:00:00 2001 From: Sven Verweij <37927107+SvenVw@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:09:27 +0200 Subject: [PATCH 2/4] fix: type conversion --- fdm-calculator/src/balance/nitrogen/removal/residue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.ts index 17dc5f8eb..fc42a0d22 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.ts @@ -75,7 +75,7 @@ export function calculateNitrogenRemovalByResidue( // Fallback to default yield from cultivation_catalogue if (yieldForThisHarvest === null) { - yieldForThisHarvest = cultivationDetail.b_lu_yield + yieldForThisHarvest = new Decimal(cultivationDetail.b_lu_yield ?? 0) } if (yieldForThisHarvest !== null) { From bff49f4858329b83eeebd0a0dc97cefd77930c3d Mon Sep 17 00:00:00 2001 From: Sven Verweij <37927107+SvenVw@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:12:32 +0200 Subject: [PATCH 3/4] nitpicks --- .changeset/pink-readers-serve.md | 2 +- .../src/balance/nitrogen/emission/ammonia/residues.test.ts | 4 ++-- fdm-calculator/src/balance/nitrogen/removal/residue.test.ts | 2 +- fdm-calculator/src/balance/nitrogen/removal/residue.ts | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.changeset/pink-readers-serve.md b/.changeset/pink-readers-serve.md index 9f478a798..6b5eee0a9 100644 --- a/.changeset/pink-readers-serve.md +++ b/.changeset/pink-readers-serve.md @@ -2,4 +2,4 @@ "@svenvw/fdm-calculator": patch --- -Fix dividing by 0 error at nitrogen balance calculation when b_lu_hi is undefined or 0 +Fix divide-by-zero in nitrogen balance when b_lu_hi is undefined or 0 diff --git a/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts b/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts index 81f9247db..ccf294294 100644 --- a/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts +++ b/fdm-calculator/src/balance/nitrogen/emission/ammonia/residues.test.ts @@ -307,9 +307,9 @@ describe("calculateNitrogenEmissionViaAmmoniaByResidues", () => { ) //Check for approximation due to floating point - expect(result.total.toNumber()).toBeCloseTo(0, 2) + expect(result.total.equals(new Decimal(0))).toBe(true) expect(result.cultivations).toEqual([ - { id: "cultivation1", value: expect.any(Decimal) }, + { id: "cultivation1", value: new Decimal(0) }, ]) }) }) diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts index 8b1f9732c..dc4ceca38 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts @@ -20,7 +20,7 @@ describe("calculateNitrogenRemovalByResidue", () => { [ "catalogue2", { - b_lu_catalogue: "catalogue1", + b_lu_catalogue: "catalogue2", b_lu_croprotation: "quinoa", b_lu_yield: 1000, b_lu_n_harvestable: 20, diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.ts index fc42a0d22..195c690b5 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.ts @@ -75,7 +75,9 @@ export function calculateNitrogenRemovalByResidue( // Fallback to default yield from cultivation_catalogue if (yieldForThisHarvest === null) { - yieldForThisHarvest = new Decimal(cultivationDetail.b_lu_yield ?? 0) + yieldForThisHarvest = new Decimal( + cultivationDetail.b_lu_yield ?? 0, + ) } if (yieldForThisHarvest !== null) { @@ -123,7 +125,7 @@ export function calculateNitrogenRemovalByResidue( } }) - // Aggregate the total maount of Nitrogen removed by crop residues + // Aggregate the total amount of Nitrogen removed by crop residues const totalValue = removalsResidue.reduce((acc, residue) => { return acc.add(residue.value) }, new Decimal(0)) From 3b0576bebc27366a0f417847f34e9e5f8fb23364 Mon Sep 17 00:00:00 2001 From: Sven Verweij <37927107+SvenVw@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:47:34 +0200 Subject: [PATCH 4/4] Bump version number --- .changeset/pink-readers-serve.md | 5 ----- fdm-calculator/CHANGELOG.md | 6 ++++++ fdm-calculator/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/pink-readers-serve.md diff --git a/.changeset/pink-readers-serve.md b/.changeset/pink-readers-serve.md deleted file mode 100644 index 6b5eee0a9..000000000 --- a/.changeset/pink-readers-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@svenvw/fdm-calculator": patch ---- - -Fix divide-by-zero in nitrogen balance when b_lu_hi is undefined or 0 diff --git a/fdm-calculator/CHANGELOG.md b/fdm-calculator/CHANGELOG.md index 2925c69a6..0242e3290 100644 --- a/fdm-calculator/CHANGELOG.md +++ b/fdm-calculator/CHANGELOG.md @@ -1,5 +1,11 @@ # fdm-calculator +## 0.6.1 + +### Patch Changes + +- a9acf19: Fix divide-by-zero in nitrogen balance when b_lu_hi is undefined or 0 + ## 0.6.0 ### Minor Changes diff --git a/fdm-calculator/package.json b/fdm-calculator/package.json index a8124aa51..b24fc9b1d 100644 --- a/fdm-calculator/package.json +++ b/fdm-calculator/package.json @@ -1,7 +1,7 @@ { "name": "@svenvw/fdm-calculator", "private": false, - "version": "0.6.0", + "version": "0.6.1", "description": "Calculate various insights based on the Farm Data Model", "license": "MIT", "homepage": "https://github.com/SvenVw/fdm",