Displaying differences for changeset
 
display as  

tools/MetaModelTools/src/data/interpretors/CligenData.java

@@ -17,17 +17,50 @@
  */
 public class CligenData {
 
-    private static final int MAX_YEARS = 100;
-    private static final int MAX_YEAR_AVERAGE_INDEX = MAX_YEARS;
+    public static final int MAX_YEARS = 100;
+    public static final int MONTH_AVERAGE_INDEX = 31;
+    public static final int MAX_YEAR_AVERAGE_INDEX = MAX_YEARS;
 
-    private double[][][][] monthlyData = new double[MAX_YEARS + 1][12][31][10];  //Daily Averages
-    private double[][] monthlyAverage = new double[12][10];
-    private static final int[] monthDays = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+    public static final int PRCP_INDEX = 0;
+    public static final int DUR_INDEX = 1;
+    public static final int TP_INDEX = 2;
+    public static final int IP_INDEX = 3;
+    public static final int TMAX_INDEX = 4;
+    public static final int TMIN_INDEX = 5;
+    public static final int RAD_INDEX = 6;
+    public static final int W_VL_INDEX = 7;
+    public static final int W_DIR_INDEX = 8;
+    public static final int TDEW_INDEX = 9;
+    public static final int DATA_TYPES_LENGTH = 10;
+
+    public static final int OBS_MONTHLY_TMAX = 0;
+    public static final int OBS_MONTHLY_TMIN = 1;
+    public static final int OBS_MONTHLY_RAD = 2;
+    public static final int OBS_MONTHLY_PRCP = 3;
+    public static final int OBS_MONTHLY_LENGTH = 4;
+
+    private static final int DAILY_VALUE_TOKENS = 13;
+
+    //  All monthly data for observeredYears years.  (Max out, i.e. cap output, at MAX_YEARS yrs)
+    private double[][][][] dailyData = new double[MAX_YEARS + 1][12][MONTH_AVERAGE_INDEX + 1][DATA_TYPES_LENGTH];  //Daily Averages
+    private double[][] yearlyData = new double[MAX_YEARS][DATA_TYPES_LENGTH];  //Yearly summaries
+
+    //  Montly averages, over entire observed years period, for prcp, dur, tp, ip, tmax, tmin, rad, w-vl, w-dir, tdew.
+    private double[][] monthlyAverage = new double[12][DATA_TYPES_LENGTH];
+
+    public static final int[] monthDays = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
     private String messages = "";
     private boolean badClimateData = false;
     private String stationName = "";
-    private double[][] observedMmonthlyAverage = new double[4][12];
-    private int observedYears;
+
+    //  Entire observedYears years averaged by month
+    private double[][] observedMmonthlyAverage = new double[12][OBS_MONTHLY_LENGTH];
+
+    //  How many years total in the file
+    private int observedYears = 0;
+
+    private int yearCount = 0;
+
     private int elevation = 0;
     private String climateVersion;
     private int yearsSimulated;
@@ -50,18 +83,109 @@
         return messages;
     }
 
+    /**
+     * Calculates if not yet calculated, the annual average precipitation based
+     * on "observed" monthly averages found at the top of the climate file. This
+     * does not represent the actual yearly or yearsSimulated averages, which
+     * can be found in other functions.
+     *
+     * @return Returns a double value representing a calculated annual average
+     * precipitation based on "observed" monthly values found in the top of the
+     * climate file.
+     */
     public double annualAvgPrecip() {
         if (Double.isNaN(annualAvgPrecip)) {
             double avg = 0.0;
             for (int i = 0; i < 12; i++) {
-                avg += observedMmonthlyAverage[3][i];
+                avg += observedMmonthlyAverage[i][3];
             }
-            annualAvgPrecip = avg/12.0;
+            annualAvgPrecip = avg / 12.0;
         }
 
         return annualAvgPrecip;
     }
 
+    public int observedYears() {
+        return observedYears;
+    }
+
+    public int yearsSimulated() {
+        return yearsSimulated;
+    }
+
+    public int yearsInFile() {
+        return yearCount;
+    }
+
+    public int elevation() {
+        return elevation;
+    }
+
+    public String climateVersion() {
+        return climateVersion;
+    }
+
+    public int beginningYear() {
+        return beginningYear;
+    }
+
+    public String stationName() {
+        return stationName;
+    }
+
+    public double[][] monthlyAverages() {
+        return monthlyAverage;
+    }
+
+    public double[][] observedMonthlyAverages() {
+        return observedMmonthlyAverage;
+    }
+
+    public double[] observedMonthlyAverages(int month) {
+        if ((month >= 0) && (month < 12)) {
+            return observedMmonthlyAverage[month];
+        }
+
+        return null;
+    }
+
+    public double observedMonthlyAverages(int month, int dataType) {
+        if ((month >= 0) && (month < 12) && (dataType >= 0) && (dataType < OBS_MONTHLY_LENGTH)) {
+            return observedMmonthlyAverage[month][dataType];
+        }
+        return Double.NaN;
+    }
+
+    public double[] yearlySummary(int yearIndex) {
+        if ((yearIndex < yearCount) && (yearIndex >= 0)) {
+            return yearlyData[yearIndex];
+        }
+
+        return null;
+    }
+
+    public double yearlySummary(int yearIndex, int dataType) {
+        if ((yearIndex < yearCount) && (yearIndex >= 0) && (dataType >= 0) && (dataType < DATA_TYPES_LENGTH)) {
+            return yearlyData[yearIndex][dataType];
+        }
+
+        return Double.NaN;
+    }
+
+    public double simulationAverage(int dataType) {
+        if ((dataType >= 0) && (dataType < DATA_TYPES_LENGTH)) {
+            double total = 0.0;
+
+            for (int i = 0; i < 12; i++) {
+                total += this.monthlyAverage[i][dataType];
+            }
+
+            return (total / 12.0);
+        }
+
+        return Double.NaN;
+    }
+
     private void readClimateData(String windFileData) throws IOException {
         BufferedReader climateData;
         climateData = new BufferedReader(new StringReader(windFileData));
@@ -79,208 +203,306 @@
                 continue;
             }
 
-            if (climateLine.contains("Station:")) {
-                stationName = climateLine.substring(climateLine.indexOf("Station:") + 9, climateLine.indexOf("CLIGEN") - (climateLine.indexOf("Station:") + 9)).trim();
-                continue;
-            }
+            if (!foundData) {
 
-            if (climateLine.contains("Latitude ")) {
-                climateLine = climateData.readLine();
-                if (null != climateLine) {
-                    count++;
-                    String[] tokens = climateLine.trim().split("\\s+");
+                if (climateLine.contains("Station:")) {
+                    stationName = climateLine.substring(climateLine.indexOf("Station:") + 9, climateLine.indexOf("CLIGEN") - (climateLine.indexOf("Station:") + 9)).trim();
+                    continue;
+                }
 
-                    if (tokens.length >= 7) {
-                        elevation = Integer.parseInt(tokens[2]);
-                        observedYears = Integer.parseInt(tokens[3]);
-                        beginningYear = Integer.parseInt(tokens[4]);
-                        yearsSimulated = Integer.parseInt(tokens[5]);
+                if (climateLine.contains("Latitude ")) {
+                    climateLine = climateData.readLine();
+                    if (null != climateLine) {
+                        count++;
+                        String[] tokens = climateLine.trim().split("\\s+");
+
+                        if (tokens.length >= 7) {
+                            elevation = Integer.parseInt(tokens[2]);
+                            observedYears = Integer.parseInt(tokens[3]);
+                            beginningYear = Integer.parseInt(tokens[4]);
+                            yearsSimulated = Integer.parseInt(tokens[5]);
+                        } else {
+                            messages += "\n#\nClimate file is invalid.  Data line that follows the headers on line " + count + " is incomplete.";
+                            badClimateData = true;
+                            break;
+                        }
+
                     } else {
-                        messages += "\n#\nClimate file is invalid.  Data line that follows the headers on line " + count + " is incomplete.";
+                        messages += "\n#\nClimate file is invalid.  No data line follows the headers on line " + count;
                         badClimateData = true;
                         break;
                     }
+                    continue;
+                }
 
-                } else {
-                    messages += "\n#\nClimate file is invalid.  No data line follows the headers on line " + count;
-                    badClimateData = true;
-                    break;
-                }
-                continue;
-            }
+                if (climateLine.contains("Observed monthly ave max temperature (C)")) {
+                    climateLine = climateData.readLine();
+                    if (null != climateLine) {
+                        count++;
+                        String[] tokens = climateLine.trim().split("\\s+");
 
-            if (climateLine.contains("Observed monthly ave max temperature (C)")) {
-                climateLine = climateData.readLine();
-                if (null != climateLine) {
-                    count++;
-                    String[] tokens = climateLine.trim().split("\\s+");
+                        if (tokens.length >= 12) {
+                            for (int i = 0; i < 12; i++) {
+                                observedMmonthlyAverage[i][OBS_MONTHLY_TMAX] = Double.parseDouble(tokens[i]);
+                            }
+                        } else {
+                            messages += "\n#\nClimate file is invalid.  Data line that follows the observed monthly average max temperatures header on line " + count + " is incomplete.";
+                            badClimateData = true;
+                            break;
+                        }
 
-                    if (tokens.length >= 12) {
-                        for (int i = 0; i < 12; i++) {
-                            observedMmonthlyAverage[0][i] = Double.parseDouble(tokens[i]);
-                        }
                     } else {
-                        messages += "\n#\nClimate file is invalid.  Data line that follows the observed monthly average max temperatures header on line " + count + " is incomplete.";
+                        messages += "\n#\nClimate file is invalid.  No data line that follows the observed monthly average max temperatures header on line " + count;
                         badClimateData = true;
                         break;
                     }
+                    continue;
+                }
 
-                } else {
-                    messages += "\n#\nClimate file is invalid.  No data line that follows the observed monthly average max temperatures header on line " + count;
-                    badClimateData = true;
-                    break;
-                }
-                continue;
-            }
+                if (climateLine.contains("Observed monthly ave min temperature (C)")) {
+                    climateLine = climateData.readLine();
+                    if (null != climateLine) {
+                        count++;
+                        String[] tokens = climateLine.trim().split("\\s+");
 
-            if (climateLine.contains("Observed monthly ave min temperature (C)")) {
-                climateLine = climateData.readLine();
-                if (null != climateLine) {
-                    count++;
-                    String[] tokens = climateLine.trim().split("\\s+");
+                        if (tokens.length >= 12) {
+                            for (int i = 0; i < 12; i++) {
+                                observedMmonthlyAverage[i][OBS_MONTHLY_TMIN] = Double.parseDouble(tokens[i]);
+                            }
+                        } else {
+                            messages += "\n#\nClimate file is invalid.  Data line that follows the observed monthly average min temperatures header on line " + count + " is incomplete.";
+                            badClimateData = true;
+                            break;
+                        }
 
-                    if (tokens.length >= 12) {
-                        for (int i = 0; i < 12; i++) {
-                            observedMmonthlyAverage[1][i] = Double.parseDouble(tokens[i]);
-                        }
                     } else {
-                        messages += "\n#\nClimate file is invalid.  Data line that follows the observed monthly average min temperatures header on line " + count + " is incomplete.";
+                        messages += "\n#\nClimate file is invalid.  No data line that follows the observed monthly average min temperatures header on line " + count;
                         badClimateData = true;
                         break;
                     }
+                    continue;
+                }
 
-                } else {
-                    messages += "\n#\nClimate file is invalid.  No data line that follows the observed monthly average min temperatures header on line " + count;
-                    badClimateData = true;
-                    break;
-                }
-                continue;
-            }
+                if (climateLine.contains("Observed monthly ave solar radiation (Langleys/day)")) {
+                    climateLine = climateData.readLine();
+                    if (null != climateLine) {
+                        count++;
+                        String[] tokens = climateLine.trim().split("\\s+");
 
-            if (climateLine.contains("Observed monthly ave solar radiation (Langleys/day)")) {
-                climateLine = climateData.readLine();
-                if (null != climateLine) {
-                    count++;
-                    String[] tokens = climateLine.trim().split("\\s+");
+                        if (tokens.length >= 12) {
+                            for (int i = 0; i < 12; i++) {
+                                observedMmonthlyAverage[i][OBS_MONTHLY_RAD] = Double.parseDouble(tokens[i]);
+                            }
+                        } else {
+                            messages += "\n#\nClimate file is invalid.  Data line that follows the Observed monthly ave solar radiation (Langleys/day) header on line " + count + " is incomplete.";
+                            badClimateData = true;
+                            break;
+                        }
 
-                    if (tokens.length >= 12) {
-                        for (int i = 0; i < 12; i++) {
-                            observedMmonthlyAverage[2][i] = Double.parseDouble(tokens[i]);
-                        }
                     } else {
-                        messages += "\n#\nClimate file is invalid.  Data line that follows the Observed monthly ave solar radiation (Langleys/day) header on line " + count + " is incomplete.";
+                        messages += "\n#\nClimate file is invalid.  No data line that follows the Observed monthly ave solar radiation (Langleys/day) header on line " + count;
                         badClimateData = true;
                         break;
                     }
+                    continue;
+                }
 
-                } else {
-                    messages += "\n#\nClimate file is invalid.  No data line that follows the Observed monthly ave solar radiation (Langleys/day) header on line " + count;
-                    badClimateData = true;
-                    break;
-                }
-                continue;
-            }
+                if (climateLine.contains("Observed monthly ave precipitation (mm)")) {
+                    climateLine = climateData.readLine();
+                    if (null != climateLine) {
+                        count++;
+                        String[] tokens = climateLine.trim().split("\\s+");
 
-            if (climateLine.contains("Observed monthly ave precipitation (mm)")) {
-                climateLine = climateData.readLine();
-                if (null != climateLine) {
-                    count++;
-                    String[] tokens = climateLine.trim().split("\\s+");
+                        if (tokens.length >= 12) {
+                            for (int i = 0; i < 12; i++) {
+                                observedMmonthlyAverage[i][OBS_MONTHLY_PRCP] = Double.parseDouble(tokens[i]);
+                            }
+                        } else {
+                            messages += "\n#\nClimate file is invalid.  Data line that follows the Observed monthly ave precipitation (mm) header on line " + count + " is incomplete.";
+                            badClimateData = true;
+                            break;
+                        }
 
-                    if (tokens.length >= 12) {
-                        for (int i = 0; i < 12; i++) {
-                            observedMmonthlyAverage[3][i] = Double.parseDouble(tokens[i]);
-                        }
                     } else {
-                        messages += "\n#\nClimate file is invalid.  Data line that follows the Observed monthly ave precipitation (mm) header on line " + count + " is incomplete.";
+                        messages += "\n#\nClimate file is invalid.  No data line that follows the Observed monthly ave precipitation (mm) header on line " + count;
                         badClimateData = true;
                         break;
                     }
+                    continue;
+                }
 
-                } else {
-                    messages += "\n#\nClimate file is invalid.  No data line that follows the Observed monthly ave precipitation (mm) header on line " + count;
-                    badClimateData = true;
-                    break;
+                if (climateLine.contains("da mo year  prcp")) {
+                    climateLine = climateData.readLine();
+                    if (null != climateLine) {
+                        count++;
+                        foundData = true;
+                    }
+                    continue;
                 }
-                continue;
-            }
+            } else {
+                //  If we got to here, then we are now reading the monthly data lines...
+                int currentYear = -1;
+                int currentMonth = -1;
+                int numDays = 0;
+                int monthDayCount = 0;
+                yearCount = 0;
+                int[] runningTotal = new int[DATA_TYPES_LENGTH];
 
-            if (climateLine.contains("da mo year  prcp")) {
-                climateLine = climateData.readLine();
-                if (null != climateLine) {
-                    count++;
-                    foundData = true;
-                }
-                continue;
-            }
+                while (true) {
+                    String[] tokens = climateLine.trim().split("\\s+");
 
-            //  If we got to here, then we are now reading the monthly data lines...
-            if (foundData) {
-                String[] tokens = climateLine.trim().split("\\s+");
+                    if (tokens.length >= DAILY_VALUE_TOKENS) {
+                        int day, month, year;
 
-                if (tokens.length >= 13) {
-                    int day, month, year;
-                    double dayAverage = 0;
+                        day = Integer.parseInt(tokens[0]) - 1;
+                        month = Integer.parseInt(tokens[1]) - 1;
+                        year = Integer.parseInt(tokens[2]) - 1;
 
-                    day = Integer.parseInt(tokens[0]) - 1;
-                    month = Integer.parseInt(tokens[1]) - 1;
-                    year = Integer.parseInt(tokens[2]) - 1;
-
-                    if ((year >= 99) && (month == 11) && (day == 30)) {
-                        foundEndOfCycle = true;
-                    }
-
-                    if (year < 100) {
-                        for (int i = 0; i < 10; i++) {
-                            monthlyData[year][month][day][i] = Double.parseDouble(tokens[i + 3]);
-                            monthlyData[MAX_YEAR_AVERAGE_INDEX][month][day][i] += monthlyData[year][month][day][i];
+                        if (((year >= (MAX_YEARS - 1)) || (yearCount >= yearsSimulated)) && (month == 11) && (day == 30)) {
+                            foundEndOfCycle = true;
                         }
 
-                        if ((month == 2) && (day == 29)) {
-                            febCount++;
+                        //Catch month transition and save yearly averages...do this before checking year transition to avoid doing this twice.
+                        if (month != currentMonth) {
+                            if (currentMonth == -1) {
+                                currentMonth = month;
+                                monthDayCount = 0;
+                            } else {
+                                for (int i = 0; i < DATA_TYPES_LENGTH; i++) {
+                                    dailyData[currentYear][currentMonth][MONTH_AVERAGE_INDEX][i] /= monthDayCount;
+                                    dailyData[MAX_YEAR_AVERAGE_INDEX][currentMonth][MONTH_AVERAGE_INDEX][i] += dailyData[currentYear][currentMonth][MONTH_AVERAGE_INDEX][i];
+                                }
+                                monthDayCount = 0;
+                                currentMonth = month;
+                            }
+                        }
+
+                        //Catch year transition and save yearly averages.
+                        if (year != currentYear) {
+                            if (currentYear == -1) {
+                                currentYear = year;
+                                for (int i = 0; i < DATA_TYPES_LENGTH; i++) {
+                                    runningTotal[i] = 0;
+                                }
+                            } else {
+                                for (int i = 0; i < DATA_TYPES_LENGTH; i++) {
+                                    yearlyData[currentYear][i] = runningTotal[i] / numDays;
+                                    runningTotal[i] = 0;
+                                }
+                                currentYear = year;
+                            }
+                            numDays = 0;
+                            yearCount++;
+                        }
+
+                        if (year < MAX_YEARS) {
+                            for (int i = 0; i < DATA_TYPES_LENGTH; i++) {
+                                double dataValue = Double.parseDouble(tokens[i + 3]);
+
+                                //Set value in matrix for this day/month/year/dataType
+                                dailyData[year][month][day][i] = dataValue;
+
+                                //Add to MAX_YEAR_AVERAGE_INDEX averages for this day/month/year/dataType
+                                dailyData[MAX_YEAR_AVERAGE_INDEX][month][day][i] += dataValue;
+
+                                //Add to yearly averages for this dataTypeIndex
+                                runningTotal[i] += dataValue;
+
+                                //Add to monthly averages for this year for this dataTypeIndex
+                                dailyData[year][month][MONTH_AVERAGE_INDEX][i] += dataValue;
+                            }
+
+                            //  If its February and a leap year, count the number of these that occured in this data set.
+                            if ((month == 1) && (day == 29)) {
+                                febCount++;
+                            }
+
+                            //Increment number of days of data read this year.
+                            numDays++;
+
+                            //Increment number of days of data read this month/year
+                            monthDayCount++;
+
+                        } else {
+                            messages += "\n#\nClimate file was longer than " + MAX_YEARS + " years.  Data clipped to " + MAX_YEARS + " years.";
+                            foundEndOfCycle = true;
+                            break;
                         }
 
                     } else {
-                        messages += "\n#\nClimate file was longer than 100 years.  Data clipped to 100 years.";
+                        if (!foundEndOfCycle) {
+                            messages += "\n#\nMissing daily climate data on line " + count + "of the cligen data file.  Expected 13 fields and found only " + tokens.length + " fields instead.";
+                            badClimateData = true;
+                            break;
+                        }
+                    }
+
+                    climateLine = climateData.readLine();
+                    if (null == climateLine) {
                         break;
                     }
-                } else {
-                    if (!foundEndOfCycle) {
-                        messages += "\n#\nMissing daily climate data on line " + count + "of the cligen data file.  Expected 13 fields and found only " + tokens.length + " fields instead.";
-                        badClimateData = true;
-                        break;
+                    count++;
+                }
+
+                if (foundEndOfCycle) {
+
+                    //Get final year's averages since while loop will exit right after filling in the last year of data, but not do that year's averages.
+                    for (int i = 0; i < DATA_TYPES_LENGTH; i++) {
+                        yearlyData[currentYear][i] = runningTotal[i] / numDays;
+                        dailyData[currentYear][currentMonth][MONTH_AVERAGE_INDEX][i] /= monthDayCount;
+                        dailyData[MAX_YEAR_AVERAGE_INDEX][currentMonth][MONTH_AVERAGE_INDEX][i] += dailyData[currentYear][currentMonth][MONTH_AVERAGE_INDEX][i];
                     }
-                }
-            }
 
-            for (int j = 0; j < 12; j++) {
-                double[] monthlyAvg = new double[10];
-                int febDayCounter = 0;
-                for (int k = 0; k < monthDays[j]; k++) {
-                    for (int l = 0; l < 10; l++) {
-                        if (j != 1) {
-                            monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k][l] /= MAX_YEARS;
-                            monthlyAvg[l] += monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k][l];
-                        } else { // In February
-                            if (k == 28) { // On leap year day 29
-                                monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k][l] /= febCount;
-                                monthlyAvg[l] += monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k][l] * febCount;
-                                febDayCounter += febCount;
-                            } else {
-                                monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k][l] /= MAX_YEARS;
-                                monthlyAvg[l] += monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k][l] * 28;
-                                febDayCounter += 28;
+                    ////////////////////////////////////////////////////////////////////////
+                    // Calculates MAX_YEARS year averages...by day and by month for each dataType.
+                    //
+                    //    Also calculate daily averages each month over the MAX_YEARS years...saves a 
+                    //  daily average for the entire MAX_YEARS years, so the MAX_YEAR_AVERAGE_INDEX line of this matrix contains an average for the entire simulation.
+                    /////////////////////////////////////////////////////////////////////////////////////////////////
+                    for (int monthIndex = 0; monthIndex < 12; monthIndex++) {
+                        double[] monthlyAvg = new double[DATA_TYPES_LENGTH];
+                        int febDayCounter = 0;
+
+                        // For each day of this month.
+                        for (int monthDay = 0; monthDay < monthDays[monthIndex]; monthDay++) {
+                            // For each data type on this day
+                            for (int dataTypeIndex = 0; dataTypeIndex < DATA_TYPES_LENGTH; dataTypeIndex++) {
+                                if (monthIndex != 1) {
+                                    dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][monthDay][dataTypeIndex] /= yearsSimulated;
+                                    monthlyAvg[dataTypeIndex] += dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][monthDay][dataTypeIndex];
+                                } else { // In February
+                                    if (monthDay == 28) { // On leap year day 29
+                                        dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][monthDay][dataTypeIndex] /= febCount;
+                                        monthlyAvg[dataTypeIndex] += dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][monthDay][dataTypeIndex] * febCount;
+                                        febDayCounter += febCount;
+                                    } else {
+                                        dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][monthDay][dataTypeIndex] /= yearsSimulated;
+                                        monthlyAvg[dataTypeIndex] += dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][monthDay][dataTypeIndex] * 28;
+                                        febDayCounter += 28;
+                                    }
+                                }
                             }
                         }
+
+                        //Calculate monthly averages over entire yearsSimulated years.
+                        for (int dataTypeIndex = 0; dataTypeIndex < DATA_TYPES_LENGTH; dataTypeIndex++) {
+                            if (monthIndex != 1) {
+                                monthlyAverage[monthIndex][dataTypeIndex] = monthlyAvg[dataTypeIndex] / monthDays[monthIndex];
+                            } else {
+                                monthlyAverage[monthIndex][dataTypeIndex] = monthlyAvg[dataTypeIndex] / febDayCounter;
+                            }
+
+                            //  This value should match the one saved just above...check on this...
+                            dailyData[MAX_YEAR_AVERAGE_INDEX][monthIndex][MONTH_AVERAGE_INDEX][dataTypeIndex] /= yearsSimulated;
+                        }
                     }
-                }
 
-                for (int l = 0; l < 10; l++) {
-                    if (j != 1) {
-                        monthlyAverage[j][l] = monthlyAvg[l] / monthDays[j];
-                    } else {
-                        monthlyAverage[j][l] = monthlyAvg[l] / febDayCounter;
-                    }
+                    //Done with this file...
+                    break;
+                } else {
+                    messages += "\n#\nDid not find an entire " + MAX_YEARS + " year simulation of climate data.";
+                    badClimateData = true;
+                    break;
                 }
             }
         }

tools/MetaModelTools/src/data/interpretors/WindGenData.java

@@ -8,6 +8,14 @@
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.StringReader;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -17,19 +25,38 @@
  */
 public class WindGenData {
 
-    private static final int MAX_YEARS = 100;
-    private static final int MAX_YEAR_AVERAGE_INDEX = MAX_YEARS;
+    public static final int MPS_THRESHOLD = 8;
+    public static final int MAX_YEARS = 100;
+    public static final int MAX_YEAR_AVERAGE_INDEX = MAX_YEARS;
 
-    private double[][][] monthlyData = new double[MAX_YEARS + 1][12][31];  //Daily Averages
-    private double[] monthlyAverage = new double[12];
-    private static int[] monthDays = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+    private double[][][] dailyData = new double[MAX_YEARS][12][31];  //Daily Averages
+    private double[][] monthlyAverage = new double[MAX_YEARS + 1][12];
+    private double[] yearlyAverage = new double[MAX_YEARS + 1];
+
+    private double[][][] dailyEnergyData = new double[MAX_YEARS + 1][12][31];  //Daily Averages
+    private double[][] monthlyEnergyData = new double[MAX_YEARS + 1][12];
+    private double[] yearlyEnergyData = new double[MAX_YEARS + 1];
+
+    public static int[] monthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
     private String messages = "";
     private boolean badWindData = false;
     private String stationName = "";
     private String period = "";
     private int elevation = 0;
+    private Period windPeriod;
+    private int yearCount = 0;
 
     public WindGenData(String windFileData) {
+
+        for (int year = 0; year < MAX_YEARS; year++) {
+            for (int month = 0; month < 12; month++) {
+                for (int day = 0; day < 31; day++) {
+                    dailyData[year][month][day] = -1.0;
+                }
+            }
+        }
+        
         try {
             readWindData(windFileData);
         } catch (IOException ex) {
@@ -44,77 +71,245 @@
         String windLine;
         int count = 0;
         int febCount = 0;
+        boolean foundData = false;
+        int lastYear = -1;
+        double yearTotal = 0;
+        double yearEnergyTotal = 0;
+        double monthEnergyTotal = 0;
+        int numDays = 0;
+        int numMonthDays = 0;
+        int lastMonth = -1;
+        double monthTotal = 0;
 
         while ((windLine = windData.readLine()) != null) {
             count++;
-            if (windLine.startsWith("#")) {
-                if ( windLine.contains("station:")){
+            if (!foundData && windLine.startsWith("#")) {
+                if (windLine.contains("station:")) {
                     stationName = windLine.substring(windLine.indexOf("station: ") + 9);
-                }else{
-                    if ( windLine.contains("period: ")){
+                } else {
+                    if (windLine.contains("period: ")) {
                         period = windLine.substring(windLine.indexOf("period: ") + 8, windLine.indexOf("el:") - (windLine.indexOf("period: ") + 8));
                         String elString = windLine.substring(windLine.indexOf("el:") + 3);
                         elevation = Integer.parseInt(elString.replace("m", " ").trim());
+                    } else {
+                        if (windLine.contains("day mo year dir   hr1")) {
+                            if ((windLine = windData.readLine()) != null) {
+                                if (windLine.contains("deg   m/s  m/s")) {
+                                    if ((windLine = windData.readLine()) != null) {
+                                        if (windLine.contains("# ----------------")) {
+                                            foundData = true;
+                                        } else {
+                                            messages += "\n#\nMissing comment underline line after deg m/s m/s... line";
+                                            badWindData = true;
+                                            break;
+                                        }
+                                    } else {
+                                        messages += "\n#\nMissing next line after deg m/s... line";
+                                        badWindData = true;
+                                        break;
+                                    }
+                                }
+                            } else {
+                                messages += "\n#\nMissing next line after day mo year... line";
+                                badWindData = true;
+                                break;
+                            }
+                        }
                     }
                 }
                 continue;
-            }
-            String[] tokens = windLine.trim().split("\\s+");
-            if (tokens.length >= 28) {
-                int day, month, year;
-                double dayAverage = 0;
+            } else {
+                if (foundData) {
+                    String[] tokens = windLine.trim().split("\\s+");
+                    if (tokens.length >= 28) {
+                        int day, month, year;
+                        double dayAverage = 0;
 
-                day = Integer.parseInt(tokens[0]) - 1;
-                month = Integer.parseInt(tokens[1]) - 1;
-                year = Integer.parseInt(tokens[2]) - 1;
+                        day = Integer.parseInt(tokens[0]) - 1;
+                        month = Integer.parseInt(tokens[1]) - 1;
+                        year = Integer.parseInt(tokens[2]) - 1;
 
-                if (year < 100) {
-                    for (int i = 4; i < 28; i++) {
-                        dayAverage += Double.parseDouble(tokens[i]);
-                    }
+                        if (month != lastMonth) {
+                            if (lastMonth != -1) {
+                                monthlyAverage[lastYear][lastMonth] = monthTotal / numMonthDays;
+                                monthlyAverage[MAX_YEARS][lastMonth] += monthlyAverage[lastYear][lastMonth];
+                                monthlyEnergyData[lastYear][lastMonth] = monthEnergyTotal;
+                            }
+                            monthTotal = 0;
+                            numMonthDays = 0;
+                            lastMonth = month;
+                            monthEnergyTotal = 0;
+                        }
 
-                    monthlyData[year][month][day] = dayAverage / 24.0;
-                    monthlyData[MAX_YEAR_AVERAGE_INDEX][month][day] += monthlyData[year][month][day];
-                    if ((month == 2) && (day == 29)) {
-                        febCount++;
+                        if (year != lastYear) {
+                            if (lastYear != -1) {
+                                yearlyAverage[lastYear] = yearTotal / numDays;
+                                yearlyAverage[MAX_YEARS] += yearlyAverage[lastYear];
+                                yearlyEnergyData[lastYear] = yearEnergyTotal;
+                            }
+                            yearCount++;
+                            yearTotal = 0;
+                            numDays = 0;
+                            lastYear = year;
+                            yearEnergyTotal = 0;
+                        }
+
+                        if ((year <= period().getYears()) && (year < MAX_YEARS)) {
+                            for (int i = 4; i < 28; i++) {
+                                dayAverage += Double.parseDouble(tokens[i]);
+                            }
+
+                            dayAverage /= 24.0;
+
+                            dailyData[year][month][day] = dayAverage;
+                            //dailyData[MAX_YEAR_AVERAGE_INDEX][month][day] += dayAverage;
+
+                            if (dayAverage > MPS_THRESHOLD) {
+                                dailyEnergyData[year][month][day] = 0.6 * Math.pow(dayAverage - MPS_THRESHOLD, 2);
+                            } else {
+                                dailyEnergyData[year][month][day] = 0;
+                            }
+
+                            if ((month == 2) && (day == 29)) {
+                                febCount++;
+                            }
+
+                            dailyEnergyData[MAX_YEARS][month][day] += dailyEnergyData[year][month][day];
+                            
+                            yearEnergyTotal += dailyEnergyData[year][month][day];
+                            monthEnergyTotal += dailyEnergyData[year][month][day];
+                            monthTotal += dayAverage;
+                            numMonthDays++;
+                            yearTotal += dayAverage;
+                            numDays++;
+                        } else {
+                            messages += "\n#\nWind file was longer than 100 years.  Data clipped to 100 years.";
+                            break;
+                        }
+                    } else {
+                        messages += "\n#\nMissing hourly wind data on line " + count + "of the windgen data file.  Expected 28 fields and found only " + tokens.length + " fields instead.";
+                        badWindData = true;
+                        break;
                     }
                 } else {
-                    messages += "\n#\nWind file was longer than 100 years.  Data clipped to 100 years.";
-                    break;
+                    // Blank line??  Regardless ignore it for now...maybe generate an error if we discover that this cannot/shoud not happen in a .win file.
                 }
-            } else {
-                messages += "\n#\nMissing hourly wind data on line " + count + "of the windgen data file.  Expected 28 fields and found only " + tokens.length + " fields instead.";
-                badWindData = true;
-                break;
             }
         }
-        
-        for (int j = 0; j < 12; j++) {
-            double monthlyAvg = 0;
-            int febDayCounter = 0;
-            for (int k = 0; k < monthDays[j]; k++) {
-                if (j != 1) {
-                    monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k] /= MAX_YEARS;
-                    monthlyAvg += monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k];
-                } else { // In February
-                    if (k == 28) { // On leap year day 29
-                        monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k] /= febCount;
-                        monthlyAvg += monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k] * febCount;
-                        febDayCounter += febCount;
-                    } else {
-                        monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k] /= MAX_YEARS;
-                        monthlyAvg += monthlyData[MAX_YEAR_AVERAGE_INDEX][j][k] * 28;
-                        febDayCounter += 28;
-                    }
+
+        if (foundData && (yearCount > 0)) {
+
+            monthlyAverage[lastYear][lastMonth] = monthTotal / numMonthDays;
+            yearlyAverage[lastYear] = yearTotal / numDays;
+            monthlyEnergyData[lastYear][lastMonth] = monthEnergyTotal;
+            yearlyEnergyData[lastYear] = yearEnergyTotal;
+            yearCount++;
+
+            yearlyAverage[MAX_YEARS] /= yearCount;
+            yearlyEnergyData[MAX_YEARS] /= yearCount;
+
+            for (int i = 0; i < 12; i++) {
+                monthlyAverage[MAX_YEARS][i] /= yearCount;
+                monthlyEnergyData[MAX_YEARS][i] /= yearCount;
+            }
+
+        }
+    }
+
+    public int yearsSimulated() {
+        return period().getYears();
+    }
+
+    public int yearsInFile() {
+        return yearCount;
+    }
+
+    public int elevation() {
+        return elevation;
+    }
+
+    public double[][] monthlyAverages() {
+        return monthlyAverage;
+    }
+
+    public double monthlyAverage(int year, int month) {
+        if ((year < yearCount) && ((month >= 0) && (month < 12))) {
+            return monthlyAverage[year][month];
+        }
+
+        return Double.NaN;
+    }
+
+    public String stationName() {
+        return stationName;
+    }
+
+    public double yearlyAverage(int yearIndex) {
+        if ((yearIndex < yearCount) && (yearIndex >= 0)) {
+            return yearlyAverage[yearIndex];
+        }
+
+        return Double.NaN;
+    }
+
+    public double[] monthlyAverage(int yearIndex) {
+        if ((yearIndex < yearCount) && (yearIndex >= 0)) {
+            return monthlyAverage[yearIndex];
+        }
+
+        return null;
+    }
+
+    public double windEnergy(int month, int day, int period) {
+        double energyVal = 0;
+
+        if (period > 365) {
+            energyVal = Double.NaN;
+        } else {
+            int currentMonth = month;
+            int startDay = day;
+            int dayCount = 0;
+
+            while (dayCount < period) {
+                for (int tDay = startDay; tDay < monthDays[currentMonth]; tDay++) {
+                    energyVal += (dailyEnergyData[MAX_YEARS][currentMonth][tDay] / yearCount);
+                    dayCount++;
                 }
-
-            }
-            if (j != 1) {
-                monthlyAverage[j] = monthlyAvg / monthDays[j];
-            } else {
-                monthlyAverage[j] = monthlyAvg / febDayCounter;
+                startDay = 0;
+                currentMonth++;
+                if ( currentMonth == 12){
+                    currentMonth = 0;
+                }
             }
         }
+
+        return energyVal;
+    }
+
+    public double simulationAverage() {
+        return yearlyAverage[MAX_YEARS];
+    }
+
+    public double[] simulationMonthlyAverage() {
+        return monthlyAverage[MAX_YEARS];
+    }
+
+    public Period period() {
+        if (null == windPeriod) {
+            String periods[] = period.trim().split("-");
+            if (periods.length == 2) {
+                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd");
+                LocalDate startDate = LocalDate.parse(periods[0], df);
+                LocalDate endDate = LocalDate.parse(periods[1], df);
+                windPeriod = Period.between(startDate, endDate);
+
+            } else {
+                this.badWindData = true;
+                this.messages = "\n#\nPeriod string found in file is not properly formatted.";
+            }
+        }
+
+        return windPeriod;
     }
 
     public boolean badWindData() {