StandardStepMethod.java [src/java/m/hydraulics/standardstep] Revision: 4fc13d47e981f11a30d3ae7c1afae3532c21bb12 Date: Fri Feb 05 10:16:38 MST 2016
package m.hydraulics.standardstep;
import hydraulics.ChannelGeometry;
import hydraulics.GeneralFunctions;
import java.awt.Color;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.IOException;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* Last Updated: 5-February-2016
* @author Chris Dumler
* @since 22-June-2015
*/
public class StandardStepMethod {
//Inputs
String mainFolder = "U:/Java Projects/StandardStepMethod/RegularGeometryTest";
boolean irregularGeometry = false;
boolean downstreamCalculation = true;
boolean useThalwegElevation = true;
boolean createGraph = true;
boolean createSummaryFile = true;
double measuredDownstreamDepth = 6.369;
double discharge_DS = 200;
//Uniform Geometry Cross-Section Characteristics
double bottomWidth = 10;
double sideSlope = 2;
//Uniform Geometry Reach Characteristics
double manning_n = .035;
double bedSlope = 0.0004;
double seepage = 0.0;
double channelLength = 40000; //Distance between sample x-sections
int numberOfCrossSections = 200; //Length between calculated x-section
//Sets
public void setBottomWidth(double bottomWidth){
this.bottomWidth = bottomWidth;
}
public void setSideSlope(double sideSlope){
this.sideSlope = sideSlope;
}
public void setDepth_DS(double measuredDownstreamDepth){
this.measuredDownstreamDepth = measuredDownstreamDepth;
}
public void setDischarge_DS(double discharge_DS){
this.discharge_DS = discharge_DS;
}
public void setManningRoughness(double manning_n){
this.manning_n = manning_n;
}
public void setBedSlope(double bedSlope){
this.bedSlope = bedSlope;
}
public void setSeepage(double seepage){
this.seepage = seepage;
}
public void setChannelLength(double channelLength){
this.channelLength = channelLength;
}
public void setNumberOfCrossSections(int numberOfCrossSections){
this.numberOfCrossSections = numberOfCrossSections;
}
public void setMainFolder(String mainFolder){
this.mainFolder = mainFolder;
}
public void setIrregularGeometry(boolean irregularGeometry){
this.irregularGeometry = irregularGeometry;
}
public void setDownstreamCalculation(boolean downstreamCalculation){
this.downstreamCalculation = downstreamCalculation;
}
public void setUseThalwegElevation(boolean useThalwegElevation){
this.useThalwegElevation = useThalwegElevation;
}
public void setCreateGraph(boolean createGraph){
this.createSummaryFile = createGraph;
}
public void setCreateSummaryFile(boolean createSummaryFile){
this.createGraph = createSummaryFile;
}
//gets
public String getElevationGraphTitle(){
if (downstreamCalculation){
return "Downstream Elevation Profile";
}
else{
return "Upstream Elevation Profile";
}
}
public String getElevationGraph(){
if (downstreamCalculation){
String title = "_" + measuredDownstreamDepth + "m_StartDepth_DownstreamElevationProfile.jpg";
return title;
}
else{
String title = "_" + measuredDownstreamDepth + "m_StartDepth_UpstreamElevationProfile.jpg";
return title;
}
}
public File getElevationGraphOutput(){
if (downstreamCalculation){
String title = "_" + measuredDownstreamDepth + "m_StartDepth_DownstreamElevationProfile.out";
return new File(mainFolder, title);
}
else{
String title = "_" + measuredDownstreamDepth + "m_StartDepth_UpstreamElevationProfile.out";
return new File(mainFolder, title);
}
}
public String getSummaryTitle(){
if (downstreamCalculation){
return " Downstream Summary Data";
}
else{
return " Upstream Summary Data";
}
}
public String getSummary(){
if (downstreamCalculation){
String title = "_" + measuredDownstreamDepth + "m_StartDepth_DownstreamData.txt";
return title;
}
else{
String title = "_" + measuredDownstreamDepth + "m_StartDepth_UpstreamData.txt";
return title;
}
}
/**
* Calculates the water depth at each subsequent cross section using the
* Standard Step Equation.
* For irregular channel geometries, uses xy-point cross sections and channel
* reach characteristics provided by text files in destination folder.
* Cross-sections must be formatted as below:
* (0|100)(20|100)(30|95)(40|90)(50|90)(60|95)(70|100)(90|100)
* (0|100)(20|99.96)(35|94.96)(50|89.96)(65|89.96)(80|94.96)(95|99.96)(115|100)
* Note: Each pair of numbers within a set of parentheses represents an xy-point
* along the cross section. The y-point can be used to determine elevation and
* bed slope.
* Reach data must be formatted as below:
* 100|.035|.05|0
* Note: The first number is the reach length, the second is manning's n, the
* third is the seepage, and the forth is the reach slope. This is optional as it
* can also be determined using the thalweg elevation from the given cross-sections.
* For uniform-trapezoidal channels, the channel variables can be set using the
* appropriate 'set' methods and the graphs and summary file will be created in
* the designated folder.
*
* Returns a graph of the longitudinal depth and elevation profiles as well as a text
* file containing all the important information for each cross-section and reach. For irregular channels, the graphs
* and summary file are created in the same folder that contains the 'reaches' and 'crossSections'
* text files. For uniform channels, the graphs and summary file are created in the designated folder.
*
* @throws IOException
*
*/
public void run() throws IOException {
int numberOfReaches;
if (irregularGeometry) {
numberOfReaches = readLines(mainFolder + File.separator + "reaches.txt");
}
else{
numberOfReaches = numberOfCrossSections-1;
}
double[][][] crossSectionResultsArray = new double[numberOfReaches + 1][2][4];
double[][] reachResultsArray = new double[numberOfReaches + 1][2];
double [][][] crossSectionGeometries;
double [][] reachProperties;
if (irregularGeometry) {
crossSectionGeometries = setCrossSectionGeometries();
reachProperties = setReachProperties();
}
else{
crossSectionGeometries = new double[numberOfReaches+1][1][1];
reachProperties = new double[numberOfReaches+1][1];
}
double downstreamDistance = 0;
double bedElevation = 0;
double depth_DS = measuredDownstreamDepth;
for (int currentReach = 0; currentReach < numberOfReaches; currentReach++) {
double[][] currentCrossSectionGeometry_DS = crossSectionGeometries[currentReach];
double[][] currentCrossSectionGeometry_US = crossSectionGeometries[currentReach+1];
double[] currentReachProperties = reachProperties[currentReach];
double length;
double reachSlope;
double currentReachSeepage;
if (irregularGeometry) {
length = currentReachProperties[0];
currentReachSeepage = currentReachProperties[2];
if(useThalwegElevation){
reachSlope = calcThalwegElevationSlope(currentReach);
}
else{
reachSlope = currentReachProperties[3];
}
} else {
length = channelLength/numberOfReaches;
currentReachSeepage = seepage;
reachSlope = bedSlope;
}
if (downstreamCalculation == false){
length = -length;
}
ChannelGeometry DSValues = setDSValues(currentCrossSectionGeometry_DS,
currentReachProperties,
reachSlope,
depth_DS);
double velocity_DS = calcVelocity(DSValues);
double frictionSlope_DS = calcFrictionSlope(DSValues);
double critDepth_DS = DSValues.calcCriticalDepth();
double normDepth_DS = DSValues.calcNormalDepth();
ChannelGeometry USValues = setUSValues(currentCrossSectionGeometry_US,
currentReachProperties,
length,
reachSlope,
depth_DS);
double critDepth_US = USValues.calcCriticalDepth();
double normDepth_US = USValues.calcNormalDepth();
double[] bounds = calcBoundaryConditions(depth_DS, critDepth_US, normDepth_US);
double lower = bounds[0];
double upper = bounds[1];
USValues = setUSValues(currentCrossSectionGeometry_US,
currentReachProperties,
length,
reachSlope,
lower);
double velocity_US = calcVelocity(USValues);
double frictionSlope_US = calcFrictionSlope(USValues);
double err_lower = standardStepEquation(velocity_DS,
velocity_US,
frictionSlope_DS,
frictionSlope_US,
depth_DS,
lower,
reachSlope,
length);
USValues = setUSValues(currentCrossSectionGeometry_US,
currentReachProperties,
length,
reachSlope,
upper);
velocity_US = calcVelocity(USValues);
frictionSlope_US = calcFrictionSlope(USValues);
double err_upper = standardStepEquation(velocity_DS,
velocity_US,
frictionSlope_DS,
frictionSlope_US,
depth_DS,
upper,
reachSlope,
length);
double error = 1000;
double guessDepth_US = (lower + upper) / 2;
int ctr = 0;
if (err_lower > 0 && err_upper < 0) {
while (Math.abs(error) > .0001 && ctr < 100) {
guessDepth_US = (lower + upper) / 2;
USValues = setUSValues(currentCrossSectionGeometry_US,
currentReachProperties,
length,
reachSlope,
guessDepth_US);
velocity_US = calcVelocity(USValues);
frictionSlope_US = calcFrictionSlope(USValues);
error = standardStepEquation(velocity_DS, velocity_US,
frictionSlope_DS, frictionSlope_US,
depth_DS, guessDepth_US,
reachSlope,
length);
if (error <= 0) {
upper = guessDepth_US;
} else {
lower = guessDepth_US;
}
ctr = ctr + 1;
}
}
else if (err_lower < 0 && err_upper > 0) {
while (Math.abs(error) > .0001 && ctr < 100) {
guessDepth_US = (lower + upper) / 2;
USValues = setUSValues(currentCrossSectionGeometry_US,
currentReachProperties,
length,
reachSlope,
guessDepth_US);
velocity_US = calcVelocity(USValues);
frictionSlope_US = calcFrictionSlope(USValues);
error = standardStepEquation(velocity_DS, velocity_US,
frictionSlope_DS, frictionSlope_US,
depth_DS, guessDepth_US,
reachSlope,
length);
if (error >= 0) {
upper = guessDepth_US;
} else {
lower = guessDepth_US;
}
ctr = ctr + 1;
}
}
else {
guessDepth_US = (lower + upper) / 2;
System.out.println("Could not solve standard step equation " + downstreamDistance + " m downstream." );
}
if (currentReach == 0) {
crossSectionResultsArray[currentReach] = writeCrossSectionResultsArray(depth_DS,
critDepth_DS,
normDepth_DS,
downstreamDistance,
bedElevation,
discharge_DS);
downstreamDistance = downstreamDistance + length;
bedElevation = bedElevation - (reachSlope * length);
discharge_DS = discharge_DS + (currentReachSeepage*length);
crossSectionResultsArray[currentReach + 1] = writeCrossSectionResultsArray(guessDepth_US,
critDepth_US,
normDepth_US,
downstreamDistance,
bedElevation,
discharge_DS);
reachResultsArray[currentReach] = writeReachResultsArray(length,
reachSlope);
}
else {
downstreamDistance = downstreamDistance + length;
bedElevation = bedElevation - (reachSlope * length);
discharge_DS = discharge_DS + (currentReachSeepage*length);
crossSectionResultsArray[currentReach + 1] = writeCrossSectionResultsArray(guessDepth_US,
critDepth_US,
normDepth_US,
downstreamDistance,
bedElevation,
discharge_DS);
reachResultsArray[currentReach] = writeReachResultsArray(length,
reachSlope);
}
depth_DS = guessDepth_US;
} //end for statement
if (createGraph){
graphLongitudinalProfile(crossSectionResultsArray,
numberOfReaches,
getElevationGraphTitle(),
getElevationGraph(),
"Water Surface Elevation",
"Critical Depth",
"Normal Depth",
"Channel Bed Elevation",
"Elevation (m)");
}
if (createSummaryFile){
writeSummaryFile(crossSectionResultsArray,
reachResultsArray);
}
}//end calcStandardStepMethod
/**
* Calculates the max and min water elevations to plug into the Standard Step
* Equation based on the water surface profile.
*
* @param depth_DS The depth at the downstream cross-section.
* @param criticalDepth The critical depth at the upstream cross-section.
* @param normalDepth The normal depth at the upstream cross-section.
*
* @return An array containing the minimum(a) and maximum(b) water depths.
*
* @throws IOException
*/
public double[] calcBoundaryConditions(double depth_DS,
double criticalDepth,
double normalDepth) throws IOException {
String waterSurfaceProfile;
double a = .01;
double b = 999;
if (normalDepth > criticalDepth && normalDepth < 900) { //test if slope is mild
if (depth_DS < criticalDepth) {
waterSurfaceProfile = "M3";
a = 0.01;
b = criticalDepth;
} else if (depth_DS > normalDepth) {
waterSurfaceProfile = "M1";
a = normalDepth;
b = (2.0 * depth_DS);
} else {
waterSurfaceProfile = "M2";
a = criticalDepth;
b = normalDepth;
}
} else if (normalDepth < criticalDepth) {//test if slope is steep
if (depth_DS < normalDepth) {
waterSurfaceProfile = "S3";
a = .01;
b = normalDepth;
} else if (depth_DS > criticalDepth) {
waterSurfaceProfile = "S1";
a = criticalDepth;
b = (2.0 * depth_DS);
} else {
waterSurfaceProfile = "S2";
a = normalDepth;
b = criticalDepth;
}
} else if (Math.abs(normalDepth - criticalDepth) < .001) {//test if slope is critical
if (depth_DS < criticalDepth) {
waterSurfaceProfile = "C3";
a = .01;
b = criticalDepth;
} else {
waterSurfaceProfile = "C1";
a = criticalDepth;
b = (2.0 * depth_DS);
}
} else if (normalDepth > 100 * depth_DS) { //test if slope is horizontal
if (depth_DS < criticalDepth) {
waterSurfaceProfile = "H3";
a = .01;
b = criticalDepth;
} else {
waterSurfaceProfile = "H2";
a = criticalDepth;
b = normalDepth;
}
} else {
waterSurfaceProfile = "undefined";
} //end if
double[] boundaries = new double[2];
boundaries[0] = a;
boundaries[1] = b;
return boundaries;
}//end calcBoundaryConditions
/**
* Creates a 2-dimensional array containing the calculated depth values for the current
* cross-section. This array is then imported into a 3-dimensional array containing the
* depth values for every cross-section in a given channel.
*
* @param waterDepth The calculated depth at the current cross-section.
* @param critDepth The calculated critical depth at the given cross-section.
* @param normDepth The calculated normal depth at the given cross-section.
* @param distance_DS The distance of the given cross-section from the origin.
* @param bedElevation The elevation of the channel bed above or below the origin.
*
* @return A 2-dimensional array containing the calculated depth values for
* the current cross-section.
*/
public double[][] writeCrossSectionResultsArray(double waterDepth,
double critDepth,
double normDepth,
double distance_DS,
double bedElevation,
double discharge){
double[][] results = new double[2][4];
results[0][0] = distance_DS;
results[0][1] = discharge;
results[1][0] = waterDepth;
results[1][1] = critDepth;
results[1][2] = normDepth;
results[1][3] = bedElevation;
return results;
}//end writeDepthArray
public double[] writeReachResultsArray(double length,
double slope){
double[] results = new double[2];
results[0] = length;
results[1] = slope;
return results;
}
/**
* Determines the number of lines in a given text file (including blank lines).
*
* @param file_path The location of the 'crossSections' or 'reaches' text file.
*
* @return The number of lines in the text file.
*
* @throws IOException
*/
public int readLines(String file_path) throws IOException {
int numberOfLines = 0;
try{
String aLine;
FileReader fr = new FileReader(file_path);
BufferedReader bf = new BufferedReader(fr);
while ((aLine = bf.readLine()) != null) {
numberOfLines++;
}
bf.close();
}
catch(IOException e){
System.out.println(e.getMessage());
}
return numberOfLines;
}//end readLines
/**
* Transfers a text file to a one 1-dimensional array. Each line of the text file
* is written to its corresponding array location.
*
* @param file_path The location of the 'crossSections' or 'reaches' text file.
*
* @return A 1-dimensional array containing every line in a given text file.
*
* @throws IOException
*/
public String[] transferTXTFile(String file_path) throws IOException {
String[] crossSections = new String[0];
try{
FileReader fr = new FileReader(file_path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines(file_path);
crossSections = new String[numberOfLines];
int i;
for (i = 0; i < numberOfLines; i++) {
crossSections[i] = textReader.readLine();
}
textReader.close();
}
catch(IOException e){
System.out.println(e.getMessage());
}
return crossSections;
}//end transferTXTFile
/**
* Determines the largest number of xy-points in any one of the provided cross-sections.
* This value is used to create the cross-sections array.
*
* @return The largest number of points in any of the given cross-sections.
*
* @throws IOException
*/
public int calcLargestCrossSection() throws IOException {
String[] sections = transferTXTFile(mainFolder + File.separator + "crossSections.txt");
int numberOfLines = readLines(mainFolder + File.separator + "crossSections.txt");
int i;
int n;
int m = 0;
for (i = 0; i < numberOfLines; i++) {
String[] xypoints = sections[i].split("\\(");
n = xypoints.length;
if (n > m) {
m = n;
}
}
m = m - 1;
return m;
}//end calcLargestCrossSection
/**
* Splits the xy-point strings to creates a 3-dimensional array containing
* all the x and y points for each cross-section in a given channel.
*
* @return A 3-dimensional array containing all x and y points for every given cross-section
* along the channel length.
*
* @throws IOException
*/
public double[][][] setCrossSectionGeometries() throws IOException {
int numberOfSections = readLines(mainFolder + File.separator + "crossSections.txt");
String[] sections = transferTXTFile(mainFolder + File.separator + "crossSections.txt");
int length = calcLargestCrossSection();
String[][] xypointlist;
int i;
double[][][] dimensionalArray = new double[numberOfSections][2][length];
for (i = 0; i < numberOfSections; i++) {
String crossSection = sections[i];
String newCrossSection = crossSection.replaceAll("\\)", "");
String[] xypoints = newCrossSection.split("\\(");
double[][] xyPoints_new = new double[length][2];
int j;
for (j = 1; j < xypoints.length; j++) {
String[] xy = xypoints[j].split("\\|");
xyPoints_new[j - 1][0] = Double.parseDouble(xy[0]);
xyPoints_new[j - 1][1] = Double.parseDouble(xy[1]);
}
dimensionalArray[i] = xyPoints_new;
}
return dimensionalArray;
}//end setCrossSectionGeometries
/**
* Splits the reach property strings to creates a 2-dimensional array containing
* all the reach properties for every reach along the channel length.
*
* @return A 2-dimensional array containing all the reach properties for every
* reach along the channel length.
*
* @throws IOException
*/
public double[][] setReachProperties() throws IOException {
int numberOfSections = readLines(mainFolder + File.separator + "reaches.txt");
String[] reaches = transferTXTFile(mainFolder + File.separator + "reaches.txt");
double[][] reachProperties = new double[numberOfSections][4];
int i;
for (i = 0; i < numberOfSections; i++) {
String reach = reaches[i];
String[] new_reach = reach.split("\\|");
if(useThalwegElevation){
for (int j = 0; j < 3; j++) {
reachProperties[i][j] = Double.parseDouble(new_reach[j]);
}
}
else{
for (int j = 0; j < 4; j++) {
reachProperties[i][j] = Double.parseDouble(new_reach[j]);
}
}
}
return reachProperties;
}//end setReachProperties
/**
* Calculates the velocity at the current cross-section using the calculated area
* and discharge.
*
* @param values The ChannelGeometry object containing the correct values for current
* cross-section. Created by the 'setUSValues' and 'setDSValues' methods.
*
* @return The water velocity at the current cross-section.
*/
public double calcVelocity(ChannelGeometry values) { //Need to move to ChannelGeomety Class?
if (irregularGeometry) {
double area = values.calcIrregularArea();
double velocity = values.discharge / area;
return velocity;
} else {
double area = values.calcTrapezoidalArea();
double velocity = values.discharge / area;
return velocity;
}
}//end calcVelocity
/**
* Calculates the friction slope at the current cross-section using the calculated area,
* hydraulic radius, manning's n, and discharge.
*
* @param values The ChannelGeometry object containing the correct values for current
* cross-section. Created by the 'setUSValues' and 'setDSValues' methods.
*
* @return The water friction slope at the current cross-section.
*/
public double calcFrictionSlope(ChannelGeometry values) {
if (irregularGeometry) {
double area = values.calcIrregularArea();
double hydrRadius = values.calcIrregularHydraulicRadius();
double frictionSlope = Math.pow(((values.n * values.discharge)
/ (area * Math.pow(hydrRadius, 2. / 3.))), 2.);
return frictionSlope;
} else {
double area = values.calcTrapezoidalArea();
double hydrRadius = values.calcTrapezoidalHydraulicRadius();
double frictionSlope = Math.pow(((values.n * values.discharge)
/ (area * Math.pow(hydrRadius, 2. / 3.))), 2.);
return frictionSlope;
}
}//end calcFrictionSlope
/**
* Calculates the Thalweg Elevation of the current cross-section using the
* elevation data from the xy-point cross-section geometries. Then uses the
* thalweg elevation from the up and downstream cross-sections to determine the
* average slope between the two cross-sections.
*
* @param currentReach The reach being calculated by the current iteration of the
* Standard Step Method.
*
* @return The reach slope based on the thalweg elevations of the up and downstream
* cross-sections.
*
* @throws IOException
*/
public double calcThalwegElevationSlope(int currentReach)throws IOException {
GeneralFunctions general = new GeneralFunctions();
double[][][] geometries = setCrossSectionGeometries();
double[][] properties = setReachProperties();
double[][] crossSection1 = geometries[currentReach];
double thalwegElevation1 = general.min(general.getColumn(crossSection1, 1));
double[][] crossSection2 = geometries[currentReach + 1];
double thalwegElevation2 = general.min(general.getColumn(crossSection2, 1));
double currentReachLength = properties[currentReach][0];
double slope = (thalwegElevation2 - thalwegElevation1)/currentReachLength;
return slope;
}//end calcThalwegElevation
/**
* Creates a new ChannelGeometry object and sets the ChannelGeometry variables
* to the values of the cross-section downstream of the current reach.
*
* @param currentCrossSectionGeometry_DS An array containing the xy-points for the
* downstream cross-section.
* @param currentReachProperties An array containing the properties of the current reach.
* @param bedSlope
* @param depth The calculated depth of the downstream cross-section.
*
* @return A new ChannelGeometry object with the values set for the downstream cross-section.
*
* @throws IOException
*/
public ChannelGeometry setDSValues(double[][] currentCrossSectionGeometry_DS,
double[] currentReachProperties,
double bedSlope,
double depth) throws IOException {
ChannelGeometry DSValues = new ChannelGeometry();
DSValues.setGeometryType(irregularGeometry);
if (irregularGeometry) {
DSValues.setXYPoints(currentCrossSectionGeometry_DS);
DSValues.setDepth(depth);
DSValues.setDischarge(discharge_DS);
DSValues.setManningRoughness(currentReachProperties[1]);
DSValues.setBedSlope(bedSlope);
} else {
DSValues.setBottomWidth(bottomWidth);
DSValues.setSideSlope(sideSlope);
DSValues.setDepth(depth);
DSValues.setDischarge(discharge_DS);
DSValues.setManningRoughness(manning_n);
DSValues.setBedSlope(bedSlope);
}
return DSValues;
}//end setDSValues
/**
* Creates a new ChannelGeometry object and sets the ChannelGeometry variables
* to the values of the cross-section upstream of the current reach.
*
* @param currentCrossSectionGeometry_US An array containing the xy-points for the
* upstream cross-section.
* @param currentReachProperties An array containing the properties of the current reach.
* @param currentReachLength The distance between the up and downstream cross-sections.
* @param bedSlope
* @param depth The calculated depth of the upstream cross-section.
*
* @return A new ChannelGeometry object with the values set for the upstream cross-section.
*
* @throws IOException
*/
public ChannelGeometry setUSValues(double[][] currentCrossSectionGeometry_US,
double[] currentReachProperties,
double currentReachLength,
double bedSlope,
double depth) throws IOException {
ChannelGeometry USValues = new ChannelGeometry();
USValues.setGeometryType(irregularGeometry);
if (irregularGeometry) {
USValues.setXYPoints(currentCrossSectionGeometry_US);
USValues.setDepth(depth);
double currentReachSeepage = currentReachProperties[2];
USValues.setDischarge(discharge_DS+(currentReachSeepage*currentReachLength));
USValues.setManningRoughness(currentReachProperties[1]);
USValues.setBedSlope(bedSlope);
} else {
USValues.setBottomWidth(bottomWidth);
USValues.setSideSlope(sideSlope);
USValues.setDepth(depth);
USValues.setDischarge(discharge_DS+(seepage*currentReachLength));
USValues.setManningRoughness(manning_n);
USValues.setBedSlope(bedSlope);
}
return USValues;
}//end setUSValues
/**
* Calculates the standard step equation using the predetermined values for the downstream
* cross-section and guess values for the upstream cross-section based on the set boundaries.
*
* @param velocity_DS The calculated velocity at the downstream cross-section.
* @param velocity_US The calculated velocity at the upstream cross-section.
* @param frictionSlope_DS The calculated friction slope at the downstream cross-section.
* @param frictionSlope_US The calculated friction slope at the upstream cross-section.
* @param measuredDownstreamDepth The calculated depth at the downstream cross-section.
* @param depth_US The calculated depth at the upstream cross-section.
* @param bedSlope The bed slope between the up and downstream cross-sections.
* @param length The distance between the up and downstream cross sections.
*
* @return An error value based on the guessed upstream depth value. The closer the error is to zero,
* the closer the guess depth is to the actual depth.
*
* @throws IOException
*/
private double standardStepEquation(double velocity_DS,
double velocity_US,
double frictionSlope_DS,
double frictionSlope_US,
double measuredDownstreamDepth,
double depth_US,
double bedSlope,
double length) throws IOException {
double error = (((depth_US + (Math.pow(velocity_US, 2.) / (2 * 9.81)))
- (measuredDownstreamDepth + (Math.pow(velocity_DS, 2.) / (2. * 9.81))))
/ (((frictionSlope_US + frictionSlope_DS) / 2) - (bedSlope)))
+ length;
return error;
}//end standardStepEquation
/**
* Creates a graph of the longitudinal depth and elevation profiles of the given
* channel reach and saves them to the designated folder as jpeg's.
*
* @param resultsArray A 3-dimensional array containing the results of the
* Standard Step Method calculations.
* @param numberOfReaches The total number of reaches calculated.
* @param graphTitle The title of the graph.
* @param graphOutputName The file name under which the graph jpeg will be saved.
* @param series1_name The name of the depth or elevation series.
* @param series2_name The name of the critical depth series.
* @param series3_name The name of the normal depth series.
* @param series4_name The name of the bed elevation series.
* @param yAxis_name The name of the y-axis.
*
* @throws IOException
*/
public void graphLongitudinalProfile(double[][][] resultsArray,
int numberOfReaches,
String graphTitle,
String graphOutputName,
String series1_name,
String series2_name,
String series3_name,
String series4_name,
String yAxis_name) throws IOException {
GeneralFunctions general = new GeneralFunctions();
//Graph data
XYSeries series1 = new XYSeries(series1_name);
for (int i = 0; i < numberOfReaches + 1; i++) {
series1.add(resultsArray[i][0][0], resultsArray[i][1][0]+resultsArray[i][1][3]);
}
XYSeries series2 = new XYSeries(series2_name);
for (int i = 0; i < numberOfReaches + 1; i++) {
series2.add(resultsArray[i][0][0], resultsArray[i][1][1]+resultsArray[i][1][3]);
}
XYSeries series3 = new XYSeries(series3_name);
for (int i = 0; i < numberOfReaches + 1; i++) {
series3.add(resultsArray[i][0][0], resultsArray[i][1][2]+resultsArray[i][1][3]);
}
XYSeries series4 = new XYSeries(series4_name);
for (int i = 0; i < numberOfReaches + 1; i++) {
series4.add(resultsArray[i][0][0], resultsArray[i][1][3]);
}
XYPlot plot = new XYPlot();
XYDataset dataset1 = new XYSeriesCollection(series1);
XYItemRenderer currentRenderer = new XYLineAndShapeRenderer(true, false);
currentRenderer.setSeriesPaint(0, Color.blue);
plot.setDataset(2, dataset1);
plot.setRenderer(2, currentRenderer);
XYDataset dataset2 = new XYSeriesCollection(series2);
XYItemRenderer currentRenderer2 = new XYLineAndShapeRenderer(true, false);
currentRenderer2.setSeriesPaint(0, Color.red);
plot.setDataset(1, dataset2);
plot.setRenderer(1, currentRenderer2);
XYDataset dataset3 = new XYSeriesCollection(series3);
XYItemRenderer currentRenderer3 = new XYLineAndShapeRenderer(true, false);
currentRenderer3.setSeriesPaint(0, Color.green);
plot.setDataset(0, dataset3);
plot.setRenderer(0, currentRenderer3);
XYDataset dataset4 = new XYSeriesCollection(series4);
XYItemRenderer currentRenderer4 = new XYLineAndShapeRenderer(true, false);
currentRenderer4.setSeriesPaint(0, Color.black);
plot.setDataset(3, dataset4);
plot.setRenderer(3, currentRenderer4);
//Create the X Axis
ValueAxis xAxis = new NumberAxis("Downstream Distance (m)");
plot.setDomainAxis(0, xAxis);
//Create the Y Axis
ValueAxis yAxis = new NumberAxis(yAxis_name);
plot.setRangeAxis(0, yAxis);
//Set extra plot preferences
general.setAxisPreferences(plot);
//Create the chart with the plot
JFreeChart chart = new JFreeChart(graphTitle, general.titleFont, plot, true);
//Set legend Font
LegendTitle legendTitle = chart.getLegend();
legendTitle.setItemFont(general.masterFont);
try {
String path = mainFolder + File.separator + graphOutputName;
ChartUtilities.saveChartAsJPEG(new File(path), chart, 1280, 800);
System.out.println(path);
} catch (IOException e) {
System.err.println("A problem occurred while trying to create the chart.");
}
}//end graphLongitudinalProfile
/**
* Writes out the formatted output file as expected by eRAMS to be used for a JHighchart XY
* @param crossSectionResultsArray
* @param reachResultsArray
* @throws IOException
*/
public void writeSummaryFile(double[][][] crossSectionResultsArray,
double reachResultsArray[][]) throws IOException {
//open the file writer and set path
String summaryOutputName = getSummary();
String path = mainFolder + File.separator + summaryOutputName;
FileWriter writer = new FileWriter(path, false);
PrintWriter print_line = new PrintWriter(writer);
//Print the needed values
String summaryTitle = getSummaryTitle();
print_line.printf("%s" + "\r\n", summaryTitle);
print_line.printf("%s" + "\r\n", "");
for(int i=0; i<crossSectionResultsArray.length; i++){
print_line.printf("%-35s" + "\r\n", "");
print_line.printf("%s" + "%.3f" + "%s" + "\r\n", "Cross Section " + i + ": ",crossSectionResultsArray[i][0][0]," m downstream");
print_line.printf("%-35s" + "%15.6f" + "%s" + "\r\n"," Depth: ", crossSectionResultsArray[i][1][0]," m");
print_line.printf("%-35s" + "%15.6f" + "%s" + "\r\n"," Discharge: ", crossSectionResultsArray[i][0][1]," m^3/s");
print_line.printf("%-35s" + "%15.6f" + "%s" + "\r\n"," Critical Depth: ", crossSectionResultsArray[i][1][1]," m");
print_line.printf("%-35s" + "%15.6f" + "%s" + "\r\n"," Normal Depth: ", crossSectionResultsArray[i][1][2]," m");
print_line.printf("%-35s" + "%15.6f" + "%s" + "\r\n"," Bed Elevation (Above Origin): ", crossSectionResultsArray[i][1][3]," m");
print_line.printf("%-35s" + "%15.6f" + "%s" + "\r\n"," Water Surface Elevation: ", crossSectionResultsArray[i][1][2]
+crossSectionResultsArray[i][1][0]," m");
print_line.printf("%-35s" + "\r\n", "");
print_line.printf("%-35s" + "\r\n","Reach " + (i+1));
print_line.printf("%-35s" + "%15.6f" +"%s" + "\r\n"," Length: ", reachResultsArray[i][0]," m");
print_line.printf("%-35s" + "%15.6f" +"%s" + "\r\n"," Slope: ", reachResultsArray[i][1]," m/m");
}
// Close the file writer
print_line.close();
writer.close();
System.out.println("Text File located at:\t" + path);
}//end writeSummaryFile
/**
* Created new Standard Step Model object and starts 'run' method.
*
* @param args
*
* @throws IOException
*/
public static void main(String[] args) throws IOException {
StandardStepMethod model = new StandardStepMethod();
model.run();
}//end main
}//end StandardStepMeth