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; 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 string Validate(CarbonRequest farmInput) { 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 CarbonRequest MapFarmMapsToMiterra(FarmMapsCarbonRequest farmInput) { 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 } } }); } } } 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) { 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]; } } } }