From f19238b63e74c240ecc4fb66d414328e30a82691 Mon Sep 17 00:00:00 2001 From: Sven Verweij <37927107+SvenVw@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:08:29 +0200 Subject: [PATCH 1/2] fix: calculation of crop residue biomass at nitrogen balance calculation --- .changeset/sour-kings-drive.md | 5 +++++ fdm-calculator/src/balance/nitrogen/removal/residue.ts | 1 + fdm-calculator/src/balance/nitrogen/volatization/residues.ts | 1 + 3 files changed, 7 insertions(+) create mode 100644 .changeset/sour-kings-drive.md diff --git a/.changeset/sour-kings-drive.md b/.changeset/sour-kings-drive.md new file mode 100644 index 000000000..539094931 --- /dev/null +++ b/.changeset/sour-kings-drive.md @@ -0,0 +1,5 @@ +--- +"@svenvw/fdm-calculator": patch +--- + +Fix calculation of crop residue biomass at nitrogen balance calculation diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.ts index 6b7e276f0..1784dad53 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.ts @@ -103,6 +103,7 @@ export function calculateNitrogenRemovalByResidue( // Calculate the amount of Nitrogen removed by crop residues of this cultivation const removal = b_lu_yield + .dividedBy(b_lu_hi) .times(b_lu_hi_res) .times(b_lu_n_residue) .dividedBy(new Decimal(1000)) // Convert from g N / ha to kg N / ha diff --git a/fdm-calculator/src/balance/nitrogen/volatization/residues.ts b/fdm-calculator/src/balance/nitrogen/volatization/residues.ts index 5e14c2901..9c77afa09 100644 --- a/fdm-calculator/src/balance/nitrogen/volatization/residues.ts +++ b/fdm-calculator/src/balance/nitrogen/volatization/residues.ts @@ -111,6 +111,7 @@ export function calculateNitrogenVolatizationViaAmmoniaByResidue( // Calculate the amount of Nitrogen volatilized by crop residues of this cultivation const removal = b_lu_yield + .dividedBy(b_lu_hi) .times(b_lu_hi_res) .times(b_lu_n_residue) .times(emissionFactor) From a088e0d7482a588c5523f76c422377c8372d8941 Mon Sep 17 00:00:00 2001 From: Sven Verweij <37927107+SvenVw@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:29:28 +0200 Subject: [PATCH 2/2] test: update values for change in calculation and add required parameters --- .../balance/nitrogen/removal/index.test.ts | 8 +++- .../balance/nitrogen/removal/residue.test.ts | 37 +++++++++++-------- .../nitrogen/volatization/residues.test.ts | 18 +++++++-- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/fdm-calculator/src/balance/nitrogen/removal/index.test.ts b/fdm-calculator/src/balance/nitrogen/removal/index.test.ts index e374db633..e94388580 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/index.test.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/index.test.ts @@ -9,6 +9,8 @@ describe("calculateNitrogenRemoval", () => { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", m_cropresidue: true, + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), }, ] const harvests: FieldInput["harvests"] = [ @@ -45,9 +47,9 @@ describe("calculateNitrogenRemoval", () => { cultivationDetailsMap, ) - expect(result.total.toNumber()).toBeCloseTo(-21.2) // -20 from harvest + -1.2 from residue + expect(result.total.toNumber()).toBeCloseTo(-23) // -20 from harvest + -3 from residue expect(result.harvests.total.toNumber()).toBeCloseTo(-20) - expect(result.residues.total.toNumber()).toBeCloseTo(-1.2) + expect(result.residues.total.toNumber()).toBeCloseTo(-3) }) it("should handle cases with no harvests or residues", () => { @@ -56,6 +58,8 @@ describe("calculateNitrogenRemoval", () => { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", m_cropresidue: false, + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), }, ] const harvests: FieldInput["harvests"] = [] diff --git a/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts b/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts index 4a209c52c..5159ba4a5 100644 --- a/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts +++ b/fdm-calculator/src/balance/nitrogen/removal/residue.test.ts @@ -24,7 +24,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: false, // No residue left }, ] @@ -47,7 +48,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: true, }, ] @@ -74,8 +76,8 @@ describe("calculateNitrogenRemovalByResidue", () => { cultivationDetailsMap, ) - expect(result.total.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point - expect(result.cultivations[0].value.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point + 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 calculate nitrogen removal for multiple harvests, averaging yields", () => { @@ -83,7 +85,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: true, }, ] @@ -108,8 +111,8 @@ describe("calculateNitrogenRemovalByResidue", () => { cultivationDetailsMap, ) - expect(result.total.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point - expect(result.cultivations[0].value.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point + 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 handle missing harvest data using cultivation defaults", () => { @@ -117,7 +120,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: true, }, ] @@ -129,8 +133,8 @@ describe("calculateNitrogenRemovalByResidue", () => { cultivationDetailsMap, ) - expect(result.total.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point - expect(result.cultivations[0].value.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point + 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 handle missing cultivation details and throw an error", () => { @@ -138,7 +142,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: true, }, ] @@ -161,7 +166,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: undefined, // Undefined residue handling }, ] @@ -184,7 +190,8 @@ describe("calculateNitrogenRemovalByResidue", () => { { b_lu: "cultivation1", b_lu_catalogue: "catalogue1", - // b_lu_start: new Date(), + b_lu_start: new Date("2022-01-01"), + b_lu_end: new Date("2022-12-31"), m_cropresidue: true, }, ] @@ -206,7 +213,7 @@ describe("calculateNitrogenRemovalByResidue", () => { cultivationDetailsMap, ) - expect(result.total.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point - expect(result.cultivations[0].value.toNumber()).toBeCloseTo(-1.2) //Approximation due to floating point + expect(result.total.toNumber()).toBeCloseTo(-3) //Approximation due to floating point + expect(result.cultivations[0].value.toNumber()).toBeCloseTo(-3) //Approximation due to floating point }) }) diff --git a/fdm-calculator/src/balance/nitrogen/volatization/residues.test.ts b/fdm-calculator/src/balance/nitrogen/volatization/residues.test.ts index 208e7796d..790821ac4 100644 --- a/fdm-calculator/src/balance/nitrogen/volatization/residues.test.ts +++ b/fdm-calculator/src/balance/nitrogen/volatization/residues.test.ts @@ -24,6 +24,8 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { { 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, }, ] @@ -50,7 +52,7 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { ) //Check for approximation due to floating point - expect(result.total.toNumber()).toBeCloseTo(-2.688, 2) + expect(result.total.toNumber()).toBeCloseTo(-6.72, 2) expect(result.cultivations).toEqual([ { id: "cultivation1", value: expect.any(Decimal) }, ]) @@ -61,6 +63,8 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { { 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, }, ] @@ -102,7 +106,7 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { ) //Check for approximation due to floating point - expect(result.total.toNumber()).toBeCloseTo(-2.688, 2) + expect(result.total.toNumber()).toBeCloseTo(-6.72, 2) expect(result.cultivations).toEqual([ { id: "cultivation1", value: expect.any(Decimal) }, ]) @@ -113,6 +117,8 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { { 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, }, ] @@ -135,6 +141,8 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { { 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: false, }, ] @@ -170,6 +178,8 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { { 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: undefined, // Undefined residue handling }, ] @@ -206,6 +216,8 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { { 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, }, ] @@ -241,7 +253,7 @@ describe("calculateNitrogenVolatizationViaAmmoniaByResidue", () => { cultivationDetailsMap, ) - expect(result.total.toNumber()).toBeCloseTo(-2.688, 1) + expect(result.total.toNumber()).toBeCloseTo(-6.72, 1) expect(result.cultivations).toEqual([ { id: "cultivation1", value: expect.any(Decimal) }, ])