//--------------------------------------------------------------------- //private static void WriteAnnualLog(IEcoregion ecoregion, int year, AnnualClimate_Monthly annualClimateMonthly, AnnualClimate_Daily annualClimate_Daily) private static void WriteAnnualLog(IEcoregion ecoregion, int year, AnnualClimate_Monthly annualClimateMonthly) { AnnualLog.Clear(); AnnualLog al = new AnnualLog(); //al.SimulationPeriod = TBD al.Time = year; al.EcoregionName = ecoregion.Name; al.EcoregionIndex = ecoregion.Index; //if (future_allData_granularity == TemporalGranularity.Daily) // al.BeginGrow = annualClimate_Daily.BeginGrowing; //else al.BeginGrow = annualClimateMonthly.BeginGrowing; //if (future_allData_granularity == TemporalGranularity.Daily) // al.EndGrow = annualClimate_Daily.EndGrowing; //else al.EndGrow = annualClimateMonthly.EndGrowing; al.TAP = annualClimateMonthly.TotalAnnualPrecip; al.MAT = annualClimateMonthly.MeanAnnualTemperature; al.PDSI = Future_MonthlyData[year][ecoregion.Index].PDSI; // VS: might need FWI in annual climate //al.FWI = Future_MonthlyData[year][ecoregion.Index].FWI; AnnualLog.AddObject(al); AnnualLog.WriteToFile(); }
public static void GenerateEcoregionClimateData(IEcoregion ecoregion, int startYear, double latitude, double fieldCapacity, double wiltingPoint) { // JM: these next three lines are not currently used, but may need to be modified if used: //int numberOftimeSteps = Climate.ModelCore.EndTime - Climate.ModelCore.StartTime; //annualPDSI = new double[Climate.ModelCore.Ecoregions.Count, future_allData.Count]; //landscapeAnnualPDSI = new double[future_allData.Count]; double[] temperature_normals = new double[12]; double[] precip_normals = new double[12]; double availableWaterCapacity = fieldCapacity - wiltingPoint; Climate.ModelCore.UI.WriteLine(" Core.StartTime = {0}, Core.EndTime = {1}.", ModelCore.StartTime, ModelCore.EndTime); //Climate.ModelCore.UI.WriteLine(" Climate.LandscapeAnnualPDSI.Length = {0}.", Climate.LandscapeAnnualPDSI.Length); //First Calculate Climate Normals from Spin-up data int timeStepIndex = 0; foreach (KeyValuePair <int, AnnualClimate_Monthly[]> timeStep in Spinup_MonthlyData) { //Climate.ModelCore.UI.WriteLine(" Calculating Weather for SPINUP: timeStep = {0}, actualYear = {1}", timeStep.Key, startYear + timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, latitude, Climate.Phase.SpinUp_Climate, timeStep.Key, timeStepIndex); Spinup_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] += annualClimateMonthly.MonthlyTemp[mo]; precip_normals[mo] += annualClimateMonthly.MonthlyPrecip[mo]; } timeStepIndex++; } // Calculate AVERAGE T normal. for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] /= (double)Spinup_MonthlyData.Count; precip_normals[mo] /= (double)Spinup_MonthlyData.Count; //Climate.ModelCore.UI.WriteLine("Month = {0}, Original Monthly T normal = {1}", mo, month_Temp_normal[mo]); } timeStepIndex = 0; PDSI_Calculator.InitializeEcoregion_PDSI(temperature_normals, precip_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); foreach (KeyValuePair <int, AnnualClimate_Monthly[]> timeStep in Future_MonthlyData) { //Climate.ModelCore.UI.WriteLine(" Completed calculations for Future_Climate: TimeStepYear = {0}, actualYear = {1}", timeStep.Key, startYear + timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, latitude, Climate.Phase.Future_Climate, timeStep.Key, timeStepIndex); Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly;
//--------------------------------------------------------------------------- public static double CalculateAnnualActualEvapotranspiration(AnnualClimate_Monthly annualClimate, double fieldCapacity) { //I don't think this method is every called. // field capacity input as cm // variable with xVariableName indicate conversion to mm double xFieldCap = fieldCapacity * 10.0; double waterAvail = 0.0; double actualET = 0.0; double oldWaterAvail = 0.0; double accPotWaterLoss = 0.0; for (int month = 0; month < 12; month++) { double monthlyRain = annualClimate.MonthlyPrecip[month]; double potentialET = annualClimate.MonthlyPET[month]; //Calc potential water loss this month double potWaterLoss = monthlyRain - potentialET; //If monthlyRain doesn't satisfy potentialET, add this month's potential //water loss to accumulated water loss from soil if (potWaterLoss < 0.0) { accPotWaterLoss += potWaterLoss; double xAccPotWaterLoss = accPotWaterLoss * 10.0; //Calc water retained in soil given so much accumulated potential //water loss Pastor and Post. 1984. Can. J. For. Res. 14:466:467. waterAvail = fieldCapacity * System.Math.Exp((.000461 - 1.10559 / xFieldCap) * (-1.0 * xAccPotWaterLoss)); if (waterAvail < 0.0) { waterAvail = 0.0; } //changeSoilMoisture - during this month double changeSoilMoisture = waterAvail - oldWaterAvail; //Calc actual evapotranspiration (AET) if soil water is drawn down actualET += (monthlyRain - changeSoilMoisture); } //If monthlyRain satisfies potentialET, don't draw down soil water else { waterAvail = oldWaterAvail + potWaterLoss; if (waterAvail >= fieldCapacity) { waterAvail = fieldCapacity; } double changeSoilMoisture = waterAvail - oldWaterAvail; //If soil partially recharged, reduce accumulated potential //water loss accordingly accPotWaterLoss += changeSoilMoisture; //If soil completely recharged, reset accumulated potential //water loss to zero if (waterAvail >= fieldCapacity) { accPotWaterLoss = 0.0; } //If soil water is not drawn upon, add potentialET to AET actualET += potentialET; } oldWaterAvail = waterAvail; //Climate.TextLog.WriteLine("Actual ET Calcs. Rain={0},PET={1}, potWaterLoss={2:0.0},,fieldcapacity={3:0.000}, oldwaterAvail={4:0.000}, actualET={5:0.000}", monthlyRain, potentialET, potWaterLoss, fieldCapacity, oldWaterAvail, actualET); } return(actualET); }
//public static void GenerateClimate_GetPDSI(int startYear, int endYear, int latitude, double fieldCapacity, double wiltingPoint) //{ // string outputFilePath = @"PDSI_BaseBDA_Genrated_Climate.csv"; // File.WriteAllText(outputFilePath, String.Empty); // foreach (IEcoregion ecoregion in Climate.ModelCore.Ecoregions) // { // AnnualClimate_Monthly[] acs; // int numOfYears = endYear - startYear + 1; // acs = new AnnualClimate_Monthly[numOfYears]; // //foreach time step it should be called // for (int i = startYear; i <= endYear; i++) // { // acs[i - startYear] = new AnnualClimate_Monthly(ecoregion, 0, latitude); // Latitude should be given // //Climate.ModelCore.UI.WriteLine(ac.MonthlyTemp[0].ToString() + "\n"); // //Climate.ModelCore.UI.WriteLine(ac.MonthlyPrecip[0].ToString() + "\n"); // } // double[] mon_T_normal = new double[12];//new double[12] { 19.693, 23.849, 34.988, 49.082, 60.467, 70.074, 75.505, 73.478, 64.484, 52.634, 36.201, 24.267 }; // IClimateRecord[] climateRecs = new ClimateRecord[12]; // //If timestep is 0 then calculate otherwise get the mon_T_normal for timestep 0 // Climate.TimestepData = future_allData[0]; // for (int mo = 0; mo < 12; mo++) // { // climateRecs[mo] = Climate.TimestepData[ecoregion.Index, mo]; // mon_T_normal[mo] = (climateRecs[mo].AvgMinTemp + climateRecs[mo].AvgMinTemp) / 2; // } // double AWC = fieldCapacity - wiltingPoint; // //double latitude = Landis.Extension.Succession.Century.EcoregionData.Latitude[ecoregion]; // new PDSI_Calculator().CalculatePDSI(acs, mon_T_normal, AWC, latitude, /*outputFilePath,*/ UnitSystem.metrics); // } //} //public static void GenerateEcoregionClimateData() //{ //} public static void GenerateEcoregionClimateData(IEcoregion ecoregion, int startYear, double latitude, double fieldCapacity, double wiltingPoint) { Climate.ModelCore.UI.WriteLine(" Generating Ecoregion Climate Data for ecoregion = {0}.", ecoregion.Name); int numberOftimeSteps = Climate.ModelCore.EndTime - Climate.ModelCore.StartTime; annualPDSI = new double[Climate.ModelCore.Ecoregions.Count, future_allData.Count]; //numberOftimeSteps + 1]; landscapeAnnualPDSI = new double[future_allData.Count]; //numberOftimeSteps+1]; double[] temperature_normals = new double[12]; double availableWaterCapacity = fieldCapacity - wiltingPoint; //Climate.ModelCore.UI.WriteLine(" Latitude = {0}, Available Water = {1}.", latitude, availableWaterCapacity); //IClimateRecord[] climateRecs = new ClimateRecord[12]; //int minimumTime = 5000; //Firt Calculate Climate Normals from Spin-up data foreach (KeyValuePair <int, IClimateRecord[, ]> timeStep in spinup_allData) { //Climate.ModelCore.UI.WriteLine(" Calculating Weather for SPINUP Year = {0}.", timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, startYear + timeStep.Key, latitude, Climate.Phase.SpinUp_Climate, timeStep.Key); Spinup_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] += annualClimateMonthly.MonthlyTemp[mo]; } } // Calculate AVERAGE T normal. for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] /= (double)spinup_allData.Count; //Climate.ModelCore.UI.WriteLine("Month = {0}, Original Monthly T normal = {1}", mo, month_Temp_normal[mo]); } int timestepIndex = 0; // Next calculate PSDI for the future data foreach (KeyValuePair <int, AnnualClimate_Monthly[]> timeStep in Future_MonthlyData) //foreach (KeyValuePair<int, IClimateRecord[,]> timeStep in future_allData) { //if (timeStep.Key < minimumTime) // minimumTime = timeStep.Key; //if (timestepIndex > numberOftimeSteps) // break; //Climate.ModelCore.UI.WriteLine(" Calculating Weather for FUTURE Year = {0}.", timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, startYear + timeStep.Key, latitude, Climate.Phase.Future_Climate, timeStep.Key); Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI = PDSI_Calculator.CalculatePDSI(annualClimateMonthly, temperature_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); Climate.LandscapeAnnualPDSI[timestepIndex] += (Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI / Climate.ModelCore.Ecoregions.Count); //Climate.ModelCore.UI.WriteLine("Calculated PDSI for Ecoregion {0}, timestep {1}, PDSI Year {2}; PDSI={3:0.00}.", ecoregion.Name, timestepIndex, timeStep.Key, PDSI); timestepIndex++; } }
//--------------------------------------------------------------------- private static void WriteAnnualLog(IEcoregion ecoregion, int year, AnnualClimate_Monthly annualClimateMonthly) { AnnualLog.Clear(); AnnualLog al = new AnnualLog(); //al.SimulationPeriod = TBD al.Time = year; al.EcoregionName = ecoregion.Name; al.EcoregionIndex = ecoregion.Index; al.BeginGrow = annualClimateMonthly.BeginGrowing; al.EndGrow = annualClimateMonthly.EndGrowing; al.TAP = annualClimateMonthly.TotalAnnualPrecip; al.MAT = annualClimateMonthly.MeanAnnualTemperature; al.PDSI = Future_MonthlyData[year][ecoregion.Index].PDSI; AnnualLog.AddObject(al); AnnualLog.WriteToFile(); }
public static void GenerateEcoregionClimateData(IEcoregion ecoregion, int startYear, double latitude, double fieldCapacity, double wiltingPoint) { // JM: these next three lines are not currently used, but may need to be modified if used: //int numberOftimeSteps = Climate.ModelCore.EndTime - Climate.ModelCore.StartTime; //annualPDSI = new double[Climate.ModelCore.Ecoregions.Count, future_allData.Count]; //landscapeAnnualPDSI = new double[future_allData.Count]; double[] temperature_normals = new double[12]; double[] precip_normals = new double[12]; double availableWaterCapacity = fieldCapacity - wiltingPoint; Climate.TextLog.WriteLine("Core.StartTime = {0}, Core.EndTime = {1}.", ModelCore.StartTime, ModelCore.EndTime); //Climate.TextLog.WriteLine(" Climate.LandscapeAnnualPDSI.Length = {0}.", Climate.LandscapeAnnualPDSI.Length); //First Calculate Climate Normals from Spin-up data int timeStepIndex = 0; foreach (KeyValuePair<int, AnnualClimate_Monthly[]> timeStep in Spinup_MonthlyData) { //Climate.TextLog.WriteLine(" Calculating Weather for SPINUP: timeStep = {0}, actualYear = {1}", timeStep.Key, startYear + timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, latitude, Climate.Phase.SpinUp_Climate, timeStep.Key, timeStepIndex); Spinup_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] += annualClimateMonthly.MonthlyTemp[mo]; precip_normals[mo] += annualClimateMonthly.MonthlyPrecip[mo]; } timeStepIndex++; } // Calculate AVERAGE T normal. for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] /= (double)Spinup_MonthlyData.Count; precip_normals[mo] /= (double)Spinup_MonthlyData.Count; //Climate.TextLog.WriteLine("Month = {0}, Original Monthly T normal = {1}", mo, month_Temp_normal[mo]); } timeStepIndex = 0; //PDSI_Calculator.InitializeEcoregion_PDSI(temperature_normals, precip_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); foreach (KeyValuePair<int, AnnualClimate_Monthly[]> timeStep in Future_MonthlyData) { //Climate.TextLog.WriteLine(" Completed calculations for Future_Climate: TimeStepYear = {0}, actualYear = {1}", timeStep.Key, startYear + timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, latitude, Climate.Phase.Future_Climate, timeStep.Key, timeStepIndex); Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; // Next calculate PSDI for the future data //Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI = PDSI_Calculator.CalculateEcoregion_PDSI(annualClimateMonthly, temperature_normals, precip_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); //Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI = PDSI_Calculator.CalculateEcoregion_PDSI(annualClimateMonthly, temperature_normals, precip_normals, latitude, UnitSystem.metrics, ecoregion); // Climate.LandscapeAnnualPDSI[timeStepIndex] += (Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI / Climate.ModelCore.Ecoregions.Count); //Climate.TextLog.WriteLine("Calculated PDSI for Ecoregion {0}, timestep {1}, PDSI Year {2}; PDSI={3:0.00}.", ecoregion.Name, timeStepIndex, timeStep.Key, Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI); timeStepIndex++; WriteAnnualLog(ecoregion, startYear + timeStep.Key, annualClimateMonthly); } }
//--------------------------------------------------------------------------- public static double CalculateAnnualActualEvapotranspiration(AnnualClimate_Monthly annualClimate, double fieldCapacity) { //I don't think this method is every called. // field capacity input as cm // variable with xVariableName indicate conversion to mm double xFieldCap = fieldCapacity * 10.0; double waterAvail = 0.0; double actualET = 0.0; double oldWaterAvail = 0.0; double accPotWaterLoss = 0.0; for (int month = 0; month < 12; month++) { double monthlyRain = annualClimate.MonthlyPrecip[month]; double potentialET = annualClimate.MonthlyPET[month]; //Calc potential water loss this month double potWaterLoss = monthlyRain - potentialET; //If monthlyRain doesn't satisfy potentialET, add this month's potential //water loss to accumulated water loss from soil if (potWaterLoss < 0.0) { accPotWaterLoss += potWaterLoss; double xAccPotWaterLoss = accPotWaterLoss * 10.0; //Calc water retained in soil given so much accumulated potential //water loss Pastor and Post. 1984. Can. J. For. Res. 14:466:467. waterAvail = fieldCapacity * System.Math.Exp((.000461 - 1.10559 / xFieldCap) * (-1.0 * xAccPotWaterLoss)); if (waterAvail < 0.0) waterAvail = 0.0; //changeSoilMoisture - during this month double changeSoilMoisture = waterAvail - oldWaterAvail; //Calc actual evapotranspiration (AET) if soil water is drawn down actualET += (monthlyRain - changeSoilMoisture); } //If monthlyRain satisfies potentialET, don't draw down soil water else { waterAvail = oldWaterAvail + potWaterLoss; if (waterAvail >= fieldCapacity) waterAvail = fieldCapacity; double changeSoilMoisture = waterAvail - oldWaterAvail; //If soil partially recharged, reduce accumulated potential //water loss accordingly accPotWaterLoss += changeSoilMoisture; //If soil completely recharged, reset accumulated potential //water loss to zero if (waterAvail >= fieldCapacity) accPotWaterLoss = 0.0; //If soil water is not drawn upon, add potentialET to AET actualET += potentialET; } oldWaterAvail = waterAvail; //Climate.ModelCore.UI.WriteLine("Actual ET Calcs. Rain={0},PET={1}, potWaterLoss={2:0.0},,fieldcapacity={3:0.000}, oldwaterAvail={4:0.000}, actualET={5:0.000}", monthlyRain, potentialET, potWaterLoss, fieldCapacity, oldWaterAvail, actualET); } return actualET; }
//public static void GenerateClimate_GetPDSI(int startYear, int endYear, int latitude, double fieldCapacity, double wiltingPoint) //{ // string outputFilePath = @"PDSI_BaseBDA_Genrated_Climate.csv"; // File.WriteAllText(outputFilePath, String.Empty); // foreach (IEcoregion ecoregion in Climate.ModelCore.Ecoregions) // { // AnnualClimate_Monthly[] acs; // int numOfYears = endYear - startYear + 1; // acs = new AnnualClimate_Monthly[numOfYears]; // //foreach time step it should be called // for (int i = startYear; i <= endYear; i++) // { // acs[i - startYear] = new AnnualClimate_Monthly(ecoregion, 0, latitude); // Latitude should be given // //Climate.ModelCore.UI.WriteLine(ac.MonthlyTemp[0].ToString() + "\n"); // //Climate.ModelCore.UI.WriteLine(ac.MonthlyPrecip[0].ToString() + "\n"); // } // double[] mon_T_normal = new double[12];//new double[12] { 19.693, 23.849, 34.988, 49.082, 60.467, 70.074, 75.505, 73.478, 64.484, 52.634, 36.201, 24.267 }; // IClimateRecord[] climateRecs = new ClimateRecord[12]; // //If timestep is 0 then calculate otherwise get the mon_T_normal for timestep 0 // Climate.TimestepData = future_allData[0]; // for (int mo = 0; mo < 12; mo++) // { // climateRecs[mo] = Climate.TimestepData[ecoregion.Index, mo]; // mon_T_normal[mo] = (climateRecs[mo].AvgMinTemp + climateRecs[mo].AvgMinTemp) / 2; // } // double AWC = fieldCapacity - wiltingPoint; // //double latitude = Landis.Extension.Succession.Century.EcoregionData.Latitude[ecoregion]; // new PDSI_Calculator().CalculatePDSI(acs, mon_T_normal, AWC, latitude, /*outputFilePath,*/ UnitSystem.metrics); // } //} //public static void GenerateEcoregionClimateData() //{ //} public static void GenerateEcoregionClimateData(IEcoregion ecoregion, int startYear, double latitude, double fieldCapacity, double wiltingPoint) { Climate.ModelCore.UI.WriteLine(" Generating Ecoregion Climate Data for ecoregion = {0}.", ecoregion.Name); int numberOftimeSteps = Climate.ModelCore.EndTime - Climate.ModelCore.StartTime; annualPDSI = new double[Climate.ModelCore.Ecoregions.Count, future_allData.Count]; //numberOftimeSteps + 1]; landscapeAnnualPDSI = new double[future_allData.Count]; //numberOftimeSteps+1]; double[] temperature_normals = new double[12]; double availableWaterCapacity = fieldCapacity - wiltingPoint; //Climate.ModelCore.UI.WriteLine(" Latitude = {0}, Available Water = {1}.", latitude, availableWaterCapacity); //IClimateRecord[] climateRecs = new ClimateRecord[12]; //int minimumTime = 5000; //Firt Calculate Climate Normals from Spin-up data foreach (KeyValuePair<int, IClimateRecord[,]> timeStep in spinup_allData) { //Climate.ModelCore.UI.WriteLine(" Calculating Weather for SPINUP Year = {0}.", timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, startYear + timeStep.Key, latitude, Climate.Phase.SpinUp_Climate, timeStep.Key); Spinup_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] += annualClimateMonthly.MonthlyTemp[mo]; } } // Calculate AVERAGE T normal. for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] /= (double)spinup_allData.Count; //Climate.ModelCore.UI.WriteLine("Month = {0}, Original Monthly T normal = {1}", mo, month_Temp_normal[mo]); } int timestepIndex = 0; // Next calculate PSDI for the future data foreach (KeyValuePair<int, AnnualClimate_Monthly[]> timeStep in Future_MonthlyData) //foreach (KeyValuePair<int, IClimateRecord[,]> timeStep in future_allData) { //if (timeStep.Key < minimumTime) // minimumTime = timeStep.Key; //if (timestepIndex > numberOftimeSteps) // break; //Climate.ModelCore.UI.WriteLine(" Calculating Weather for FUTURE Year = {0}.", timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, startYear + timeStep.Key, latitude, Climate.Phase.Future_Climate, timeStep.Key); Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI = PDSI_Calculator.CalculatePDSI(annualClimateMonthly, temperature_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); Climate.LandscapeAnnualPDSI[timestepIndex] += (Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI / Climate.ModelCore.Ecoregions.Count); //Climate.ModelCore.UI.WriteLine("Calculated PDSI for Ecoregion {0}, timestep {1}, PDSI Year {2}; PDSI={3:0.00}.", ecoregion.Name, timestepIndex, timeStep.Key, PDSI); timestepIndex++; } }