//Reads in the forcing file.  forcingFileStartDate is used if a VIC
        //file is being imported to allow the date of each row to be determined
        //and stored.
        private void readForcingFile(string forcingFile, ForcingFormat format,
                                     DateTime forcingFileStartDate)
        {
            DateTime startDate = new DateTime(dates[0].startYear, dates[0].startMonth, 1);//period to be adjusted starts on this date
            DateTime endDate   = new DateTime(dates[0].endYear, dates[0].endMonth, 1);

            endDate = endDate.AddMonths(1);//period to be adjusted ends on the day before this date

            switch (format)
            {
            case ForcingFormat.VIC:
                forcingData = readForcingFileVIC(forcingFile, startDate, endDate, forcingFileStartDate);
                break;

            case ForcingFormat.DHSVM:
                forcingData = readForcingFileDHSVM(forcingFile, startDate, endDate);
                break;

            case ForcingFormat.GSFLOW:
                forcingDataGSFLOW = readForcingFileGSFLOW(forcingFile, startDate, endDate);
                break;

            default:
                throw new InvalidEnumArgumentException();
            }
        }
        //write out copies of the forcing file, one for each ensemble, adjusting the precip and temp columns in the process
        private void writeAdjustedForcingFiles(string forcingFile, ForcingFormat format)
        {
            switch (format)
            {
            case ForcingFormat.VIC:
            case ForcingFormat.DHSVM:
                writeAdjustedForcingFilesVICorDHSVM(forcingFile, format);
                break;

            case ForcingFormat.GSFLOW:
                writeAdjustedForcingFilesGSFLOW(forcingFile, format);
                break;

            default:
                throw new InvalidEnumArgumentException();
            }
        }
        /// <summary>
        /// Reads in a forcing file and writes out a copy for each ensemble
        /// with the precipitation and temperatures adjusted according to the
        /// ensemble results.
        /// </summary>
        /// <param name="forcingFile">The path to the forcing file.</param>
        /// <param name="VIC">True if VIC, false if DHSVM</param>
        public void adjustForcingFile(string forcingFile, ForcingFormat format,
                                      bool generateDatabase, DateTime forcingFileStartDate = default(DateTime))
        {
            if (outputFolderName == "")
            {
                return;
            }
            if (format == ForcingFormat.VIC && forcingFileStartDate == default(DateTime))
            {
                return;
            }

            //read in forcing file
            readForcingFile(forcingFile, format, forcingFileStartDate);

            //write adjusted data to output folder
            writeAdjustedForcingFiles(forcingFile, format);

            //generate pisces database if requested
            //if (generateDatabase)
            //    generatePiscesDatabase();
        }
        private void writeAdjustedForcingFilesVICorDHSVM(string forcingFile,
                                                         ForcingFormat format)
        {
            findMonthlyValues(format);
            for (int range = 0; range < dates.Count - 1; range++)
            {
                var output = new List <string> [ensembles.Length];
                for (int i = 0; i < output.Length; i++)
                {
                    output[i] = new List <string>();
                }

                int         index     = 0;
                MonthlyData monthData = monthlyData[0];

                foreach (KeyValuePair <DateTime, double[]> pair in forcingData)
                {
                    if (format == ForcingFormat.VIC)
                    {
                        if (pair.Key.Day == 1)
                        {
                            monthData = monthlyData[index++];
                        }

                        //value in vic = Precip, MaxTemp, MinTemp, Wind, AvgTemp;     monthData.changeFactors = future date ranges * ensembles * precip, temp
                        for (int ensemble = 0; ensemble < ensembles.Length; ensemble++)
                        {
                            double precip = pair.Value[0];
                            if (monthData.changeFactors[range, ensemble, 0] != 0)//multiply precip value by change factor if factor is not 0, change factor will be 0 sometimes with summer only
                            {
                                precip *= monthData.changeFactors[range, ensemble, 0];
                            }
                            output[ensemble].Add(precip.ToString("F04") + "\t" + (pair.Value[1] + monthData.changeFactors[range, ensemble, 1]).ToString("F04") +
                                                 "\t" + (pair.Value[2] + monthData.changeFactors[range, ensemble, 1]).ToString("F04") + "\t" + pair.Value[3].ToString("F04"));
                        }
                    }
                    else if (format == ForcingFormat.DHSVM)
                    {
                        if (pair.Key.Day == 1 && pair.Key.Hour == 0)
                        {
                            monthData = monthlyData[index++];
                        }

                        string date    = pair.Key.ToString("MM/dd/yyyy-HH");
                        string glacier = "";//if the DHSVM file has 9 columns, the last column has something to do with glacier lapse rates
                        if (pair.Value.Length == 8)
                        {
                            glacier = pair.Value[7].ToString("F08");
                        }

                        //value = temp, ?, ?, ?, ?, precip, ?, ?,  monthData.changeFactors = future date ranges * ensembles * precip, temp
                        for (int ensemble = 0; ensemble < ensembles.Length; ensemble++)
                        {
                            double precip = pair.Value[5];
                            if (monthData.changeFactors[range, ensemble, 0] != 0)//multiply precip value by change factor if factor is not 0, change factor will be 0 sometimes with summer only
                            {
                                precip *= monthData.changeFactors[range, ensemble, 0];
                            }
                            output[ensemble].Add(date + " " + (pair.Value[0] + monthData.changeFactors[range, ensemble, 1]).ToString("F04") + " " + pair.Value[1].ToString("F04") + " " +
                                                 pair.Value[2].ToString("F04") + " " + pair.Value[3].ToString("F04") + " " + pair.Value[4].ToString("F04") + " " +
                                                 precip.ToString("F07") + " " + pair.Value[6].ToString("F08") + " " + glacier);
                        }
                    }
                }

                for (int ensemble = 0; ensemble < output.Length; ensemble++)
                {
                    var fname = outputFolderName + "/" + makeValidFileName(ensembles[ensemble].ensembleName) + "_" + dates[range + 1].ToStringWithUnderscores() + "_" + Path.GetFileName(forcingFile);
                    using (TextWriter fileTW = new StreamWriter(fname)) {
                        fileTW.NewLine = "\n";
                        for (int i = 0; i < output[ensemble].Count; i++)
                        {
                            fileTW.WriteLine(output[ensemble][i]);
                        }
                    }
                }
            }
        }
        private void writeAdjustedForcingFilesGSFLOW(string forcingFile,
                                                     ForcingFormat format)
        {
            for (int range = 0; range < dates.Count - 1; range++)
            {
                var output = new List <KeyValuePair <DateTime, Dictionary <string, double[]> > > [ensembles.Length];
                for (int i = 0; i < ensembles.Length; i++)
                {
                    output[i] = copyForcingDataGSFLOW();
                }

                //use precip as surrogate for number of grid points to adjust
                for (int i = 0; i < varsGSFLOW["precip"]; i++)
                {
                    forcingData = getVIClikeGSFLOWforcingData(i);
                    findMonthlyValues(format);

                    int         monthIdx  = 0;
                    MonthlyData monthData = monthlyData[0];

                    int dateIdx = 0;
                    foreach (KeyValuePair <DateTime, double[]> pair in forcingData)
                    {
                        if (pair.Key.Day == 1)
                        {
                            monthData = monthlyData[monthIdx++];
                        }

                        //values = precip, tmax, tmin, tavg     monthData.changeFactors = future date ranges * ensembles * precip, temp
                        for (int ensemble = 0; ensemble < ensembles.Length; ensemble++)
                        {
                            double precip       = pair.Value[0];
                            double precipFactor = monthData.changeFactors[range, ensemble, 0];
                            double tempFactor   = monthData.changeFactors[range, ensemble, 1];
                            if (precipFactor != 0)    //multiply precip value by change factor if factor is not 0, change factor will be 0 sometimes with summer only
                            {
                                precip *= precipFactor;
                            }
                            output[ensemble][dateIdx].Value["precip"][i] = precip;
                            output[ensemble][dateIdx].Value["tmax"][i]   = pair.Value[1] + tempFactor;
                            output[ensemble][dateIdx].Value["tmin"][i]   = pair.Value[2] + tempFactor;
                        }
                        dateIdx++;
                    }
                }

                //write output files to GSFLOW format
                for (int ensemble = 0; ensemble < ensembles.Length; ensemble++)
                {
                    var fname = outputFolderName + "/" + makeValidFileName(ensembles[ensemble].ensembleName) + "_" + dates[range + 1].ToStringWithUnderscores() + "_" + Path.GetFileName(forcingFile);
                    using (TextWriter fileTW = new StreamWriter(fname)) {
                        fileTW.NewLine = "\n";
                        //write header
                        foreach (var line in headerGSFLOW)
                        {
                            fileTW.WriteLine(line);
                        }
                        for (int i = 0; i < output[ensemble].Count; i++)
                        {
                            //write date
                            fileTW.Write(output[ensemble][i].Key.ToString("yyyy M d H m s") + " ");
                            //write each var
                            var numVars = varsOrderedGSFLOW.Count;
                            for (int j = 0; j < numVars; j++)
                            {
                                var var  = varsOrderedGSFLOW[j];
                                var line = string.Join(" ", output[ensemble][i].Value[var].Select(x => x.ToString("F02")).ToArray());
                                fileTW.Write(line);

                                if (j < numVars - 1)
                                {
                                    fileTW.Write(" ");
                                }
                            }
                            fileTW.WriteLine("");
                        }
                    }
                }
            }
        }
        //Creates a list of MonthlyData objects, one for each month, containing data about each month
        private void findMonthlyValues(ForcingFormat format)
        {
            double totalTemp = 0, avgTemp = 0, totalPrecip = 0;
            int    numOfTimePeriodsThisMonth = 0, month = 0, year = 0, index = 0;

            double[,,] changeFactors;//temporary array to pass to MonthlyData object
            Dictionary <int, int>[] precipPercentiles, tempPercentiles;
            int precipPercentile, tempPercentile;

            List <KeyValuePair <int, double> >[] precipValues = new List <KeyValuePair <int, double> > [12]; //a list of totalPrecip values by month
            List <KeyValuePair <int, double> >[] tempValues = new List <KeyValuePair <int, double> > [12];   //a list of average temp values by month

            //initialize lists
            monthlyData = new List <MonthlyData>();
            for (int i = 0; i < 12; i++)
            {
                precipValues[i] = new List <KeyValuePair <int, double> >();
                tempValues[i]   = new List <KeyValuePair <int, double> >();
            }

            //creates a MonthlyData object for each month in forcingData
            foreach (KeyValuePair <DateTime, double[]> pair in forcingData)
            {
                if ((pair.Key.Day == 1 && (format == ForcingFormat.VIC || format == ForcingFormat.GSFLOW)) ||
                    (format == ForcingFormat.DHSVM && pair.Key.Day == 1 && pair.Key.Hour == 0))  //new month

                {
                    if (numOfTimePeriodsThisMonth != 0)
                    {
                        //add new MonthlyData object to monthlyData
                        avgTemp = totalTemp / numOfTimePeriodsThisMonth;
                        monthlyData.Add(new MonthlyData(index, year, month, totalPrecip, avgTemp));
                        precipValues[month].Add(new KeyValuePair <int, double>(index, totalPrecip));
                        tempValues[month].Add(new KeyValuePair <int, double>(index, avgTemp));
                        index++;
                    }

                    //reset variables
                    month = pair.Key.Month - 1;
                    year  = pair.Key.Year;
                    numOfTimePeriodsThisMonth = 0;
                    totalTemp = totalPrecip = 0;
                }

                switch (format)
                {
                case ForcingFormat.VIC:
                    //value = Precip, MaxTemp, MinTemp, Wind, AvgTemp
                    totalPrecip += pair.Value[0];
                    totalTemp   += pair.Value[4];
                    break;

                case ForcingFormat.DHSVM:
                    //value = temp, ?, ?, ?, ?, precip, ?, ?
                    totalPrecip += pair.Value[5];
                    totalTemp   += pair.Value[0];
                    break;

                case ForcingFormat.GSFLOW:
                    //values = precip, tmax, tmin, tavg
                    totalPrecip += pair.Value[0];
                    totalTemp   += pair.Value[3];
                    break;

                default:
                    throw new InvalidEnumArgumentException();
                }

                numOfTimePeriodsThisMonth++;
            }

            //add last MonthlyData object to monthlyData
            avgTemp = totalTemp / numOfTimePeriodsThisMonth;
            monthlyData.Add(new MonthlyData(index, year, month, totalPrecip, avgTemp));
            precipValues[month].Add(new KeyValuePair <int, double>(index, totalPrecip));
            tempValues[month].Add(new KeyValuePair <int, double>(index, avgTemp));

            //find percentiles
            precipPercentiles = getPercentiles(precipValues);
            tempPercentiles   = getPercentiles(tempValues);

            //get data from ProcessData instance
            ensembles = processor.getEnsembles();
            setNamePadding();

            //add percentiles change factors to each monthlyData object
            for (int range = 0; range < dates.Count - 1; range++)
            {
                foreach (MonthlyData md in monthlyData)
                {
                    if (md.changeFactors == null)
                    {
                        changeFactors = new double[dates.Count - 1, ensembles.Length, 2];//ensembles * precip, temp
                    }
                    else
                    {
                        changeFactors = md.changeFactors;
                    }
                    precipPercentile = precipPercentiles[md.month][md.index];
                    tempPercentile   = tempPercentiles[md.month][md.index];
                    //hDE = 12 months * 49 quantiles .02 - .98 * precip, temp * future periods
                    //fill changeFactors array
                    for (int i = 0; i < ensembles.Length; i++)
                    {
                        ProcessData.Ensemble ensemble = ensembles[i];
                        //precip
                        changeFactors[range, i, 0] = ensemble.hybridDeltaEnsemble[md.month, precipPercentile, 0, range];

                        //temp
                        changeFactors[range, i, 1] = ensemble.hybridDeltaEnsemble[md.month, tempPercentile, 1, range];
                    }

                    //fill in remaining fields in md
                    md.precipPct     = precipPercentile;
                    md.tempPct       = tempPercentile;
                    md.changeFactors = changeFactors;
                }
            }
        }