StandardStepMethod.java [src/java/hydraulics] Revision: b1a7e551b0536e3210dc7b1b7211cca8080fd9f2  Date: Tue Aug 04 11:33:25 MDT 2015
package hydraulics;

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;

public class StandardStepMethod {
    
    boolean irregularGeometry =false;

    //Downstream x-section characteristics
    double bottomWidth = 10;
    double sideSlope = 2;
    double measuredDownstreamDepth = 7;
    double discharge_DS = 200;

    //Reach Characteristics
    double manning_n = .035;
    double bedSlope = 0.0004;
    double seepage = 0;
    boolean downstream = true; //Designates whether the water surface profile
    //is being calculated up or downstream from the original sample location
    //(designated x-section 0). True if downstream/False if upstream.
    double channelLength = 20000; //Distance between sample x-sections
    double reachLength = 100; //Length between calculated x-section
    
    String subFolder = "Test2";
    //String subFolder = "ChinExample4_11";
    String mainFolder = "C:/Users/Chris/My Documents/StandardStepMethod" + File.separator + subFolder ;
    
    //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 setReachLength(double reachLength){
        this.reachLength = reachLength;
    }
    
    public void setMainFolder(String mainFolder){
        this.mainFolder = mainFolder;
    }
    
    public void setSubFolder(String subFolder){
        this.subFolder = subFolder;
    }
    
    public void setStreamDirection(boolean downstream){
        this.downstream = downstream;
    }
    
    //gets
    public String getElevationGraphTitle(){
        return "Longitudinal Elevation Profile";
    }
    
    public String getDepthGraphTitle(){
        return "Longitudinal Depth Profile";
    }
    
    public String getElevationGraphOutputName(){
        if (downstream){
            return subFolder + " Downstream Longitudinal Elevation Profile.png";
        }
        else{
            return subFolder + " Upstream Longitudinal Elevation Profile.png";
        }
    }
    
    public String getDepthGraphOutputName(){
        if (downstream){
            return subFolder + " Downstream Longitudinal Depth Profile.png";
        }
        else{
            return subFolder + " Upstream Longitudinal Depth Profile.png";
        }
    }
    
    public String getSummaryTitle(){
        if (downstream){
            return subFolder + " Downstream Summary Data.txt";
        }
        else{
            return subFolder + " Upstream Summary Data.txt";
        }
    }
    public String getSummaryOuputName(){
        if (downstream){
            return subFolder + " Downstream Summary Data.txt";
        }
        else{
            return subFolder + " Upstream Summary Data.txt";
        }
    }
    
    public static void main(String[] args) throws IOException {
        StandardStepMethod model = new StandardStepMethod();
        model.run();
    }

    public void run() throws IOException {

    calcStandardStepMethod();
        
    } //end of run

    public void calcStandardStepMethod() throws IOException {
        
        int numberOfReaches;

        if (irregularGeometry) {
            numberOfReaches = readLines(mainFolder + File.separator + "reaches.txt");
        } else {
            double numReach = channelLength / reachLength;
            if (numReach == Math.floor(numReach) && !Double.isInfinite(numReach)) {
                numberOfReaches = (int) numReach;
            } else {
                System.out.println("Variable reachLength must be factor of channelLength");
                numberOfReaches = 1;
            }
        }

        double[][][] elevationArray = new double[numberOfReaches + 1][2][4];
        double[][][] depthArray = new double[numberOfReaches + 1][2][4];
        
        double downstreamDistance = 0;
        double bedElevation = 0;
        double depth_DS = measuredDownstreamDepth;
        for (int currentReach = 0; currentReach < numberOfReaches; currentReach++) {
            
            double length;
            if (irregularGeometry) {
                double[][] reachProperties = setReachProperties();
                length = reachProperties[currentReach][0];
            } else {
                length = reachLength;
            }
            

            double reachSlope;
            if (irregularGeometry) {
                double[][] reachProperties = setReachProperties();
                reachSlope = reachProperties[currentReach][1];
            } else {
                reachSlope = bedSlope;
            }
            
            if (downstream == false){
                length = -length;
            }
            
            ChannelGeometry DSValues = setDSValues(currentReach,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(currentReach,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(currentReach,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(currentReach,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(currentReach,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(currentReach,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****");
            }
            
            
            
            boolean append_to_file;
            if (currentReach == 0) {
                elevationArray[currentReach] = writeElevationArray(depth_DS,
                                                                    critDepth_DS,
                                                                    normDepth_DS,
                                                                    downstreamDistance,
                                                                    bedElevation);
                depthArray[currentReach] = writeDepthArray(depth_DS,
                                                                    critDepth_DS,
                                                                    normDepth_DS,
                                                                    downstreamDistance,
                                                                    bedElevation);
                append_to_file = false;
                String summaryOutputName = getSummaryOuputName();
                String summaryTitle = getSummaryTitle();
                
                writeToFile(summaryTitle,append_to_file,summaryOutputName);
                append_to_file = true;
                writeToFile("",append_to_file,summaryOutputName);
                writeToFile("Cross Section " + currentReach + ": " + downstreamDistance + " m downstream",append_to_file,summaryOutputName);
                writeToFile("   Depth: " + depth_DS,append_to_file,summaryOutputName);
                writeToFile("   Critical Depth: " + critDepth_DS,append_to_file,summaryOutputName);
                writeToFile("   Normal Depth: " + normDepth_DS,append_to_file,summaryOutputName);
                writeToFile("   Bed Elevation: " + bedElevation,append_to_file,summaryOutputName);
                writeToFile("   Water Surface Elevation: " + (depth_DS + bedElevation),append_to_file,summaryOutputName);
                writeToFile("",append_to_file,summaryOutputName);
                
                
                downstreamDistance = downstreamDistance + length;
                bedElevation = bedElevation - (reachSlope * length);
                
                
                elevationArray[currentReach + 1] = writeElevationArray(guessDepth_US,
                                                                            critDepth_US,
                                                                            normDepth_US,
                                                                            downstreamDistance,
                                                                            bedElevation);
                depthArray[currentReach + 1] = writeDepthArray(guessDepth_US,
                                                                    critDepth_US,
                                                                    normDepth_US,
                                                                    downstreamDistance,
                                                                    bedElevation);
                
                writeToFile("Cross Section " + (currentReach + 1) + ": " + downstreamDistance + " m downstream",append_to_file,summaryOutputName);
                writeToFile("   Depth: " + guessDepth_US,append_to_file,summaryOutputName);
                writeToFile("   Critical Depth: " + critDepth_US,append_to_file,summaryOutputName);
                writeToFile("   Normal Depth: " + normDepth_US,append_to_file,summaryOutputName);
                writeToFile("   Bed Elevation: " + bedElevation,append_to_file,summaryOutputName);
                writeToFile("   Water Surface Elevation: " + (guessDepth_US + bedElevation),append_to_file,summaryOutputName);
                writeToFile("",append_to_file,summaryOutputName);
                
            } else {
                downstreamDistance = downstreamDistance + length;
                
                
                bedElevation = bedElevation - (reachSlope * length);
                
                 
                elevationArray[currentReach + 1] = writeElevationArray(guessDepth_US,
                                                                        critDepth_US,
                                                                        normDepth_US,
                                                                        downstreamDistance,
                                                                        bedElevation);
                depthArray[currentReach + 1] = writeDepthArray(guessDepth_US,
                                                                        critDepth_US,
                                                                        normDepth_US,
                                                                        downstreamDistance,
                                                                        bedElevation);
                append_to_file = true;
                String summaryOutputName = getSummaryOuputName();
                writeToFile("Cross Section " + (currentReach + 1) + ": " + downstreamDistance + " m downstream",append_to_file,summaryOutputName);
                writeToFile("   Depth: " + guessDepth_US,append_to_file,summaryOutputName);
                writeToFile("   Critical Depth: " + critDepth_US,append_to_file,summaryOutputName);
                writeToFile("   Normal Depth: " + normDepth_US,append_to_file,summaryOutputName);
                writeToFile("   Bed Elevation: " + bedElevation,append_to_file,summaryOutputName);
                writeToFile("   Water Surface Elevation: " + (guessDepth_US + bedElevation),append_to_file,summaryOutputName);
                writeToFile("",append_to_file,summaryOutputName);
                
            }
            
            depth_DS = guessDepth_US;
        } //end for statement

        graphLongitudinalProfile(elevationArray,
                numberOfReaches,
                getElevationGraphTitle(),
                getElevationGraphOutputName(),
                mainFolder,
                "Water Surface Elevation",
                "Critical Depth",
                "Normal Depth",
                "Channel Bed Elevation",
                "Elevation (m)");
        graphLongitudinalProfile(depthArray,
                numberOfReaches,
                getDepthGraphTitle(),
                getDepthGraphOutputName(),
                mainFolder,
                "Water Surface Depth",
                "Critical Depth",
                "Normal Depth",
                "Channel Bed (x-axis)",
                "Depth (m)");
        
    } //end calcStandardStepMethod
    
    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

    public double[][] writeElevationArray(double waterDepth,
                                            double critDepth,
                                            double normDepth,
                                            double distance_DS,
                                            double bedElevation) {

        double[][] results = new double[2][4];
        results[0][0] = distance_DS;
        results[1][0] = waterDepth + bedElevation;
        results[1][1] = critDepth + bedElevation;
        results[1][2] = normDepth + bedElevation;
        results[1][3] = bedElevation;

        return results;
    }
    
    public double[][] writeDepthArray(double waterDepth,
                                        double critDepth,
                                        double normDepth,
                                        double distance_DS,
                                        double bedElevation){
        
        double[][] results = new double[2][4];
        results[0][0] = distance_DS;
        results[1][0] = waterDepth;
        results[1][1] = critDepth;
        results[1][2] = normDepth;
        
        return results;
    }

    public int readLines(String file_path) throws IOException { //determine number of lines in text file to find how many cross sections there are.
        
        FileReader fr = new FileReader(file_path);
        BufferedReader bf = new BufferedReader(fr);
        String aLine;
        int numberOfLines = 0;
        while ((aLine = bf.readLine()) != null) {
            numberOfLines++;
        }
        bf.close();
        return numberOfLines;
    }

    public String[] transferTXTFile(String file_path) throws IOException { //read text file and add entries to single dimension array.
        
        FileReader fr = new FileReader(file_path);
        BufferedReader textReader = new BufferedReader(fr);

        int numberOfLines = readLines(file_path);
        String[] crossSections = new String[numberOfLines];

        int i;
        for (i = 0; i < numberOfLines; i++) {
            crossSections[i] = textReader.readLine();
        }
        textReader.close();
        return crossSections;

    }

    public int calcLargestCrossSection() throws IOException { //determine the longest cross section to determine the length of the new array.
        
        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;
    }

    public double[][][] setCrossSectionArray() 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;
    }

    public double[][] setReachProperties() throws IOException {
        
        int numberOfSections = readLines(mainFolder + File.separator + "reaches.txt");
        String[] reaches = transferTXTFile(mainFolder + File.separator + "reaches.txt");
        double[][] properties = new double[numberOfSections][4];
        int i;
        for (i = 0; i < numberOfSections; i++) {
            String reach = reaches[i];
            String[] new_reach = reach.split("\\|");
            for (int j = 0; j < 4; j++) {
                properties[i][j] = Double.parseDouble(new_reach[j]);
            }
        }
        return properties;
    }

    /*public void testEGLChange(int currentReach) throws IOException {
        setDSValues(currentReach);
        double EGL1 = calcFrictionSlope();

        this.setUSValues(currentReach);
        double EGL2 = calcFrictionSlope();

        System.out.println(EGL1 + ":" + EGL2);
    } //end testEGLChange
    */

    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 of calcVelocity

    public double calcFrictionSlope(ChannelGeometry values) { //Need to move to ChannelGeometry Class?

        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 of calcFrictionSlope

    public ChannelGeometry setDSValues(int currentReach,
                                            double depth) throws IOException {
        
        ChannelGeometry DSValues = new ChannelGeometry();
        DSValues.setGeometryType(irregularGeometry);

        if (irregularGeometry) {
            double[][][] geometries = setCrossSectionArray();
            double[][] properties = setReachProperties();
            DSValues.setXYPoints(geometries[currentReach]);
            DSValues.setDepth(depth);
            DSValues.setDischarge(discharge_DS);
            DSValues.setManningRoughness(properties[currentReach][2]);
            DSValues.setBedSlope(properties[currentReach][1]);
        } 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

    public ChannelGeometry setUSValues(int currentReach,
                                            double depth) throws IOException {
        
        ChannelGeometry USValues = new ChannelGeometry();
        USValues.setGeometryType(irregularGeometry);

        if (irregularGeometry) {
            double[][][] geometries = setCrossSectionArray();
            double[][] properties = setReachProperties();
            USValues.setXYPoints(geometries[currentReach + 1]);
            USValues.setDepth(depth);
            USValues.setDischarge(discharge_DS);
            USValues.setManningRoughness(properties[currentReach][2]);
            USValues.setBedSlope(properties[currentReach][1]);
        } else {
            USValues.setBottomWidth(bottomWidth);
            USValues.setSideSlope(sideSlope);
            USValues.setDepth(depth);
            USValues.setDischarge(discharge_DS);
            USValues.setManningRoughness(manning_n);
            USValues.setBedSlope(bedSlope);
        }
        return USValues;
    }//end of setUSValues

    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) - (Math.abs(bedSlope))))
                + length;

        return error;
    } //end standardStepEquation

    public void graphLongitudinalProfile(double[][][] resultsArray,
            int numberOfReaches,
            String graphTitle,
            String graphOutputName,
            String mainFolder,
            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++) {
            //Graph the rating curve
            series1.add(resultsArray[i][0][0], resultsArray[i][1][0]);
        }
        XYSeries series2 = new XYSeries(series2_name);
        for (int i = 0; i < numberOfReaches + 1; i++) {
            //Graph the rating curve
            series2.add(resultsArray[i][0][0], resultsArray[i][1][1]);
        }
        XYSeries series3 = new XYSeries(series3_name);
        for (int i = 0; i < numberOfReaches + 1; i++) {
            //Graph the rating curve
            series3.add(resultsArray[i][0][0], resultsArray[i][1][2]);
        }
        XYSeries series4 = new XYSeries(series4_name);
        for (int i = 0; i < numberOfReaches + 1; i++) {
            //Graph the rating curve
            series4.add(resultsArray[i][0][0], resultsArray[i][1][3]);
        }

        //Graph the effective discharge curve
        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 graphRatingCurve
    
    public void writeToFile(String textLine, boolean append_to_file, String summaryOutputName) throws IOException {
        FileWriter write = new FileWriter(mainFolder + File.separator + summaryOutputName,append_to_file);
        PrintWriter print_line = new PrintWriter(write);
        print_line.printf("%s" + "%n", textLine);
        print_line.close();
    }

} //end of StandardStepMethd