mQnFlow.java [src/java/cfa] Revision: 9c9d8df5ca0e3a6720b7a988951da99376960c05 Date: Thu Jun 05 11:52:26 MDT 2014
package cfa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
/**
* Last Updated: 16-October-2012
* @author Tyler Wible
* @since 29-June-2011
*/
public class mQnFlow {
/**
* Finds the m-day statistical average low value from the data set
* @param timeData the data set
* @param m the m-day average value desired
* @param ctr a counter of how large variables need to be
* @return the m-day average statistical low value of the data set
*/
public double minMflow(ArrayList<String> timeData, int m, int ctr){
double minMflow = 999999999;
//Pull out data from ArrayList
String currentLine = " $$ ";
String[] date = new String[ctr];
String[] flow = new String[ctr];
double[] Flows = new double[(int) Math.ceil(ctr/m)];
ctr=0;
for(int i=0; i<Flows.length; i++){
Flows[i] = 999999999;
}
Iterator<String> iterate1 = timeData.iterator( );
while(iterate1.hasNext()){
currentLine = (String) iterate1.next();
date[ctr] = currentLine.substring(0,currentLine.indexOf("$$"));
flow[ctr] = currentLine.substring(currentLine.indexOf("$$")+2);
ctr++;
}
//Find 'm' consecutive days with the same flow value
double[][] dates = new double[m][3];
int consecutiveFlowctr=0;
double consecutiveAverage = 0;
double yearUp4=0,yearDown4=0,yearUp100=0,yearDown100=0,yearUp400,yearDown400;
boolean leapyear = false;
ctr=0;
for(int i=0; i<date.length; i++){
if((date.length - i) >= m){
for(int j=0; j<m; j++){
dates[j][0] = Double.parseDouble(date[i+j].substring(0,4));//year
dates[j][1] = Double.parseDouble(date[i+j].substring(5,7));//month
dates[j][2] = Double.parseDouble(date[i+j].substring(8));//day
//Compare dates to find consecutive days, if days aren't consecutive break the loop
if(j==0){
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else if(j!=0 && (dates[j-1][0] == dates[j][0])){//compare year
if(dates[j-1][1] == dates[j][1]){//check if same month
if((dates[j-1][2] + 1) == dates[j][2]){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else if((dates[j-1][1] + 1) == dates[j][1]){//check if last day of month and first day of next
if(dates[j-1][1]==1 ||dates[j-1][1]==3 || dates[j-1][1]==5 || dates[j-1][1]==7 || dates[j-1][1]==8 || dates[j-1][1]==10 || dates[j-1][1]==12){
if((dates[j-1][2]==31) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else if(dates[j-1][1]==4 || dates[j-1][1]==6 || dates[j-1][1]==9 || dates[j-1][1]==11){
if((dates[j-1][2]==30) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else if(dates[j-1][1]==2){//If February check for leap years
leapyear = false;
yearUp4 = Math.ceil(dates[j-1][0]/4);
yearDown4 = Math.floor(dates[j-1][0]/4);
yearUp100 = Math.ceil(dates[j-1][0]/100);
yearDown100 = Math.floor(dates[j-1][0]/100);
yearUp400 = Math.ceil(dates[j-1][0]/400);
yearDown400 = Math.floor(dates[j-1][0]/400);
if(yearUp400 == yearDown400){
leapyear = true;
}else if(yearUp100 == yearDown100){
leapyear = false;
}else if(yearUp4 == yearDown4){
leapyear = true;
}
if(!leapyear && (dates[j-1][2]==28) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else if(leapyear && (dates[j-1][2]==29) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else{
break;
}
}else{
break;
}
}else if(j!=0 && (dates[j-1][0] + 1) == dates[j][0]){//check if last day of the year and first day of next
if(dates[j-1][1] == 31 && dates[j][1] == 1){//compare months
if((dates[j-1][2]==31) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else{
break;
}
}else{
break;
}
}
//If there are seven consecutive days find the average of the flows
if(consecutiveFlowctr == m ){
consecutiveAverage = consecutiveAverage/m;
Flows[ctr] = consecutiveAverage;
ctr++;
i = i + m - 1;
}
consecutiveAverage = 0;
consecutiveFlowctr = 0;
}
}
//Sort all the "m" day flow to find the "time"'s minimum
if(Flows.length > 0){
Arrays.sort(Flows);
if(Flows.length >= 2 && Flows[0] == 0 && Flows[1] != 0){
minMflow = Flows[1];
}else if(Flows.length >= 3 && Flows[0] == 0 && Flows[1] == 0 && Flows[2] != 0){
minMflow = Flows[1];
}else{
minMflow = Flows[0];
}
}
if(minMflow == 0){
minMflow = 10;
}
return minMflow;
}
/**
* Finds the m-day statistical average high value from the data set
* @param timeData the data set
* @param m the m-day average value desired
* @param ctr a counter of how large variables need to be
* @return the m-day average statistical high value of the data set
*/
public double maxMflow(ArrayList<String> timeData, int m, int ctr){
double maxMflow = 999999999;
//Pull out data from ArrayList
String currentLine = " $$ ";
String[] date = new String[ctr];
String[] flow = new String[ctr];
double[] Flows = new double[(int) Math.ceil(ctr/m)];
ctr=0;
for(int i=0; i<Flows.length; i++){
Flows[i] = 999999999;
}
Iterator<String> iterate1 = timeData.iterator( );
while(iterate1.hasNext()){
currentLine = (String) iterate1.next();
date[ctr] = currentLine.substring(0,currentLine.indexOf("$$"));
flow[ctr] = currentLine.substring(currentLine.indexOf("$$")+2);
ctr++;
}
//Find seven consecutive days with the same flow value
double[][] dates = new double[m][3];
int consecutiveFlowctr=0;
double consecutiveAverage = 0;
double yearUp4=0,yearDown4=0,yearUp100=0,yearDown100=0,yearUp400,yearDown400;
boolean leapyear = false;
ctr=0;
for(int i=0; i<date.length; i++){
if((date.length - i) >= m){
for(int j=0; j<m; j++){
dates[j][0] = Double.parseDouble(date[i+j].substring(0,4));//year
dates[j][1] = Double.parseDouble(date[i+j].substring(5,7));//month
dates[j][2] = Double.parseDouble(date[i+j].substring(8));//day
//Compare dates to find consecutive days, if days aren't consecutive break the loop
if(j==0){
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else if(j!=0 && (dates[j-1][0] == dates[j][0])){//compare year
if(dates[j-1][1] == dates[j][1]){//check if same month
if((dates[j-1][2] + 1) == dates[j][2]){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else if((dates[j-1][1] + 1) == dates[j][1]){//check if last day of month and first day of next
if(dates[j-1][1]==1 ||dates[j-1][1]==3 || dates[j-1][1]==5 || dates[j-1][1]==7 || dates[j-1][1]==8 || dates[j-1][1]==10 || dates[j-1][1]==12){
if((dates[j-1][2]==31) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else if(dates[j-1][1]==4 || dates[j-1][1]==6 || dates[j-1][1]==9 || dates[j-1][1]==11){
if((dates[j-1][2]==30) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else if(dates[j-1][1]==2){//If February check for leap years
yearUp4 = Math.ceil(dates[j-1][0]/4);
yearDown4 = Math.floor(dates[j-1][0]/4);
yearUp100 = Math.ceil(dates[j-1][0]/100);
yearDown100 = Math.floor(dates[j-1][0]/100);
yearUp400 = Math.ceil(dates[j-1][0]/400);
yearDown400 = Math.floor(dates[j-1][0]/400);
if(yearUp400 == yearDown400){
leapyear = true;
}else if(yearUp100 == yearDown100){
leapyear = false;
}else if(yearUp4 == yearDown4){
leapyear = true;
}
if(!leapyear && (dates[j-1][2]==28) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else if(leapyear && (dates[j-1][2]==29) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else{
break;
}
}else{
break;
}
}else if(j!=0 && (dates[j-1][0] + 1) == dates[j][0]){//check if last day of the year and first day of next
if(dates[j-1][1] == 31 && dates[j][1] == 1){//compare months
if((dates[j-1][2]==31) && (dates[j][2]==1)){//Check if is subsequent day
consecutiveAverage = consecutiveAverage + Double.parseDouble(flow[i+j]);
consecutiveFlowctr++;
}else{
break;
}
}else{
break;
}
}else{
break;
}
}
//If there are seven consecutive days find the average of the flows
if(consecutiveFlowctr == m ){
consecutiveAverage = consecutiveAverage/m;
Flows[ctr] = consecutiveAverage;
ctr++;
i = i + m - 1;
}
consecutiveAverage = 0;
consecutiveFlowctr = 0;
}
}
//Sort all the "m" day flow to find the "time"'s minimum
if(Flows.length > 0){
Arrays.sort(Flows);
if(Flows.length >= 2 && Flows[0] == 0 && Flows[1] != 0){
maxMflow = Flows[Flows.length - 1];
}else if(Flows.length >= 3 && Flows[0] == 0 && Flows[1] == 0 && Flows[2] != 0){
maxMflow = Flows[Flows.length - 1];
}else{
maxMflow = Flows[Flows.length - 1];
}
}
return maxMflow;
}
/**
* @param m the m day average of flows
* @param n the n return period of flows
* @param FlowTextData flow data with associated date
*/
public String[] main(int m, int n, String[][] FlowTextData, String period, String minMax){
double mQnFlow = 0;
String[] returnValue = new String[2];
//Check if m or n is zero
if(m == 0 || n == 0){
returnValue[0] = "";
returnValue[1] = String.valueOf(mQnFlow);
return returnValue;
}
//Find the time interval of interest, make sure there is sufficient data for the specified return period "n"
String time1 = "", time2 = "";
int endInt = 0;
if(period.equalsIgnoreCase("year")){
endInt = 4;
}else if(period.equalsIgnoreCase("month")){
endInt = 7;
}
//Find the number of unique time intervals available in the data for a maximum sized list
int ctr = 0;
for(int i=0; i<(FlowTextData.length); i++){
if(i == 0){
ctr++;
continue;
}
time1 = FlowTextData[i-1][0].substring(0,endInt);
time2 = FlowTextData[i][0].substring(0,endInt);
if (!time1.equalsIgnoreCase(time2)){
ctr++;
}
}
if (ctr < n){
String message = "There is insufficient available flow data for the " + m + "Q" + n + " flow calculation and the specified date range";
returnValue[0] = message;
returnValue[1] = String.valueOf(mQnFlow);
return returnValue;
}
String[] times = new String[ctr];
ctr=0;
for(int i=0; i<(FlowTextData.length); i++){
if(i==0){
times[ctr] = FlowTextData[i][0].substring(0,endInt);
ctr++;
continue;
}
time1 = FlowTextData[i-1][0].substring(0,endInt);
time2 = FlowTextData[i][0].substring(0,endInt);
if (!time1.equalsIgnoreCase(time2)){
times[ctr] = FlowTextData[i][0].substring(0,endInt);
ctr++;
}
}
//Sort all the m consecutive low flows in ascending order
ArrayList<String> timeData = new ArrayList<String>();
double[] mQnFlows = new double[ctr];
double zero = 0;
ctr=0;
//For each unique time period find all of its data and search it for m consecutive low flows
for(int j=0; j<times.length; j++){
for(int i=0; i<FlowTextData.length; i++){
if(FlowTextData[i][0].substring(0,endInt).equalsIgnoreCase(times[j])){
zero = Double.parseDouble(FlowTextData[i][1]);
if(zero != 0){
timeData.add(FlowTextData[i][0] + "$$" + FlowTextData[i][1]);
ctr++;
}
}
}
if(minMax.equalsIgnoreCase("minimum")){
mQnFlows[j] = minMflow(timeData,m,ctr);
}else{
mQnFlows[j] = maxMflow(timeData,m,ctr);
}
timeData.removeAll(timeData);
ctr=0;
}
//Sort the Data by flow to prepare for ranking
Arrays.sort(mQnFlows);
//Find the recurrence interval of the sorted flows T = 1/p = (N+1)/M
double totalSamples = mQnFlows.length;
double[] sortedRank = new double[mQnFlows.length];
double[] rankedFlow = new double[mQnFlows.length];
double[] recurenceInterval = new double[mQnFlows.length];
int i=0, h=0, g=0;
for(i=1; (i<mQnFlows.length +1); i++){
if((i != mQnFlows.length) && (mQnFlows[i-1] == (mQnFlows[i]))){
//Find how many elements equal
h = i;
while((h != mQnFlows.length) && (mQnFlows[h-1] ==(mQnFlows[h]))){
h++;
}
//Give all the equal elements the rank of the largest equal element (max rank for tied rank scenarios)
for(g=i; g<=h; g++){
sortedRank[g-1] = h;
rankedFlow[g-1] = mQnFlows[g-1];
recurenceInterval[g-1] = (totalSamples + 1)/(sortedRank[g-1]);
if (g==h){
//If on the last repeated element, set the initial counter "i" that last
//rank value as to not repeat comparing already sorted and ranked values
i=h;
}
}
}else {
sortedRank[i-1] = i;
rankedFlow[i-1] = mQnFlows[i-1];
recurenceInterval[i-1] = (totalSamples + 1)/(sortedRank[i-1]);
}
}
//Find the "n" recurrence interval and return its corresponding flow as the mQnFlow
double target = (double) n;
for(i=0; i < (recurenceInterval.length - 1); i++){
if(n < recurenceInterval[i] && n > recurenceInterval[i+1]){
//Linear interpolation for flow value for "n" recurrence interval
mQnFlow = ((target-recurenceInterval[i+1])/(recurenceInterval[i]-recurenceInterval[i+1]))*(rankedFlow[i] - rankedFlow[i+1]) + rankedFlow[i+1];
}else if(n == recurenceInterval[i]){
mQnFlow = rankedFlow[i];
}
}
String message = "";
if(mQnFlow == 0){
message = "There is no " + m + " consecutive day flow recorded so there was no " + m + "Q" + n + " flow value calculated.";
}
returnValue[0] = message;
returnValue[1] = String.valueOf(mQnFlow);
return returnValue;
}
}