diff --git a/H.Core/Calculators/Climate/ClimateNormalCalculator.cs b/H.Core/Calculators/Climate/ClimateNormalCalculator.cs index b60d38e3..074cf7e1 100644 --- a/H.Core/Calculators/Climate/ClimateNormalCalculator.cs +++ b/H.Core/Calculators/Climate/ClimateNormalCalculator.cs @@ -226,21 +226,21 @@ public Dictionary> GetNormalsForA int startYear = customTimeFrameStart; int endYear = customTimeFrameEnd; - //Precipitation} + // Precipitation var precipNormal = new Dictionary(); var listOfPrecips = new List(); - //Temperature + // Temperature var temperatureNormals = new Dictionary(); var listOfTemperatures = new List(); - //Evapotranspiration + // Evapotranspiration var evapotransNormals = new Dictionary(); var listOfEvapotrans = new List(); foreach (var item in customClimateDatas) { - //precip values + // Precipitation values var precip = new SpecificClimateValueType() { ClimateNormalType = ClimateType.Precipitation, @@ -250,7 +250,7 @@ public Dictionary> GetNormalsForA }; listOfPrecips.Add(precip); - //temperature values + // Temperature values var temperature = new SpecificClimateValueType() { ClimateNormalType = ClimateType.Temperature, @@ -260,7 +260,7 @@ public Dictionary> GetNormalsForA }; listOfTemperatures.Add(temperature); - //evapotrans value + // Evapotranspiration values var evapotrans = new SpecificClimateValueType() { ClimateNormalType = ClimateType.Evapotranspiration, @@ -271,7 +271,7 @@ public Dictionary> GetNormalsForA listOfEvapotrans.Add(evapotrans); } - //Get the normals for each month + // Get the normals for each month foreach (var months in Enum.GetValues(typeof(Months)).Cast()) { var m = GetStartandEndJulianDays(months); diff --git a/H.Core/Calculators/Climate/ClimateService.cs b/H.Core/Calculators/Climate/ClimateService.cs index b109fa55..62b88f36 100644 --- a/H.Core/Calculators/Climate/ClimateService.cs +++ b/H.Core/Calculators/Climate/ClimateService.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System; using System.Linq; +using H.Core.Services.Initialization.Climate; namespace H.Core.Calculators.Climate { diff --git a/H.Core/Enumerations/CropTypeExtensions.cs b/H.Core/Enumerations/CropTypeExtensions.cs index 6dc8c12a..aeac4f81 100644 --- a/H.Core/Enumerations/CropTypeExtensions.cs +++ b/H.Core/Enumerations/CropTypeExtensions.cs @@ -419,7 +419,6 @@ public static IOrderedEnumerable GetValidCropTypes() { return new List { - //CropType.NotSelected, CropType.Barley, CropType.BarleySilage, CropType.BeansDryField, diff --git a/H.Core/H.Core.csproj b/H.Core/H.Core.csproj index 19e04e2a..97ba75b0 100644 --- a/H.Core/H.Core.csproj +++ b/H.Core/H.Core.csproj @@ -663,6 +663,8 @@ + + @@ -681,6 +683,8 @@ + + diff --git a/H.Core/Models/Farm.cs b/H.Core/Models/Farm.cs index 5108c8fe..ed1acffd 100644 --- a/H.Core/Models/Farm.cs +++ b/H.Core/Models/Farm.cs @@ -231,6 +231,9 @@ public ObservableCollection DefaultManureCompositi public ObservableCollection DefaultsCompositionOfBeddingMaterials { get; set; } + /// + /// Indicates the location of the farm + /// public int PolygonId { get { return _polygonId; } diff --git a/H.Core/Services/Initialization/Climate/ClimateInitializationService.cs b/H.Core/Services/Initialization/Climate/ClimateInitializationService.cs new file mode 100644 index 00000000..40266cd9 --- /dev/null +++ b/H.Core/Services/Initialization/Climate/ClimateInitializationService.cs @@ -0,0 +1,56 @@ +using System.Collections.ObjectModel; +using System.Linq; +using H.Core.Calculators.Climate; +using H.Core.Models; +using H.Core.Providers.Climate; + +namespace H.Core.Services.Initialization.Climate +{ + public class ClimateInitializationService : IClimateInitializationService + { + #region Fields + + private readonly NasaClimateProvider _nasaClimateProvider; + private readonly ClimateNormalCalculator _climateNormalCalculator; + + #endregion + + #region Constructors + + public ClimateInitializationService() + { + _nasaClimateProvider = new NasaClimateProvider(); + _climateNormalCalculator = new ClimateNormalCalculator(); + } + + #endregion + + #region Public Methods + + public void InitializeClimate(Farm farm) + { + var dailyClimateData = _nasaClimateProvider.GetCustomClimateData(farm.Latitude, farm.Longitude); + + var startYear = dailyClimateData.Min(x => x.Date.Year); + var endYear = dailyClimateData.Max(x => x.Date.Year); + + this.InitializeClimate(farm, startYear, endYear); + } + + public void InitializeClimate(Farm farm, int startYear, int endYear) + { + var dailyClimateData = _nasaClimateProvider.GetCustomClimateData(farm.Latitude, farm.Longitude); + var climateForPeriod = dailyClimateData.Where(x => x.Date.Year >= startYear && x.Date.Year <= endYear).ToList(); + var temperatureNormals = _climateNormalCalculator.GetTemperatureDataByDailyValues(climateForPeriod, startYear, endYear); + var precipitationNormals = _climateNormalCalculator.GetPrecipitationDataByDailyValues(climateForPeriod, startYear, endYear); + var evapotranspirationNormals = _climateNormalCalculator.GetEvapotranspirationDataByDailyValues(climateForPeriod, startYear, endYear); + + farm.ClimateData.DailyClimateData.AddRange(climateForPeriod); + farm.ClimateData.EvapotranspirationData = evapotranspirationNormals; + farm.ClimateData.PrecipitationData = precipitationNormals; + farm.ClimateData.TemperatureData = temperatureNormals; + } + + #endregion + } +} \ No newline at end of file diff --git a/H.Core/Services/Initialization/Climate/IClimateInitializationService.cs b/H.Core/Services/Initialization/Climate/IClimateInitializationService.cs new file mode 100644 index 00000000..1ea44184 --- /dev/null +++ b/H.Core/Services/Initialization/Climate/IClimateInitializationService.cs @@ -0,0 +1,10 @@ +using H.Core.Models; + +namespace H.Core.Services.Initialization.Climate +{ + public interface IClimateInitializationService + { + void InitializeClimate(Farm farm); + void InitializeClimate(Farm farm, int startYear, int endYear); + } +} \ No newline at end of file diff --git a/H.Core/Services/Initialization/Geography/GeographyInitializationService.cs b/H.Core/Services/Initialization/Geography/GeographyInitializationService.cs new file mode 100644 index 00000000..e06444b8 --- /dev/null +++ b/H.Core/Services/Initialization/Geography/GeographyInitializationService.cs @@ -0,0 +1,40 @@ +using H.Core.Models; +using H.Core.Providers; +using H.Core.Providers.Soil; + +namespace H.Core.Services.Initialization.Geography +{ + public class GeographyInitializationService : IGeographyInitializationService + { + #region Fields + + private readonly IGeographicDataProvider _geographicDataProvider; + + #endregion + + #region Constructors + + public GeographyInitializationService() + { + _geographicDataProvider = new GeographicDataProvider(); + _geographicDataProvider.Initialize(); + } + + #endregion + + #region Public Methods + + public void InitializeGeography(Farm farm) + { + var geographicData = _geographicDataProvider.GetGeographicalData(farm.PolygonId); + if (geographicData.DefaultSoilData == null) + { + geographicData.DefaultSoilData = new SoilData(); + } + + farm.GeographicData = geographicData; + } + + #endregion + } +} \ No newline at end of file diff --git a/H.Core/Services/Initialization/Geography/IGeographyInitializationService.cs b/H.Core/Services/Initialization/Geography/IGeographyInitializationService.cs new file mode 100644 index 00000000..5065dbe9 --- /dev/null +++ b/H.Core/Services/Initialization/Geography/IGeographyInitializationService.cs @@ -0,0 +1,9 @@ +using H.Core.Models; + +namespace H.Core.Services.Initialization.Geography +{ + public interface IGeographyInitializationService + { + void InitializeGeography(Farm farm); + } +} \ No newline at end of file diff --git a/H.Core/Services/LandManagement/FieldResultsService.cs b/H.Core/Services/LandManagement/FieldResultsService.cs index 7d035bde..291b3c4f 100644 --- a/H.Core/Services/LandManagement/FieldResultsService.cs +++ b/H.Core/Services/LandManagement/FieldResultsService.cs @@ -75,14 +75,14 @@ public partial class FieldResultsService : IFieldResultsService #region Constructors public FieldResultsService( - ICBMSoilCarbonCalculator icbmSoilCarbonCalculator, - IPCCTier2SoilCarbonCalculator ipccTier2SoilCarbonCalculator, + ICBMSoilCarbonCalculator icbmSoilCarbonCalculator, + IPCCTier2SoilCarbonCalculator ipccTier2SoilCarbonCalculator, N2OEmissionFactorCalculator n2OEmissionFactorCalculator, IInitializationService initializationService) { if (initializationService != null) { - _initializationService = initializationService; + _initializationService = initializationService; } else { diff --git a/H.Integration/Hay LCI/HayLCIIntegrationTest.cs b/H.Integration/Hay LCI/HayLCIIntegrationTest.cs index 9d93d0e1..e1ab0263 100644 --- a/H.Integration/Hay LCI/HayLCIIntegrationTest.cs +++ b/H.Integration/Hay LCI/HayLCIIntegrationTest.cs @@ -31,6 +31,8 @@ using H.Core.Providers.Soil; using H.Core.Calculators.Carbon; using H.Core.Calculators.Nitrogen; +using H.Core.Services.Initialization.Climate; +using H.Core.Services.Initialization.Geography; using H.Core.Test; namespace H.Integration.Hay_LCI @@ -87,6 +89,8 @@ class Table3Item private string _baseOutputDirectory; private bool _usingIrrigation; private List _slcList; + private IClimateInitializationService _climateInitializationService; + private IGeographyInitializationService _geographyInitializationService; #endregion @@ -126,7 +130,7 @@ public void TestInitialize() _fertilizerBlendConverter = new FertilizerBlendConverter(); - + var iCBMSoilCarbonCalculator = new ICBMSoilCarbonCalculator(_climateProvider, _n2OEmissionFactorCalculator); var n2oEmissionFactorCalculator = new N2OEmissionFactorCalculator(_climateProvider); var ipcc = new IPCCTier2SoilCarbonCalculator(_climateProvider, n2oEmissionFactorCalculator); @@ -137,6 +141,9 @@ public void TestInitialize() var manureCompositionProvider = new Table_6_Manure_Types_Default_Composition_Provider(); _manureCompositionTypes = manureCompositionProvider.ManureCompositionData; + + _climateInitializationService = new ClimateInitializationService(); + _geographyInitializationService = new GeographyInitializationService(); } [TestCleanup] @@ -615,17 +622,7 @@ private void AssignClimateData(List farms) foreach (var farm in farms) { - var nasaClimate = _nasaClimateProvider.GetCustomClimateData(farm.Latitude, farm.Longitude); - var climateForPeriod = nasaClimate.Where(x => x.Date.Year >= startYear && x.Date.Year <= endYear).ToList(); - var temperatureNormalsForPeriod = _climateNormalCalculator.GetTemperatureDataByDailyValues(climateForPeriod, startYear, endYear); - var precipitationNormalsForPeriod = _climateNormalCalculator.GetPrecipitationDataByDailyValues(climateForPeriod, startYear, endYear); - var evapotranspirationNormalsForPeriod = _climateNormalCalculator.GetEvapotranspirationDataByDailyValues(climateForPeriod, startYear, endYear); - - farm.ClimateData.DailyClimateData.AddRange(climateForPeriod); - - farm.ClimateData.EvapotranspirationData = evapotranspirationNormalsForPeriod; - farm.ClimateData.PrecipitationData = precipitationNormalsForPeriod; - farm.ClimateData.TemperatureData = temperatureNormalsForPeriod; + _climateInitializationService.InitializeClimate(farm, startYear, endYear); currentCount++; diff --git a/H.Template/H.Template.csproj b/H.Template/H.Template.csproj new file mode 100644 index 00000000..b559cde9 --- /dev/null +++ b/H.Template/H.Template.csproj @@ -0,0 +1,64 @@ + + + + + Debug + AnyCPU + {D8488FC4-6BD1-471A-9B82-DA6785492316} + Exe + H.Template + H.Template + v4.8.1 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {08D833EF-D06E-42F1-B548-89E985DFC26B} + H.Core + + + {0C9D716E-6579-4EE6-AEA6-5B019563AD95} + H.Infrastructure + + + + \ No newline at end of file diff --git a/H.Template/Program.cs b/H.Template/Program.cs new file mode 100644 index 00000000..fe472918 --- /dev/null +++ b/H.Template/Program.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using H.Core.Calculators.Climate; +using H.Core.Enumerations; +using H.Core.Models; +using H.Core.Models.Animals; +using H.Core.Models.Animals.Dairy; +using H.Core.Models.LandManagement.Fields; +using H.Core.Providers.Animals.Table_69; +using H.Core.Services.Initialization.Climate; +using H.Core.Services.Initialization.Crops; +using H.Core.Services.Initialization.Geography; + +namespace H.Template +{ + internal class Program + { + #region Fields + + private static readonly IClimateInitializationService _climateInitializationService; + private static readonly IGeographyInitializationService _geographyInitializationService; + private static readonly ICropInitializationService _cropInitializationService; + + #endregion + + static Program() + { + _climateInitializationService = new ClimateInitializationService(); + _geographyInitializationService = new GeographyInitializationService(); + _cropInitializationService = new CropInitializationService(); + } + + static void Main(string[] args) + { + Run(); + } + + static void Run() + { + // An object to hold settings that can be referenced from all farms created by the user + var globalSettings = new GlobalSettings(); + + // Create a farm + var farm = new Farm(); + + /* + * All farms need to have their location set. + */ + + // Place the farm within an SLC polygon (Lethbridge, AB) + farm.PolygonId = 793011; + + // Specify coordinates + farm.Latitude = 49.682; + farm.Longitude = -112.682; + + /* + * Set climate data according to location + */ + + _climateInitializationService.InitializeClimate(farm); + + /* + * Set geographic data (soil properties, etc.) according to location + */ + + _geographyInitializationService.InitializeGeography(farm); + + /* + * Choose components to add to the farm + */ + + // Add one field component. Choose a start year and an end year with at least a couple of decades in between + var fieldComponent = new FieldSystemComponent + { + StartYear = 1985, + EndYear = 2020 + }; + + // Many crops exist in the system (Enumeration file) but only a subset are currently supported for carbon modelling. Choose from the list of supported crop types + var validCropTypes = CropTypeExtensions.GetValidCropTypes().ToList(); + var barley = validCropTypes.Single(x => x == CropType.Barley); + var wheat = validCropTypes.Single(x => x == CropType.Wheat); + + // Grow wheat in one year + var wheatYear = new CropViewItem + { + CropType = wheat, + Year = 2020, + }; + + // Grow barley in the previous year + var barleyYear = new CropViewItem() + { + CropType = barley, + Year = 2019, + }; + + /* + * We have now specified the rotation that will be used for this field. Starting in 2020 we grew wheat, then in 2019 we grew barley. Holos will + * use this as the crop rotation sequence going back to our start year for this field (1985). It is not necessary to manually code this sequence going all the way + * back to the start year - Holos will do this on behalf of the user as long as the crop sequence is minimally described (i.e. Wheat-Barley) + * + * Holos will then back-populate the field history + * + * 2020 wheat + * 2019 barley + * 2018 wheat + * 2017 barley + * ... + */ + + // Associate the cropping data with the field + wheatYear.FieldSystemComponentGuid = fieldComponent.Guid; + barleyYear.FieldSystemComponentGuid = fieldComponent.Guid; + + fieldComponent.CropViewItems.Add(wheatYear); + fieldComponent.CropViewItems.Add(barleyYear); + + // Set defaults for each year (yield, irrigation, pesticide passes, etc. + _cropInitializationService.InitializeCrop(wheatYear, farm, globalSettings); + _cropInitializationService.InitializeCrop(barleyYear, farm, globalSettings); + + farm.Components.Add(fieldComponent); + } + } +} diff --git a/H.Template/Properties/AssemblyInfo.cs b/H.Template/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..31a2d098 --- /dev/null +++ b/H.Template/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("H.Template")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("H.Template")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d8488fc4-6bd1-471a-9b82-da6785492316")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/H.sln.DotSettings b/H.sln.DotSettings new file mode 100644 index 00000000..e918c795 --- /dev/null +++ b/H.sln.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file