@@ -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; |
} |
} |
} |
@@ -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() { |