Displaying differences for changeset
 
display as  

src/java/cfa/DoubleArray.java

@@ -1529,6 +1529,63 @@
         }
         return leapYear;
     }
+    /**
+     * Loops through and finds "m-day" consecutive values and takes the arithmetic average of them
+     * @param flowData  a string[][] containing: column1 = dates, column2 = flowValues
+     * @param numDays  an integer representing the number (m) of consecutive days to be desired for analysis
+     * @returns  an ArrayList containing an ArrayList of each set of "m-day" consecutive set of flows for analysis (min, max, average, etc)
+     * @throws IOException
+     */
+    public Object[] getMdayData(String[][] flowData, int numDays) throws IOException{
+        DoubleMath doubleMath = new DoubleMath();
+        
+        //Loop through flow data and find "m"-day consecutive flows
+        ArrayList<String> allDate = new ArrayList<String>();
+        ArrayList<Double> allData = new ArrayList<Double>();
+        try{
+            for(int i=0; i<flowData.length; i++){
+                ArrayList<String> mDayDate = new ArrayList<String>();
+                ArrayList<Double> mDayData = new ArrayList<Double>();
+                int ctr = i;
+                for(int j=0; j<numDays; j++){
+                    if(j==0){
+                        //Keep the first day
+                        mDayDate.add(flowData[ctr][0]);
+                        mDayData.add(Double.parseDouble(flowData[ctr][1]));
+                    }else{
+                        //Compare the current day to the previous day for consecutive-ness
+                        boolean checkNextDate = checkSubsequentDates(flowData[ctr-1][0], flowData[ctr][0]);
+                        if(checkNextDate){
+                            mDayDate.add(flowData[ctr][0]);
+                            mDayData.add(Double.parseDouble(flowData[ctr][1]));
+                        }else{
+                            //If not consecutive days, break out of the loop and move to the next date for flowData
+                            mDayDate.clear();
+                            mDayData.clear();
+                            i = ctr - 1;//Skip to newest date since there is a break in the consecutive day data
+                            break;
+                        }
+                    }
+                    ctr++;
+                }
+                if(mDayData.size() == numDays){
+                    //Add this m-consecutive day set of data to the all data array list for statistics later
+                    String startDate = mDayDate.get(0);
+                    String endDate = mDayDate.get(numDays - 1);
+                    allDate.add(startDate + " to " + endDate);
+                    allData.add(doubleMath.meanArithmetic(mDayData));
+                }
+            }
+        }catch(ArrayIndexOutOfBoundsException e){
+            //If the consecutive day counter (ctr) goes beyond the length of data available,
+            //stop the subroutine and return the existing results
+            Object[] returnArray = {allDate, allData};
+            return returnArray;
+        }
+        
+        Object[] returnArray = {allDate, allData};
+        return returnArray;
+    }
 //    /**
 //     * Reduces all data to just that within the specified date range
 //     * @param allData  all water quality data for the earlier provided date range and station ID (column1 = date, column2 = value)

src/java/cfa/DoubleMath.java

@@ -187,8 +187,8 @@
     }
     /**
      * Calculates the arithmetic mean of the provided double[] array
-     * @param data  the double[] array of which the average is desired
-     * @return  the double value of the average of the data array
+     * @param data  the double[] array of which the arithmetic mean is desired
+     * @return  the double value of the arithmetic mean of the data array
      */
     public double meanArithmetic(double[] data){
         //Calculates the average of a double array
@@ -203,8 +203,8 @@
     }
     /**
      * Calculates the arithmetic mean of the provided ArrayList<Double>
-     * @param data  the ArrayList<Double> of which the average is desired
-     * @return  the double value of the average of the data array
+     * @param data  the ArrayList<Double> of which the arithmetic mean is desired
+     * @return  the double value of the arithmetic mean of the data array
      */
     public double meanArithmetic(ArrayList<Double> data){
         //Calculates the average of a double array
@@ -215,6 +215,32 @@
         return average;
     }
     /**
+     * Calculates the harmonic mean of the provided double[] array, 
+     * only calculates for real positive values.
+     * 
+     * Note that the final estimate of the harmonic mean is a weighted average 
+     * of the harmonic mean of the non-zero elements and zero.
+     * @param data  the double[] array of which the harmonic mean is desired
+     * @return  the double value of the harmonic mean of the data array
+     */
+    public double meanHarmonic(double[] data){
+        //Calculate properties of harmonic mean
+        double reciprocalSum = 0, nZeros = 0, nNonZeros = 0;
+        for(int i=0; i<data.length; i++){
+            if(data[i] > 0){
+                reciprocalSum = reciprocalSum + (1/data[i]);//sum of reciprocals
+            }else{
+                nZeros++;
+            }
+            nNonZeros++;
+        }
+        
+        //Compute harmonic mean (with correction for the number of zero items in the array)
+        double meanHarmonic = (nNonZeros - nZeros) / (reciprocalSum * ((nNonZeros - nZeros)/nNonZeros));
+        
+        return meanHarmonic;
+    }
+    /**
      * Finds the average of the Log10 of a double[] array
      * @param data  the double[] array that the average is desired for
      * @return  the double value of the average of the Log10 of the data array

src/java/cfa/FlowStatistics.java

@@ -74,7 +74,7 @@
                                                     String period3End) throws IOException, ParseException{
         //Get today's date for output purposes
         Date currentDate = new Date();
-        SimpleDateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
         String today = desiredDateFormat.format(currentDate);
         stationName = stationName.replace(",", "");
         
@@ -253,8 +253,8 @@
             statsSummaryTable[165][0] = "December (Coefficient of Variation)";
         }
         statsSummaryTable[statsSummaryTable.length - 4][0] = "Flow Statistics based on Indicators of Hydrologic Alteration from:";
-        statsSummaryTable[statsSummaryTable.length - 3][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.\t";
-        statsSummaryTable[statsSummaryTable.length - 2][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.\t";
+        statsSummaryTable[statsSummaryTable.length - 3][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 - 2][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 - 1][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.";
         
         //Calculate all data statistics
@@ -446,17 +446,21 @@
         return returnArray;
     }
     /**
-     * 
-     * @param statsSummaryTable
-     * @param flowData
-     * @param highPercentile
-     * @param lowPercentile
-     * @param m
-     * @param dataHeader
-     * @param showMonthlyTF
-     * @param seasonBegin
-     * @param seasonEnd
-     * @return
+     * 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,
@@ -596,7 +600,7 @@
         double centroid = centroidSum / sum;
         
         //Calculate 3-day statistics
-        Object[] resultArray = getMdayData(flowData, 3);
+        Object[] resultArray = doubleArray.getMdayData(flowData, 3);
         ArrayList<String> average_3day_date = (ArrayList<String>) resultArray[0];
         ArrayList<Double> average_3day = (ArrayList<Double>) resultArray[1];
         double max_3day = doubleMath.max(average_3day);
@@ -605,7 +609,7 @@
         String min_3day_date = getDateOfValue(average_3day_date, average_3day, min_3day);
         
         //Calculate 7-day statistics
-        resultArray = getMdayData(flowData, 7);
+        resultArray = doubleArray.getMdayData(flowData, 7);
         ArrayList<String> average_7day_date = (ArrayList<String>) resultArray[0];
         ArrayList<Double> average_7day = (ArrayList<Double>) resultArray[1];
         double max_7day = doubleMath.max(average_7day);
@@ -615,7 +619,7 @@
         String min_7day_date = getDateOfValue(average_7day_date, average_7day, min_7day);
         
         //Calculate 30-day statistics
-        resultArray = getMdayData(flowData, 30);
+        resultArray = doubleArray.getMdayData(flowData, 30);
         ArrayList<String> average_30day_date = (ArrayList<String>) resultArray[0];
         ArrayList<Double> average_30day = (ArrayList<Double>) resultArray[1];
         double max_30day = doubleMath.max(average_30day);
@@ -624,7 +628,7 @@
         String min_30day_date = getDateOfValue(average_30day_date, average_30day, min_30day);
         
         //Calculate 90-day statistics
-        resultArray = getMdayData(flowData, 90);
+        resultArray = doubleArray.getMdayData(flowData, 90);
         ArrayList<String> average_90day_date = (ArrayList<String>) resultArray[0];
         ArrayList<Double> average_90day = (ArrayList<Double>) resultArray[1];
         double max_90day = doubleMath.max(average_90day);
@@ -635,7 +639,7 @@
         //Calculate mQn (7Q10)Statistics
         double min_Mday = 0;
         if(m != 0){
-            resultArray = getMdayData(flowData, m);
+            resultArray = doubleArray.getMdayData(flowData, m);
             ArrayList<Double> average_Mday = (ArrayList<Double>) resultArray[1];
             min_Mday = doubleMath.min(average_Mday);
         }
@@ -853,64 +857,6 @@
         return returnArray;
     }
     /**
-     * Loops through and finds "m-day" consecutive values and takes the average of them
-     * @param flowData  a string[][] containing: column1 = dates, column2 = flowValues
-     * @param numDays  an integer representing the number (m) of consecutive days to be desired for analysis
-     * @returns  an ArrayList containing an ArrayList of each set of "m-day" consecutive set of flows for analysis (min, max, average, etc)
-     * @throws IOException
-     */
-    private Object[] getMdayData(String[][] flowData, int numDays) throws IOException{
-        DoubleMath doubleMath = new DoubleMath();
-        DoubleArray doubleArray = new DoubleArray();
-        
-        //Loop through flow data and find "m"-day consecutive flows
-        ArrayList<String> allDate = new ArrayList<String>();
-        ArrayList<Double> allData = new ArrayList<Double>();
-        try{
-            for(int i=0; i<flowData.length; i++){
-                ArrayList<String> mDayDate = new ArrayList<String>();
-                ArrayList<Double> mDayData = new ArrayList<Double>();
-                int ctr = i;
-                for(int j=0; j<numDays; j++){
-                    if(j==0){
-                        //Keep the first day
-                        mDayDate.add(flowData[ctr][0]);
-                        mDayData.add(Double.parseDouble(flowData[ctr][1]));
-                    }else{
-                        //Compare the current day to the previous day for consecutive-ness
-                        boolean checkNextDate = doubleArray.checkSubsequentDates(flowData[ctr-1][0], flowData[ctr][0]);
-                        if(checkNextDate){
-                            mDayDate.add(flowData[ctr][0]);
-                            mDayData.add(Double.parseDouble(flowData[ctr][1]));
-                        }else{
-                            //If not consecutive days, break out of the loop and move to the next date for flowData
-                            mDayDate.clear();
-                            mDayData.clear();
-                            i = ctr - 1;//Skip to newest date since there is a break in the consecutive day data
-                            break;
-                        }
-                    }
-                    ctr++;
-                }
-                if(mDayData.size() == numDays){
-                    //Add this m-consecutive day set of data to the all data array list for statistics later
-                    String startDate = mDayDate.get(0);
-                    String endDate = mDayDate.get(numDays - 1);
-                    allDate.add(startDate + " to " + endDate);
-                    allData.add(doubleMath.meanArithmetic(mDayData));
-                }
-            }
-        }catch(ArrayIndexOutOfBoundsException e){
-            //If the consecutive day counter (ctr) goes beyond the length of data available,
-            //stop the subroutine and return the existing results
-            Object[] returnArray = {allDate, allData};
-            return returnArray;
-        }
-        
-        Object[] returnArray = {allDate, allData};
-        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

src/java/cfa/guiDC_Model.java

@@ -53,6 +53,7 @@
     String period3End = "";
     double highPercentile = 0.75;
     double lowPercentile = 0.25;
+    boolean showMonthlyStatsTF = false;
     String mQnPeriod = "false";//"7Q10";//
     String userData = "";//"Date\tFlow\n1999-04-29\t8.3\n1999-05-09\t60.2\n1999-05-29\t20.1$$Date\t00600\n1999-04-29\t8.3\n1999-05-09\t60.2\n1999-05-29\t20.1";//"Date\tFlow\n1999-04-29\t8.3\n1999-05-09\t60.2\n1999-05-29\t20.1";//
     boolean mergeDatasets = false;//true;//
@@ -201,6 +202,9 @@
     public void setLowPercentile(double lowPercentile) {
         this.lowPercentile = lowPercentile;
     }
+    public void setShowMonthlyStatsTF(boolean showMonthlyStatsTF) {
+        this.showMonthlyStatsTF = showMonthlyStatsTF;
+    }
     public void setMQNperiod(String mQnPeriod) {
         this.mQnPeriod = mQnPeriod;
     }
@@ -292,7 +296,7 @@
         
         //Calculate the flow stats file
         FlowStatistics flowStats = new FlowStatistics();
-        Object[] returnValue = flowStats.calculateAllStatisticsSummaries(mainFolder, stationID, stationName, sortedData_combined, highPercentile, lowPercentile, m, n, true
+        Object[] returnValue = flowStats.calculateAllStatisticsSummaries(mainFolder, stationID, stationName, sortedData_combined, highPercentile, lowPercentile, m, n, showMonthlyStatsTF
                                                      seasonBegin, seasonEnd, period1Begin, period1End, period2Begin, period2End, period3Begin, period3End);
         double mQn = (Double) returnValue[0];
         String MQNmessage = (String) returnValue[1];
@@ -677,7 +681,7 @@
         
         //Calculate the flow stats file
         FlowStatistics flowStats = new FlowStatistics();
-        Object[] returnValue = flowStats.calculateAllStatisticsSummaries(mainFolder, stationID, stationName, sortedData_combined, highPercentile, lowPercentile, m, n, true
+        Object[] returnValue = flowStats.calculateAllStatisticsSummaries(mainFolder, stationID, stationName, sortedData_combined, highPercentile, lowPercentile, m, n, showMonthlyStatsTF
                                             seasonBegin, seasonEnd, period1Begin, period1End, period2Begin, period2End, period3Begin, period3End);
         double mQn = (Double) returnValue[0];
         String MQNmessage = (String) returnValue[1];

src/java/cfa/guiTimeseries_Model.java

@@ -69,6 +69,7 @@
     boolean medianTF = false;
     double highPercentile = 0.75;
     double lowPercentile = 0.25;
+    boolean showMonthlyStatsTF = false;
     String userData = "";//"Date\tFlow\n1999-04-29\t8.3\n1999-05-09\t60.2\n1999-05-29\t20.1";//
     boolean mergeDatasets = false;//true;// 
     String mergeMethod = "user";//"public";//"max";//"average";//"min";//
@@ -413,6 +414,9 @@
     public void setLowPercentile(double lowPercentile) {
         this.lowPercentile = lowPercentile;
     }
+    public void setShowMonthlyStatsTF(boolean showMonthlyStatsTF) {
+        this.showMonthlyStatsTF = showMonthlyStatsTF;
+    }
     public void setUserData(String userData) {
         this.userData = userData;
     }
@@ -1828,7 +1832,7 @@
         FlowStatistics flowStats = new FlowStatistics();
         if(wqTest.equalsIgnoreCase("flow")){
             //Calculate Hydrologic Indicators of Alteration
-            flowStats.calculateAllStatisticsSummaries(mainFolder, stationID, stationName, sortedData_combined, highPercentile, lowPercentile, 0, 0, true,
+            flowStats.calculateAllStatisticsSummaries(mainFolder, stationID, stationName, sortedData_combined, highPercentile, lowPercentile, 0, 0, showMonthlyStatsTF,
                         seasonBegin, seasonEnd, period1Begin, period1End, period2Begin, period2End, period3Begin, period3End);
         }else{
             //Report that there cannot be flow statistics for water quality data

src/java/m/cfa/DurationCurve_V1_0.java

@@ -49,6 +49,7 @@
                 model.setPeriod3End(m.get("period3_end").getString(VALUE));
                 model.setHighPercentile(m.get("highPercentile").getDouble(VALUE));
                 model.setLowPercentile(m.get("lowPercentile").getDouble(VALUE));
+                model.setShowMonthlyStatsTF(m.get("showMonthlyStatsTF").getBoolean(VALUE));
                 model.setMQNperiod(m.get("mqn_period").getString(VALUE));
                 model.setUserData(m.get("user_data").getString(VALUE));
                 model.setMergeDatasets(m.get("merge_datasets").getBoolean(VALUE));

src/java/m/cfa/DurationCurve_V1_0Req.json

@@ -105,6 +105,11 @@
       "value": 0.25
     },
     {
+      "name": "showMonthlyStatsTF",
+      "description": "If true, and the 'wq_test' is flow, then monthly flow statistics will be included in the flow-statistics result file If false, only annual and period of record statistics will be included.",
+      "value": false
+    },
+    {
       "name": "mqn_period",
       "description": "Format for m-day average n-year period low flow, ex. 7Q10 = 7-day average 10-year low flow. (7q10 | false) ",
       "value": "false"

src/java/m/cfa/Timeseries_V1_0.java

@@ -51,6 +51,7 @@
                 model.setMedianTF(m.get("medianTF").getBoolean(VALUE));
                 model.setHighPercentile(m.get("highPercentile").getDouble(VALUE));
                 model.setLowPercentile(m.get("lowPercentile").getDouble(VALUE));
+                model.setShowMonthlyStatsTF(m.get("showMonthlyStatsTF").getBoolean(VALUE));
                 model.setUserData(m.get("user_data").getString(VALUE));
                 model.setMergeDatasets(m.get("merge_datasets").getBoolean(VALUE));
                 model.setMergeMethod(m.get("merge_method").getString(VALUE));

src/java/m/cfa/Timeseries_V1_0Req.json

@@ -47,18 +47,6 @@
       "value": "Max"
     },
     {
-      "name": "highPercentile",
-      "description": "The percentile limit for defining 'high' flow pulses for analysis and statistics",
-      "unit": "%",
-      "value": 0.75
-    },
-    {
-      "name": "lowPercentile",
-      "description": "The percentile limit for defining 'low' flow pulses for analysis and statistics",
-      "unit": "%",
-      "value": 0.25
-    },
-    {
       "name": "numBins",
       "description": "Number of bins for histogram graph",
       "value": 10
@@ -114,6 +102,23 @@
       "value": false
     },
     {
+      "name": "highPercentile",
+      "description": "The percentile limit for defining 'high' flow pulses for analysis and statistics",
+      "unit": "%",
+      "value": 0.75
+    },
+    {
+      "name": "lowPercentile",
+      "description": "The percentile limit for defining 'low' flow pulses for analysis and statistics",
+      "unit": "%",
+      "value": 0.25
+    },
+    {
+      "name": "showMonthlyStatsTF",
+      "description": "If true, and the 'wq_test' is flow, then monthly flow statistics will be included in the flow-statistics result file If false, only annual and period of record statistics will be included.",
+      "value": false
+    },
+    {
       "name": "user_data",
       "description": "String containing user uploaded data with one line header, first column dates, second column values in a tab-delimited format.",
       "value": ""