From 8651f534c918c1931a553eadbb00e6355b1cb475 Mon Sep 17 00:00:00 2001 From: Francisco Salas Date: Mon, 17 Feb 2025 08:27:19 +0100 Subject: [PATCH 1/7] aw6383: climate scenario --- CarbonCalculation.cs | 1 + CarbonCalculation24.cs | 327 +++++++++++++++++++++++++++++++++++++++- CarbonCalculation25.cs | 6 + ICarbonCalculation.cs | 1 + Models/CarbonSummary.cs | 51 +++++++ 5 files changed, 379 insertions(+), 7 deletions(-) diff --git a/CarbonCalculation.cs b/CarbonCalculation.cs index 2363233..5e46f0b 100644 --- a/CarbonCalculation.cs +++ b/CarbonCalculation.cs @@ -14,6 +14,7 @@ namespace CarbonLib public abstract CarbonRequest MapFarmMapsToMiterra(FarmMapsCarbonRequest farmInput); public abstract string Validate(CarbonRequest farmInput); public abstract CarbonSummary Calculate(CarbonRequest farmInput); + public abstract CarbonSummary CalculateClimateScenario(CarbonRequest farmInput); public double? GetCropYield(string cropCode, int year, int postalCode) { diff --git a/CarbonCalculation24.cs b/CarbonCalculation24.cs index b836c1c..8a1f51e 100644 --- a/CarbonCalculation24.cs +++ b/CarbonCalculation24.cs @@ -230,9 +230,124 @@ namespace FarmMapsAPI.Carbon return cropYield; } + public CarbonSummary CalculateClimateScenario(CarbonRequest farmInput) + { + var simpleResult = Calculate(farmInput); + var carbonResultList = new List(); + var knmiFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "KNMI_data.csv")); + var climateFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "klimaatscenario.csv")); + + for (int i = 1; i < 9; i++) + { + var climateData = InitClimateFile(knmiFile, climateFile, i); + var result = Calculate(farmInput, i, climateData); + carbonResultList.Add(result); + } + + var carbonTotal = new List(); + + + + var summaryTotal = new CarbonSummaryList { CropFieldClimate = new List(), CarbonSummary = simpleResult }; + var cropFieldSummaryList = new CropFieldSummaryList { Name = carbonResultList[0].CropField[0].Name, SummaryList = new List() }; + + for(var year = 2011; year < 2051; year++) + { + var yearData = carbonResultList.SelectMany(x => x.CropField[0].Summary.Where(x => x.Year == year)).ToList(); + if (yearData.Count == 0) + { + continue; + } + var buldensityData = GetMinMaxMedian(yearData, year, "Bulk_Density"); + var balanceData = GetMinMaxMedian(yearData, year, "Balance"); + var initialData = GetMinMaxMedian(yearData, year, "Initial"); + var om_iniData = GetMinMaxMedian(yearData, year, "OM_ini"); + var iniCcontentData = GetMinMaxMedian(yearData, year, "IniCcontent"); + var co2seqData = GetMinMaxMedian(yearData, year, "CO2seq"); + var soc_CarbonCompostData = GetMinMaxMedian(yearData, year, "SOC_CarbonCompost"); + var soc_CarbonGreenManure = GetMinMaxMedian(yearData, year, "SOC_CarbonGreenManure"); + var soc_CarbonResiduesData = GetMinMaxMedian(yearData, year, "SOC_CarbonResidues"); + var soc_CarbonManureManure = GetMinMaxMedian(yearData, year, "SOC_CarbonManure"); + var emisionData = GetMinMaxMedian(yearData, year, "Emision"); + cropFieldSummaryList.SummaryList.Add(new YearSummaryClimate + { + Year = year, + Bulk_Density = buldensityData, + Balance = balanceData, + Initial = initialData, + IniCcontent = iniCcontentData, + OM_ini = om_iniData, + CO2seq = co2seqData, + SOC_CarbonCompost = soc_CarbonCompostData, + SOC_CarbonGreenManure = soc_CarbonGreenManure, + SOC_CarbonResidues = soc_CarbonResiduesData, + SOC_CarbonManure = soc_CarbonManureManure, + Emision = emisionData, + Crop = yearData[0].Crop, + Total_crop_area = yearData[0].Total_crop_area, + }); + } + summaryTotal.CropFieldClimate.Add(cropFieldSummaryList); + + foreach(var yearSummary in summaryTotal.CarbonSummary.CropField[0].Summary) + { + //var yearValues = summaryTotal.CropFieldClimate.Where(x => x.SummaryList[0].Year == yearSummary.Year).Select(y => y.SummaryList[0]).ToList(); + var yearValues = summaryTotal.CropFieldClimate[0].SummaryList.Where(x => x.Year == yearSummary.Year).ToList(); + foreach (var cropFieldClimate in summaryTotal.CropFieldClimate) + { + var yeardata = cropFieldClimate.SummaryList.Where(x => x.Year == yearSummary.Year); + var test = yeardata.Select(x => x.Bulk_Density).First()[1]; + } + var Bulk_Density = yearValues.Select(x => x.Bulk_Density).First()[1]; + var balance = yearValues.Select(x => x.Balance).First()[1]; + var Initial = yearValues.Select(x => x.Initial).First()[1]; + var IniCcontent = yearValues.Select(x => x.IniCcontent).First()[1]; + var OM_ini = yearValues.Select(x => x.OM_ini).First()[1]; + var CO2seq = yearValues.Select(x => x.CO2seq).First()[1]; + var SOC_CarbonCompost = yearValues.Select(x => x.SOC_CarbonCompost).First()[1]; + var SOC_CarbonGreenManure = yearValues.Select(x => x.SOC_CarbonGreenManure).First()[1]; + var SOC_CarbonResidues = yearValues.Select(x => x.SOC_CarbonResidues).First()[1]; + var SOC_CarbonManure = yearValues.Select(x => x.SOC_CarbonManure).First()[1]; + var Emision = yearValues.Select(x => x.Emision).First()[1]; + yearSummary.Bulk_Density = Bulk_Density; + yearSummary.Initial = Initial; + yearSummary.IniCcontent = IniCcontent; + yearSummary.OM_ini = OM_ini; + yearSummary.OM_ini_Climate = yearValues.Select(x => x.OM_ini).First(); + yearSummary.CO2seq = CO2seq; + yearSummary.SOC_CarbonCompost = SOC_CarbonCompost; + yearSummary.SOC_CarbonGreenManure = SOC_CarbonGreenManure; + yearSummary.SOC_CarbonResidues = SOC_CarbonResidues; + yearSummary.SOC_CarbonManure = SOC_CarbonManure; + yearSummary.Emision = Emision; + } + + + return summaryTotal.CarbonSummary; + } + + private List GetMinMaxMedian(List yearData, int year, string varName) + { + + if (yearData.Count == 0) + { + + } + var minValue = (double)yearData.Min(s => s.GetType().GetProperty(varName).GetValue(s)); + var medianValue = CalculateMedian(yearData.Select(s => Convert.ToDouble(s.GetType().GetProperty(varName).GetValue(s))).ToList()); + var maxValue = (double)yearData.Max(s => s.GetType().GetProperty(varName).GetValue(s)); + return new List { minValue, medianValue, maxValue }; + } + public CarbonSummary Calculate(CarbonRequest farmInput) + { + return Calculate(farmInput, 0); + } + + public CarbonSummary Calculate(CarbonRequest farmInput, int climateScenarioNumber = 0, Dictionary<(string, string, int), ClimateVariable> climate = null) { var knmiFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "KNMI_data.csv")); + var climateFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "klimaatscenario.csv")); // soilTypeData (external input) var soilTypeData = GetSoilTypeData(farmInput); @@ -405,7 +520,15 @@ namespace FarmMapsAPI.Carbon } cropAreaFarm.Add(("Farmname", loopYear), croplist); - Dictionary> climateVariable = GetClimateVariable(knmiFile, dataTransformationSet, gisSoilSet, loopYear, farmInput); + Dictionary> climateVariable; + if (climateScenarioNumber == 0) + { + climateVariable = GetClimateVariable(knmiFile, dataTransformationSet, gisSoilSet, loopYear, farmInput, climateFile, climateScenarioNumber); + } + else + { + climateVariable = GetClimateVariable2(knmiFile, dataTransformationSet, gisSoilSet, loopYear, farmInput, climateFile, climateScenarioNumber, climate); + } // Crop and soil areas // soilArea keys: (fieldname, year, soil) @@ -1926,7 +2049,7 @@ namespace FarmMapsAPI.Carbon return soilBulkDensities; } - private static Dictionary> GetClimateVariable(string knmiFile, SetsForDataTransformation dataTransformationSet, GIS_Soils_Sets gisSoilSet, int loopYear, CarbonRequest farmInput) + private Dictionary<(string, string, int), ClimateVariable> InitClimateFile(string knmiFile, string climateFile = null, int climateScenarioNumber = 0) { var data = new List(); using (StreamReader r = new StreamReader(knmiFile)) @@ -1939,6 +2062,139 @@ namespace FarmMapsAPI.Carbon } + var dataClimate = new List(); + if (climateFile != null && climateScenarioNumber > 0) + { + using (StreamReader r = new StreamReader(climateFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + dataClimate.Add(line); + } + } + } + + // climate (zone, month, year) + var climate = new Dictionary<(string, string, int), ClimateVariable>(); + + if (dataClimate.Count() > 0) + { + foreach (var row in dataClimate) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || row.Split(';')[0] == "KNMI_zone") + { + continue; + } + var rowArr = row.Split(';'); + if (int.Parse(rowArr[3]) == climateScenarioNumber) + { + climate.Add(($"zone{rowArr[0]}", $"M{rowArr[2]}", int.Parse(rowArr[1])), new ClimateVariable(double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture), double.Parse(rowArr[6], CultureInfo.InvariantCulture))); + } + } + + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + if (int.Parse(rowArr[2]) <= 2023) + { + if (climate.Any(x => x.Key.Item1 == rowArr[0] && x.Key.Item2 == rowArr[1] && x.Key.Item3 == int.Parse(rowArr[2]))) + { + climate[(rowArr[0], rowArr[1], int.Parse(rowArr[2]))].Temperature = double.Parse(rowArr[3], CultureInfo.InvariantCulture); + climate[(rowArr[0], rowArr[1], int.Parse(rowArr[2]))].Precipitation = double.Parse(rowArr[4], CultureInfo.InvariantCulture); + climate[(rowArr[0], rowArr[1], int.Parse(rowArr[2]))].Evapotranspiration = double.Parse(rowArr[5], CultureInfo.InvariantCulture); + } + else + { + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + + } + else + { + if (climate.Any(x => x.Key.Item1 == rowArr[0] && x.Key.Item2 == rowArr[1] && x.Key.Item3 == int.Parse(rowArr[2]))) + { + continue; + } + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + } + else + { + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + + return climate; + } + + private static Dictionary> GetClimateVariable2(string knmiFile, SetsForDataTransformation dataTransformationSet, GIS_Soils_Sets gisSoilSet, int loopYear, CarbonRequest farmInput, string climateFile = null, int climateScenarioNumber = 0, Dictionary<(string, string, int), ClimateVariable> climate = null) + { + var climateVariable = new Dictionary>(); + + var farmPostalCode = farmInput.PostalCode; + if (farmInput.geometry != null) + { + // determine poatalcode from geometry + string res = GetPostalCodeFromGeometry(farmInput.geometry); + farmPostalCode = 8211; + } + var farmZone = dataTransformationSet.KNMI_zone_Reg.SingleOrDefault(x => x.Reg.Contains(farmPostalCode)).KNMI_zone; + foreach (var field in farmInput.CropFields.Select(s => s.Name)) + { + var monthClimateList = new List(); + foreach (var month in gisSoilSet.AllMonths) + { + var climateYear = loopYear > 2050 || loopYear < 2011 ? 2012 : loopYear; + var monthData = climate.Single(x => x.Key.Item1 == farmZone && x.Key.Item2 == month && x.Key.Item3 == climateYear).Value; + var newMonthData = new ClimateVariable(monthData.Temperature, monthData.Precipitation, monthData.Evapotranspiration * 1.25); + monthClimateList.Add(newMonthData); + } + climateVariable.Add(field, monthClimateList); + } + + return climateVariable; + + } + + private static Dictionary> GetClimateVariable(string knmiFile, SetsForDataTransformation dataTransformationSet, GIS_Soils_Sets gisSoilSet, int loopYear, CarbonRequest farmInput, string climateFile = null, int climateScenarioNumber = 0) + { + var data = new List(); + using (StreamReader r = new StreamReader(knmiFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + data.Add(line); + } + } + + + var dataClimate = new List(); + if (climateFile != null && climateScenarioNumber > 0) + { + using (StreamReader r = new StreamReader(climateFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + dataClimate.Add(line); + } + } + } + var farmPostalCode = farmInput.PostalCode; if (farmInput.geometry != null) { @@ -1951,15 +2207,48 @@ namespace FarmMapsAPI.Carbon // climate (zone, month, year) var climate = new Dictionary<(string, string, int), ClimateVariable>(); - foreach (var row in data) + if (dataClimate.Count() > 0) { - if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + foreach (var row in dataClimate) { - continue; + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || row.Split(';')[0] == "KNMI_zone") + { + continue; + } + var rowArr = row.Split(';'); + if (int.Parse(rowArr[3]) == climateScenarioNumber) + { + climate.Add(($"zone{rowArr[0]}", $"M{rowArr[2]}", int.Parse(rowArr[1])), new ClimateVariable(double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture), double.Parse(rowArr[6], CultureInfo.InvariantCulture))); + } + } + + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + if (climate.Any(x => x.Key.Item1 == rowArr[0] && x.Key.Item2 == rowArr[1] && x.Key.Item3 == int.Parse(rowArr[2]))) + { + continue; + } + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); } - var rowArr = row.Split(';'); - climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); } + else + { + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + var climateVariable = new Dictionary>(); @@ -2069,5 +2358,29 @@ namespace FarmMapsAPI.Carbon } } + private static double CalculateMedian(List numbers) + { + if (numbers == null || numbers.Count == 0) + { + throw new InvalidOperationException("The list is empty or null."); + } + + numbers.Sort(); + + int count = numbers.Count; + if (count % 2 == 0) + { + // Even number of elements + double mid1 = numbers[count / 2 - 1]; + double mid2 = numbers[count / 2]; + return (mid1 + mid2) / 2.0; + } + else + { + // Odd number of elements + return numbers[count / 2]; + } + } + } } diff --git a/CarbonCalculation25.cs b/CarbonCalculation25.cs index 57b6c8d..2a36461 100644 --- a/CarbonCalculation25.cs +++ b/CarbonCalculation25.cs @@ -32,6 +32,12 @@ namespace FarmMapsAPI.Carbon return response; } + public CarbonSummary CalculateClimateScenario(CarbonRequest farmInput) + { + var response = new CarbonSummary(); + return response; + } + public double? GetCropYield(string cropCode, int year, int postalCode) { throw new NotImplementedException(); diff --git a/ICarbonCalculation.cs b/ICarbonCalculation.cs index 9097fe3..33171a0 100644 --- a/ICarbonCalculation.cs +++ b/ICarbonCalculation.cs @@ -13,6 +13,7 @@ namespace FarmMapsAPI.Carbon string Validate(CarbonRequest farmInput); CarbonRequest MapFarmMapsToMiterra(FarmMapsCarbonRequest farmInput); CarbonSummary Calculate(CarbonRequest farmInput); + CarbonSummary CalculateClimateScenario(CarbonRequest farmInput); double? GetCropYield(string cropCode, int year, int postalCode); } } diff --git a/Models/CarbonSummary.cs b/Models/CarbonSummary.cs index 196f675..eb396eb 100644 --- a/Models/CarbonSummary.cs +++ b/Models/CarbonSummary.cs @@ -11,6 +11,14 @@ namespace FarmMapsAPI.Carbon.Models public List CropField { get; set; } } + public class CarbonSummaryList + { + [JsonProperty("cropFieldClimate")] + public List CropFieldClimate { get; set; } + [JsonProperty("cropField")] + public CarbonSummary CarbonSummary { get; set; } + } + public class CropFieldSummary { [JsonProperty("name")] @@ -19,6 +27,14 @@ namespace FarmMapsAPI.Carbon.Models public List Summary { get; set; } } + public class CropFieldSummaryList + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("summary")] + public List SummaryList { get; set; } + } + public class YearSummary { [JsonProperty("crop")] @@ -37,6 +53,8 @@ namespace FarmMapsAPI.Carbon.Models public double IniCcontent { get; set; } [JsonProperty("oM_ini")] public double OM_ini { get; set; } + [JsonProperty("oM_ini_Climate")] + public List OM_ini_Climate { get; set; } [JsonProperty("cO2seq")] public double CO2seq { get; set; } [JsonProperty("soC_CarbonCompost")] @@ -51,6 +69,39 @@ namespace FarmMapsAPI.Carbon.Models public double Emision { get; set; } } + public class YearSummaryClimate + { + [JsonProperty("crop")] + public string Crop { get; set; } + [JsonProperty("year")] + public int Year { get; set; } + [JsonProperty("bulk_Density")] + public List Bulk_Density { get; set; } + [JsonProperty("total_crop_area")] + public double Total_crop_area { get; set; } + [JsonProperty("balance")] + public List Balance { get; set; } + [JsonProperty("initial")] + public List Initial { get; set; } + [JsonProperty("iniCcontent")] + public List IniCcontent { get; set; } + [JsonProperty("oM_ini")] + public List OM_ini { get; set; } + [JsonProperty("cO2seq")] + public List CO2seq { get; set; } + [JsonProperty("soC_CarbonCompost")] + public List SOC_CarbonCompost { get; set; } + [JsonProperty("soC_CarbonGreenManure")] + public List SOC_CarbonGreenManure { get; set; } + [JsonProperty("soC_CarbonResidues")] + public List SOC_CarbonResidues { get; set; } + [JsonProperty("soC_CarbonManure")] + public List SOC_CarbonManure { get; set; } + [JsonProperty("emision")] + public List Emision { get; set; } + } + + public class FarmYearSummary { [JsonProperty("year")] From f1f742d4343b510a809f25f8a1a57768d7c0d968 Mon Sep 17 00:00:00 2001 From: jenkins Date: Mon, 17 Feb 2025 07:30:45 +0000 Subject: [PATCH 2/7] [ci skip] Updated project references #121 --- CarbonLib.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CarbonLib.csproj b/CarbonLib.csproj index 22e93b3..ee4dca5 100644 --- a/CarbonLib.csproj +++ b/CarbonLib.csproj @@ -8,11 +8,11 @@ false false false - 4.13.0 + 4.14.0 - + From fcbb6c9356123015999988f4b5c467964646dd1f Mon Sep 17 00:00:00 2001 From: Francisco Salas Date: Fri, 7 Mar 2025 20:37:55 +0100 Subject: [PATCH 3/7] aw6374: modelYear as string --- Models/FarmMapsCarbonRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Models/FarmMapsCarbonRequest.cs b/Models/FarmMapsCarbonRequest.cs index dc925ac..7eeabfe 100644 --- a/Models/FarmMapsCarbonRequest.cs +++ b/Models/FarmMapsCarbonRequest.cs @@ -13,7 +13,7 @@ namespace FarmMapsAPI.Carbon.Models { public class FarmMapsCarbonRequest { - public int? ModelYear { get; set; } + public string ModelYear { get; set; } public string ScenarioName { get; set; } public int PostalCode { get; set; } From 710e73b5f098430fe1cede93ba1c4882162d8a44 Mon Sep 17 00:00:00 2001 From: Francisco Salas Date: Mon, 10 Mar 2025 08:11:51 +0100 Subject: [PATCH 4/7] aw6374: climate calculation in modelyear 2025 --- CarbonCalculation24.cs | 94 +- CarbonCalculation25.cs | 2371 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 2358 insertions(+), 107 deletions(-) diff --git a/CarbonCalculation24.cs b/CarbonCalculation24.cs index 8a1f51e..eae6e58 100644 --- a/CarbonCalculation24.cs +++ b/CarbonCalculation24.cs @@ -232,98 +232,8 @@ namespace FarmMapsAPI.Carbon public CarbonSummary CalculateClimateScenario(CarbonRequest farmInput) { - var simpleResult = Calculate(farmInput); - var carbonResultList = new List(); - var knmiFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "KNMI_data.csv")); - var climateFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "klimaatscenario.csv")); - - for (int i = 1; i < 9; i++) - { - var climateData = InitClimateFile(knmiFile, climateFile, i); - var result = Calculate(farmInput, i, climateData); - carbonResultList.Add(result); - } - - var carbonTotal = new List(); - - - - var summaryTotal = new CarbonSummaryList { CropFieldClimate = new List(), CarbonSummary = simpleResult }; - var cropFieldSummaryList = new CropFieldSummaryList { Name = carbonResultList[0].CropField[0].Name, SummaryList = new List() }; - - for(var year = 2011; year < 2051; year++) - { - var yearData = carbonResultList.SelectMany(x => x.CropField[0].Summary.Where(x => x.Year == year)).ToList(); - if (yearData.Count == 0) - { - continue; - } - var buldensityData = GetMinMaxMedian(yearData, year, "Bulk_Density"); - var balanceData = GetMinMaxMedian(yearData, year, "Balance"); - var initialData = GetMinMaxMedian(yearData, year, "Initial"); - var om_iniData = GetMinMaxMedian(yearData, year, "OM_ini"); - var iniCcontentData = GetMinMaxMedian(yearData, year, "IniCcontent"); - var co2seqData = GetMinMaxMedian(yearData, year, "CO2seq"); - var soc_CarbonCompostData = GetMinMaxMedian(yearData, year, "SOC_CarbonCompost"); - var soc_CarbonGreenManure = GetMinMaxMedian(yearData, year, "SOC_CarbonGreenManure"); - var soc_CarbonResiduesData = GetMinMaxMedian(yearData, year, "SOC_CarbonResidues"); - var soc_CarbonManureManure = GetMinMaxMedian(yearData, year, "SOC_CarbonManure"); - var emisionData = GetMinMaxMedian(yearData, year, "Emision"); - cropFieldSummaryList.SummaryList.Add(new YearSummaryClimate - { - Year = year, - Bulk_Density = buldensityData, - Balance = balanceData, - Initial = initialData, - IniCcontent = iniCcontentData, - OM_ini = om_iniData, - CO2seq = co2seqData, - SOC_CarbonCompost = soc_CarbonCompostData, - SOC_CarbonGreenManure = soc_CarbonGreenManure, - SOC_CarbonResidues = soc_CarbonResiduesData, - SOC_CarbonManure = soc_CarbonManureManure, - Emision = emisionData, - Crop = yearData[0].Crop, - Total_crop_area = yearData[0].Total_crop_area, - }); - } - summaryTotal.CropFieldClimate.Add(cropFieldSummaryList); - - foreach(var yearSummary in summaryTotal.CarbonSummary.CropField[0].Summary) - { - //var yearValues = summaryTotal.CropFieldClimate.Where(x => x.SummaryList[0].Year == yearSummary.Year).Select(y => y.SummaryList[0]).ToList(); - var yearValues = summaryTotal.CropFieldClimate[0].SummaryList.Where(x => x.Year == yearSummary.Year).ToList(); - foreach (var cropFieldClimate in summaryTotal.CropFieldClimate) - { - var yeardata = cropFieldClimate.SummaryList.Where(x => x.Year == yearSummary.Year); - var test = yeardata.Select(x => x.Bulk_Density).First()[1]; - } - var Bulk_Density = yearValues.Select(x => x.Bulk_Density).First()[1]; - var balance = yearValues.Select(x => x.Balance).First()[1]; - var Initial = yearValues.Select(x => x.Initial).First()[1]; - var IniCcontent = yearValues.Select(x => x.IniCcontent).First()[1]; - var OM_ini = yearValues.Select(x => x.OM_ini).First()[1]; - var CO2seq = yearValues.Select(x => x.CO2seq).First()[1]; - var SOC_CarbonCompost = yearValues.Select(x => x.SOC_CarbonCompost).First()[1]; - var SOC_CarbonGreenManure = yearValues.Select(x => x.SOC_CarbonGreenManure).First()[1]; - var SOC_CarbonResidues = yearValues.Select(x => x.SOC_CarbonResidues).First()[1]; - var SOC_CarbonManure = yearValues.Select(x => x.SOC_CarbonManure).First()[1]; - var Emision = yearValues.Select(x => x.Emision).First()[1]; - yearSummary.Bulk_Density = Bulk_Density; - yearSummary.Initial = Initial; - yearSummary.IniCcontent = IniCcontent; - yearSummary.OM_ini = OM_ini; - yearSummary.OM_ini_Climate = yearValues.Select(x => x.OM_ini).First(); - yearSummary.CO2seq = CO2seq; - yearSummary.SOC_CarbonCompost = SOC_CarbonCompost; - yearSummary.SOC_CarbonGreenManure = SOC_CarbonGreenManure; - yearSummary.SOC_CarbonResidues = SOC_CarbonResidues; - yearSummary.SOC_CarbonManure = SOC_CarbonManure; - yearSummary.Emision = Emision; - } - - - return summaryTotal.CarbonSummary; + var simpleResult = Calculate(farmInput); + return simpleResult; } private List GetMinMaxMedian(List yearData, int year, string varName) diff --git a/CarbonCalculation25.cs b/CarbonCalculation25.cs index 2a36461..79edabb 100644 --- a/CarbonCalculation25.cs +++ b/CarbonCalculation25.cs @@ -1,8 +1,14 @@ -using CarbonLib; +using Base.Core.Common; +using Base.Core.Common.Geometry; +using CarbonLib; using CarbonService.Models; using FarmMapsAPI.Carbon.Models; +using NetTopologySuite.Geometries; +using OSGeo.OGR; using System; using System.Collections.Generic; +using System.Globalization; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -11,36 +17,2371 @@ namespace FarmMapsAPI.Carbon { public class CarbonCalculation25 : ICarbonCalculation { + private readonly string configPath; + + private SetsForDataTransformation dataTransformationSet; + private GIS_Soils_Sets gisSoilSet; + private CropSets cropSet; + private ParameterSet parameterSet; + private FarmInputsetsModel farmInputSet; + + private List cropYieldConfig; + private List manCcontConfig; + private List cropPropertyConfig; + private List yieldGreenManureConfig; + private List cropCoverMonthConfig; + + private List mappingCropFarmmapsMiterraRothC; + private List mappingGreenManureFarmmapsMiterraRothC; + public CarbonCalculation25(string configPath) { + this.configPath = configPath; - } + var dataTransformationSetFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "SetsForDataTransformation.json")); + var gisSoilFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "GIS_Soil_Sets.json")); + var cropSetFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "CropSets.json")); + var parameterRothCFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "ParametersRothC.json")); + var farmInputSetFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "Farm_input_sets.json")); + + var cropYieldFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "CropYield.json")); + var manCcontFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "ManCcont.json")); + var cropPropertyFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "CropProperties.json")); + var yieldGreenManureFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "YieldGreenManure.json")); + var cropCoverMonthFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "CropCoverMonth.json")); + + var mappingCropFarmmapsMiterraFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "Mapping", "MappingCropsFarmmapsMiterraRothC.json")); + var mappingGreenManureFarmmapsMiterraFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "Mapping", "MappingGreenManureFarmmapsMiterraRothC.json")); + + // sets + //var regionSet = GamsSets.ReadSets(regionSetFile); + dataTransformationSet = GamsSets.ReadSets(dataTransformationSetFile); + gisSoilSet = GamsSets.ReadSets(gisSoilFile); + cropSet = GamsSets.ReadSets(cropSetFile); + parameterSet = GamsSets.ReadSets(parameterRothCFile); + farmInputSet = GamsSets.ReadSets(farmInputSetFile); + + cropYieldConfig = GamsSets.ReadSets>(cropYieldFile); + manCcontConfig = GamsSets.ReadSets>(manCcontFile); + cropPropertyConfig = GamsSets.ReadSets>(cropPropertyFile); + yieldGreenManureConfig = GamsSets.ReadSets>(yieldGreenManureFile); + cropCoverMonthConfig = GamsSets.ReadSets>(cropCoverMonthFile); + + // mapping + mappingCropFarmmapsMiterraRothC = GamsSets.ReadSets>(mappingCropFarmmapsMiterraFile); + mappingGreenManureFarmmapsMiterraRothC = GamsSets.ReadSets>(mappingGreenManureFarmmapsMiterraFile); - public CarbonRequest MapFarmMapsToMiterra(FarmMapsCarbonRequest farmInput) - { - throw new NotImplementedException(); } public string Validate(CarbonRequest farmInput) { - throw new NotImplementedException(); + var postalCodePresent = dataTransformationSet.KNMI_zone_Reg.Any(x => x.Reg.Any(y => y == farmInput.PostalCode)); + if (!postalCodePresent) + { + return $"Unknown postalcode (reg) {farmInput.PostalCode}"; + } + + var allCrops = farmInput.CropFields.SelectMany(s => s.HistoricalCropData.SelectMany(x => x.Crops)).Distinct(); + foreach (var crop in allCrops) + { + if (string.IsNullOrEmpty(crop.Crop)) + { + return "Missing crop"; + } + var cropPresent = cropPropertyConfig.Any(x => x.Name.ToLower() == crop.Crop.ToLower()); + if (!cropPresent) + { + return $"Unknown crop {crop.Crop}"; + } + } + + + var allSoils = farmInput.CropFields.Select(s => s.SoilType); + foreach (var soil in allSoils) + { + if (!gisSoilSet.SoilType.Any(x => x == soil)) + { + return $"Unknown soil {soil}"; + } + } + + var allGreenManure = farmInput.CropFields.SelectMany(s => s.GreenManures.SelectMany(x => x.GreenManureTypes)).Distinct(); + foreach (var greenManure in allGreenManure) + { + if (!yieldGreenManureConfig.Any(x => x.ManureName.ToLower() == greenManure.Type.ToLower())) + { + return $"Unknown green manure {greenManure.Type}"; + } + } + + var allOrgManure = farmInput.CropFields.SelectMany(x => x.HistoricalCropData.SelectMany(s => s.Crops.Where(w => w.OrganicManures != null).SelectMany(y => y.OrganicManures.Select(r => r.Type)))).Distinct(); + foreach (var orgManure in allOrgManure) + { + if (!manCcontConfig.Any(x => x.ManCcont == orgManure)) + { + return $"Unknown organic manure {orgManure}"; + } + } + + //var allYears + return null; } - public CarbonSummary Calculate(CarbonRequest farmInput) + public CarbonRequest MapFarmMapsToMiterra(FarmMapsCarbonRequest farmInput) { - var response = new CarbonSummary(); - return response; - } + var mappedInput = new CarbonRequest(); + mappedInput.PostalCode = farmInput.PostalCode; + mappedInput.CropFields = new List(); + foreach (var cropField in farmInput.CropFields) + { + var mappedCropData = new List(); + var greenManures = new List(); + mappedInput.CropFields.Add(new CropField + { + Name = cropField.Name, + Area = cropField.Area, + HistoricalCropData = mappedCropData, + SoilType = MapSoil(cropField.SoilType), + SoilProperty = new SoilProperty { Clay_Content = cropField.SoilProperty.Clay_Content, OM_Const = cropField.SoilProperty.OM_Const, C_Const = cropField.SoilProperty.C_Const, Depth10 = cropField.SoilProperty.Depth10, Depth = cropField.SoilProperty.Depth, OM_Choice = cropField.SoilProperty.OM_Choice }, + GreenManures = greenManures + }); + foreach (var crops in cropField.HistoricalCropData) + { + foreach (var cropYear in crops.Crops) + { + if (!string.IsNullOrEmpty(cropYear.MiterraCropName)) + { + mappedCropData.Add(new HistoricalCropData + { + Year = crops.Year, + Crops = new List { + new OrgManureApplied { + Crop = cropYear.MiterraCropName, + CropRes = cropYear.CropRes, + OrganicManures = + cropYear.OrganicManures.Where(y=>y.Quantity > 0 && !string.IsNullOrEmpty(y.Type)).Select(x => new OrganicManureType { Type = x.Type, Quantity = x.Quantity.HasValue? x.Quantity.Value : 0 }).ToList(), + CropYield = cropYear.CropYield, + Irrigation = crops.Irrigations} } + }); + } + else + { + var cropMapping = mappingCropFarmmapsMiterraRothC.FirstOrDefault(x => x.CropCode == cropYear.CropCode); + if (cropMapping != null) + { + var orgManure = new List(); + if (cropYear.OrganicManures != null) + { + foreach (var manure in cropYear.OrganicManures) + { + if (!string.IsNullOrEmpty(manure.Type) && manure.Quantity.HasValue && manure.Quantity > 0) + { + orgManure.Add(new OrganicManureType { Type = manure.Type, Quantity = manure.Quantity.HasValue ? manure.Quantity.Value : 0 }); + } + } + } + var crop = mappedCropData.SingleOrDefault(x => x.Year == crops.Year); + if (crop == null) + { + mappedCropData.Add(new HistoricalCropData { Year = crops.Year, Crops = new List { new OrgManureApplied { Crop = cropMapping.MiterraRothCCrop, OrganicManures = orgManure, CropYield = cropYear.CropYield, CropRes = cropYear.CropRes } } }); + } + else + { + crop.Crops.Add(new OrgManureApplied { Crop = cropMapping.MiterraRothCCrop, OrganicManures = orgManure, CropYield = cropYear.CropYield, CropRes = cropYear.CropRes }); + } + } + else + { + mappedCropData.Add(new HistoricalCropData { Year = crops.Year, Crops = new List { new OrgManureApplied { Crop = cropYear.CropCode, OrganicManures = null, CropYield = cropYear.CropYield, CropRes = cropYear.CropRes } } }); + } + } + } - public CarbonSummary CalculateClimateScenario(CarbonRequest farmInput) - { - var response = new CarbonSummary(); - return response; + foreach (var cropYear in crops.GreenManures) + { + if (string.IsNullOrEmpty(cropYear.CropCode)) + { + continue; + } + var greenManure = cropYear.CropCode;// mappingGreenManureFarmmapsMiterraRothC.FirstOrDefault(x => x.CropCode == cropYear.CropCode && x.PurposeCode == "118"); + var manureYear = greenManures.SingleOrDefault(x => x.Year == crops.Year); + if (manureYear == null) + { + greenManures.Add(new GreenManure { Year = crops.Year, GreenManureTypes = new List { new GreenManureType { Type = greenManure, Quality = cropYear.Quality == QualityFarmMaps.Good ? Quality.Good : cropYear.Quality == QualityFarmMaps.Bad ? Quality.Bad : Quality.Average } } }); + } + } + } + } + return mappedInput; } public double? GetCropYield(string cropCode, int year, int postalCode) { - throw new NotImplementedException(); + string provinceCode = GetProvinceCode(dataTransformationSet, postalCode); + var crpYield = cropYieldConfig.SingleOrDefault(x => x.CropName.ToLower() == cropCode.ToLower()); + if (crpYield == null) + { + return 0; + } + var crpYieldProvince = crpYield.Yields.SingleOrDefault(x => x.ProvinceCode == provinceCode); + if (crpYieldProvince == null) + { + return 0; + } + var cropYield = crpYieldProvince.YearData.SingleOrDefault(x => x.Year == year)?.YieldValue; + return cropYield; + } + + public CarbonSummary CalculateClimateScenario(CarbonRequest farmInput) + { + var simpleResult = Calculate(farmInput); + var carbonResultList = new List(); + var knmiFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "KNMI_data.csv")); + var climateFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "klimaatscenario.csv")); + + for (int i = 1; i < 9; i++) + { + var climateData = InitClimateFile(knmiFile, climateFile, i); + var result = Calculate(farmInput, i, climateData); + carbonResultList.Add(result); + } + + var carbonTotal = new List(); + + + + var summaryTotal = new CarbonSummaryList { CropFieldClimate = new List(), CarbonSummary = simpleResult }; + var cropFieldSummaryList = new CropFieldSummaryList { Name = carbonResultList[0].CropField[0].Name, SummaryList = new List() }; + + for (var year = 2011; year < 2051; year++) + { + var yearData = carbonResultList.SelectMany(x => x.CropField[0].Summary.Where(x => x.Year == year)).ToList(); + if (yearData.Count == 0) + { + continue; + } + var buldensityData = GetMinMaxMedian(yearData, year, "Bulk_Density"); + var balanceData = GetMinMaxMedian(yearData, year, "Balance"); + var initialData = GetMinMaxMedian(yearData, year, "Initial"); + var om_iniData = GetMinMaxMedian(yearData, year, "OM_ini"); + var iniCcontentData = GetMinMaxMedian(yearData, year, "IniCcontent"); + var co2seqData = GetMinMaxMedian(yearData, year, "CO2seq"); + var soc_CarbonCompostData = GetMinMaxMedian(yearData, year, "SOC_CarbonCompost"); + var soc_CarbonGreenManure = GetMinMaxMedian(yearData, year, "SOC_CarbonGreenManure"); + var soc_CarbonResiduesData = GetMinMaxMedian(yearData, year, "SOC_CarbonResidues"); + var soc_CarbonManureManure = GetMinMaxMedian(yearData, year, "SOC_CarbonManure"); + var emisionData = GetMinMaxMedian(yearData, year, "Emision"); + cropFieldSummaryList.SummaryList.Add(new YearSummaryClimate + { + Year = year, + Bulk_Density = buldensityData, + Balance = balanceData, + Initial = initialData, + IniCcontent = iniCcontentData, + OM_ini = om_iniData, + CO2seq = co2seqData, + SOC_CarbonCompost = soc_CarbonCompostData, + SOC_CarbonGreenManure = soc_CarbonGreenManure, + SOC_CarbonResidues = soc_CarbonResiduesData, + SOC_CarbonManure = soc_CarbonManureManure, + Emision = emisionData, + Crop = yearData[0].Crop, + Total_crop_area = yearData[0].Total_crop_area, + }); + } + summaryTotal.CropFieldClimate.Add(cropFieldSummaryList); + + foreach (var yearSummary in summaryTotal.CarbonSummary.CropField[0].Summary) + { + //var yearValues = summaryTotal.CropFieldClimate.Where(x => x.SummaryList[0].Year == yearSummary.Year).Select(y => y.SummaryList[0]).ToList(); + var yearValues = summaryTotal.CropFieldClimate[0].SummaryList.Where(x => x.Year == yearSummary.Year).ToList(); + foreach (var cropFieldClimate in summaryTotal.CropFieldClimate) + { + var yeardata = cropFieldClimate.SummaryList.Where(x => x.Year == yearSummary.Year); + var test = yeardata.Select(x => x.Bulk_Density).First()[1]; + } + var Bulk_Density = yearValues.Select(x => x.Bulk_Density).First()[1]; + var balance = yearValues.Select(x => x.Balance).First()[1]; + var Initial = yearValues.Select(x => x.Initial).First()[1]; + var IniCcontent = yearValues.Select(x => x.IniCcontent).First()[1]; + var OM_ini = yearValues.Select(x => x.OM_ini).First()[1]; + var CO2seq = yearValues.Select(x => x.CO2seq).First()[1]; + var SOC_CarbonCompost = yearValues.Select(x => x.SOC_CarbonCompost).First()[1]; + var SOC_CarbonGreenManure = yearValues.Select(x => x.SOC_CarbonGreenManure).First()[1]; + var SOC_CarbonResidues = yearValues.Select(x => x.SOC_CarbonResidues).First()[1]; + var SOC_CarbonManure = yearValues.Select(x => x.SOC_CarbonManure).First()[1]; + var Emision = yearValues.Select(x => x.Emision).First()[1]; + yearSummary.Bulk_Density = Bulk_Density; + yearSummary.Initial = Initial; + yearSummary.IniCcontent = IniCcontent; + yearSummary.OM_ini = OM_ini; + yearSummary.OM_ini_Climate = yearValues.Select(x => x.OM_ini).First(); + yearSummary.CO2seq = CO2seq; + yearSummary.SOC_CarbonCompost = SOC_CarbonCompost; + yearSummary.SOC_CarbonGreenManure = SOC_CarbonGreenManure; + yearSummary.SOC_CarbonResidues = SOC_CarbonResidues; + yearSummary.SOC_CarbonManure = SOC_CarbonManure; + yearSummary.Emision = Emision; + } + + + return summaryTotal.CarbonSummary; + } + + private List GetMinMaxMedian(List yearData, int year, string varName) + { + + if (yearData.Count == 0) + { + + } + var minValue = (double)yearData.Min(s => s.GetType().GetProperty(varName).GetValue(s)); + var medianValue = CalculateMedian(yearData.Select(s => Convert.ToDouble(s.GetType().GetProperty(varName).GetValue(s))).ToList()); + var maxValue = (double)yearData.Max(s => s.GetType().GetProperty(varName).GetValue(s)); + return new List { minValue, medianValue, maxValue }; + } + + public CarbonSummary Calculate(CarbonRequest farmInput) + { + return Calculate(farmInput, 0); + } + + public CarbonSummary Calculate(CarbonRequest farmInput, int climateScenarioNumber = 0, Dictionary<(string, string, int), ClimateVariable> climate = null) + { + var knmiFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "KNMI_data.csv")); + var climateFile = Helper.GetPlatformIndependentDirectoryPath(Path.Combine(configPath, "klimaatscenario.csv")); + + // soilTypeData (external input) + var soilTypeData = GetSoilTypeData(farmInput); + + //soilPropertiesField (external input) + var soilPropertiesField = GetSoilPropertiesField(farmInput); + + // HistoricalCropData (external input) + var historicalCropdata = GetHistoricalCropdata(farmInput); + + // cropAreaSheet (external input) + var cropAreaField = GetCropAreaField(farmInput); + + var year = GetYears(farmInputSet, farmInput); + + + ////////////////////////////////////////////// + // precalculations + ////////////////////////////////////////////// + + + //soilPropSoilType + var soilPropSoilType = GetSoilPropSoilType(soilTypeData, soilPropertiesField); + + //if OM_cont > 0, then C_cont = OM_cont *0.54, else take C_cont from input + foreach (var item in soilPropertiesField) + { + var soilProps = soilPropSoilType.Keys.Where(x => x.Item1 == item.Key).ToList(); + double? sumC_Cont = null; + foreach (var soilProp in soilProps) + { + if (soilPropSoilType[soilProp].OM_Cont > 0) + { + if (sumC_Cont == null) + { + sumC_Cont = soilPropSoilType[soilProp].OM_Cont * 0.54; + } + else + { + sumC_Cont += soilPropSoilType[soilProp].OM_Cont * 0.54; + } + } + } + if (sumC_Cont.HasValue) + { + item.Value.C_Cont = sumC_Cont.Value; + } + } + + var oM_corr_SoilType = new Dictionary<(string, string), double>(); + var c_corr_SoilType = new Dictionary<(string, string), double>(); + foreach (var item in soilPropertiesField) + { + var soilOfItem = soilTypeData[item.Key].FirstOrDefault(); + var initialSoilKey = historicalCropdata.Keys.FirstOrDefault(x => x.Item1 == item.Key && x.Item2 == year.First()); + var initialSoil = historicalCropdata[initialSoilKey].FirstOrDefault(); + var soilPropertyDepth10 = item.Value.Depth10; + if (item.Value.Depth.HasValue && item.Value.Depth.Value == 10) + { + soilPropertyDepth10 = true; + } + // Different corrections for depth (10, 25, 30 cm) + // depth of 10cm has same result as previous checkbox (sample taken at 10cm) + parameterSet.LayerDepth = item.Value.Depth.HasValue ? item.Value.Depth.Value : parameterSet.LayerDepth; + if (initialSoil == "Temp_gras" && soilPropertyDepth10) + { + c_corr_SoilType.Add((item.Key, soilOfItem), item.Value.C_Cont * 0.97); + } + else if (cropSet.Grass_nat.Contains(initialSoil) && soilPropertyDepth10 && (soilOfItem == "Klei" || soilOfItem == "Zand")) + { + if (soilOfItem == "Klei") + { + c_corr_SoilType.Add((item.Key, soilOfItem), item.Value.C_Cont * 0.67); + } + else + { + c_corr_SoilType.Add((item.Key, soilOfItem), item.Value.C_Cont * 0.81); + } + } + else + { + c_corr_SoilType.Add((item.Key, soilOfItem), item.Value.C_Cont); + } + } + + var oM_Corr = new Dictionary(); + foreach (var item in oM_corr_SoilType) + { + oM_Corr.Add(item.Key.Item1, item.Value); + } + var c_Corr = new Dictionary(); + foreach (var item in c_corr_SoilType) + { + c_Corr.Add(item.Key.Item1, item.Value); + oM_corr_SoilType.Add(item.Key, item.Value * (1 / 0.54)); + } + + // soilBulkDensities + Dictionary soilBulkDensities = GetSoilBulkDensities(soilPropertiesField, soilTypeData, soilPropSoilType, oM_corr_SoilType); + + foreach (var soilBulkDensity in soilBulkDensities) + { + if (soilPropSoilType.ContainsKey((soilBulkDensity.Key, "Klei"))) + { + soilPropSoilType[(soilBulkDensity.Key, "Klei")].Bulk_Density = (1.0 / soilBulkDensity.Value.Clay); + soilBulkDensity.Value.Clay = (1.0 / soilBulkDensity.Value.Clay); + } + if (soilPropSoilType.ContainsKey((soilBulkDensity.Key, "Zand"))) + { + soilPropSoilType[(soilBulkDensity.Key, "Zand")].Bulk_Density = (1.0 / soilBulkDensity.Value.Sand); + soilBulkDensity.Value.Sand = (1.0 / soilBulkDensity.Value.Sand); + } + } + + var bulkDens = new Dictionary(); + foreach (var soilBulkDensity in soilBulkDensities) + { + bulkDens.Add(soilBulkDensity.Key, (soilBulkDensity.Value.Clay + soilBulkDensity.Value.Sand)); + } + + foreach (var item in soilPropertiesField) + { + var soilProps = soilPropSoilType.Keys.Where(x => x.Item1 == item.Key).ToList(); + var sumBulkDensity = 0.0; + foreach (var soilProp in soilProps) + { + sumBulkDensity += soilPropSoilType[soilProp].Bulk_Density; + } + item.Value.Bulk_Density = sumBulkDensity; + } + // finish precalculations + + + ////////////////////////////////////////// + // loop rothc + ////////////////////////////////////////// + + var soc_Field = new Dictionary>(); + + var cropAreaField1 = new Dictionary<(string, int), List>(); + var carbonInputs = new GamsThreeKeyParameter(); + var soc_Balance = new Dictionary<(string, int), List>(); + var socIni = new Dictionary<(string, int), List>(); + var cropAreaFarm = new Dictionary<(string, int), List>(); + + // start loop year + foreach (var loopYear in year) + { + var historicalCropYearKeys = historicalCropdata.Keys.Where(k => k.Item2 == loopYear).Distinct().ToList(); + foreach (var historicalCropYearKey in historicalCropYearKeys) + { + foreach (var historicalCropKeyValue in historicalCropdata[historicalCropYearKey]) + { + if (cropAreaField1.ContainsKey(historicalCropYearKey)) + { + cropAreaField1[historicalCropYearKey].Add(new ColumnValue(historicalCropKeyValue, cropAreaField[historicalCropYearKey.Item1])); + } + else + { + cropAreaField1.Add(historicalCropYearKey, new List { new ColumnValue(historicalCropKeyValue, cropAreaField[historicalCropYearKey.Item1]) }); + } + } + } + + // cropAreaFarm + var croplist = new List(); + foreach (var field in farmInput.CropFields.Select(s => s.Name)) + { + croplist.AddRange(cropAreaField1[(field, loopYear)]); + } + cropAreaFarm.Add(("Farmname", loopYear), croplist); + + Dictionary> climateVariable; + if (climateScenarioNumber == 0) + { + climateVariable = GetClimateVariable(knmiFile, dataTransformationSet, gisSoilSet, loopYear, farmInput, climateFile, climateScenarioNumber); + } + else + { + climateVariable = GetClimateVariable2(knmiFile, dataTransformationSet, gisSoilSet, loopYear, farmInput, climateFile, climateScenarioNumber, climate); + } + + // Crop and soil areas + // soilArea keys: (fieldname, year, soil) + var soilArea = new Dictionary<(string, int, string), List>(); + foreach (var cropArea in cropAreaField1) + { + foreach (var soilType in soilTypeData[cropArea.Key.Item1]) + { + foreach (var crparea in cropArea.Value) + { + var key = (cropArea.Key.Item1, loopYear, crparea.Key); + if (soilArea.ContainsKey(key)) + { + soilArea[key].Add(new ColumnValue(soilType, crparea.Value)); + } + else + { + soilArea.Add(key, new List { new ColumnValue(soilType, crparea.Value) }); + } + } + } + } + + // Mineral soils + var mineralSoilArea = new Dictionary<(string, int), List>(); + foreach (var cropArea in cropAreaField1) + { + foreach (var soilType in soilTypeData[cropArea.Key.Item1]) + { + if (!gisSoilSet.MineralSoils.Contains(soilType)) + { + continue; + } + var total = 0.0; + foreach (var crparea in cropArea.Value) + { + total += crparea.Value; + var key = (cropArea.Key.Item1, loopYear); + if (mineralSoilArea.ContainsKey(key)) + { + var miniralSoil = mineralSoilArea[key].FirstOrDefault(x => x.Key == crparea.Key); + if (miniralSoil == null) + { + mineralSoilArea[key].Add(new ColumnValue(crparea.Key, crparea.Value)); + } + else + { + miniralSoil.Value += crparea.Value; + } + } + else + { + mineralSoilArea.Add(key, new List { new ColumnValue(crparea.Key, crparea.Value) }); + } + } + } + } + + // carbon input + + // This part had organic manure per year per cropfield + var carbonInputManure2 = new Dictionary<(string, string), List>(); + var carbonInputCompost2 = new Dictionary<(string, string), ColumnValue>(); + foreach (var field in farmInput.CropFields) + { + foreach (var cropData in field.HistoricalCropData.Where(x => x.Year == loopYear).SelectMany(s => s.Crops)) + { + if (cropData.OrganicManures == null) + { + continue; + } + foreach (var compost in cropData.OrganicManures) + { + if (farmInputSet.ManureSources_liv.Any(x => x.ManureSource_liv.ToUpper() == compost.Type.ToUpper())) + { + var result = compost.Quantity * manCcontConfig.SingleOrDefault(x => x.ManCcont.ToUpper() == compost.Type.ToUpper())?.Value ?? 0; + if (carbonInputManure2.ContainsKey((field.Name, cropData.Crop))) + { + carbonInputManure2[(field.Name, cropData.Crop)].Add(new ColumnValue(compost.Type, result)); + } + else + { + carbonInputManure2.Add((field.Name, cropData.Crop), new List { new ColumnValue(compost.Type, result) }); + } + } + else if (farmInputSet.composts.Any(x => x.compost.ToUpper() == compost.Type.ToUpper())) + { + var result = compost.Quantity * manCcontConfig.SingleOrDefault(x => x.ManCcont.ToUpper() == compost.Type.ToUpper())?.Value ?? 0; + if (carbonInputCompost2.ContainsKey((field.Name, cropData.Crop))) + { + carbonInputCompost2[(field.Name, cropData.Crop)] = new ColumnValue(compost.Type, result); + } + else + { + carbonInputCompost2.Add((field.Name, cropData.Crop), new ColumnValue(compost.Type, result)); + } + } + } + } + } + + // CarbonInputCompost + + // cropYield + var yieldField = new Dictionary<(string, int), List>(); + foreach (var fieldYear in cropAreaField1) + { + string provinceCode = GetProvinceCode(dataTransformationSet, farmInput.PostalCode); + + var valueList = new List(); + foreach (var item in fieldYear.Value) + { + var crpYield = cropYieldConfig.SingleOrDefault(x => x.CropName.ToLower() == item.Key.ToLower()); + if (crpYield != null) + { + double yieldValue = 0; + var yieldProvinceYear = crpYield.Yields.Single(x => x.ProvinceCode == provinceCode).YearData.FirstOrDefault(y => y.Year == loopYear); + if (yieldProvinceYear == null) + { + yieldValue = 0; + } + else + { + yieldValue = yieldProvinceYear.YieldValue; + } + valueList.Add(new ColumnValue(crpYield.CropName, yieldValue)); + } + } + yieldField.Add(fieldYear.Key, valueList); + + var farmfield = farmInput.CropFields.SingleOrDefault(x => x.Name == fieldYear.Key.Item1); + var crop = farmfield.HistoricalCropData.SingleOrDefault(x => x.Year == fieldYear.Key.Item2); + foreach (var cropItem in crop.Crops) + { + if (cropItem.CropYield.HasValue) + { + valueList.SingleOrDefault(x => x.Key.ToLower() == cropItem.Crop.ToLower()).Value = cropItem.CropYield.Value; + } + } + } + + // DM_Yield_Field + // dm_Yield_Field key: (field, year) + var dm_Yield_Field = new Dictionary<(string, int), List>(); + foreach (var yieldFieldYear in yieldField) + { + var valueList = new List(); + foreach (var value in yieldFieldYear.Value) + { + var newValue = value.Value * 0.001; + var dmValue = cropPropertyConfig.SingleOrDefault(x => x.Name == value.Key)?.DM_content ?? 0; + newValue = newValue * dmValue; + valueList.Add(new ColumnValue(value.Key, newValue)); + } + dm_Yield_Field.Add(yieldFieldYear.Key, valueList); + } + + var harvestIndexField = new Dictionary<(string, int), List>(); + foreach (var dmField in dm_Yield_Field) + { + var valueList = new List(); + foreach (var item in dmField.Value) + { + var newValue = 0.0; + switch (item.Key) + { + // maybe in json strawcrops? + case "Maize": + newValue = 0.024 * item.Value + 0.228; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Corn_cob_mix": + newValue = 0.024 * item.Value + 0.228; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Winter_wheat": + newValue = 0.0246 * item.Value + 0.3192; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Summer_wheat": + newValue = 0.0246 * item.Value + 0.3192; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Summer_barley": + newValue = 0.0256 * item.Value + 0.3727; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "winter_barley": + newValue = 0.0256 * item.Value + 0.3727; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Rapeseed": + newValue = 0.008 * item.Value + 0.3037; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Rye": + newValue = 0.0256 * item.Value + 0.3727; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "oats": + newValue = 0.0256 * item.Value + 0.3727; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Sunflower": + newValue = 0.0077 * item.Value + 0.3045; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + case "Other_cereals": + newValue = 0.0256 * item.Value + 0.3727; + valueList.Add(new ColumnValue(item.Key, newValue)); + break; + default: + break; + } + } + if (valueList.Count > 0) + { + harvestIndexField.Add(dmField.Key, valueList); + } + } + + // AboveGroundResidues + var aboveGroundResidues = new Dictionary<(string, int), List>(); + var stubbleChaff = new Dictionary<(string, int), List>(); + var strawYield = new Dictionary<(string, int), List>(); + + foreach (var harvestField in harvestIndexField) + { + var valueList = new List(); + var valueListStubbleChaff = new List(); + var valueListStrawYield = new List(); + foreach (var harvestValue in harvestField.Value) + { + var dm_YieldValue = dm_Yield_Field[harvestField.Key].SingleOrDefault(x => x.Key == harvestValue.Key); + var result = (dm_YieldValue.Value / harvestValue.Value) - dm_YieldValue.Value; + valueList.Add(new ColumnValue(harvestValue.Key, result)); + valueListStubbleChaff.Add(new ColumnValue(harvestValue.Key, result * parameterSet.StubbleFraction)); + valueListStrawYield.Add(new ColumnValue(harvestValue.Key, result * (1 - parameterSet.StubbleFraction))); + } + aboveGroundResidues.Add(harvestField.Key, valueList); + stubbleChaff.Add(harvestField.Key, valueListStubbleChaff); + strawYield.Add(harvestField.Key, valueListStrawYield); + } + + + // BelowGroundCarbonInput + // (field, year) --> crop,value + var belowGroundCarbonInput = new Dictionary<(string, int), List>(); + foreach (var stubbleC in stubbleChaff) + { + var valueList = new List(); + foreach (var stubbleKeyValue in stubbleC.Value) + { + var dmYieldValue = dm_Yield_Field[stubbleC.Key].Single(s => s.Key.ToLower() == stubbleKeyValue.Key.ToLower()); + var strawYieldValue = strawYield[stubbleC.Key].Single(s => s.Key.ToLower() == stubbleKeyValue.Key.ToLower()); + var dmContentStraw = cropSet.StrawCrops.Single(s => s.StrawCrop.ToLower() == stubbleKeyValue.Key.ToLower()); + + var result = ((dmYieldValue.Value + ((stubbleKeyValue.Value + strawYieldValue.Value) * dmContentStraw.DM_Content)) * parameterSet.CarbonBiomass) / ((1 / parameterSet.FracBelowGroundCinput) - 1); + valueList.Add(new ColumnValue(stubbleKeyValue.Key, result)); + } + belowGroundCarbonInput.Add(stubbleC.Key, valueList); + } + + // CarbonInputs + // (field, year, crop) + // what to do with carbon residues?? + // other cereals?? (has value in cInputCropRes and is strawCrop) + foreach (var cropArea in cropAreaField1.Where(x => x.Key.Item2 == loopYear)) + { + foreach (var crop in cropArea.Value) + { + var cInputCropRes = cropPropertyConfig.SingleOrDefault(s => s.Name.ToLower() == crop.Key.ToLower())?.C_input_CropRes ?? 0.0; + carbonInputs.AddValue((cropArea.Key.Item1, cropArea.Key.Item2, crop.Key), "CarbonResidues", cInputCropRes); + + if (cropSet.StrawCrops.Any(x => x.StrawCrop.ToLower() == crop.Key.ToLower())) + { + var belowGroundCarbon = belowGroundCarbonInput[cropArea.Key].SingleOrDefault(x => x.Key.ToLower() == crop.Key.ToLower()); + var below2 = GetColumnValueForKey(belowGroundCarbonInput, cropArea.Key, crop.Key); + var stubble = GetColumnValueForKey(stubbleChaff, cropArea.Key, crop.Key); + var dm_contentStraw = cropSet.StrawCrops.SingleOrDefault(x => x.StrawCrop.ToLower() == crop.Key.ToLower())?.DM_Content ?? 0; + var strawYld = strawYield[cropArea.Key].SingleOrDefault(x => x.Key.ToLower() == crop.Key.ToLower())?.Value ?? 0; + var fracR = cropPropertyConfig.SingleOrDefault(x => x.Name.ToLower() == crop.Key.ToLower())?.FracR ?? 0.0; + + var field = farmInput.CropFields.SingleOrDefault(x => x.Name == cropArea.Key.Item1); + var crop_res = field.HistoricalCropData.SingleOrDefault(x => x.Year == loopYear).Crops[0].CropRes ? 0 : 1; + + //var result = belowGroundCarbon.Value + (stubble * dm_contentStraw * parameterSet.CarbonBiomass) + ((1 - fracR) * strawYld * dm_contentStraw * parameterSet.CarbonBiomass); + var result = belowGroundCarbon.Value + (stubble * dm_contentStraw * parameterSet.CarbonBiomass) + (crop_res * strawYld * dm_contentStraw * parameterSet.CarbonBiomass); + + //check if key exists (from if condition (in case of other cereals)) + if (result > 12000) + { + result = 12000; + } + carbonInputs.AddOrUpdateValue((cropArea.Key.Item1, cropArea.Key.Item2, crop.Key), "CarbonResidues", result); + } + } + } + + // CarbonInputGreenManure + var carbonInputGreenManure = GetCarbonInputGreenManure(loopYear, farmInput, yieldGreenManureConfig); + + + //Total carbon input[in ton C / ha] from manure, compost, crop residues and green manure + // CarbonInputs(field, year, crop,'CarbonResidues')$(CarbonInputs(field, year,crop,'CarbonResidues')>12000) = 12000;??? + + foreach (var carbon in carbonInputManure2) + { + var sumCarbonInputManure = carbon.Value.Sum(x => x.Value); + var carbonKeyInput = carbonInputs.TrippleKeyParam.Where(x => x.Key.Item1 == carbon.Key.Item1 && x.Key.Item3.ToLower() == carbon.Key.Item2.ToLower() && x.Key.Item2 == loopYear).Select(s => s.Key).ToList(); + + foreach (var carbonKey in carbonKeyInput) + { + carbonInputs.AddValue(carbonKey, "CarbonManure", sumCarbonInputManure); + } + } + + foreach (var carbonManure in carbonInputGreenManure.Where(x => x.Key.Item2 == loopYear)) + { + var sum = carbonManure.Value.Sum(x => x.Value); + foreach (var item in historicalCropdata[carbonManure.Key]) + { + carbonInputs.AddValue((carbonManure.Key.Item1, carbonManure.Key.Item2, item), "CarbonGreenManure", sum); + } + } + + foreach (var carbon in carbonInputCompost2) + { + foreach (var historicData in historicalCropdata.Where(x => x.Key.Item2 == loopYear)) + { + var historicDataItem = historicData.Value.SingleOrDefault(x => x.ToLower() == carbon.Key.Item2.ToLower()); + if (historicDataItem != null) + { + carbonInputs.AddValueSkipIfColumnExists((historicData.Key.Item1, historicData.Key.Item2, historicDataItem), "CarbonCompost", carbon.Value.Value); + } + } + } + + // TempModFactor + var tempModFactor = new Dictionary>(); + foreach (var climateVar in climateVariable) + { + var valueList = new List(); + var count = 1; + foreach (var temperature in climateVar.Value) + { + var temp = 47.9 / (1 + Math.Exp(106.0 / (temperature.Temperature + 18.3))); + valueList.Add(new ColumnValue($"M{count}", temp)); + count++; + } + tempModFactor.Add(climateVar.Key, valueList); + } + + // CoverModFactor + // input sheet + var coverModFactor = new Dictionary>(); + + foreach (var crpCover in cropCoverMonthConfig) + { + var valueList = new List(); + for (int i = 1; i < 13; i++) + { + if (crpCover.CoverMonths.Contains($"M{i}")) + { + valueList.Add(new ColumnValue($"M{i}", 0.6)); + } + else + { + valueList.Add(new ColumnValue($"M{i}", 1.0)); + } + } + coverModFactor.Add(crpCover.CropName, valueList); + } + + // SMDMax + // field, crop + var smdMax = new Dictionary(); + foreach (var soil in soilPropertiesField) + { + var result = -(20 + (1.3 * soil.Value.Clay_Content) - (0.01 * Math.Pow(soil.Value.Clay_Content, 2))) * (parameterSet.LayerDepth / 23); + smdMax.Add(soil.Key, result); + } + + // SMDaccMonthi + var smdAccMonthi = new Dictionary>(); + + foreach (var climateItem in climateVariable) + { + var valueList = new List(); + for (int i = 0; i < climateItem.Value.Count; i++) + { + if (i == 0) + { + + /* smdMax met factor maand corrigeren + SMDmax(Field,Crop,AllMonths) = ifthen(CropCoverMonths(Crop,AllMonths)=1, + SMDmax(Field,Crop,AllMonths),SMDmax(Field,Crop,AllMonths)/1.8); + */ + var crop = cropAreaField1.SingleOrDefault(x => x.Key.Item2 == loopYear).Value[0].Key; + var cover = cropCoverMonthConfig.SingleOrDefault(x => x.CropName.ToLower() == crop.ToLower())?.CoverMonths; + var hasCover = cover.Any(x => x == $"M{i + 1}"); + var smdMaxValue = smdMax[climateItem.Key]; + if (!hasCover) + { + smdMaxValue = smdMax[climateItem.Key] / 1.8; + } + //fsa todo: add precipitation + var irrigation = 0; + var irrigations = farmInput.CropFields[0].HistoricalCropData.SingleOrDefault(x => x.Year == loopYear).Crops[0].Irrigation; + if (!string.IsNullOrEmpty(irrigations)) + { + var irrigationArray = irrigations.Split(','); + if (irrigationArray.Length > i) + { + irrigation = string.IsNullOrEmpty(irrigationArray[i]) ? 0 : Convert.ToInt16(irrigationArray[i]); + } + } + var result = climateItem.Value[i].Precipitation - climateItem.Value[i].Evapotranspiration + irrigation; + result = result < 0 ? result : 0; + result = result < smdMaxValue ? smdMaxValue : result; + valueList.Add(new ColumnValue("M1", result)); + } + else + { + /* smdMax met factor maand corrigeren + SMDmax(Field,Crop,AllMonths) = ifthen(CropCoverMonths(Crop,AllMonths)=1, + SMDmax(Field,Crop,AllMonths),SMDmax(Field,Crop,AllMonths)/1.8); + */ + var crop = cropAreaField1.SingleOrDefault(x => x.Key.Item2 == loopYear).Value[0].Key; + var cover = cropCoverMonthConfig.SingleOrDefault(x => x.CropName.ToLower() == crop.ToLower())?.CoverMonths; + var hasCover = cover.Any(x => x == $"M{i + 1}"); + var smdMaxValue = smdMax[climateItem.Key]; + if (!hasCover) + { + smdMaxValue = smdMax[climateItem.Key] / 1.8; + } + + var irrigation = 0; + var irrigations = farmInput.CropFields[0].HistoricalCropData.SingleOrDefault(x => x.Year == loopYear).Crops[0].Irrigation; + if (!string.IsNullOrEmpty(irrigations)) + { + var irrigationArray = irrigations.Split(','); + if (irrigationArray.Length > i) + { + irrigation = string.IsNullOrEmpty(irrigationArray[i]) ? 0 : Convert.ToInt16(irrigationArray[i]); + } + } + var result = climateItem.Value[i].Precipitation - climateItem.Value[i].Evapotranspiration + valueList.SingleOrDefault(x => x.Key == $"M{i}").Value + irrigation; + result = result < 0 ? result : 0; + result = result < smdMaxValue ? smdMaxValue : result; + valueList.Add(new ColumnValue($"M{i + 1}", result)); + } + } + smdAccMonthi.Add(climateItem.Key, valueList); + } + + //MoistureModFactor + var moistureModFactor = new Dictionary>(); + + foreach (var fieldSmdAccMonthi in smdAccMonthi) + { + var valueList = new List(); + foreach (var smdAccMonth in fieldSmdAccMonthi.Value) + { + /* smdMax met factor maand corrigeren + SMDmax(Field,Crop,AllMonths) = ifthen(CropCoverMonths(Crop,AllMonths)=1, + SMDmax(Field,Crop,AllMonths),SMDmax(Field,Crop,AllMonths)/1.8); + */ + var crop = cropAreaField1.SingleOrDefault(x => x.Key.Item2 == loopYear).Value[0].Key; + var cover = cropCoverMonthConfig.SingleOrDefault(x => x.CropName.ToLower() == crop.ToLower())?.CoverMonths; + var hasCover = cover.Any(x => x == smdAccMonth.Key); + var smdMaxValue = smdMax[fieldSmdAccMonthi.Key]; + if (!hasCover) + { + smdMaxValue = smdMax[fieldSmdAccMonthi.Key] / 1.8; + } + + if (smdAccMonth.Value > 0.444 * smdMaxValue) + { + valueList.Add(new ColumnValue(smdAccMonth.Key, 1)); + } + else + { + var result = (0.2 + 0.8 * ((smdMaxValue - smdAccMonth.Value) / (smdMaxValue - 0.444 * smdMaxValue))); + valueList.Add(new ColumnValue(smdAccMonth.Key, result)); + } + } + moistureModFactor.Add(fieldSmdAccMonthi.Key, valueList); + } + + + // TempCoverMoistureModFactorAverage + var tempCoverMoistureModFactorAverage = new Dictionary>(); + + foreach (var field in moistureModFactor.Select(s => s.Key)) + { + var valueList = new List(); + foreach (var coverMod in coverModFactor) + { + var result = 0.0; + foreach (var monthValue in coverMod.Value) + { + var covermodValue = monthValue.Value; + var tempModValue = tempModFactor[field].SingleOrDefault(x => x.Key == monthValue.Key).Value; + var moistureModValue = moistureModFactor[field].SingleOrDefault(x => x.Key == monthValue.Key).Value; + result += covermodValue * tempModValue * moistureModValue; + } + result = (1.0 / 12.0) * result; + valueList.Add(new ColumnValue(coverMod.Key, result)); + } + tempCoverMoistureModFactorAverage.Add(field, valueList); + } + + //step1 + + //SOCini + + if (loopYear == year.First()) + { + foreach (var field in cropAreaField1.Where(x => x.Key.Item2 == loopYear)) + { + var valueList = new List(); + var result = parameterSet.LayerDepth * bulkDens[field.Key.Item1] * c_Corr[field.Key.Item1]; //(used to be oM_Corr[field.Key.Item1] * 0.54) + foreach (var crop in field.Value) + { + valueList.Add(new ColumnValue(crop.Key, result)); + } + socIni.Add(field.Key, valueList); + } + } + else + { + foreach (var fieldItem in soc_Field) + { + var valueList = new List(); + var prev = fieldItem.Value.SingleOrDefault(x => x.Key == loopYear - 1); + if (prev == null) + { + continue; + } + foreach (var cropItem in historicalCropdata[(fieldItem.Key, loopYear)]) + { + valueList.Add(new ColumnValue(cropItem, prev.Value)); + } + socIni.Add((fieldItem.Key, loopYear), valueList); + } + } + + //step 2 + + // RPM_in_residues + // DPM_in_residues + var rpm_in_residues = new Dictionary<(string, int), List>(); + var dpm_in_residues = new Dictionary<(string, int), List>(); + foreach (var carbonInput in carbonInputs.TrippleKeyParam.Where(x => x.Key.Item2 == loopYear)) + { + var carbonResidues = carbonInput.Value.SingleOrDefault(x => x.Key == "CarbonResidues")?.Value ?? 0; + var carbonGreenManure = carbonInput.Value.SingleOrDefault(x => x.Key == "CarbonGreenManure")?.Value ?? 0; + var resultRpm = 0.0; + var resultDpm = 0.0; + if (cropSet.Perennial.Any(x => x.ToLower() == carbonInput.Key.Item3.ToLower())) + { + resultRpm = (carbonResidues) * 0.6; + resultDpm = (carbonResidues) * 0.4; + } + else + { + resultRpm = (carbonResidues + carbonGreenManure) * 0.41; + resultDpm = (carbonResidues + carbonGreenManure) * 0.59; + } + + if (rpm_in_residues.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + rpm_in_residues[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultRpm)); + } + else + { + rpm_in_residues.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultRpm) }); + } + if (dpm_in_residues.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + dpm_in_residues[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultDpm)); + } + else + { + dpm_in_residues.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultDpm) }); + } + } + + // DPM_in_Manure + // RPM_in_manure + // HUM_in_manure + var dpm_in_Manure = new Dictionary<(string, int), List>(); + var rpm_in_manure = new Dictionary<(string, int), List>(); + var hum_in_manure = new Dictionary<(string, int), List>(); + foreach (var carbonInput in carbonInputs.TrippleKeyParam.Where(x => x.Key.Item2 == loopYear)) + { + var carbonManure = carbonInput.Value.SingleOrDefault(x => x.Key == "CarbonManure")?.Value ?? 0; + var resultRpm = (carbonManure) * 0.49; + var resultDpm = (carbonManure) * 0.49; + var resultHum = (carbonManure) * 0.02; + + if (rpm_in_manure.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + rpm_in_manure[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultRpm)); + } + else + { + rpm_in_manure.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultRpm) }); + } + if (dpm_in_Manure.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + dpm_in_Manure[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultDpm)); + } + else + { + dpm_in_Manure.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultDpm) }); + } + if (hum_in_manure.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + hum_in_manure[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultHum)); + } + else + { + hum_in_manure.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultHum) }); + } + } + + // DPM_compost + // RPM_compost + // HUM_compost + var dpm_compost = new Dictionary<(string, int), List>(); + var rpm_compost = new Dictionary<(string, int), List>(); + var hum_compost = new Dictionary<(string, int), List>(); + foreach (var carbonInput in carbonInputs.TrippleKeyParam.Where(x => x.Key.Item2 == loopYear)) + { + var carbonCompost = carbonInput.Value.SingleOrDefault(x => x.Key == "CarbonCompost")?.Value ?? 0; + var resultRpm = (carbonCompost) * 0.70; + var resultDpm = (carbonCompost) * 0.15; + var resultHum = (carbonCompost) * 0.15; + + if (rpm_compost.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + rpm_compost[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultRpm)); + } + else + { + rpm_compost.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultRpm) }); + } + if (dpm_compost.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + dpm_compost[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultDpm)); + } + else + { + dpm_compost.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultDpm) }); + } + if (hum_compost.ContainsKey((carbonInput.Key.Item1, carbonInput.Key.Item2))) + { + hum_compost[(carbonInput.Key.Item1, carbonInput.Key.Item2)].Add(new ColumnValue(carbonInput.Key.Item3, resultHum)); + } + else + { + hum_compost.Add((carbonInput.Key.Item1, carbonInput.Key.Item2), new List { new ColumnValue(carbonInput.Key.Item3, resultHum) }); + } + } + + // DPM_in + // RPM_in + // HUM_in + var dpm_in = new Dictionary<(string, int), List>(); + var rpm_in = new Dictionary<(string, int), List>(); + var hum_in = new Dictionary<(string, int), List>(); + + foreach (var dpmitem in dpm_in_Manure) + { + foreach (var item in dpmitem.Value) + { + var valueDpmManure = item.Value; + var valueDpmResidues = dpm_in_residues[dpmitem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var valueDpmCompost = dpm_compost[dpmitem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var result = valueDpmManure + valueDpmResidues + valueDpmCompost; + + if (dpm_in.ContainsKey(dpmitem.Key)) + { + dpm_in[dpmitem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + dpm_in.Add(dpmitem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + foreach (var rpmitem in rpm_in_manure) + { + foreach (var item in rpmitem.Value) + { + var valueRpmManure = item.Value; + var valueRpmResidues = rpm_in_residues[rpmitem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var valueRpmCompost = rpm_compost[rpmitem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var result = valueRpmManure + valueRpmResidues + valueRpmCompost; + + if (rpm_in.ContainsKey(rpmitem.Key)) + { + rpm_in[rpmitem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + rpm_in.Add(rpmitem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + foreach (var humitem in hum_in_manure) + { + foreach (var item in humitem.Value) + { + var valueHumManure = item.Value; + var valueHumCompost = hum_compost[humitem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var result = valueHumManure + valueHumCompost; + + if (hum_in.ContainsKey(humitem.Key)) + { + hum_in[humitem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + hum_in.Add(humitem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + //step 3 + + //DPMini + var dpmIni = new Dictionary<(string, int), List>(); + foreach (var dpmItem in dpm_in) + { + foreach (var item in dpmItem.Value) + { + var tempCover = tempCoverMoistureModFactorAverage[dpmItem.Key.Item1].SingleOrDefault(x => x.Key.ToLower() == item.Key.ToLower())?.Value ?? 0; + var result = (item.Value / tempCover) / parameterSet.kDPM; + if (dpmIni.ContainsKey(dpmItem.Key)) + { + dpmIni[dpmItem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + dpmIni.Add(dpmItem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + //RPMini + var rpmIni = new Dictionary<(string, int), List>(); + foreach (var rpmItem in rpm_in) + { + foreach (var item in rpmItem.Value) + { + var tempCover = tempCoverMoistureModFactorAverage[rpmItem.Key.Item1].SingleOrDefault(x => x.Key.ToLower() == item.Key.ToLower())?.Value ?? 0; + var result = (item.Value / tempCover) / parameterSet.kRPM; + if (rpmIni.ContainsKey(rpmItem.Key)) + { + rpmIni[rpmItem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + rpmIni.Add(rpmItem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + //IOMini + var iomIni = new Dictionary<(string, int), List>(); + foreach (var socItem in socIni) + { + foreach (var item in socItem.Value) + { + var result = 0.049 * Math.Pow(item.Value, 1.139); + if (iomIni.ContainsKey(socItem.Key)) + { + iomIni[socItem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + iomIni.Add(socItem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + // BIOplusHUM_ini + var bioPlusHUM_ini = new Dictionary<(string, int), List>(); + foreach (var socItem in socIni.Where(x => x.Key.Item2 == loopYear)) + { + foreach (var item in socItem.Value) + { + var socIniValue = item.Value; + var dpmIniValue = dpmIni[socItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var rpmIniValue = rpmIni[socItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var iomIniValue = iomIni[socItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var result = socIniValue - (dpmIniValue + rpmIniValue + iomIniValue); + + if (bioPlusHUM_ini.ContainsKey(socItem.Key)) + { + bioPlusHUM_ini[socItem.Key].Add(new ColumnValue(item.Key, result)); + } + else + { + bioPlusHUM_ini.Add(socItem.Key, new List { new ColumnValue(item.Key, result) }); + } + } + } + + // BIOini + // HUMini + var bioIni = new Dictionary<(string, int), List>(); + var humIni = new Dictionary<(string, int), List>(); + + foreach (var bioPlusItem in bioPlusHUM_ini) + { + foreach (var item in bioPlusItem.Value) + { + var bioIniValue = item.Value / (1 + 0.66 / 0.02); + var humIniValue = item.Value / (1 + 0.02 / 0.66); + + if (bioIni.ContainsKey(bioPlusItem.Key)) + { + bioIni[bioPlusItem.Key].Add(new ColumnValue(item.Key, bioIniValue)); + } + else + { + bioIni.Add(bioPlusItem.Key, new List { new ColumnValue(item.Key, bioIniValue) }); + } + if (humIni.ContainsKey(bioPlusItem.Key)) + { + humIni[bioPlusItem.Key].Add(new ColumnValue(item.Key, humIniValue)); + } + else + { + humIni.Add(bioPlusItem.Key, new List { new ColumnValue(item.Key, humIniValue) }); + } + } + } + + //step 4 + + // DPMdec_fraction + // RPMdec_fraction + // BIOdec_fraction + // HUMdec_fraction + var dpmDec_fraction = new Dictionary<(string, int), List>(); + var rpmDec_fraction = new Dictionary<(string, int), List>(); + var bioDec_fraction = new Dictionary<(string, int), List>(); + var humDec_fraction = new Dictionary<(string, int), List>(); + foreach (var tempCover in tempCoverMoistureModFactorAverage) + { + foreach (var item in tempCover.Value) + { + var dpmDecValue = 1 - Math.Exp(-(item.Value * parameterSet.kDPM / 12)); + var rpmDecValue = 1 - Math.Exp(-(item.Value * parameterSet.kRPM / 12)); + var bioDecValue = 1 - Math.Exp(-(item.Value * 0.66 / 12)); + var humDecValue = 1 - Math.Exp(-(item.Value * 0.02 / 12)); + + if (dpmDec_fraction.ContainsKey((tempCover.Key, loopYear))) + { + dpmDec_fraction[(tempCover.Key, loopYear)].Add(new ColumnValue(item.Key, dpmDecValue)); + } + else + { + dpmDec_fraction.Add((tempCover.Key, loopYear), new List { new ColumnValue(item.Key, dpmDecValue) }); + } + + if (rpmDec_fraction.ContainsKey((tempCover.Key, loopYear))) + { + rpmDec_fraction[(tempCover.Key, loopYear)].Add(new ColumnValue(item.Key, rpmDecValue)); + } + else + { + rpmDec_fraction.Add((tempCover.Key, loopYear), new List { new ColumnValue(item.Key, rpmDecValue) }); + } + + if (bioDec_fraction.ContainsKey((tempCover.Key, loopYear))) + { + bioDec_fraction[(tempCover.Key, loopYear)].Add(new ColumnValue(item.Key, bioDecValue)); + } + else + { + bioDec_fraction.Add((tempCover.Key, loopYear), new List { new ColumnValue(item.Key, bioDecValue) }); + } + + if (humDec_fraction.ContainsKey((tempCover.Key, loopYear))) + { + humDec_fraction[(tempCover.Key, loopYear)].Add(new ColumnValue(item.Key, humDecValue)); + } + else + { + humDec_fraction.Add((tempCover.Key, loopYear), new List { new ColumnValue(item.Key, humDecValue) }); + } + } + } + + // step 5 + + // CO2LostRatio + var co2LostRatio = new Dictionary<(string, int), List>(); + foreach (var soilProperty in soilPropertiesField) + { + var result = 1.67 * (1.85 + 1.60 * Math.Exp(-0.0786 * soilProperty.Value.Clay_Content)); + var data1 = cropAreaField1[(soilProperty.Key, loopYear)]; + var valueList = new List(); + foreach (var item in data1) + { + valueList.Add(new ColumnValue(item.Key, result)); + } + co2LostRatio.Add((soilProperty.Key, loopYear), valueList); + } + + // CO2LostRate + var co2LostRate = new Dictionary<(string, int), List>(); + foreach (var co2 in co2LostRatio) + { + var valueList = new List(); + foreach (var item in co2.Value) + { + var result = item.Value / (1 + item.Value); + valueList.Add(new ColumnValue(item.Key, result)); + } + co2LostRate.Add(co2.Key, valueList); + } + + // step 6 + + // DPM + // RPM + // BIO + // HUM + + var dpm = new Dictionary<(string, int), List>(); + var rpm = new Dictionary<(string, int), List>(); + var bio = new Dictionary<(string, int), List>(); + var hum = new Dictionary<(string, int), List>(); + + foreach (var dpmItem in dpmIni) + { + var valueList = new List(); + foreach (var item in dpmItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + dpm.Add(dpmItem.Key, valueList); + } + + foreach (var rpmItem in rpmIni) + { + var valueList = new List(); + foreach (var item in rpmItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + rpm.Add(rpmItem.Key, valueList); + } + + foreach (var bioItem in bioIni) + { + var valueList = new List(); + foreach (var item in bioItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + bio.Add(bioItem.Key, valueList); + } + + foreach (var humItem in humIni) + { + var valueList = new List(); + foreach (var item in humItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + hum.Add(humItem.Key, valueList); + } + + // ToSOM + var toSOM = new Dictionary<(string, int), List>(); + + foreach (var dpmItem in dpm) + { + var valueList = new List(); + foreach (var item in dpmItem.Value) + { + var result = 0.0; + for (int i = 0; i < 12; i++) + { + var dpmValue = item.Value; + var dpm_inValue = dpm_in[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var dpmDec_FractionValue = dpmDec_fraction[dpmItem.Key].SingleOrDefault(x => x.Key.ToLower() == item.Key.ToLower())?.Value ?? 0; + + var temp1 = (dpmValue + (dpm_inValue / 12)) * dpmDec_FractionValue; + + var rpmValue = rpm[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var rpm_InValue = rpm_in[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var rpmDec_FractionValue = rpmDec_fraction[dpmItem.Key].SingleOrDefault(x => x.Key.ToLower() == item.Key.ToLower())?.Value ?? 0; + + var temp2 = (rpmValue + (rpm_InValue / 12)) * rpmDec_FractionValue; + + var bioValue = bio[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var bioDec_FractionValue = bioDec_fraction[dpmItem.Key].SingleOrDefault(x => x.Key.ToLower() == item.Key.ToLower())?.Value ?? 0; + + var humValue = hum[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var hum_InValue = hum_in[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var humDec_FractionValue = humDec_fraction[dpmItem.Key].SingleOrDefault(x => x.Key.ToLower() == item.Key.ToLower())?.Value ?? 0; + + var co2 = co2LostRate[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + + result = ((dpmValue + (dpm_inValue / 12)) * dpmDec_FractionValue + (rpmValue + (rpm_InValue / 12)) * rpmDec_FractionValue + (bioValue * bioDec_FractionValue) + ((humValue + (hum_InValue / 12)) * humDec_FractionValue)) * (1 - co2); + + item.Value = (dpmValue + (dpm_inValue / 12)) * (1 - dpmDec_FractionValue); + rpm[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key).Value = (rpmValue + (rpm_InValue / 12)) * (1 - rpmDec_FractionValue); + bio[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key).Value = bioValue * (1 - bioDec_FractionValue) + result * 0.46; + hum[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key).Value = (humValue + (hum_InValue / 12)) * (1 - humDec_FractionValue) + result * 0.54; + } + valueList.Add(new ColumnValue(item.Key, result)); + } + toSOM.Add(dpmItem.Key, valueList); + } + + // SOC + var soc = new Dictionary<(string, int), List>(); + + foreach (var dpmItem in dpm) + { + var valueList = new List(); + foreach (var item in dpmItem.Value) + { + if (!mineralSoilArea.ContainsKey(dpmItem.Key)) + { + continue; + } + var dpmValue = item.Value; + var rpmValue = rpm[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var bioValue = bio[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var humValue = hum[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var iomValue = iomIni[dpmItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + + var result = dpmValue + rpmValue + bioValue + humValue + iomValue; + valueList.Add(new ColumnValue(item.Key, result)); + } + soc.Add(dpmItem.Key, valueList); + } + + // step 7 + // DPMss + // RPMss + // IOMss + + var dpmSs = new Dictionary<(string, int), List>(); + var rpmSs = new Dictionary<(string, int), List>(); + var iomSs = new Dictionary<(string, int), List>(); + + foreach (var dpmItem in dpmIni) + { + var valueList = new List(); + foreach (var item in dpmItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + dpmSs.Add(dpmItem.Key, valueList); + } + + foreach (var rpmItem in rpmIni) + { + var valueList = new List(); + foreach (var item in rpmItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + rpmSs.Add(rpmItem.Key, valueList); + } + + foreach (var iomItem in iomIni) + { + var valueList = new List(); + foreach (var item in iomItem.Value) + { + valueList.Add(new ColumnValue(item.Key, item.Value)); + } + iomSs.Add(iomItem.Key, valueList); + } + + // BIOss + // HUMss + var bioSs = new Dictionary<(string, int), List>(); + var humSs = new Dictionary<(string, int), List>(); + foreach (var co2Lost in co2LostRatio) + { + var valueListBio = new List(); + var valueListHum = new List(); + foreach (var item in co2Lost.Value) + { + var co2Value = item.Value; + var tempCoverValue = 0.0; + if (tempCoverMoistureModFactorAverage.ContainsKey(co2Lost.Key.Item1)) + { + tempCoverValue = tempCoverMoistureModFactorAverage[co2Lost.Key.Item1].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + } + if (co2Value * tempCoverValue * parameterSet.kBIO > 0) + { + var sumCarbon = carbonInputs.TrippleKeyParam[(co2Lost.Key.Item1, co2Lost.Key.Item2, item.Key)].Sum(x => x.Value); + var result = sumCarbon * 0.46 / (co2Value * tempCoverValue * parameterSet.kBIO); + valueListBio.Add(new ColumnValue(item.Key, result)); + } + if (co2Value * tempCoverValue * parameterSet.kHUM > 0) + { + var sumCarbon = carbonInputs.TrippleKeyParam[(co2Lost.Key.Item1, co2Lost.Key.Item2, item.Key)].Sum(x => x.Value); + var result = sumCarbon * 0.54 / (co2Value * tempCoverValue * parameterSet.kHUM); + valueListHum.Add(new ColumnValue(item.Key, result)); + } + } + bioSs.Add(co2Lost.Key, valueListBio); + humSs.Add(co2Lost.Key, valueListHum); + } + + // SOC_SteadyState + var soc_SteadyState = new Dictionary<(string, int), List>(); + foreach (var dpms in dpmSs) + { + var valueList = new List(); + + foreach (var item in dpms.Value) + { + var dpmSValue = item.Value; + var rpmSValue = rpmSs[dpms.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var bioSValue = bioSs[dpms.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var humSValue = humSs[dpms.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var iomSValue = iomSs[dpms.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + + var result = dpmSValue + rpmSValue + bioSValue + humSValue + iomSValue; + valueList.Add(new ColumnValue(item.Key, result)); + } + soc_SteadyState.Add(dpms.Key, valueList); + } + + // SOC_Field + foreach (var item in soc.Where(x => x.Key.Item2 == loopYear)) + { + var result = item.Value.Sum(x => x.Value); + if (soc_Field.ContainsKey(item.Key.Item1)) + { + soc_Field[item.Key.Item1].Add(new YearColumnValue(loopYear, result)); + } + else + { + soc_Field.Add(item.Key.Item1, new List { new YearColumnValue(loopYear, result) }); + } + } + + // SOC_Balance + foreach (var socItem in soc) + { + var valueList = new List(); + foreach (var item in socItem.Value) + { + var socValue = item.Value; + var socIniValue = socIni[socItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var result = socValue - socIniValue; + valueList.Add(new ColumnValue(item.Key, result)); + } + soc_Balance.Add(socItem.Key, valueList); + } + + // SOC_Relative + var soc_Relative = new Dictionary<(string, int), List>(); + foreach (var socItem in socIni) + { + var valueList = new List(); + foreach (var item in socItem.Value) + { + var socIniValue = item.Value; + var socBalanceValue = soc_Balance[socItem.Key].SingleOrDefault(x => x.Key == item.Key)?.Value ?? 0; + var result = socBalanceValue / socIniValue; + valueList.Add(new ColumnValue(item.Key, result)); + } + soc_Relative.Add(socItem.Key, valueList); + } + } + //end loopYear + + + // SOC_output.gms + // SOC_Summary + var carbonSummary = new CarbonSummary(); + var cropFieldSummary = new List(); + carbonSummary.CropField = cropFieldSummary; + + var soc_Summary = new Dictionary<(string, int), List>(); + foreach (var item in cropAreaField1) + { + var sum = item.Value.Sum(x => x.Value); + soc_Summary.Add(item.Key, new List { new ColumnValue("Total_crop_area", sum) }); + } + + foreach (var item in cropAreaField1) + { + var sum = item.Value.Sum(x => x.Value); + var crpField = cropFieldSummary.SingleOrDefault(x => x.Name == item.Key.Item1); + if (crpField == null) + { + cropFieldSummary.Add(new CropFieldSummary { Name = item.Key.Item1, Summary = new List { new YearSummary { Year = item.Key.Item2, Total_crop_area = sum } } }); + } + else + { + crpField.Summary.Add(new YearSummary { Year = item.Key.Item2, Total_crop_area = sum }); + } + } + + var allFields = carbonInputs.TrippleKeyParam.Keys.Select(x => x.Item1).Distinct(); + var allYears = carbonInputs.TrippleKeyParam.Keys.Select(x => x.Item2).Distinct(); + + foreach (var fieldLoop in allFields) + { + foreach (var yLoop in allYears) + { + var sumCarbonManure = 0.0; + var sumCarbonResidues = 0.0; + var sumCarbonGreenManure = 0.0; + var sumCarbonCompost = 0.0; + foreach (var item in carbonInputs.TrippleKeyParam.Where(x => x.Key.Item1 == fieldLoop && x.Key.Item2 == yLoop)) + { + sumCarbonManure += item.Value.SingleOrDefault(x => x.Key == "CarbonManure")?.Value ?? 0; + sumCarbonResidues += item.Value.SingleOrDefault(x => x.Key == "CarbonResidues")?.Value ?? 0; + sumCarbonGreenManure += item.Value.SingleOrDefault(x => x.Key == "CarbonGreenManure")?.Value ?? 0; + sumCarbonCompost += item.Value.SingleOrDefault(x => x.Key == "CarbonCompost")?.Value ?? 0; + } + soc_Summary[(fieldLoop, yLoop)].Add(new ColumnValue("SOC_CarbonManure", sumCarbonManure)); + soc_Summary[(fieldLoop, yLoop)].Add(new ColumnValue("SOC_CarbonResidues", sumCarbonResidues)); + soc_Summary[(fieldLoop, yLoop)].Add(new ColumnValue("SOC_CarbonGreenManure", sumCarbonGreenManure)); + soc_Summary[(fieldLoop, yLoop)].Add(new ColumnValue("SOC_CarbonCompost", sumCarbonCompost)); + + var crpField = cropFieldSummary.Single(x => x.Name == fieldLoop); + var summary = crpField.Summary.Single(x => x.Year == yLoop); + summary.SOC_CarbonManure = sumCarbonManure; + summary.SOC_CarbonResidues = sumCarbonResidues; + summary.SOC_CarbonGreenManure = sumCarbonGreenManure; + summary.SOC_CarbonCompost = sumCarbonCompost; + } + } + + foreach (var item in soc_Balance) + { + var sum = item.Value.Sum(x => x.Value); + soc_Summary[item.Key].Add(new ColumnValue("Balance", sum)); + + var crpField = cropFieldSummary.Single(x => x.Name == item.Key.Item1); + var summary = crpField.Summary.Single(x => x.Year == item.Key.Item2); + summary.Balance = sum; + } + + foreach (var item in socIni) + { + var sum = item.Value.Sum(x => x.Value); + soc_Summary[item.Key].Add(new ColumnValue("Initial", sum)); + + var crpField = cropFieldSummary.Single(x => x.Name == item.Key.Item1); + var summary = crpField.Summary.Single(x => x.Year == item.Key.Item2); + summary.Initial = sum; + } + + foreach (var item in bulkDens) + { + var result = item.Value; + foreach (var lYear in allYears) + { + soc_Summary[(item.Key, lYear)].Add(new ColumnValue("Bulk_Density", result)); + } + } + + foreach (var item in bulkDens) + { + var result = item.Value; + foreach (var lYear in allYears) + { + var summaries = cropFieldSummary.Single(x => x.Name == item.Key); + var summary = summaries.Summary.Single(x => x.Year == lYear); + summary.Bulk_Density = result; + } + } + + foreach (var item in socIni) + { + var crpField = cropFieldSummary.Single(x => x.Name == item.Key.Item1); + var summary = crpField.Summary.Single(x => x.Year == item.Key.Item2); + summary.Crop = item.Value[0].Key; + } + + foreach (var item in soc_Summary) + { + var balanceValue = item.Value.SingleOrDefault(x => x.Key == "Balance")?.Value ?? 0; + var initValue = item.Value.SingleOrDefault(x => x.Key == "Initial")?.Value ?? 0; + var bulkValue = item.Value.SingleOrDefault(x => x.Key == "Bulk_Density")?.Value ?? 0; + + double result = 0; + if (bulkValue > 0) + { + result = (balanceValue + initValue) / parameterSet.LayerDepth / bulkValue; + } + + item.Value.Add(new ColumnValue("IniCcontent", result)); + + var carbonManure = item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonManure")?.Value ?? 0; + var carbonResidues = item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonResidues")?.Value ?? 0; + var carbonGreenManure = item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonGreenManure")?.Value ?? 0; + var carbonCompost = item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonCompost")?.Value ?? 0; + var emision = -1 * (carbonManure + carbonResidues + carbonGreenManure + carbonCompost - balanceValue); + item.Value.Add(new ColumnValue("Emision", emision)); + } + + foreach (var item in cropFieldSummary) + { + foreach (var crpSummary in item.Summary) + { + var result = (crpSummary.Balance + crpSummary.Initial) / parameterSet.LayerDepth / crpSummary.Bulk_Density; + crpSummary.IniCcontent = result; + } + } + + foreach (var item in soc_Summary) + { + var iniValue = item.Value.SingleOrDefault(x => x.Key == "IniCcontent")?.Value ?? 0; + var balanceValue = item.Value.SingleOrDefault(x => x.Key == "Balance")?.Value ?? 0; + + var resultOmIni = iniValue / 0.54; //carbon_organicmatter_factor + var resultCo2 = balanceValue * (44.0 / 12.0); + + item.Value.Add(new ColumnValue("OM_ini", resultOmIni)); + item.Value.Add(new ColumnValue("CO2seq", resultCo2)); + } + + foreach (var summaries in cropFieldSummary) + { + foreach (var item in summaries.Summary) + { + var iniValue = item.IniCcontent; + var balanceValue = item.Balance; + + var manure = item.SOC_CarbonManure; + var residues = item.SOC_CarbonResidues; + var greenManure = item.SOC_CarbonGreenManure; + var compost = item.SOC_CarbonCompost; + + item.OM_ini = iniValue / 0.54; //carbon_organicmatter_factor + item.CO2seq = balanceValue * (44.0 / 12.0); + + var emision = -1 * (manure + residues + greenManure + compost - balanceValue); + item.Emision = emision; + } + } + + + // SOC_Summary_Farm + var soc_Summary_Farm = new List(); + foreach (var item in cropAreaFarm) + { + var sum = item.Value.Sum(x => x.Value); + soc_Summary_Farm.Add(new FarmYearSummary { Year = item.Key.Item2, Total_crop_area = sum }); + } + + foreach (var farm in cropAreaFarm) + { + var sumCarbonMan = 0.0; + var sumCarbonRes = 0.0; + var sumCarbonGreenMan = 0.0; + var sumCarbonCom = 0.0; + var sumEmision = 0.0; + + var sumBal = 0.0; + var sumIni = 0.0; + var sumInicc = 0.0; + + foreach (var item in soc_Summary.Where(x => x.Key.Item2 == farm.Key.Item2)) + { + var cropfieldArea = item.Value.SingleOrDefault(x => x.Key == "Total_crop_area")?.Value ?? 0; + sumCarbonMan += item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonManure")?.Value ?? 0; + sumCarbonRes += item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonResidues")?.Value ?? 0; + sumCarbonGreenMan += item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonGreenManure")?.Value ?? 0; + sumCarbonCom += item.Value.SingleOrDefault(x => x.Key == "SOC_CarbonCompost")?.Value ?? 0; + sumEmision += item.Value.SingleOrDefault(x => x.Key == "Emision")?.Value ?? 0; + + sumBal += item.Value.SingleOrDefault(x => x.Key == "Balance")?.Value * cropfieldArea ?? 0; + sumIni += item.Value.SingleOrDefault(x => x.Key == "Initial")?.Value ?? 0; + sumInicc += item.Value.SingleOrDefault(x => x.Key == "IniCcontent")?.Value ?? 0; + } + var farmArea = soc_Summary_Farm.SingleOrDefault(x => x.Year == farm.Key.Item2); + if (farmArea != null && farmArea.Total_crop_area > 0) + { + var resultCarbonMan = sumCarbonMan / farmArea.Total_crop_area; + var resultCarbonRes = sumCarbonRes / farmArea.Total_crop_area; + var resultCarbonGreenMan = sumCarbonGreenMan / farmArea.Total_crop_area; + var resultCarboncom = sumCarbonCom / farmArea.Total_crop_area; + var resultEmision = sumEmision / farmArea.Total_crop_area; + + var resultBal = sumBal / farmArea.Total_crop_area; + var resultIni = sumIni / farmArea.Total_crop_area; + var resultiniCc = sumInicc / farmArea.Total_crop_area; + var resultOm_Ini = resultiniCc / 0.54; //carbon_organicmatter_factor + var resultCo2 = resultBal * (44.0 / 12.0); + var resultCo2Tot = resultCo2 * farmArea.Total_crop_area; + + farmArea.SOC_CarbonManure = resultCarbonMan; + farmArea.SOC_CarbonResidues = resultCarbonRes; + farmArea.SOC_CarbonGreenManure = resultCarbonGreenMan; + farmArea.SOC_CarbonCompost = resultCarboncom; + + farmArea.Balance = resultBal; + farmArea.Initial = resultIni; + farmArea.IniCcontent = resultiniCc; + farmArea.OM_ini = resultOm_Ini; + farmArea.CO2seq = resultCo2; + farmArea.CO2seq_total = resultCo2Tot; + farmArea.Emision = resultEmision; + } + } + return carbonSummary; + } + + private double GetColumnValueForKey(Dictionary<(string, int), List> input, (string, int) key, string column) + { + return input[key].SingleOrDefault(x => x.Key.ToLower() == column.ToLower())?.Value ?? 0; + } + + private List GetYears(FarmInputsetsModel farmInputSet, CarbonRequest farmInput) + { + // assume for all cropfields the same years apply + return farmInput.CropFields.First().HistoricalCropData.Select(x => x.Year).Distinct().OrderBy(o => o).ToList(); + } + + private Dictionary> GetSoilTypeData(CarbonRequest farmInput) + { + var soilTypeData = new Dictionary>(); + foreach (var field in farmInput.CropFields) + { + soilTypeData.Add(field.Name, new List { field.SoilType }); + } + return soilTypeData; + } + + private Dictionary GetSoilPropertiesField(CarbonRequest farmInput) + { + var soilPropertiesField = new Dictionary(); + foreach (var field in farmInput.CropFields) + { + //soilPropertiesField.Add(field.Name, new SoilPropertyType { OM_Cont = field.SoilProperty.OM_Choice.ToLower() == "c" ? field.SoilProperty.OM_Const.Value * 1.85185 : field.SoilProperty.OM_Const.Value, Clay_Content = field.SoilProperty.Clay_Content.Value, OM_Corr = field.SoilProperty.OM_Const.Value <= 20 ? field.SoilProperty.OM_Const.Value : 0, Depth10 = field.SoilProperty.Depth10.Value, Depth = field.SoilProperty.Depth }); + soilPropertiesField.Add(field.Name, new SoilPropertyType { OM_Cont = field.SoilProperty.OM_Const.HasValue ? field.SoilProperty.OM_Const.Value : 0, C_Cont = field.SoilProperty.C_Const.HasValue ? field.SoilProperty.C_Const.Value : 0, Clay_Content = field.SoilProperty.Clay_Content.Value, OM_Corr = field.SoilProperty.OM_Const.HasValue && field.SoilProperty.OM_Const.Value <= 20 ? field.SoilProperty.OM_Const.Value : 0, C_Corr = field.SoilProperty.C_Const.HasValue && field.SoilProperty.C_Const.Value <= 10.8 ? field.SoilProperty.C_Const.Value : 0, Depth10 = field.SoilProperty.Depth10.Value, Depth = field.SoilProperty.Depth }); + } + + return soilPropertiesField; + } + + private Dictionary<(string, string), SoilPropertyType> GetSoilPropSoilType(Dictionary> soilTypeData, Dictionary soilPropertiesField) + { + var soilPropSoilType = new Dictionary<(string, string), SoilPropertyType>(); + foreach (var item in soilTypeData) + { + foreach (var item2 in item.Value) + { + soilPropSoilType.Add((item.Key, item2), new SoilPropertyType { Bulk_Density = soilPropertiesField[item.Key].Bulk_Density, Clay_Content = soilPropertiesField[item.Key].Clay_Content, OM_Cont = soilPropertiesField[item.Key].OM_Cont, OM_Corr = soilPropertiesField[item.Key].OM_Corr, C_Cont = soilPropertiesField[item.Key].C_Cont, C_Corr = soilPropertiesField[item.Key].C_Corr }); // soilPropertiesField[item.Key]); + } + } + return soilPropSoilType; + } + + private Dictionary<(string, int), List> GetHistoricalCropdata(CarbonRequest farmInput) + { + var historicalCropData = new Dictionary<(string, int), List>(); + foreach (var field in farmInput.CropFields) + { + foreach (var cropYear in field.HistoricalCropData) + { + historicalCropData.Add((field.Name, cropYear.Year), cropYear.Crops.Select(x => x.Crop).ToList()); + } + } + return historicalCropData; + } + + + private Dictionary GetCropAreaField(CarbonRequest farmInput) + { + var cropAreaField = new Dictionary(); + foreach (var field in farmInput.CropFields) + { + cropAreaField.Add(field.Name, field.Area); + } + return cropAreaField; + } + + private Dictionary GetSoilBulkDensities(Dictionary soilPropertiesField, Dictionary> soilTypeData, Dictionary<(string, string), SoilPropertyType> soilPropSoilType, Dictionary<(string, string), double> oM_corr_SoilType) + { + var soilBulkDensities = new Dictionary(); + foreach (var item in soilPropertiesField) + { + soilBulkDensities.Add(item.Key, new SoilBulkDensityType()); + if (soilTypeData[item.Key].Any(x => x == "Klei")) + { + var soilBulkDensityKey = soilPropSoilType.Keys.Single(x => x.Item1 == item.Key && x.Item2 == "Klei"); + + var clay = (0.6117 + (0.003601 * item.Value.Clay_Content)) + + (0.002172 * oM_corr_SoilType[(item.Key, "Klei")] * oM_corr_SoilType[(item.Key, "Klei")]) + + (0.01715 * Math.Log(oM_corr_SoilType[(item.Key, "Klei")])); + + soilBulkDensities[item.Key].Clay = clay; + } + if (soilTypeData[item.Key].Any(x => x == "Zand")) + { + var soilBulkDensityKey = soilPropSoilType.Keys.Single(x => x.Item1 == item.Key && x.Item2 == "Zand"); + soilBulkDensities[item.Key].Sand = 0.667 + (0.021 * oM_corr_SoilType[(item.Key, "Zand")]); + } + } + return soilBulkDensities; + } + + private Dictionary<(string, string, int), ClimateVariable> InitClimateFile(string knmiFile, string climateFile = null, int climateScenarioNumber = 0) + { + var data = new List(); + using (StreamReader r = new StreamReader(knmiFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + data.Add(line); + } + } + + + var dataClimate = new List(); + if (climateFile != null && climateScenarioNumber > 0) + { + using (StreamReader r = new StreamReader(climateFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + dataClimate.Add(line); + } + } + } + + // climate (zone, month, year) + var climate = new Dictionary<(string, string, int), ClimateVariable>(); + + if (dataClimate.Count() > 0) + { + foreach (var row in dataClimate) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || row.Split(';')[0] == "KNMI_zone") + { + continue; + } + var rowArr = row.Split(';'); + if (int.Parse(rowArr[3]) == climateScenarioNumber) + { + climate.Add(($"zone{rowArr[0]}", $"M{rowArr[2]}", int.Parse(rowArr[1])), new ClimateVariable(double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture), double.Parse(rowArr[6], CultureInfo.InvariantCulture))); + } + } + + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + if (int.Parse(rowArr[2]) <= 2023) + { + if (climate.Any(x => x.Key.Item1 == rowArr[0] && x.Key.Item2 == rowArr[1] && x.Key.Item3 == int.Parse(rowArr[2]))) + { + climate[(rowArr[0], rowArr[1], int.Parse(rowArr[2]))].Temperature = double.Parse(rowArr[3], CultureInfo.InvariantCulture); + climate[(rowArr[0], rowArr[1], int.Parse(rowArr[2]))].Precipitation = double.Parse(rowArr[4], CultureInfo.InvariantCulture); + climate[(rowArr[0], rowArr[1], int.Parse(rowArr[2]))].Evapotranspiration = double.Parse(rowArr[5], CultureInfo.InvariantCulture); + } + else + { + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + + } + else + { + if (climate.Any(x => x.Key.Item1 == rowArr[0] && x.Key.Item2 == rowArr[1] && x.Key.Item3 == int.Parse(rowArr[2]))) + { + continue; + } + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + } + else + { + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + + return climate; + } + + private static Dictionary> GetClimateVariable2(string knmiFile, SetsForDataTransformation dataTransformationSet, GIS_Soils_Sets gisSoilSet, int loopYear, CarbonRequest farmInput, string climateFile = null, int climateScenarioNumber = 0, Dictionary<(string, string, int), ClimateVariable> climate = null) + { + var climateVariable = new Dictionary>(); + + var farmPostalCode = farmInput.PostalCode; + if (farmInput.geometry != null) + { + // determine poatalcode from geometry + string res = GetPostalCodeFromGeometry(farmInput.geometry); + farmPostalCode = 8211; + } + var farmZone = dataTransformationSet.KNMI_zone_Reg.SingleOrDefault(x => x.Reg.Contains(farmPostalCode)).KNMI_zone; + foreach (var field in farmInput.CropFields.Select(s => s.Name)) + { + var monthClimateList = new List(); + foreach (var month in gisSoilSet.AllMonths) + { + var climateYear = loopYear > 2050 || loopYear < 2011 ? 2012 : loopYear; + var monthData = climate.Single(x => x.Key.Item1 == farmZone && x.Key.Item2 == month && x.Key.Item3 == climateYear).Value; + var newMonthData = new ClimateVariable(monthData.Temperature, monthData.Precipitation, monthData.Evapotranspiration * 1.25); + monthClimateList.Add(newMonthData); + } + climateVariable.Add(field, monthClimateList); + } + + return climateVariable; + + } + + private static Dictionary> GetClimateVariable(string knmiFile, SetsForDataTransformation dataTransformationSet, GIS_Soils_Sets gisSoilSet, int loopYear, CarbonRequest farmInput, string climateFile = null, int climateScenarioNumber = 0) + { + var data = new List(); + using (StreamReader r = new StreamReader(knmiFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + data.Add(line); + } + } + + + var dataClimate = new List(); + if (climateFile != null && climateScenarioNumber > 0) + { + using (StreamReader r = new StreamReader(climateFile)) + { + string line; + while ((line = r.ReadLine()) != null) + { + dataClimate.Add(line); + } + } + } + + var farmPostalCode = farmInput.PostalCode; + if (farmInput.geometry != null) + { + // determine poatalcode from geometry + string res = GetPostalCodeFromGeometry(farmInput.geometry); + farmPostalCode = 8211; + } + + var farmZone = dataTransformationSet.KNMI_zone_Reg.SingleOrDefault(x => x.Reg.Contains(farmPostalCode)).KNMI_zone; + // climate (zone, month, year) + var climate = new Dictionary<(string, string, int), ClimateVariable>(); + + if (dataClimate.Count() > 0) + { + foreach (var row in dataClimate) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || row.Split(';')[0] == "KNMI_zone") + { + continue; + } + var rowArr = row.Split(';'); + if (int.Parse(rowArr[3]) == climateScenarioNumber) + { + climate.Add(($"zone{rowArr[0]}", $"M{rowArr[2]}", int.Parse(rowArr[1])), new ClimateVariable(double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture), double.Parse(rowArr[6], CultureInfo.InvariantCulture))); + } + } + + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + if (climate.Any(x => x.Key.Item1 == rowArr[0] && x.Key.Item2 == rowArr[1] && x.Key.Item3 == int.Parse(rowArr[2]))) + { + continue; + } + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + else + { + foreach (var row in data) + { + if (string.IsNullOrEmpty(row) || row.Split(';').Length == 0 || string.IsNullOrEmpty(row.Split(';')[0])) + { + continue; + } + var rowArr = row.Split(';'); + climate.Add((rowArr[0], rowArr[1], int.Parse(rowArr[2])), new ClimateVariable(double.Parse(rowArr[3], CultureInfo.InvariantCulture), double.Parse(rowArr[4], CultureInfo.InvariantCulture), double.Parse(rowArr[5], CultureInfo.InvariantCulture))); + } + } + + + var climateVariable = new Dictionary>(); + + foreach (var field in farmInput.CropFields.Select(s => s.Name)) + { + var monthClimateList = new List(); + foreach (var month in gisSoilSet.AllMonths) + { + var climateYear = loopYear > 2050 || loopYear < 2011 ? 2012 : loopYear; + var monthData = climate.Single(x => x.Key.Item1 == farmZone && x.Key.Item2 == month && x.Key.Item3 == climateYear).Value; + var newMonthData = new ClimateVariable(monthData.Temperature, monthData.Precipitation, monthData.Evapotranspiration * 1.25); + monthClimateList.Add(newMonthData); + } + climateVariable.Add(field, monthClimateList); + } + + return climateVariable; + } + + private string GetProvinceCode(SetsForDataTransformation dataTransformationSet, int postalCode) + { + // get number of postalcode based on geometry? + var farm_reg = dataTransformationSet.NUTS0NUTSII.SingleOrDefault(s => s.reg.Any(x => x == postalCode)); + if (farm_reg == null) + { + throw new Exception($"reg {postalCode} not found"); + } + var provinceCode = farm_reg.prov; + return provinceCode; + } + + private Dictionary<(string, int), List> GetCarbonInputGreenManure(int loopYear, CarbonRequest farmInput, List yieldGreenManureConfig) + { + var carbonInputGreenManure = new Dictionary<(string, int), List>(); + + if (farmInput == null) + { + } + else + { + foreach (var field in farmInput.CropFields) + { + foreach (var manures in field.GreenManures) + { + foreach (var manure in manures.GreenManureTypes) + { + var manureQ = yieldGreenManureConfig.SingleOrDefault(x => x.ManureName.ToLower() == manure.Type.ToLower()); + double manureQuality2 = manure.Quality == Quality.Good ? manureQ.GoodQuality : manure.Quality == Quality.Average ? manureQ.AverageQuality : manure.Quality == Quality.Bad ? manureQ.BadQuality : 0; + if (manureQuality2 > 0) + { + carbonInputGreenManure.Add((field.Name, manures.Year), new List { new ColumnValue(manure.Type, manureQuality2) }); + } + } + } + } + } + + return carbonInputGreenManure; + } + + private static string GetPostalCodeFromGeometry(NetTopologySuite.Geometries.Geometry geometry) + { + //// Set crs default geometry factory to EPSG:4326 + NetTopologySuite.NtsGeometryServices.Instance = new NetTopologySuite.NtsGeometryServices(NetTopologySuite.Geometries.Implementation.CoordinateArraySequenceFactory.Instance, + new PrecisionModel(PrecisionModels.Floating), 4326); + // Register all vector drivers + Ogr.RegisterAll(); + + // item.geometry is always in WGS84 so reproject to EPSG:28992 + var localReference = new LocalReference("EPSG:28992"); + var localGeometry = localReference.ToLocalPolygon(geometry as Polygon); + + // get postal code from shape file + // open shape file + using (var postalcodes = Ogr.Open("config/PC4/PC4.shp", 0)) + { + // get first layer + var pc4Layer = postalcodes.GetLayerByIndex(0); + + // set spatial filter to geometry ( only intersecting features are retrieved ) + pc4Layer.SetSpatialFilter(localGeometry.Centroid.ToOGRGeometry()); + + // get next feature + var pc4Feature = pc4Layer.GetNextFeature(); + + // if feature retrieved get the PC4 attribute from it + if (pc4Feature is object) + { + return pc4Feature.GetFieldAsString("PC4"); + } + } + + return ""; + } + + private string MapSoil(string soil) + { + switch (soil) + { + case "6": + case "7": + return "Klei"; + case "1": + return "Zand"; + default: + return "Loss"; + } + } + + private static double CalculateMedian(List numbers) + { + if (numbers == null || numbers.Count == 0) + { + throw new InvalidOperationException("The list is empty or null."); + } + + numbers.Sort(); + + int count = numbers.Count; + if (count % 2 == 0) + { + // Even number of elements + double mid1 = numbers[count / 2 - 1]; + double mid2 = numbers[count / 2]; + return (mid1 + mid2) / 2.0; + } + else + { + // Odd number of elements + return numbers[count / 2]; + } } } } From 370869ea723bf24eadcbfec181be984c55feba27 Mon Sep 17 00:00:00 2001 From: Francisco Salas Date: Fri, 28 Mar 2025 14:23:00 +0100 Subject: [PATCH 5/7] fix median of balance --- CarbonCalculation25.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CarbonCalculation25.cs b/CarbonCalculation25.cs index 79edabb..008f3b7 100644 --- a/CarbonCalculation25.cs +++ b/CarbonCalculation25.cs @@ -311,6 +311,7 @@ namespace FarmMapsAPI.Carbon var SOC_CarbonResidues = yearValues.Select(x => x.SOC_CarbonResidues).First()[1]; var SOC_CarbonManure = yearValues.Select(x => x.SOC_CarbonManure).First()[1]; var Emision = yearValues.Select(x => x.Emision).First()[1]; + yearSummary.Balance = balance; yearSummary.Bulk_Density = Bulk_Density; yearSummary.Initial = Initial; yearSummary.IniCcontent = IniCcontent; From 5ae8dc6611e951e9be552b0c5d895e24327c06b8 Mon Sep 17 00:00:00 2001 From: jenkins Date: Fri, 4 Apr 2025 08:48:18 +0000 Subject: [PATCH 6/7] Updated project references #125 --- CarbonLib.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CarbonLib.csproj b/CarbonLib.csproj index ee4dca5..2816d64 100644 --- a/CarbonLib.csproj +++ b/CarbonLib.csproj @@ -8,11 +8,11 @@ false false false - 4.14.0 + 4.16.0 - + From db213f41df6d5fc1fab2ce24037761043d6b4565 Mon Sep 17 00:00:00 2001 From: jenkins Date: Fri, 4 Apr 2025 08:58:29 +0000 Subject: [PATCH 7/7] [ci skip] Updated project references #126 --- CarbonLib.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CarbonLib.csproj b/CarbonLib.csproj index 2816d64..cf9b20f 100644 --- a/CarbonLib.csproj +++ b/CarbonLib.csproj @@ -12,7 +12,7 @@ - +