From 3956bade2db8a0e2e614e216c5b86dab95c30f0f Mon Sep 17 00:00:00 2001 From: holos-aafc <95769272+holos-aafc@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:23:12 -0600 Subject: [PATCH] AD unit tests --- .../N2OEmissionFactorCalculatorTest.cs | 13 +- .../Services/Animals/DigestateServiceTest.cs | 72 +++++++- .../N2OEmissionFactorCalculator.Manure.cs | 4 +- H.Core/Services/Animals/DigestateService.cs | 162 ++++++++++++++---- H.Core/Services/Animals/IManureService.cs | 2 +- H.Core/Services/Animals/ManureService.cs | 2 +- H.Infrastructure/KmlHelpers.cs | 1 + 7 files changed, 209 insertions(+), 47 deletions(-) diff --git a/H.Core.Test/Calculators/Nitrogen/N2OEmissionFactorCalculatorTest.cs b/H.Core.Test/Calculators/Nitrogen/N2OEmissionFactorCalculatorTest.cs index 622f29fc..03b8001b 100644 --- a/H.Core.Test/Calculators/Nitrogen/N2OEmissionFactorCalculatorTest.cs +++ b/H.Core.Test/Calculators/Nitrogen/N2OEmissionFactorCalculatorTest.cs @@ -42,9 +42,6 @@ public void TestInitialize() { var n2oEmissionFactorCalculator = new N2OEmissionFactorCalculator(_climateProvider); - - - _sut = n2oEmissionFactorCalculator; _sut.ManureService = base._mockManureServiceObject; _sut.ClimateProvider = base._mockClimateProviderObject; @@ -572,7 +569,7 @@ public void CalculateAmmoniaEmissionsFromImportedManure() [TestMethod] public void GetManureNitrogenRemainingForFieldTest() { - _mockManureService.Setup(x => x.GetTotalNitrogenRemainingForFarmAndYear(It.IsAny(), It.IsAny())).Returns(600); + _mockManureService.Setup(x => x.GetTotalManureNitrogenRemainingForFarmAndYear(It.IsAny(), It.IsAny())).Returns(600); var cropViewItem = new CropViewItem() {Year = 2022, Area = 20}; var farm = new Farm(); @@ -870,13 +867,19 @@ public void CalculateDirectN2ONFromLeftOverManureForField() _farm.Components.Add(fieldWithOutManureApplications); - _mockManureService.Setup(x => x.GetTotalNitrogenRemainingForFarmAndYear(It.IsAny(), It.IsAny())).Returns(10); + _mockManureService.Setup(x => x.GetTotalManureNitrogenRemainingForFarmAndYear(It.IsAny(), It.IsAny())).Returns(10); var result = _sut.CalculateDirectN2ONFromLeftOverManureForField(_farm, _viewItem); Assert.AreEqual(0.0021318977402640473, result); } + [TestMethod] + public void GetTotalDigestateNitrogenRemainingForFarmAndYearTest() + { + + } + #endregion } } diff --git a/H.Core.Test/Services/Animals/DigestateServiceTest.cs b/H.Core.Test/Services/Animals/DigestateServiceTest.cs index 4bf31373..66aa11b8 100644 --- a/H.Core.Test/Services/Animals/DigestateServiceTest.cs +++ b/H.Core.Test/Services/Animals/DigestateServiceTest.cs @@ -58,6 +58,7 @@ public void TestInitialize() Date = DateTime.Now, FlowRateOfAllSubstratesInDigestate = 100, TotalAmountOfCarbonInRawDigestateAvailableForLandApplication = 10, + TotalAmountOfNitrogenFromRawDigestateAvailableForLandApplication = 20, }; var dailyOutput2 = new DigestorDailyOutput() @@ -65,9 +66,18 @@ public void TestInitialize() Date = DateTime.Now.AddDays(1), FlowRateOfAllSubstratesInDigestate = 100, TotalAmountOfCarbonInRawDigestateAvailableForLandApplication = 30, + TotalAmountOfNitrogenFromRawDigestateAvailableForLandApplication = 50, }; - _dailyResults = new List() { dailyOutput1, dailyOutput2 }; + var dailyOutput3 = new DigestorDailyOutput() + { + Date = DateTime.Now.AddDays(-1000), + FlowRateOfAllSubstratesInDigestate = 100, + TotalAmountOfCarbonInRawDigestateAvailableForLandApplication = 30, + TotalAmountOfNitrogenFromRawDigestateAvailableForLandApplication = 50, + }; + + _dailyResults = new List() { dailyOutput1, dailyOutput2, dailyOutput3 }; _mockAdCalculator.Setup(x => x.CalculateResults(It.IsAny(), It.IsAny>())).Returns(new List(_dailyResults)); @@ -154,6 +164,66 @@ public void GetTotalAmountOfDigestateAppliedOnDay() Assert.AreEqual(50, result); } + [TestMethod] + public void GetTotalNitrogenRemainingAtEndOfYearReturnsNonZero() + { + _adComponent.IsLiquidSolidSeparated = false; + + var year = DateTime.Now.Year; + + var totalNitrogen = _sut.GetTotalNitrogenRemainingAtEndOfYear(year, _farm); + + Assert.AreEqual(70, totalNitrogen); + } + + [TestMethod] + public void CalculateSolidAmountsAvailable() + { + var fieldSystemComponent = new FieldSystemComponent(); + var digestateApplication = new DigestateApplicationViewItem(); + digestateApplication.DigestateState = DigestateState.SolidPhase; + digestateApplication.AmountAppliedPerHectare = 20; + + var cropViewItem = new CropViewItem(); + cropViewItem.Area = 50; + cropViewItem.DigestateApplicationViewItems.Add(digestateApplication); + fieldSystemComponent.CropViewItems.Add(cropViewItem); + + _farm.Components.Clear(); + _farm.Components.Add(fieldSystemComponent); + + var digestorOutput = new DigestorDailyOutput(); + var outputDate = DateTime.Now; + var outputNumber = 1; + var tanks = new List(); + tanks.Add(new DigestateTank() + { + TotalSolidDigestateAvailable = 2000, + NitrogenFromSolidDigestate = 900, + CarbonFromSolidDigestate = 777, + }); + + var tank = new DigestateTank(); + + var component = new AnaerobicDigestionComponent(); + + digestorOutput.FlowRateSolidFraction = 10; + digestorOutput.TotalAmountOfNitrogenInRawDigestateAvailableForLandApplicationFromSolidFraction = 2000; + digestorOutput.TotalAmountOfCarbonInRawDigestateAvailableForLandApplicationFromSolidFraction = 8999; + + _sut.CalculateSolidAmountsAvailable( + digestorOutput, + outputDate, + _farm, + outputNumber, + tanks, + tank, + component); + + Assert.AreEqual(4912.3184079601988, tank.CarbonFromSolidDigestate); + Assert.AreEqual(1457.2139303482586, tank.NitrogenFromSolidDigestate); + } + #endregion } } \ No newline at end of file diff --git a/H.Core/Calculators/Nitrogen/N2OEmissionFactorCalculator.Manure.cs b/H.Core/Calculators/Nitrogen/N2OEmissionFactorCalculator.Manure.cs index 7a6a0a41..e7b1941a 100644 --- a/H.Core/Calculators/Nitrogen/N2OEmissionFactorCalculator.Manure.cs +++ b/H.Core/Calculators/Nitrogen/N2OEmissionFactorCalculator.Manure.cs @@ -179,7 +179,7 @@ public double CalculateDirectN2ONFromLeftOverManureForField( var weightedEmissionFactor = CalculateWeightedOrganicNitrogenEmissionFactor(itemsByYear, farm); // The total N after all applications and exports have been subtracted - var totalNitrogenRemaining = this.ManureService.GetTotalNitrogenRemainingForFarmAndYear(viewItem.Year, farm); + var totalNitrogenRemaining = this.ManureService.GetTotalManureNitrogenRemainingForFarmAndYear(viewItem.Year, farm); var emissionsFromNitrogenRemaining = this.CalculateTotalDirectN2ONFromRemainingManureNitrogen( weightedEmissionFactor: weightedEmissionFactor, totalManureNitrogenRemaining: totalNitrogenRemaining); @@ -1579,7 +1579,7 @@ public double GetManureNitrogenRemainingForField(CropViewItem viewItem, Farm far var totalAreaOfFarm = farm.GetTotalAreaOfFarm(includeNativeGrasslands: false, viewItem.Year); var fractionOfAreaByThisField = viewItem.Area / totalAreaOfFarm; - var manureNitrogenRemaining = this.ManureService.GetTotalNitrogenRemainingForFarmAndYear(viewItem.Year, farm); + var manureNitrogenRemaining = this.ManureService.GetTotalManureNitrogenRemainingForFarmAndYear(viewItem.Year, farm); var amountOfNitrogenAssignedToThisField = fractionOfAreaByThisField * manureNitrogenRemaining; diff --git a/H.Core/Services/Animals/DigestateService.cs b/H.Core/Services/Animals/DigestateService.cs index 5b9fb0ff..df8057a4 100644 --- a/H.Core/Services/Animals/DigestateService.cs +++ b/H.Core/Services/Animals/DigestateService.cs @@ -55,6 +55,45 @@ public List GetDailyResults(Farm farm) return dailyResults; } + /// + /// Equation 4.6.1-4 + /// + /// (kg N) + /// + public double GetTotalManureNitrogenRemainingForFarmAndYear(int year, Farm farm) + { + //var totalAvailableNitrogen = this.GetTotalNitrogenCreated(year); + + //var items = farm.GetCropViewItemsByYear(year, false); + //var localSourcedNitrogenApplied = 0d; + //var importedNitrogenApplied = 0d; + //foreach (var cropViewItem in items) + //{ + // foreach (var manureApplicationViewItem in cropViewItem.GetLocalSourcedApplications(year)) + // { + // localSourcedNitrogenApplied += manureApplicationViewItem.AmountOfNitrogenAppliedPerHectare * cropViewItem.Area; + // } + + // foreach (var manureApplicationViewItem in cropViewItem.GetManureImportsByYear(year)) + // { + // importedNitrogenApplied += manureApplicationViewItem.AmountOfNitrogenAppliedPerHectare * cropViewItem.Area; + // } + //} + + //var totalAppliedNitrogen = localSourcedNitrogenApplied;//this.GetTotalNitrogenAppliedToAllFields(year); + //var totalExportedNitrogen = this.GetTotalNitrogenFromExportedManure(year, farm); + + //// If all manure used was imported and none from local sources were used or created then there is no remaining N since all imports are used + //if (totalAvailableNitrogen == 0 && totalAppliedNitrogen == 0 && importedNitrogenApplied > 0) + //{ + // return 0; + //} + + //return totalAvailableNitrogen - (totalAppliedNitrogen - importedNitrogenApplied) - totalExportedNitrogen; + + return 0; + } + public DateTime GetDateOfMaximumAvailableDigestate(Farm farm, DigestateState state, int year, List digestorDailyOutputs) { var tankStates = this.GetDailyTankStates(farm, digestorDailyOutputs); @@ -355,6 +394,39 @@ public double GetTotalCarbonRemainingAtEndOfYear(int year, Farm farm, AnaerobicD return totalCarbon; } + public double GetTotalAmountOfDigestateAppliedOnDay(DateTime dateTime, Farm farm, DigestateState state) + { + var result = 0d; + + foreach (var farmFieldSystemComponent in farm.FieldSystemComponents) + { + foreach (var cropViewItem in farmFieldSystemComponent.CropViewItems) + { + foreach (var digestateApplicationViewItem in cropViewItem.DigestateApplicationViewItems) + { + if (digestateApplicationViewItem.DateCreated.Date == dateTime.Date && digestateApplicationViewItem.DigestateState == state) + { + result += digestateApplicationViewItem.AmountAppliedPerHectare * cropViewItem.Area; + } + } + } + } + + return result; + } + + public double GetTotalCarbonAppliedToField(CropViewItem cropViewItem, int year) + { + var result = 0d; + + foreach (var digestateApplicationViewItem in cropViewItem.DigestateApplicationViewItems.Where(x => x.DateCreated.Year == year)) + { + result += digestateApplicationViewItem.AmountOfCarbonAppliedPerHectare * cropViewItem.Area; + } + + return result; + } + public double GetTotalNitrogenRemainingAtEndOfYear(int year, Farm farm) { var dailyResults = this.GetDailyResults(farm); @@ -387,40 +459,6 @@ public double GetTotalNitrogenRemainingAtEndOfYear(int year, Farm farm) { return 0; } - - } - - public double GetTotalAmountOfDigestateAppliedOnDay(DateTime dateTime, Farm farm, DigestateState state) - { - var result = 0d; - - foreach (var farmFieldSystemComponent in farm.FieldSystemComponents) - { - foreach (var cropViewItem in farmFieldSystemComponent.CropViewItems) - { - foreach (var digestateApplicationViewItem in cropViewItem.DigestateApplicationViewItems) - { - if (digestateApplicationViewItem.DateCreated.Date == dateTime.Date && digestateApplicationViewItem.DigestateState == state) - { - result += digestateApplicationViewItem.AmountAppliedPerHectare * cropViewItem.Area; - } - } - } - } - - return result; - } - - public double GetTotalCarbonAppliedToField(CropViewItem cropViewItem, int year) - { - var result = 0d; - - foreach (var digestateApplicationViewItem in cropViewItem.DigestateApplicationViewItems.Where(x => x.DateCreated.Year == year)) - { - result += digestateApplicationViewItem.AmountOfCarbonAppliedPerHectare * cropViewItem.Area; - } - - return result; } public double GetTotalCarbonRemainingForField(CropViewItem cropViewItem, int year, Farm farm, AnaerobicDigestionComponent component) @@ -450,7 +488,11 @@ public double GetTotalCarbonRemainingForField(CropViewItem cropViewItem, int yea return result; } - public double GetTotalCarbonForField(CropViewItem cropViewItem, int year, Farm farm, AnaerobicDigestionComponent component) + public double GetTotalCarbonForField( + CropViewItem cropViewItem, + int year, + Farm farm, + AnaerobicDigestionComponent component) { var totalAppliedToField = this.GetTotalCarbonAppliedToField(cropViewItem, year); var totalCarbonRemainingForField = this.GetTotalCarbonRemainingForField(cropViewItem, year, farm, component); @@ -460,11 +502,57 @@ public double GetTotalCarbonForField(CropViewItem cropViewItem, int year, Farm f return result; } - #endregion + public void CalculateSolidAmountsAvailable( + DigestorDailyOutput outputOnCurrentDay, + DateTime outputDate, + Farm farm, + int outputNumber, + List result, + DigestateTank tank, + AnaerobicDigestionComponent component) + { + /* + * Calculate solid amounts available + */ + + var totalSolidFractionOnThisDay = outputOnCurrentDay.FlowRateSolidFraction; + var totalSolidDigestateUsedForFieldApplications = this.GetTotalAmountOfDigestateAppliedOnDay(outputDate, farm, DigestateState.SolidPhase); + var totalSolidDigestateFromPreviousDay = outputNumber == 0 ? 0 : result.ElementAt(outputNumber - 1).TotalSolidDigestateAvailable; + var totalSolidProduced = totalSolidFractionOnThisDay + totalSolidDigestateFromPreviousDay; + var totalSolidDigestateAvailableAfterFieldApplications = totalSolidProduced - totalSolidDigestateUsedForFieldApplications; + + //// Nitrogen from solid digestate + var totalNitrogenFromSolidDigestateOnThisDay = outputOnCurrentDay.TotalAmountOfNitrogenInRawDigestateAvailableForLandApplicationFromSolidFraction; + var totalNitrogenFromSolidDigestateFromPreviousDay = outputNumber == 0 ? 0 : result.ElementAt(outputNumber - 1).NitrogenFromSolidDigestate; + var totalNitrogenFromSolidDigestateAvailable = totalNitrogenFromSolidDigestateOnThisDay + totalNitrogenFromSolidDigestateFromPreviousDay; + + //// Carbon from solid digestate + var totalCarbonFromSolidDigestateOnThisDay = outputOnCurrentDay.TotalAmountOfCarbonInRawDigestateAvailableForLandApplicationFromSolidFraction; + var totalCarbonFromSolidDigestateFromPreviousDay = outputNumber == 0 ? 0 : result.ElementAt(outputNumber - 1).CarbonFromSolidDigestate; + var totalCarbonFromSolidDigestateAvailable = totalCarbonFromSolidDigestateOnThisDay + totalCarbonFromSolidDigestateFromPreviousDay; - #region Private Methods + if (component.IsLiquidSolidSeparated) + { + tank.TotalSolidDigestateAvailable = totalSolidDigestateAvailableAfterFieldApplications; + tank.TotalSolidDigestateProduced = totalSolidProduced; + tank.NitrogenFromSolidDigestate = totalNitrogenFromSolidDigestateAvailable; + tank.CarbonFromSolidDigestate = totalCarbonFromSolidDigestateAvailable; + var totalFractionOfSolidDigestateUsedFromLandApplications = totalSolidDigestateUsedForFieldApplications / totalSolidProduced; + var totalCarbonUsed = totalFractionOfSolidDigestateUsedFromLandApplications * totalCarbonFromSolidDigestateAvailable; + var totalNitrogenUsed = totalFractionOfSolidDigestateUsedFromLandApplications * totalNitrogenFromSolidDigestateAvailable; + if (this.SubtractAmountsFromLandApplications) + { + tank.CarbonFromSolidDigestate -= totalCarbonUsed; + tank.NitrogenFromSolidDigestate -= totalNitrogenUsed; + } + } + } + + #endregion + + #region Private Methods #endregion } diff --git a/H.Core/Services/Animals/IManureService.cs b/H.Core/Services/Animals/IManureService.cs index 04871ab6..1adad47b 100644 --- a/H.Core/Services/Animals/IManureService.cs +++ b/H.Core/Services/Animals/IManureService.cs @@ -91,7 +91,7 @@ public interface IManureService /// /// (kg N) /// - double GetTotalNitrogenRemainingForFarmAndYear(int year, Farm farm); + double GetTotalManureNitrogenRemainingForFarmAndYear(int year, Farm farm); diff --git a/H.Core/Services/Animals/ManureService.cs b/H.Core/Services/Animals/ManureService.cs index a4f6f294..ec1f5c06 100644 --- a/H.Core/Services/Animals/ManureService.cs +++ b/H.Core/Services/Animals/ManureService.cs @@ -606,7 +606,7 @@ public List> GetTotalTanAppliedToAllFields(int year, L /// /// (kg N) /// - public double GetTotalNitrogenRemainingForFarmAndYear(int year, Farm farm) + public double GetTotalManureNitrogenRemainingForFarmAndYear(int year, Farm farm) { var totalAvailableNitrogen = this.GetTotalNitrogenCreated(year); diff --git a/H.Infrastructure/KmlHelpers.cs b/H.Infrastructure/KmlHelpers.cs index 77a53775..9f6d60b0 100644 --- a/H.Infrastructure/KmlHelpers.cs +++ b/H.Infrastructure/KmlHelpers.cs @@ -23,6 +23,7 @@ public class KmlHelpers "Alberta_No_Styles.kml", "BC_No_Styles.kml" }; + public bool IsPointInPolygon(Polygon polygon, Vector point) { bool inside = false;