FlowStatistics.java [src/java/m/cfa] Revision: default  Date:
package m.cfa;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
* Last Updated: 31-May-2017
* @author Tyler Wible
* @since 29-June-2011
*/
public class FlowStatistics {
    //Gets
    public String getFlowStatistics_summary() {
        return "flow_statistics.csv";
    }
    /**
     * Calculates the statistics (min, max) for various numbers of consecutive 
     * days of daily data and other hydrologic indicators of alteration.
     * Additionally, this calculates the same statistics for each year within 
     * the dataset
     * @param directory  the file path where the summary will be saved
     * @param stationId  the station ID for the current station, used to label the output
     * @param stationName  the station name for the current station, used to label the  output
     * @param flowData  the String[][] containing sorted data for the time series 
     * (column 1 = dates (yyyy-mm-dd) column 2 = value
     * @param highPercentile  the percentile value for defining a "high flow pulse"
     * typically greater than 75% = 0.75
     * @param lowPercentile  the percentile value for defining a "low flow pulse"
     * typically lower than 25% = 0.25
     * @param m  used to calculate an "m-day-average" flow
     * @param n  used to calculate an "m-day-average" low flow which has a
     * linearly interpolated recurrence interval of "n" years
     * @param showMonthlyTF  a flag to show monthly statistics (min/max/etc.) or not (which reduces the total output of the tool)
     * @param seasonBegin  the month and date (MM-dd) of the start of a seasonal analysis to be averaged over the period of data
     * @param seasonEnd  the month and date (MM-dd) of the end of a seasonal analysis to be averaged over the period of data
     * @param period1Begin  the begin date of the first period of analysis (yyyy-MM-dd), if blank ("") then no period 1 analysis is performed
     * @param period1End  the end date of the first period of analysis (yyyy-MM-dd), if blank ("") then no period 1 analysis is performed
     * @param period2Begin  the begin date of the second period of analysis (yyyy-MM-dd), if blank ("") then no period 2 analysis is performed
     * @param period2End  the end date of the first period of analysis (yyyy-MM-dd), if blank ("") then no period 2 analysis is performed
     * @param period3Begin  the begin date of the third period of analysis (yyyy-MM-dd), if blank ("") then no period 3 analysis is performed
     * @param period3End  the end date of the first period of analysis (yyyy-MM-dd), if blank ("") then no period 3 analysis is performed
     * @param waterYearTF  if true, it calculates statistics per water year (10/1 through 9/30), if false it calculates statistics per calendar year (1/1 through 12/31)
     * @return  an Object[] where returnArray[0] = flow value of "m-day-average 
     * n-year recurrence low flow"
     * returnValue[1] = the error message (if any) associated with calculating 
     * the mQn flow
     * @throws IOException
     * @throws ParseException
     */
    public Object[] calculateAllStatisticsSummaries(String directory,
                                                    String stationId,
                                                    String stationName,
                                                    String[][] flowData,
                                                    double highPercentile,
                                                    double lowPercentile,
                                                    int m,
                                                    int n,
                                                    boolean showMonthlyTF,
                                                    String seasonBegin,
                                                    String seasonEnd,
                                                    String period1Begin,
                                                    String period1End,
                                                    String period2Begin,
                                                    String period2End,
                                                    String period3Begin,
                                                    String period3End,
                                                    boolean waterYearTF) throws IOException, ParseException{
        //Get today's date for output purposes
        Date currentDate = new Date();
        SimpleDateFormat outputOnlyDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String today = outputOnlyDateFormat.format(currentDate);
        stationName = stationName.replace(",", "");
        
        //Initialize the summary result table
        int summarySize = 65;
        if(showMonthlyTF) summarySize = 197;
        
        String[][] statsSummaryTable = new String[summarySize][1];
        statsSummaryTable[0][0] = "Flow Statistics for " + stationId + "; " + stationName + "; created on " + today;
        statsSummaryTable[1][0] = "Analysis Period (calendar year)";
        statsSummaryTable[2][0] = "Count";
        statsSummaryTable[3][0] = "Maximum [cfs]";
        statsSummaryTable[4][0] = "Minimum [cfs]";
        statsSummaryTable[5][0] = "Upper Quartile [cfs]";
        statsSummaryTable[6][0] = "Lower Quartile [cfs]";
        statsSummaryTable[7][0] = "Median [cfs]";
        statsSummaryTable[8][0] = "Mean [cfs]";
        statsSummaryTable[9][0] = "Standard Deviation [cfs]";
        statsSummaryTable[10][0] = "Variance";
        statsSummaryTable[11][0] = "Skewness";
        statsSummaryTable[12][0] = "Coefficient of Variation";
        statsSummaryTable[13][0] = "Maximum (1-day) [cfs]";
        statsSummaryTable[14][0] = "Date of Maximum (1-day)";
        statsSummaryTable[15][0] = "Minimum (1-day) [cfs]";
        statsSummaryTable[16][0] = "Date of Minimum (1-day)";
        statsSummaryTable[17][0] = "Maximum (3-day) [cfs]";
        statsSummaryTable[18][0] = "Dates of Maximum (3-day)";
        statsSummaryTable[19][0] = "Minimum (3-day) [cfs]";
        statsSummaryTable[20][0] = "Dates of Minimum (3-day)";
        statsSummaryTable[21][0] = "Maximum (7-day) [cfs]";
        statsSummaryTable[22][0] = "Dates of Maximum (7-day)";
        statsSummaryTable[23][0] = "Minimum (7-day) [cfs]";
        statsSummaryTable[24][0] = "Dates of Minimum (7-day)";
        statsSummaryTable[25][0] = "Minimum (7-day) / Annual Mean  [cfs]";
        statsSummaryTable[26][0] = "Maximum (30-day) [cfs]";
        statsSummaryTable[27][0] = "Dates of Maximum (30-day)";
        statsSummaryTable[28][0] = "Minimum (30-day) [cfs]";
        statsSummaryTable[29][0] = "Dates of Minimum (30-day)";
        statsSummaryTable[30][0] = "Maximum (90-day) [cfs]";
        statsSummaryTable[31][0] = "Dates of Maximum (90-day)";
        statsSummaryTable[32][0] = "Minimum (90-day) [cfs]";
        statsSummaryTable[33][0] = "Dates of Minimum (90-day)";
        statsSummaryTable[34][0] = "Number of Zero Flow Days";
        statsSummaryTable[35][0] = "Number of Flow Reversals";
        statsSummaryTable[36][0] = "Number of Flow Rises";
        statsSummaryTable[37][0] = "Number of Flow Falls";
        statsSummaryTable[38][0] = "Number of High Pulses (> " + highPercentile + " percentile)";
        statsSummaryTable[39][0] = "Threshold for High Pulses (> " + highPercentile + " percentile) [cfs]";
        statsSummaryTable[40][0] = "Average Duration of High Pulses (> " + highPercentile + " percentile) [days]";
        statsSummaryTable[41][0] = "Number of Low Pulses (< " + lowPercentile + " percentile)";
        statsSummaryTable[42][0] = "Threshold for Low Pulses (< " + lowPercentile + " percentile) [cfs]";
        statsSummaryTable[43][0] = "Average Duration of Low Pulses (< " + lowPercentile + " percentile) [days]";
        statsSummaryTable[44][0] = "Average Positive Difference Between Consecutive Days [cfs]";
        statsSummaryTable[45][0] = "Average Negative Difference Between Consecutive Days [cfs]";
        statsSummaryTable[46][0] = "Temporal Centriod of Discharge [Day of Calendary Year]";
        statsSummaryTable[47][0] = "Richards-Baker Flow 'Flashiness' Index";
        statsSummaryTable[48][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Count)";
        statsSummaryTable[49][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Maximum) [cfs]";
        statsSummaryTable[50][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Minimum) [cfs]";
        statsSummaryTable[51][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Upper Quartile) [cfs]";
        statsSummaryTable[52][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Lower Quartile) [cfs]";
        statsSummaryTable[53][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Median) [cfs]";
        statsSummaryTable[54][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Mean) [cfs]";
        statsSummaryTable[55][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Standard Deviation) [cfs]";
        statsSummaryTable[56][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Variance)";
        statsSummaryTable[57][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Skewness)";
        statsSummaryTable[58][0] = "Season " + seasonBegin + " to " + seasonEnd + " (Coefficient of Variation)";
        
        if(showMonthlyTF){
            statsSummaryTable[59][0] = "January (Count)";
            statsSummaryTable[60][0] = "January (Maximum) [cfs]";
            statsSummaryTable[61][0] = "January (Minimum) [cfs]";
            statsSummaryTable[62][0] = "January (Upper Quartile) [cfs]";
            statsSummaryTable[63][0] = "January (Lower Quartile) [cfs]";
            statsSummaryTable[64][0] = "January (Median) [cfs]";
            statsSummaryTable[65][0] = "January (Mean) [cfs]";
            statsSummaryTable[66][0] = "January (Standard Deviation) [cfs]";
            statsSummaryTable[67][0] = "January (Variance)";
            statsSummaryTable[68][0] = "January (Skewness)";
            statsSummaryTable[69][0] = "January (Coefficient of Variation)";
            statsSummaryTable[70][0] = "February (Count)";
            statsSummaryTable[71][0] = "February (Maximum) [cfs]";
            statsSummaryTable[72][0] = "February (Minimum) [cfs]";
            statsSummaryTable[73][0] = "February (Upper Quartile) [cfs]";
            statsSummaryTable[74][0] = "February (Lower Quartile) [cfs]";
            statsSummaryTable[75][0] = "February (Median) [cfs]";
            statsSummaryTable[76][0] = "February (Mean) [cfs]";
            statsSummaryTable[77][0] = "February (Standard Deviation) [cfs]";
            statsSummaryTable[78][0] = "February (Variance)";
            statsSummaryTable[79][0] = "February (Skewness)";
            statsSummaryTable[80][0] = "February (Coefficient of Variation)";
            statsSummaryTable[81][0] = "March (Count)";
            statsSummaryTable[82][0] = "March (Maximum) [cfs]";
            statsSummaryTable[83][0] = "March (Minimum) [cfs]";
            statsSummaryTable[84][0] = "March (Upper Quartile) [cfs]";
            statsSummaryTable[85][0] = "March (Lower Quartile) [cfs]";
            statsSummaryTable[86][0] = "March (Median) [cfs]";
            statsSummaryTable[87][0] = "March (Mean) [cfs]";
            statsSummaryTable[88][0] = "March (Standard Deviation) [cfs]";
            statsSummaryTable[89][0] = "March (Variance)";
            statsSummaryTable[90][0] = "March (Skewness)";
            statsSummaryTable[91][0] = "March (Coefficient of Variation)";
            statsSummaryTable[92][0] = "April (Count)";
            statsSummaryTable[93][0] = "April (Maximum) [cfs]";
            statsSummaryTable[94][0] = "April (Minimum) [cfs]";
            statsSummaryTable[95][0] = "April (Upper Quartile) [cfs]";
            statsSummaryTable[96][0] = "April (Lower Quartile) [cfs]";
            statsSummaryTable[97][0] = "April (Median) [cfs]";
            statsSummaryTable[98][0] = "April (Mean) [cfs]";
            statsSummaryTable[99][0] = "April (Standard Deviation) [cfs]";
            statsSummaryTable[100][0] = "April (Variance)";
            statsSummaryTable[101][0] = "April (Skewness)";
            statsSummaryTable[102][0] = "April (Coefficient of Variation)";
            statsSummaryTable[103][0] = "May (Count)";
            statsSummaryTable[104][0] = "May (Maximum) [cfs]";
            statsSummaryTable[105][0] = "May (Minimum) [cfs]";
            statsSummaryTable[106][0] = "May (Upper Quartile) [cfs]";
            statsSummaryTable[107][0] = "May (Lower Quartile) [cfs]";
            statsSummaryTable[108][0] = "May (Median) [cfs]";
            statsSummaryTable[109][0] = "May (Mean) [cfs]";
            statsSummaryTable[110][0] = "May (Standard Deviation) [cfs]";
            statsSummaryTable[111][0] = "May (Variance)";
            statsSummaryTable[112][0] = "May (Skewness)";
            statsSummaryTable[113][0] = "May (Coefficient of Variation)";
            statsSummaryTable[114][0] = "June (Count)";
            statsSummaryTable[115][0] = "June (Maximum) [cfs]";
            statsSummaryTable[116][0] = "June (Minimum) [cfs]";
            statsSummaryTable[117][0] = "June (Upper Quartile) [cfs]";
            statsSummaryTable[118][0] = "June (Lower Quartile) [cfs]";
            statsSummaryTable[119][0] = "June (Median) [cfs]";
            statsSummaryTable[120][0] = "June (Mean) [cfs]";
            statsSummaryTable[121][0] = "June (Standard Deviation) [cfs]";
            statsSummaryTable[122][0] = "June (Variance)";
            statsSummaryTable[123][0] = "June (Skewness)";
            statsSummaryTable[124][0] = "June (Coefficient of Variation)";
            statsSummaryTable[125][0] = "July (Count)";
            statsSummaryTable[126][0] = "July (Maximum) [cfs]";
            statsSummaryTable[127][0] = "July (Minimum) [cfs]";
            statsSummaryTable[128][0] = "July (Upper Quartile) [cfs]";
            statsSummaryTable[129][0] = "July (Lower Quartile) [cfs]";
            statsSummaryTable[130][0] = "July (Median) [cfs]";
            statsSummaryTable[131][0] = "July (Mean) [cfs]";
            statsSummaryTable[132][0] = "July (Standard Deviation) [cfs]";
            statsSummaryTable[133][0] = "July (Variance)";
            statsSummaryTable[134][0] = "July (Skewness)";
            statsSummaryTable[135][0] = "July (Coefficient of Variation)";
            statsSummaryTable[136][0] = "August (Count)";
            statsSummaryTable[137][0] = "August (Maximum) [cfs]";
            statsSummaryTable[138][0] = "August (Minimum) [cfs]";
            statsSummaryTable[139][0] = "August (Upper Quartile) [cfs]";
            statsSummaryTable[140][0] = "August (Lower Quartile) [cfs]";
            statsSummaryTable[141][0] = "August (Median) [cfs]";
            statsSummaryTable[142][0] = "August (Mean) [cfs]";
            statsSummaryTable[143][0] = "August (Standard Deviation) [cfs]";
            statsSummaryTable[144][0] = "August (Variance)";
            statsSummaryTable[145][0] = "August (Skewness)";
            statsSummaryTable[146][0] = "August (Coefficient of Variation)";
            statsSummaryTable[147][0] = "September (Count)";
            statsSummaryTable[148][0] = "September (Maximum) [cfs]";
            statsSummaryTable[149][0] = "September (Minimum) [cfs]";
            statsSummaryTable[150][0] = "September (Upper Quartile) [cfs]";
            statsSummaryTable[151][0] = "September (Lower Quartile) [cfs]";
            statsSummaryTable[152][0] = "September (Median) [cfs]";
            statsSummaryTable[153][0] = "September (Mean) [cfs]";
            statsSummaryTable[154][0] = "September (Standard Deviation) [cfs]";
            statsSummaryTable[155][0] = "September (Variance)";
            statsSummaryTable[156][0] = "September (Skewness)";
            statsSummaryTable[157][0] = "September (Coefficient of Variation)";
            statsSummaryTable[158][0] = "October (Count)";
            statsSummaryTable[159][0] = "October (Maximum) [cfs]";
            statsSummaryTable[160][0] = "October (Minimum) [cfs]";
            statsSummaryTable[161][0] = "October (Upper Quartile) [cfs]";
            statsSummaryTable[162][0] = "October (Lower Quartile) [cfs]";
            statsSummaryTable[163][0] = "October (Median) [cfs]";
            statsSummaryTable[164][0] = "October (Mean) [cfs]";
            statsSummaryTable[165][0] = "October (Standard Deviation) [cfs]";
            statsSummaryTable[166][0] = "October (Variance)";
            statsSummaryTable[167][0] = "October (Skewness)";
            statsSummaryTable[168][0] = "October (Coefficient of Variation)";
            statsSummaryTable[169][0] = "November (Count)";
            statsSummaryTable[170][0] = "November (Maximum) [cfs]";
            statsSummaryTable[171][0] = "November (Minimum) [cfs]";
            statsSummaryTable[172][0] = "November (Upper Quartile) [cfs]";
            statsSummaryTable[173][0] = "November (Lower Quartile) [cfs]";
            statsSummaryTable[174][0] = "November (Median) [cfs]";
            statsSummaryTable[175][0] = "November (Mean) [cfs]";
            statsSummaryTable[176][0] = "November (Standard Deviation) [cfs]";
            statsSummaryTable[177][0] = "November (Variance)";
            statsSummaryTable[178][0] = "November (Skewness)";
            statsSummaryTable[179][0] = "November (Coefficient of Variation)";
            statsSummaryTable[180][0] = "December (Count)";
            statsSummaryTable[181][0] = "December (Maximum) [cfs]";
            statsSummaryTable[182][0] = "December (Minimum) [cfs]";
            statsSummaryTable[183][0] = "December (Upper Quartile) [cfs]";
            statsSummaryTable[184][0] = "December (Lower Quartile) [cfs]";
            statsSummaryTable[185][0] = "December (Median) [cfs]";
            statsSummaryTable[186][0] = "December (Mean) [cfs]";
            statsSummaryTable[187][0] = "December (Standard Deviation) [cfs]";
            statsSummaryTable[188][0] = "December (Variance)";
            statsSummaryTable[189][0] = "December (Skewness)";
            statsSummaryTable[190][0] = "December (Coefficient of Variation)";
        }
        statsSummaryTable[statsSummaryTable.length - 6][0] = "Flow Statistics based on Indicators of Hydrologic Alteration from:";
        statsSummaryTable[statsSummaryTable.length - 5][0] = "B.D. Richter; J.V. Baumgartner; J. Powell; D.P. Braun. 1996. 'A Method For Assessing Hydrologic Aleration Within Ecosystems.' Conservation Biology 10(4): 1163-1174.";
        statsSummaryTable[statsSummaryTable.length - 4][0] = "B.D. Richter; J.V. Baumgartner; R. Wigington; D.P Braun. 1997. 'How Much Water Does A River Need?' Freshwater Biology. 37: 231-249.";
        statsSummaryTable[statsSummaryTable.length - 3][0] = "B.D. Richter; J.V. Baumgartner; D.P. Braun; J. Powell. 1998. 'A Spatial Assessment Of Hydrologic Alteration Within A River Network.' Regul. Rivers: Res. Mgmt. 14: 329-340.";
        statsSummaryTable[statsSummaryTable.length - 2][0] = "Richards-Baker Flashiness Index from:";
        statsSummaryTable[statsSummaryTable.length - 1][0] = "D.B. Baker; R.P. Richards; T.T. Loftus; J.W. Kramer. 2004. 'A New Flashiness Index: Characteristics and Applications to Midwestern Rivers and Streams.' Journal of the Americal Water Resources Association (JAWRA) April 2004: 503-522.";
        
        //Calculate all data statistics
        //These are not annual statistics because the data can include more than 1 year
        String startDate = flowData[0][0];
        String endDate = flowData[flowData.length - 1][0];
        Object[] resultArray = calculateFlowStatistics(statsSummaryTable, 
                                                       flowData,
                                                       highPercentile,
                                                       lowPercentile,
                                                       m,
                                                       "All: " + startDate + " to " + endDate,
                                                       showMonthlyTF,
                                                       seasonBegin,
                                                       seasonEnd);
        statsSummaryTable = (String[][]) resultArray[0];
        //double mQnFlow_temp = (Double) resultArray[1];
        
        //Calculate data statistics for each period
        Arrays.sort(flowData, new DateComparator());
        SimpleDateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        if(!period1Begin.isEmpty() && !period1End.isEmpty()){
            Date period1Begin_date = desiredDateFormat.parse(period1Begin);
            Date period1End_date = desiredDateFormat.parse(period1End);
            
            ArrayList<String> period1_dates = new ArrayList<>();
            ArrayList<String> period1_flows = new ArrayList<>();
            for(int i=0; i<flowData.length; i++){
                Date newDate = desiredDateFormat.parse(flowData[i][0]);
                if(newDate.compareTo(period1Begin_date) >= 0 && newDate.compareTo(period1End_date) <= 0){
                    period1_dates.add(flowData[i][0]);
                    period1_flows.add(flowData[i][1]);
                }
            }
            String[][] period1Data = new String[period1_dates.size()][2];
            for(int i=0; i<period1_dates.size(); i++){
                period1Data[i][0] = period1_dates.get(i);
                period1Data[i][1] = period1_flows.get(i);
            }
            
            //Calculate Period 1 data statistics
            resultArray = calculateFlowStatistics(statsSummaryTable, 
                                                  period1Data, 
                                                  highPercentile, 
                                                  lowPercentile, 
                                                  m, 
                                                  "Period-1 Data: " + period1Begin + " to " + period1End, 
                                                  showMonthlyTF,
                                                  seasonBegin,
                                                  seasonEnd);
            statsSummaryTable = (String[][]) resultArray[0];
            //double mQnFlow_temp = (Double) resultArray[1];
        }
        if(!period2Begin.isEmpty() && !period2End.isEmpty()){
            Date period2Begin_date = desiredDateFormat.parse(period2Begin);
            Date period2End_date = desiredDateFormat.parse(period2End);
            
            ArrayList<String> period2_dates = new ArrayList<>();
            ArrayList<String> period2_flows = new ArrayList<>();
            for(int i=0; i<flowData.length; i++){
                Date newDate = desiredDateFormat.parse(flowData[i][0]);
                if(newDate.compareTo(period2Begin_date) >= 0 && newDate.compareTo(period2End_date) <= 0){
                    period2_dates.add(flowData[i][0]);
                    period2_flows.add(flowData[i][1]);
                }
            }
            String[][] period2Data = new String[period2_dates.size()][2];
            for(int i=0; i<period2_dates.size(); i++){
                period2Data[i][0] = period2_dates.get(i);
                period2Data[i][1] = period2_flows.get(i);
            }
            
            //Calculate Period 2 data statistics
            resultArray = calculateFlowStatistics(statsSummaryTable, 
                                                  period2Data, 
                                                  highPercentile, 
                                                  lowPercentile, 
                                                  m, 
                                                  "Period-2 Data: " + period2Begin + " to " + period2End, 
                                                  showMonthlyTF,
                                                  seasonBegin,
                                                  seasonEnd);
            statsSummaryTable = (String[][]) resultArray[0];
            //double mQnFlow_temp = (Double) resultArray[1];
        }
        if(!period3Begin.isEmpty() && !period3End.isEmpty()){
            Date period3Begin_date = desiredDateFormat.parse(period3Begin);
            Date period3End_date = desiredDateFormat.parse(period3End);
            
            ArrayList<String> period3_dates = new ArrayList<>();
            ArrayList<String> period3_flows = new ArrayList<>();
            for(int i=0; i<flowData.length; i++){
                Date newDate = desiredDateFormat.parse(flowData[i][0]);
                if(newDate.compareTo(period3Begin_date) >= 0 && newDate.compareTo(period3End_date) <= 0){
                    period3_dates.add(flowData[i][0]);
                    period3_flows.add(flowData[i][1]);
                }
            }
            String[][] period3Data = new String[period3_dates.size()][2];
            for(int i=0; i<period3_dates.size(); i++){
                period3Data[i][0] = period3_dates.get(i);
                period3Data[i][1] = period3_flows.get(i);
            }
            
            //Calculate Period 3 data statistics
            resultArray = calculateFlowStatistics(statsSummaryTable, 
                                                  period3Data, 
                                                  highPercentile, 
                                                  lowPercentile, 
                                                  m, 
                                                  "Period-3 Data: " + period3Begin + " to " + period3End, 
                                                  showMonthlyTF,
                                                  seasonBegin,
                                                  seasonEnd);
            statsSummaryTable = (String[][]) resultArray[0];
            //double mQnFlow_temp = (Double) resultArray[1];
        }
        
        //Calculate Flow statistics for each year in time period
        ArrayList<Double> mQnFlows = new ArrayList<>();
        boolean moreYears = flowData.length > 0;
        String currentYear = flowData[0][0].substring(0,4);
        String finalYear = flowData[flowData.length - 1][0].substring(0,4);
        
        if(waterYearTF){
            Date firstDate = desiredDateFormat.parse(flowData[0][0]);
            Date firstWaterYear = desiredDateFormat.parse(currentYear + "-10-01");
            if(firstDate.before(firstWaterYear)){
                currentYear = String.valueOf(Integer.parseInt(currentYear) - 1);
            }
            
            Date lastDate = desiredDateFormat.parse(flowData[flowData.length - 1][0]);
            Date lastWaterYear = desiredDateFormat.parse(finalYear + "-09-30");
            if(lastDate.after(lastWaterYear)){
                finalYear = String.valueOf(Integer.parseInt(finalYear) + 1);
            }
        }
        
        while(moreYears){
            String[][] partialData = new String[0][2];
            String headerLabel = null;
            if(waterYearTF){
                //Get current water year's data
                String nextYear = String.valueOf(Integer.parseInt(currentYear) + 1);
                partialData = DoubleArray.getPeriodData(flowData, currentYear + "-10-01", nextYear + "-09-30");
                headerLabel = "Water Year: " + currentYear + "-10-01 to " + nextYear + "-09-30";
            }else{
                //Get current calendar year's data
                partialData = DoubleArray.getYearsData(flowData, currentYear);
                headerLabel = currentYear;
            }
            resultArray = calculateFlowStatistics(statsSummaryTable, 
                                                  partialData,
                                                  highPercentile,
                                                  lowPercentile,
                                                  m,
                                                  headerLabel,
                                                  showMonthlyTF,
                                                  seasonBegin,
                                                  seasonEnd);
            statsSummaryTable = (String[][]) resultArray[0];
            double mQnFlow_temp = (Double) resultArray[1];
            mQnFlows.add(mQnFlow_temp);
            
            if(waterYearTF){
                //For water year comparison
                String nextYear = String.valueOf(Integer.parseInt(currentYear) + 1);
                Date currentEndDate = desiredDateFormat.parse(nextYear + "-09-30");
                Date lastWaterYear = desiredDateFormat.parse(finalYear + "-09-30");
                if(currentEndDate.before(lastWaterYear)){
                    currentYear = String.valueOf(nextYear);
                }else{
                    moreYears = false;
                }
            }else{
                //For calendar year comparison
                int nextYear = Integer.parseInt(currentYear) + 1;
                if(finalYear.compareToIgnoreCase(String.valueOf(nextYear)) >= 0){
                    currentYear = String.valueOf(nextYear);
                }else{
                    moreYears = false;
                }
            }
        }
        
        //Call file writer for outputs fo flow statistics
        writeStatsSummaryFile(directory, statsSummaryTable);
        
        //Calculate mQn (7Q10) Statistics
        double mQnFlow = 0;
        if(m != 0 && n != 0){
            mQnFlow = DoubleArray.calculateLowFlowReturnPeriod(mQnFlows, n);
        }
        String errorMessage = "";
        if(mQnFlow == 0){
            errorMessage = "There is no " + m + " consecutive day flow recorded so there was no " + m + "Q" + n + " flow value calculated.";
        }
        
        
        Object[] returnArray = {mQnFlow, errorMessage};
        return returnArray;
    }
    /**
     * calculates flow statistics for the provided flowData and appends the column 
     * of results to the statsSummaryTable under the provided header
     * @param statsSummaryTable  the summary table to add to
     * @param flowData  the String[][] containing sorted data for the time series 
     * (column 1 = dates (yyyy-mm-dd) column 2 = value
     * @param highPercentile  the percentile value for defining a "high flow pulse"
     * typically greater than 75% = 0.75
     * @param lowPercentile  the percentile value for defining a "low flow pulse"
     * typically lower than 25% = 0.25
     * @param m  used to calculate an "m-day-average" minimum flow
     * @param dataHeader  the text header for this column of result statistics in the statsSummaryTable (i.e. 'All Data' or '1998')
     * @param showMonthlyTF  a flag to show monthly statistics (min/max/etc.) or not (which reduces the total output of the tool)
     * @param seasonBegin  the month and date (MM-dd) of the start of a seasonal analysis to be averaged over the period of data
     * @param seasonEnd  the month and date (MM-dd) of the end of a seasonal analysis to be averaged over the period of data
     * @return  an Object[] containing the updated statsSummaryTable at returnObject[0] and the m-day-average minimum-flow at returnObject[1]
     * @throws IOException 
     */
    private Object[] calculateFlowStatistics(String[][] statsSummaryTable,
                                             String[][] flowData,
                                             double highPercentile,
                                             double lowPercentile,
                                             int m,
                                             String dataHeader,
                                             boolean showMonthlyTF,
                                             String seasonBegin,
                                             String seasonEnd) throws IOException, ParseException{
        //Sort Data consecutively
        Arrays.sort(flowData, new DateComparator());
        
        //Get/Store data for seasonal statistics
        String[][] seasonalData_String = DoubleArray.getSeasonalData(flowData, seasonBegin, seasonEnd);
        ArrayList<Double> seasonal_data = new ArrayList<>();
        for(int i=0; i<seasonalData_String.length; i++){
            double value = Double.parseDouble(seasonalData_String[i][1]);
            seasonal_data.add(value);
        }
        
        //Set up monthly data arrays
        ArrayList<Double> jan_data = new ArrayList<>();
        ArrayList<Double> feb_data = new ArrayList<>();
        ArrayList<Double> mar_data = new ArrayList<>();
        ArrayList<Double> apr_data = new ArrayList<>();
        ArrayList<Double> may_data = new ArrayList<>();
        ArrayList<Double> jun_data = new ArrayList<>();
        ArrayList<Double> jul_data = new ArrayList<>();
        ArrayList<Double> aug_data = new ArrayList<>();
        ArrayList<Double> sep_data = new ArrayList<>();
        ArrayList<Double> oct_data = new ArrayList<>();
        ArrayList<Double> nov_data = new ArrayList<>();
        ArrayList<Double> dec_data = new ArrayList<>();
        
        //Calculate 1-day statistics
        ArrayList<Double> allData = new ArrayList<>();
        ArrayList<Double> diffPositive = new ArrayList<>();
        ArrayList<Double> diffNegative = new ArrayList<>();
        double max_1day = -9999, min_1day = 9999;
        String max_1day_date = "-1", min_1day_date = "-1";
        boolean increasing = false;
        int ctr_zero = 0, ctr_rises = 0, ctr_falls = 0, ctr_reversals = 0;
        String date1 = "1900-01-01";
        double centroidSum = 0, sum = 0, RBI_numerator = 0, oldValue = 0;
        for(int i=0; i<flowData.length; i++){
            String date2 = flowData[i][0];
            double month = Double.parseDouble(flowData[i][0].substring(5,7));
            int month_int =  (int) month;
            double value = Double.parseDouble(flowData[i][1]);
            allData.add(value);
            
            //Store data for monthly averages
            switch (month_int) {
                case 1:  jan_data.add(value); break;
                case 2:  feb_data.add(value); break;
                case 3:  mar_data.add(value); break;
                case 4:  apr_data.add(value); break;
                case 5:  may_data.add(value); break;
                case 6:  jun_data.add(value); break;
                case 7:  jul_data.add(value); break;
                case 8:  aug_data.add(value); break;
                case 9:  sep_data.add(value); break;
                case 10:  oct_data.add(value); break;
                case 11:  nov_data.add(value); break;
                case 12:  dec_data.add(value); break;
                default: break;
            }
            
            //Calculate Max
            if(max_1day < value){
                max_1day_date = date2;
                max_1day = value;
            }
            
            //Calculate Min
            if(min_1day > value){
                min_1day_date = date2;
                min_1day = value;
            }
            
            //Count zero flow days
            if(value == 0){
                ctr_zero++;
            }
            
            //Calculate difference
            if(DoubleArray.checkSubsequentDates(date1, date2)){
                double diff = value - oldValue;
                if(diff > 0){
                    diffPositive.add(diff);
                }else if(diff < 0){
                    diffNegative.add(diff);
                }
                RBI_numerator = RBI_numerator + Math.abs(diff);

                //Calculate flow reversals for consecutive days only
                if(value > oldValue){
                    if(!increasing){
                        ctr_reversals++;
                        ctr_rises++;
                        increasing = true;
                    }
                }else if(value < oldValue){
                    if(increasing){
                        ctr_reversals++;
                        ctr_falls++;
                        increasing = false;
                    }
                }
            }
            
            //Calculate centriod values
            double currentYear_double = Double.parseDouble(flowData[i][0].substring(0,4));
            double currentMonth_double = Double.parseDouble(flowData[i][0].substring(5,7));
            double currentDay_double = Double.parseDouble(flowData[i][0].substring(8));
            int currentYear = (int) currentYear_double;
            int currentMonth = (int) currentMonth_double;
            int currentDay = (int) currentDay_double;
            Calendar currentDate = new GregorianCalendar(currentYear, currentMonth - 1, currentDay);
            int dayOfYear = currentDate.get(Calendar.DAY_OF_YEAR);
            centroidSum = centroidSum + dayOfYear * value;
            sum = sum + value;
            
            //Reset yesterday's flow value
            oldValue = value;
            date1 = date2;
        }
        double mean_all = DoubleMath.meanArithmetic(allData);
        double centroid = centroidSum / sum;
        double flashinessIndex = RBI_numerator / sum;
        
        //Calculate 3-day statistics
        Object[] resultArray = DoubleArray.getMdayData(flowData, 3, "arithmetic");
        ArrayList<String> average_3day_date = (ArrayList<String>) resultArray[0];
        ArrayList<Double> average_3day = (ArrayList<Double>) resultArray[1];
        double max_3day = DoubleMath.max(average_3day);
        double min_3day = DoubleMath.min(average_3day);
        String max_3day_date = getDateOfValue(average_3day_date, average_3day, max_3day);
        String min_3day_date = getDateOfValue(average_3day_date, average_3day, min_3day);
        
        //Calculate 7-day statistics
        resultArray = DoubleArray.getMdayData(flowData, 7, "arithmetic");
        ArrayList<String> average_7day_date = (ArrayList<String>) resultArray[0];
        ArrayList<Double> average_7day = (ArrayList<Double>) resultArray[1];
        double max_7day = DoubleMath.max(average_7day);
        double min_7day = DoubleMath.min(average_7day);
        double min_7day_ave = DoubleMath.round(min_7day/mean_all,3);
        String max_7day_date = getDateOfValue(average_7day_date, average_7day, max_7day);
        String min_7day_date = getDateOfValue(average_7day_date, average_7day, min_7day);
        
        //Calculate 30-day statistics
        resultArray = DoubleArray.getMdayData(flowData, 30, "arithmetic");
        ArrayList<String> average_30day_date = (ArrayList<String>) resultArray[0];
        ArrayList<Double> average_30day = (ArrayList<Double>) resultArray[1];
        double max_30day = DoubleMath.max(average_30day);
        double min_30day = DoubleMath.min(average_30day);
        String max_30day_date = getDateOfValue(average_30day_date, average_30day, max_30day);
        String min_30day_date = getDateOfValue(average_30day_date, average_30day, min_30day);
        
        //Calculate 90-day statistics
        resultArray = DoubleArray.getMdayData(flowData, 90, "arithmetic");
        ArrayList<String> average_90day_date = (ArrayList<String>) resultArray[0];
        ArrayList<Double> average_90day = (ArrayList<Double>) resultArray[1];
        double max_90day = DoubleMath.max(average_90day);
        double min_90day = DoubleMath.min(average_90day);
        String max_90day_date = getDateOfValue(average_90day_date, average_90day, max_90day);
        String min_90day_date = getDateOfValue(average_90day_date, average_90day, min_90day);
        
        //Calculate mQn (7Q10)Statistics
        double min_Mday = 0;
        if(m != 0){
            resultArray = DoubleArray.getMdayData(flowData, m, "arithmetic");
            ArrayList<Double> average_Mday = (ArrayList<Double>) resultArray[1];
            min_Mday = DoubleMath.min(average_Mday);
        }
        
        //Calculate Pulse Information
        double highLimit = DoubleMath.Percentile_function(allData, highPercentile);
        double lowLimit = DoubleMath.Percentile_function(allData, lowPercentile);
        ArrayList<Double> highPulses = new ArrayList<>();
        ArrayList<Double> lowPulses = new ArrayList<>();
        int ctr_highPulse = 0, ctr_lowPulse = 0;
        double duration_highPulse = 0, duration_lowPulse = 0;
        boolean highPulseTF = false, lowPulseTF = false;
        oldValue = 0;
        date1 = "";
        for(int i=0; i<flowData.length; i++){
            //Check for consecutive days of flow data
            String date2 = flowData[i][0];
            double value = Double.parseDouble(flowData[i][1]);
            if(i>0){
                if(DoubleArray.checkSubsequentDates(date1, date2)){
                    //Calculate high pulse information
                    if(value > highLimit){
                        if(!highPulseTF){
                            //If on a new highPulse add to the counters
                            ctr_highPulse++;
                            duration_highPulse = 1;
                            highPulseTF = true;
                        }else{
                            //If still on a highPulse, add to the counter
                            duration_highPulse = duration_highPulse + 1;
                        }
                    }else{
                        //If no longer on a highPulse, store the results, reset the counters
                        if(highPulseTF){
                            highPulses.add(duration_highPulse);
                            highPulseTF = false;
                        }
                    }

                    //Calculate low pulse information
                    if(value < lowLimit){
                        if(!lowPulseTF){
                            //If on a new lowPulse add to the counters
                            ctr_lowPulse++;
                            duration_lowPulse = 1;
                            lowPulseTF = true;
                        }else{
                            //If still on a lowPulse, add to the counter
                            duration_lowPulse = duration_lowPulse + 1;
                        }
                    }else{
                        //If no longer on a lowPulse, store the results, reset the counters
                        if(lowPulseTF){
                            lowPulses.add(duration_lowPulse);
                            lowPulseTF = false;
                        }
                    }
                }else{
                    //If no longer on consecutive days, store the results (if previously on a pulse) and reset the counters
                    if(highPulseTF){
                        highPulses.add(duration_highPulse);
                        highPulseTF = false;
                    }
                    if(lowPulseTF){
                        lowPulses.add(duration_lowPulse);
                        lowPulseTF = false;
                    }
                }
            }
            //Reset yesterday's flow value
            oldValue = value;
            date1 = date2;
        }
        
        
        //Build Flow Statistics Summary for output
        int summarySize = 65;
        if(showMonthlyTF) summarySize = 197;
        String[] additionalSummary = new String[summarySize];
        additionalSummary[0] = "";//blank
        additionalSummary[1] = dataHeader;//Method
        additionalSummary[2] = String.valueOf(allData.size());//Count, overall
        additionalSummary[3] = String.valueOf(DoubleMath.round(DoubleMath.max(allData), 3));//Maximum, overall
        additionalSummary[4] = String.valueOf(DoubleMath.round(DoubleMath.min(allData), 3));//Minimum, overall
        additionalSummary[5] = String.valueOf(DoubleMath.round(DoubleMath.Percentile_function(allData,0.75), 3));//Upper Quartile, overall
        additionalSummary[6] = String.valueOf(DoubleMath.round(DoubleMath.Percentile_function(allData,0.25), 3));//Lower Quartile, overall
        additionalSummary[7] = String.valueOf(DoubleMath.round(DoubleMath.median(allData), 3));//Median, overall
        additionalSummary[8] = String.valueOf(DoubleMath.round(DoubleMath.meanArithmetic(allData), 3));//Average, overall
        additionalSummary[9] = String.valueOf(DoubleMath.round(DoubleMath.StandardDeviationSample(allData), 3));//Standard Deviation, overall
        additionalSummary[10] = String.valueOf(DoubleMath.round(DoubleMath.VarianceSample(allData), 3));//Variance, overall
        additionalSummary[11] = String.valueOf(DoubleMath.round(DoubleMath.SkewnessSample(allData), 3));//Skewness, overall
        additionalSummary[12] = String.valueOf(DoubleMath.round(DoubleMath.CoefficientOfVariation(allData), 3));//Coefficient of Variation, overall
        additionalSummary[13] = String.valueOf(DoubleMath.round(max_1day,3));//Maximum (1-day)
        additionalSummary[14] = max_1day_date;//Date of Maximum (1-day)
        additionalSummary[15] = String.valueOf(DoubleMath.round(min_1day,3));//Minimum (1-day)
        additionalSummary[16] = min_1day_date;//Date of Minimum (1-day)
        additionalSummary[17] = String.valueOf(DoubleMath.round(max_3day,3));//Maximum (3-day)
        additionalSummary[18] = max_3day_date;//Dates of Maximum (3-day)
        additionalSummary[19] = String.valueOf(DoubleMath.round(min_3day,3));//Minimum (3-day)
        additionalSummary[20] = min_3day_date;//Dates of Minimum (3-day)
        additionalSummary[21] = String.valueOf(DoubleMath.round(max_7day,3));//Maximum (7-day)
        additionalSummary[22] = max_7day_date;//Dates of Maximum (7-day)
        additionalSummary[23] = String.valueOf(DoubleMath.round(min_7day,3));//Minimum (7-day)
        additionalSummary[24] = min_7day_date;//Dates of Minimum (7-day)
        additionalSummary[25] = String.valueOf(DoubleMath.round(min_7day_ave,3));//Minimum (7-day)
        additionalSummary[26] = String.valueOf(DoubleMath.round(max_30day,3));//Maximum (30-day)
        additionalSummary[27] = max_30day_date;//Dates of Maximum (30-day)
        additionalSummary[28] = String.valueOf(DoubleMath.round(min_30day,3));//Minimum (30-day)
        additionalSummary[29] = min_30day_date;//Dates of Minimum (30-day)
        additionalSummary[30] = String.valueOf(DoubleMath.round(max_90day,3));//Maximum (90-day)
        additionalSummary[31] = max_90day_date;//Dates of Maximum (90-day)
        additionalSummary[32] = String.valueOf(DoubleMath.round(min_90day,3));//Minimum (90-day)
        additionalSummary[33] = min_90day_date;//Dates of Minimum (90-day)
        additionalSummary[34] = String.valueOf(ctr_zero);//Number of Zero Flow Days
        additionalSummary[35] = String.valueOf(ctr_reversals);//Number of Flow Reversals
        additionalSummary[36] = String.valueOf(ctr_rises);//Number of Flow Rises
        additionalSummary[37] = String.valueOf(ctr_falls);//Number of Flow Falls
        additionalSummary[38] = String.valueOf(ctr_highPulse);//Number of High Pulses
        additionalSummary[39] = String.valueOf(DoubleMath.round(highLimit,1));//Threshold for High Pulses
        additionalSummary[40] = String.valueOf(DoubleMath.round(DoubleMath.meanArithmetic(highPulses), 3));//Average Duration of High Pulses
        additionalSummary[41] = String.valueOf(ctr_lowPulse);//Number of Low Pulses
        additionalSummary[42] = String.valueOf(DoubleMath.round(lowLimit,1));//Threshold for Low Pulses
        additionalSummary[43] = String.valueOf(DoubleMath.round(DoubleMath.meanArithmetic(lowPulses), 3));//Average Duration of Low Pulses
        additionalSummary[44] = String.valueOf(DoubleMath.round(DoubleMath.meanArithmetic(diffPositive),3));//Average Positive Difference Between Consecutive Days
        additionalSummary[45] = String.valueOf(DoubleMath.round(DoubleMath.meanArithmetic(diffNegative),3));//Average Negative Difference Between Consecutive Days
        additionalSummary[46] = String.valueOf(DoubleMath.round(centroid,2));//Temporal centroid of annual discharge (Julian day, not water-year day)
        additionalSummary[47] = String.valueOf(DoubleMath.round(flashinessIndex,4));//Richards-Baker Index for flow 'flashiness'
        
        //Add seasonal stats summary
        int index = 48;
        resultArray = addSimpleStatsSummary(additionalSummary, seasonal_data, index);
        additionalSummary = (String[]) resultArray[0];
        index = (int) resultArray[1];
        
        if(showMonthlyTF){
            //January
            resultArray = addSimpleStatsSummary(additionalSummary, jan_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //February
            resultArray = addSimpleStatsSummary(additionalSummary, feb_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //March
            resultArray = addSimpleStatsSummary(additionalSummary, mar_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //April
            resultArray = addSimpleStatsSummary(additionalSummary, apr_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //May
            resultArray = addSimpleStatsSummary(additionalSummary, may_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //June
            resultArray = addSimpleStatsSummary(additionalSummary, jun_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //July
            resultArray = addSimpleStatsSummary(additionalSummary, jul_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //August
            resultArray = addSimpleStatsSummary(additionalSummary, aug_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //September
            resultArray = addSimpleStatsSummary(additionalSummary, sep_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //October
            resultArray = addSimpleStatsSummary(additionalSummary, oct_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //November
            resultArray = addSimpleStatsSummary(additionalSummary, nov_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
            //December
            resultArray = addSimpleStatsSummary(additionalSummary, dec_data, index);
            additionalSummary = (String[]) resultArray[0];
            index = (int) resultArray[1];
        }
        //References section blanks
        additionalSummary[index] = "";//blank
        additionalSummary[index + 1] = "";//blank
        additionalSummary[index + 2] = "";//blank
        additionalSummary[index + 3] = "";//blank
        additionalSummary[index + 4] = "";//blank
        additionalSummary[index + 5] = "";//blank

        //Add these statistics to the existing results
        statsSummaryTable = DoubleArray.appendcolumn_Matrix(statsSummaryTable, additionalSummary);
        
        Object[] returnArray = {statsSummaryTable, min_Mday};
        return returnArray;
    }
    /**
     * Calculates a statistics summary of the provided data and appends it 
     * (beginning at 'index') to the provided statsSummaryTable.
     * 
     * This calculates 11 parameters
     * @param statsSummaryTable
     * @param data
     * @param index
     * @return 
     */
    private Object[] addSimpleStatsSummary(String[] statsSummaryTable, ArrayList<Double> data, int index){
        statsSummaryTable[index] = String.valueOf(data.size());//count
        statsSummaryTable[index + 1] = String.valueOf(DoubleMath.round(DoubleMath.max(data), 3));//Maximum
        statsSummaryTable[index + 2] = String.valueOf(DoubleMath.round(DoubleMath.min(data), 3));//Minimum
        statsSummaryTable[index + 3] = String.valueOf(DoubleMath.round(DoubleMath.Percentile_function(data, 0.75), 3));//Upper Quartile
        statsSummaryTable[index + 4] = String.valueOf(DoubleMath.round(DoubleMath.Percentile_function(data,0.25), 3));//Lower Quartile
        statsSummaryTable[index + 5] = String.valueOf(DoubleMath.round(DoubleMath.median(data), 3));//Median
        statsSummaryTable[index + 6] = String.valueOf(DoubleMath.round(DoubleMath.meanArithmetic(data), 3));//Average
        statsSummaryTable[index + 7] = String.valueOf(DoubleMath.round(DoubleMath.StandardDeviationSample(data), 3));//Standard Deviation
        statsSummaryTable[index + 8] = String.valueOf(DoubleMath.round(DoubleMath.VarianceSample(data), 3));//Variance
        statsSummaryTable[index + 9] = String.valueOf(DoubleMath.round(DoubleMath.SkewnessSample(data), 3));//Skewness
        statsSummaryTable[index + 10] = String.valueOf(DoubleMath.round(DoubleMath.CoefficientOfVariation(data), 3));//Coefficient of Variation
        
        index = index + 11;
        Object[] returnArray = {statsSummaryTable, index};
        return returnArray;
    }
    /**
     * Loop through the provided data array and gets the corresponding index to 'value' and returns that index from the dates array
     * @param dates  a list of dates
     * @param data  a list of values corresponding to the dates in the above list
     * @param value  a value
     * @return the date corresponding to the provided value
     */
    private String getDateOfValue(ArrayList<String> dates, ArrayList<Double> data, double value){
        String dateOfValue = "null";
        for(int i=0; i<dates.size(); i++){
            if(data.get(i) == value){
                dateOfValue = dates.get(i);
                break;
            }
        }
        return dateOfValue;
    }
    /**
     * Writes the provided array to a CSV result file
     * @param directory  the folder location for the result file
     * @param statsSummary  the desired contents of the file
     * @throws IOException 
     */
    public void writeStatsSummaryFile(String directory, String[][] statsSummary) throws IOException{
        //Open a file writer for the summary of the flow statistcs per year
        String path = directory + File.separator + getFlowStatistics_summary();
        FileWriter newFile =  new FileWriter(path, false);
        PrintWriter writer = new PrintWriter(newFile);
        
        for(int i=0; i<statsSummary.length; i++){
            String currentLine = statsSummary[i][0];
            for(int j=1; j<statsSummary[i].length; j++){
                currentLine = currentLine + "," + statsSummary[i][j];
            }
            writer.printf("%s" + "\r\n", currentLine);
        }
        
        //Close file writer
        newFile.close();
        writer.close();
        System.out.println("Text File located at:\t" + path);
    }
}