/// <summary> /// Main Streamflow Disaggregation script /// Follows procedures laid out by UofI's A.Acharya and Dr.Ryu /// We programmed a monthly-to-daily-disaggregation method in 2012 initially /// based on some research by University of Idaho academics; the paper that the /// program is based can be found in the links below. We've since made several /// modifications to the program mainly to make it more robust in the sense that /// it handles more cases that would have resulted in errors and to /// make the mass-balancing more appropriate. /// /// Published Journal Article - http://ascelibrary.org/doi/abs/10.1061/(ASCE)HE.1943-5584.0000818 ///Article Manuscript - http://water.cals.uidaho.edu/publications/SimpleDisaggregation_Acharya_2013.pdf /// </summary> /// <param name="daily">daily series (cfs)</param> /// <param name="monthly">monthly series (cfs or acre-feet)</param> /// <returns></returns> public static Series RMSEInterp(Series daily, Series monthly) { // Generates the monthly totals for the RMS calculations in cu.ft/month Series SSmonthTot = MonthSum(Math.MonthlyAverage(daily)); Series TSmonthTot = MonthSum(ConvertAcreFeetToCfs(monthly)); // Builds a Series to keep track of the corresponding year with the minimum RMSe Series TSrms = RMSEGenerateMatchList(SSmonthTot, TSmonthTot); // New series for the estimated daily value Series TSdaily = new Series(); // Loop to calculate the daily estimate for (int i = 0; i < TSrms.Count; i++) { int targetYear = Convert.ToInt16(TSrms[i].Value); int sourceYear = TSrms[i].DateTime.Year; // Leap Years are fun! Catch leap/non-leap year mismatches. // If the target is a leap year, this leaves 2-29 empty DateTime tLookup; if (TSrms[i].DateTime.Month == 2 && (DateTime.IsLeapYear(targetYear) ^ DateTime.IsLeapYear(sourceYear))) { tLookup = new DateTime(targetYear, TSrms[i].DateTime.Month, 28); } else { tLookup = new DateTime(targetYear, TSrms[i].DateTime.Month, TSrms[i].DateTime.Day); } // Calculates daily ratio of the monthly total for the SS double SSmatchMonthly = SSmonthTot.Lookup(tLookup); DateTime tStart = new DateTime(targetYear, TSrms[i].DateTime.Month, 1); Series SSmatchDaily = TimeSeries.Math.FillMissingWithZero(daily.Subset(tStart, tLookup)); Series SSratioTemp = SSmatchDaily / SSmatchMonthly; // Catches NaN values if the SS monthly data is zero and leap day mass balance problems Series SSratio = new Series(); double leapDayRatio = 0.0; for (int x = 0; x < SSratioTemp.Count; x++) { Point ptX = SSratioTemp[x]; if (ptX.Value.ToString() == "NaN" || SSmatchMonthly == 0.0) { SSratio.Add(ptX.DateTime, 0.0); continue; } // Catches TS leap years and ensures that mass balance is preserved with Feb-29th if (DateTime.IsLeapYear(sourceYear) && !DateTime.IsLeapYear(targetYear) && SSratio.MinDateTime.Month == 2) { leapDayRatio = leapDayRatio + (ptX.Value / 28.0); SSratio.Add(ptX.DateTime, ptX.Value - (ptX.Value / 28.0)); } else if (!DateTime.IsLeapYear(sourceYear) && DateTime.IsLeapYear(targetYear) && SSratio.MinDateTime.Month == 2) { leapDayRatio = daily[new DateTime(SSratioTemp.MaxDateTime.Year, 2, 29)].Value / SSmatchMonthly; SSratio.Add(ptX.DateTime, ptX.Value + (leapDayRatio / 27.0)); } else { SSratio.Add(ptX); } } // Calculates the estimated daily for the TS given the monthly total and SS ratio TSdaily = RMSEGenerateDaily(TSdaily, TSmonthTot.Lookup(TSrms[i].DateTime.Date), SSmatchDaily, SSratio, targetYear, sourceYear, leapDayRatio); } return(TSdaily); }