From 8651f534c918c1931a553eadbb00e6355b1cb475 Mon Sep 17 00:00:00 2001 From: Francisco Salas Date: Mon, 17 Feb 2025 08:27:19 +0100 Subject: [PATCH] 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")]