CDPHE_lowFlowStats.java [src/java/cfa] Revision: 46c2f714b6c8c6c2e99c47bc1a60914fc136ac78 Date: Thu Dec 18 10:20:44 MST 2014
package cfa;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
/**
* Last Updated: 16-December-2014
* @author Tyler Wible
* @since 16-December-2014
*/
public class CDPHE_lowFlowStats {
//Gets
public String getFlowStatistics_summary() {
return "cdphe_lowflow.csv";
}
/**
* Calculate the CDPHE 'extreme value' design flow (see DFLOW user manual)
* based on an 'm'-day average low flow of each year fitted to a Log-Pearson
* Type III distribution and interpolated for a return period of 'R' years
* @param mainFolder the file path where the summary will be saved
* @param stationID the station ID for the current station, used to label the output
* @param stationName the station name for the current station, used to label the output
* @param flowData flow data, column1 = dates (format yyyy-mm-dd), column2 = flow values
* @param m the number of days to average for annual low flow analysis (m-day average)
* @param R the desired return period of the m-day low flow (in years)
* @param waterYearBegin the month and day (MM-dd) of the start of the water year for this analysis
* @return
* @throws IOException
* @throws ParseException
*/
public double CDPHE_ExtremeValue(String mainFolder,
String stationID,
String stationName,
String[][] flowData,
int m,
int R,
String waterYearBegin) throws IOException, ParseException{
DoubleArray doubleArray = new DoubleArray();
DoubleMath doubleMath = new DoubleMath();
//Get today's date for output purposes
Date currentDate = new Date();
SimpleDateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String today = desiredDateFormat.format(currentDate);
stationName = stationName.replace(",", "");
//Initialize the summary result table
String[][] statsSummaryTable = new String[6][2];
statsSummaryTable[0][0] = "CDPHE DFlow Statistics for " + stationID + "; " + stationName + "; created on " + today;
statsSummaryTable[1][0] = "Analysis Period (water year beginning " + waterYearBegin +")";
statsSummaryTable[2][0] = "Extreme Value-based Design Low Flow, (" + m + "-day minimum) [cfs]";
statsSummaryTable[3][0] = "Annual Low Flow (" + m + "-day minimum) [cfs]";
statsSummaryTable[4][0] = "Low Flow Statistics based on 'DFLOW' User's Manual:";
statsSummaryTable[5][0] = "Rossman, L.A. 'DFLOW User's Manual' U.S. Environmental Protection Agency Cincinnati, Ohio 45265.";
statsSummaryTable[0][1] = "";
statsSummaryTable[1][1] = "";
statsSummaryTable[2][1] = "to be added later";
statsSummaryTable[3][1] = "--";
statsSummaryTable[4][1] = "";
statsSummaryTable[5][1] = "";
int currentYear = Integer.parseInt(flowData[0][0].substring(0,4));
int finalYear = Integer.parseInt(flowData[flowData.length - 1][0].substring(0,4));
// //Start by pulling the first complete water year (determine if this is necessary
// if(flowData[0][0].compareToIgnoreCase(String.valueOf(currentYear) + "-04-01") > 0){
// //If the start date of data is after the start of the water year, reset the
// //begin date to next year so that only complete water years are analyzed
// currentYear++;
// }
int nextYear = currentYear + 1;
String beginDate = String.valueOf(currentYear) + "-" + waterYearBegin;//String beginDate = String.valueOf(currentYear) + "-04-01";
String previousDay = doubleArray.getDay(beginDate, -1);
String endDate = String.valueOf(nextYear) + previousDay.substring(4);//String endDate = String.valueOf(nextYear) + "-03-31";
//Calculate Flow statistics for each water-year in time period
ArrayList<Double> mDay_annualNonZero = new ArrayList<Double>();
int mDay_annual = 0;
boolean moreYears = finalYear > nextYear;
while(moreYears){
//Get current water year's data and calculate it's statistics
String[][] partialData = doubleArray.getPeriodData(flowData, beginDate, endDate);
//Calculate m-day statistics
Object[] resultArray = doubleArray.getMdayData(partialData, m, "arithmetic");
//ArrayList<String> average_Mday_date = (ArrayList<String>) resultArray[0];
ArrayList<Double> average_Mday = (ArrayList<Double>) resultArray[1];
//Calculate minimum flow and save it
double mDay_min = doubleMath.min(average_Mday);
if(mDay_min > 0) mDay_annualNonZero.add(mDay_min);
mDay_annual++;
//Add this water year's statistics to the existing results
String waterYearHeader = "Water Year " + String.valueOf(currentYear);
String[] additionalSummary = {"", waterYearHeader, "--", String.valueOf(mDay_min), "", ""};
statsSummaryTable = doubleArray.appendcolumn_Matrix(statsSummaryTable, additionalSummary);
//Check if this is the last year
if(finalYear >= nextYear){
currentYear++;
nextYear++;
beginDate = String.valueOf(currentYear) + "-" + waterYearBegin;//beginDate = String.valueOf(currentYear) + "-04-01";
previousDay = doubleArray.getDay(beginDate, -1);
endDate = String.valueOf(nextYear) + previousDay.substring(4);//endDate = String.valueOf(nextYear) + "-03-31";
}else{
moreYears = false;
}
}
//Convert low flows to natural-log low-flows
ArrayList<Double> lnMday_annualNonZero = new ArrayList<Double>();
for(int i=0; i<mDay_annualNonZero.size(); i++){
lnMday_annualNonZero.add( Math.log(mDay_annualNonZero.get(i)) );
}
//Determine properties of natural-log low-flows
double U = doubleMath.meanArithmetic(lnMday_annualNonZero);//Mean
double S = doubleMath.StandardDeviationSample(lnMday_annualNonZero);//Standard Deviation
double G = doubleMath.SkewnessSample(lnMday_annualNonZero);//Skewness
//Determine fraction of m-day low flows that are zero
double f0 = (mDay_annual - mDay_annualNonZero.size()) / mDay_annualNonZero.size();
//Determine cumulative probability of corresponding user-supplied return period
double P = (1./R - f0) / (1 - f0);
//Determine standard normal deviate from cumulative probability (Joiner and Rosenblatt, 1971)
double Z = 4.91 * (Math.pow(P, 0.14) - Math.pow(1-P, 0.14));
//Compute gamma deviate, K, using Wilson-Hilferty transformation (Loucks et al., 1981)
double K = (2./G) * (Math.pow(1 + (G*Z/6) - (G*G/36), 3) - 1);
//Compute design flow
double designFlow = Math.exp(U + K*S);
//Call file writer for outputs fo flow statistics
statsSummaryTable[2][0] = String.valueOf(doubleMath.round(designFlow, 3));
writeStatsSummaryFile(mainFolder, statsSummaryTable);
return designFlow;
}
/**
* Calculate the CDPHE 'human health' design flow (see DFLOW user manual)
* which is the harmonic mean of the flows
* @param mainFolder the file path where the summary will be saved
* @param stationID the station ID for the current station, used to label the output
* @param stationName the station name for the current station, used to label the output
* @param flowData flow data, column1 = dates (format yyyy-mm-dd), column2 = flow values
* @return
* @throws IOException
* @throws ParseException
*/
public double CDPHE_HumanHealth(String mainFolder,
String stationID,
String stationName,
String[][] flowData) throws IOException, ParseException{
DoubleMath doubleMath = new DoubleMath();
//Get today's date for output purposes
Date currentDate = new Date();
SimpleDateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String today = desiredDateFormat.format(currentDate);
stationName = stationName.replace(",", "");
String beginDate = flowData[0][0];
String endDate = flowData[flowData.length - 1][0];
//Calculate properties of harmonic mean
double[] flowOnlyData = new double[flowData.length];
for(int i=0; i<flowData.length; i++){
flowOnlyData[i] = Double.parseDouble(flowData[i][1]);
}
double designFlow = doubleMath.meanHarmonic(flowOnlyData);
//Initialize the summary result table
String[][] statsSummaryTable = new String[5][2];
statsSummaryTable[0][0] = "CDPHE DFlow Statistics for " + stationID + "; " + stationName + "; created on " + today;
statsSummaryTable[1][0] = "Analysis Period";
statsSummaryTable[2][0] = "Human Health-based Design Low Flow, harmonic mean [cfs]";
statsSummaryTable[3][0] = "Low Flow Statistics based on 'DFLOW' User's Manual:";
statsSummaryTable[4][0] = "Rossman, L.A. 'DFLOW User's Manual' U.S. Environmental Protection Agency Cincinnati, Ohio 45265.";
statsSummaryTable[0][1] = "";
statsSummaryTable[1][1] = beginDate + " to " + endDate;
statsSummaryTable[2][1] = String.valueOf(doubleMath.round(designFlow, 3));
statsSummaryTable[3][1] = "";
statsSummaryTable[4][1] = "";
//Call file writer for outputs fo flow statistics
writeStatsSummaryFile(mainFolder, statsSummaryTable);
return designFlow;
}
/**
* Writes the provided array to a CSV result file
* @param mainFolder the folder location for the result file
* @param statsSummary the desired contents of the file
* @throws IOException
*/
private void writeStatsSummaryFile(String mainFolder, String[][] statsSummary) throws IOException{
//Open a file writer for the summary of the flow statistcs per year
String path = mainFolder + File.separator + getFlowStatistics_summary();
FileWriter newFile = new FileWriter(path, false);
PrintWriter writer = new PrintWriter(newFile);
for(int i=0; i<statsSummary.length; i++){
String currentLine = statsSummary[i][0];
for(int j=1; j<statsSummary[i].length; j++){
currentLine = currentLine + "," + statsSummary[i][j];
}
writer.printf("%s" + "\r\n", currentLine);
}
//Close file writer
newFile.close();
writer.close();
System.out.println("Text File located at:\t" + path);
}
}