From 0256ee64173a0c34c767a8fce54c8fe11e3bb97d Mon Sep 17 00:00:00 2001 From: Dean Holzworth Date: Mon, 25 Aug 2025 13:42:59 +1000 Subject: [PATCH 1/2] Adjusted PAW calculation to be same as APSIM. --- API/API.csproj | 2 +- API/Services/Extensions.cs | 6 ++++-- API/Services/SoilServices.cs | 22 +++++++++------------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/API/API.csproj b/API/API.csproj index ec2e97f..a565daf 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -15,7 +15,7 @@ - + diff --git a/API/Services/Extensions.cs b/API/Services/Extensions.cs index ff0611d..32e704f 100644 --- a/API/Services/Extensions.cs +++ b/API/Services/Extensions.cs @@ -202,7 +202,7 @@ public static Graph ToGraph(this Models.Soil soil, double[] thickness = null, sw = sw.ConvertGravimetricToVolumetric(bdMapped).ToArray(); } // Map water to bottom of profile. - sw = Soil.SWMappedTo(sw, thickness, soil.Water.Thickness, ll); + sw = Soil.SWMappedTo(sw, thickness, soil.Water.Thickness, soil.Water.LL15, ll, soil.Water.DUL); // Calculate plant available water. paw = SoilUtilities.CalcPAWC(soil.Water.Thickness, ll, sw, xf) @@ -213,8 +213,10 @@ public static Graph ToGraph(this Models.Soil soil, double[] thickness = null, double pawc = SoilUtilities.CalcPAWC(soil.Water.Thickness, ll, soil.Water.DUL, Enumerable.Repeat(1.0, ll.Count).ToArray()) .Multiply(soil.Water.Thickness).Sum(); + // To stop the sw line crossing over ll, constrain it to ll. + var swConstainedToLL = sw.LowerConstraint(ll); return SoilGraph.Create(soil.Name, soil.Water.Thickness.ToMidPoints(), soil.Water.AirDry, soil.Water.LL15, - soil.Water.DUL, soil.Water.SAT, ll, cropName, pawc, paw, thickness?.ToMidPoints(), sw); + soil.Water.DUL, soil.Water.SAT, ll, cropName, pawc, paw, thickness?.ToMidPoints(), swConstainedToLL); } /// Get the crop lower limit (volumetric) for a soil. diff --git a/API/Services/SoilServices.cs b/API/Services/SoilServices.cs index db8ddb9..8cec9f4 100644 --- a/API/Services/SoilServices.cs +++ b/API/Services/SoilServices.cs @@ -188,7 +188,7 @@ public static double PAW(SoilDbContext context, string fullName, string cropName sw = sw.ConvertGravimetricToVolumetric(bdMapped); } - IReadOnlyList swMapped = sw.SWMappedTo(thickness, soil.Water.Thickness, ll); + IReadOnlyList swMapped = sw.SWMappedTo(thickness, soil.Water.Thickness, soil.Water.LL15, ll, soil.Water.DUL); var pawByLayer = SoilUtilities.CalcPAWC(soil.Water.Thickness, ll, swMapped, xf); return MathUtilities.Multiply(pawByLayer, soil.Water.Thickness).Sum(); } @@ -198,22 +198,18 @@ public static double PAW(SoilDbContext context, string fullName, string cropName /// The values to map. /// The thickness to map to. /// The mapped values. - public static double[] SWMappedTo(this IReadOnlyList values, IReadOnlyList fromThickness, IReadOnlyList toThickness, IReadOnlyList ll) + public static double[] SWMappedTo(this IReadOnlyList values, IReadOnlyList fromThickness, IReadOnlyList toThickness, IReadOnlyList ll15, IReadOnlyList ll, IReadOnlyList dul) { List sw = values.ToList(); List thickness = fromThickness.ToList(); - sw.Add(0.8 * values.Last()); // 1st pseudo layer below profile. - sw.Add(0.4 * values.Last()); // 2nd pseudo layer below profile. - sw.Add(0.0); // 3rd pseudo layer below profile. - thickness.Add(thickness.Last()); // 1st pseudo layer below profile. - thickness.Add(thickness.Last()); // 2nd pseudo layer below profile. - thickness.Add(3000); // 3rd pseudo layer below profile. - - var llMapped = ll.MappedTo(toThickness, thickness); - var swMM = sw.LowerConstraint(llMapped, startIndex: values.Count) - .Multiply(thickness); - return SoilUtilities.MapMass(swMM, thickness.ToArray(), toThickness.ToArray()) + sw.Add(ll15.Last()); // add a pseudo layer below profile. + thickness.Add(3000); + var swMM = sw.Multiply(thickness); + var swVolumetric = SoilUtilities.MapMass(swMM, thickness.ToArray(), toThickness.ToArray()) .Divide(toThickness); // convert back to volumetric + return swVolumetric.LowerConstraint(ll15, startIndex: 0) + .UpperConstraint(dul, startIndex: 0) + .ToArray(); } } \ No newline at end of file From 1dfb5d082e044375efc88dcd3b910debafc0d3ce Mon Sep 17 00:00:00 2001 From: Dean Holzworth Date: Mon, 25 Aug 2025 13:45:33 +1000 Subject: [PATCH 2/2] Fixed unit tests --- Tests/UnitTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/UnitTest.cs b/Tests/UnitTest.cs index 122bfc6..d39e3d9 100644 --- a/Tests/UnitTest.cs +++ b/Tests/UnitTest.cs @@ -217,7 +217,7 @@ public void PAW_ShouldReturnCorrectValue() var paw = API.Services.Soil.PAW(context, "Clay (Kerikeri No1353)", cropName: "wheat", thickness: [ 150, 500 ], sw: [ 0.4, 0.3 ], swIsGrav: false); - Assert.That(paw, Is.EqualTo(19.5996).Within(0.000001)); + Assert.That(paw, Is.EqualTo(21.72).Within(0.000001)); } @@ -233,7 +233,7 @@ public void PAWFromGravimetric_ShouldReturnCorrectValue() var paw = API.Services.Soil.PAW(context, "Clay (Kerikeri No1353)", cropName: "wheat", thickness: [ 150, 500 ], sw: [ 0.4, 0.3 ], swIsGrav: true); - Assert.That(paw, Is.EqualTo(22.165).Within(0.000001)); + Assert.That(paw, Is.EqualTo(24.676).Within(0.000001)); } [Test]