V1_0.java [src/java/m/rhem/rhem01_runmodel] Revision: 6748023c27d5260670bc6354232cfa94695052b4  Date: Tue Nov 01 10:28:40 MDT 2016
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package m.rhem.rhem01_runmodel;

import csip.Client;
import csip.Config;
import csip.Executable;
import csip.ModelDataService;
import static csip.ModelDataService.EXEC_FAILED;
import static csip.ModelDataService.EXEC_OK;
import csip.ServiceException;
import csip.annotations.Polling;
import csip.annotations.Resource;
import static csip.annotations.ResourceType.EXECUTABLE;
//import static csip.annotations.ResourceType.OUTPUT;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import javax.ws.rs.Path;
import oms3.annotations.Description;
import oms3.annotations.Name;
import org.apache.commons.io.FileUtils;
import rhem.utils.DBQueries;
import rhem.utils.DBResources;

/**
 * @version 1.0
 * @author Rumpal Sidhu
 */
@Name("RHEM-01:Run RHEM Model")
@Description("Run RHEM Model utilizing parameters including climate station, "
        + "surface soil texture class, slope percent and length, and vegetative "
        + "cover characteristics (bunchgrass, forbs/annual, shrub, and sodgrass "
        + "foliar cover; plant basal cover; rock cover; litter cover; and "
        + "cryptogam cover.")
@Path("m/rhem/runrhem/1.0")
@Polling(first = 10000, next = 2000)
@Resource(from = DBResources.class)
//@Resource(file = "/bin/win-x86/rhem_v2.3.exe", wine = true, id = "rhem", type = EXECUTABLE)
@Resource(file = "/bin/${csip.arch}/rhem_v23.exe", wine = false, id = "rhem", type = EXECUTABLE)
//@Resource(file = "*.par *.pre *.sum *.out *.run", type = OUTPUT)

public class V1_0 extends ModelDataService {

    private AoA aoa;
    private String parameterFileName;
    private String stormFileName;
    private String summaryFileName;
    private String runFileName;
    private String detailedOutputFileName;
    private Parameter parameter;

    String cligen_db = Config.getString("rhem.cligen_db", "file:/Users/rumpal/Documents/Work/csipDocuments/RHEM/cligen");

    @Override
    public void preProcess() throws ServiceException {
        try {
            int aoaId = getIntParam("AoAID", 0);
            int rhemSiteId = getIntParam("rhem_site_id", 0);
            String scenarioName = getStringParam("scenarioname");
            String scenarioDescription = getStringParam("scenariodescription");
            int unit = getIntParam("units", 0);
            String stateId = getStringParam("stateid");
            String climatestationId = getStringParam("climatestationid");
            String soilTexture = getStringParam("soiltexture");
            double slopeLength = getDoubleParam("slopelength", 0.0);
            String slopeShape = getStringParam("slopeshape");
            double slopeSteepness = getDoubleParam("slopesteepness", 0.0);
            double bunchGgrassCanopyCover = getDoubleParam("bunchgrasscanopycover", 0.0);
            double forbsCanopyCover = getDoubleParam("forbscanopycover", 0.0);
            double shrubsCanopyCover = getDoubleParam("shrubscanopycover", 0.0);
            double sodGrassCanopyCover = getDoubleParam("sodgrasscanopycover", 0.0);
            double basalCover = getDoubleParam("basalcover", 0.0);
            double rockCover = getDoubleParam("rockcover", 0.0);
            double litterCover = getDoubleParam("littercover", 0.0);
            double cryptogamsCover = getDoubleParam("cryptogamscover", 0.0);
//            if (unit != 1 && unit != 2) {
//                LOG.log(Level.SEVERE, "RHEM-01: Invalid unit");
//                throw new ServiceException("Unit should be 1-metric or 2 - English. Digit " + unit + " is not valid.");
//            }

            aoa = new AoA(aoaId, rhemSiteId, scenarioName,
                    scenarioDescription, unit, stateId, climatestationId,
                    soilTexture, slopeLength, slopeShape, slopeSteepness,
                    bunchGgrassCanopyCover, forbsCanopyCover, shrubsCanopyCover,
                    sodGrassCanopyCover, basalCover, rockCover, litterCover,
                    cryptogamsCover);
        } catch (ServiceException ex) {
            LOG.log(Level.SEVERE, "RHEM-01: Error in processing the request JSON.", ex);
            throw new ServiceException("Error in processing the request JSON.", ex);
        }
    }

    @Override
    public void doProcess() throws ServiceException {
        long milisec = new Date().getTime();
        parameterFileName = "scenario_input_" + milisec + ".par";
        stormFileName = "storm_input_" + milisec + ".pre";
        summaryFileName = "scenario_output_summary_" + milisec + ".sum";
        detailedOutputFileName = "scenario_output_summary_" + milisec + ".out";
        runFileName = milisec + ".run";

//        parameterFileName = "scenario_input_" + aoa.scenarioName + ".par";
//        stormFileName = "storm_input_" + aoa.scenarioName + ".pre";
//        summaryFileName = "scenario_output_summary_" + aoa.scenarioName + ".sum";
//        detailedOutputFileName = "scenario_output_summary_" + aoa.scenarioName + ".out";
//        runFileName = aoa.scenarioName + ".run";
//        System.out.println(new Date().getTime());
//
//
//        System.out.println("scenario_output_summary_" + aoa.scenarioName + ".out");
//        System.out.println("Name = " + detailedOutputFileName);
        parameter = new Parameter(aoa);
        try (Connection connection = getResourceJDBC(DBResources.MSSQL_RHEM);) {
            parameter.computeParameters(connection);
        } catch (ServiceException | SQLException se) {
            LOG.log(Level.SEVERE, "RHEM-01: SQLException.", se);
            throw new ServiceException("SQL problem.", se);
        }

        SimpleDateFormat sdf = new SimpleDateFormat("MMMM dd, YYYY, hh:mm a");
        Date now = new Date();
        String today = sdf.format(now);

        generateParamFile(parameter, today);
        generateRunFile();
        generateStormFile(parameter.ke, today);

        String run = runModel();
        System.out.println("run = " + run);

        if (run == null) {
            try (Connection connection = getResourceJDBC(DBResources.MSSQL_RHEM);) {
                appendToSumFile(connection);
            } catch (ServiceException | SQLException se) {
                LOG.log(Level.SEVERE, "RHEM-01: Problem in editing the summary file.", se);
                throw new ServiceException("Problem in editing the summary file.", se);
            }
        }
    }

    private void generateParamFile(Parameter param, String today) throws ServiceException {

        try (PrintWriter writer = new PrintWriter(new File(getWorkspaceDir(), parameterFileName))) {
            writer.println("! Parameter file for scenario: " + aoa.scenarioName);
            writer.println("! Date built: " + today + " (Version 2.3)");
            writer.println("! Parameter units: DIAMS(mm), DENSITY(g/cc),TEMP(deg C)");
            writer.println("BEGIN GLOBAL");
            writer.println(String.format("        %-8s=   %s", "CLEN", param.clen));
            writer.println(String.format("        %-8s=   %s", "UNITS", "metric"));
            writer.println(String.format("        %-8s=   %s", "DIAMS", param.diams));
            writer.println(String.format("        %-8s=   %s", "DENSITY", param.density));
            writer.println(String.format("        %-8s=   %s", "TEMP", 40));
            writer.println(String.format("        %-8s=   %s", "NELE", 1));
            writer.println("END GLOBAL");
            writer.println("BEGIN PLANE");
            writer.println(String.format("        %-8s=   %s", "ID", 1));
            writer.println(String.format("        %-8s=   %s", "LEN", param.slopeLength));
            writer.println(String.format("        %-8s=   %s", "WIDTH", 1.0));
            writer.println(String.format("        %-8s=   %s", "CHEZY", param.chezy));
            writer.println(String.format("        %-8s=   %s", "RCHEZY", param.chezy));
            writer.println(String.format("        %-8s=   %s", "SL", param.sl));
            writer.println(String.format("        %-8s=   %s", "SX", param.sx));
            writer.println(String.format("        %-8s=   %s", "CV", 1.00));
            writer.println(String.format("        %-8s=   %s", "SAT", 0.25));
            writer.println(String.format("        %-8s=   %s", "PR", 1));
            writer.println(String.format("        %-8s=   %s", "KSS", param.kss));
            writer.println(String.format("        %-8s=   %s", "KOMEGA", "0.000007747"));
            writer.println(String.format("        %-8s=   %s", "KCM", "0.00029936430000"));
            writer.println(String.format("        %-8s=   %s", "CA", 1.0));
            writer.println(String.format("        %-8s=   %s", "IN", 0.0));
            writer.println(String.format("        %-8s=   %s", "KE", param.ke));
            writer.println(String.format("        %-8s=   %s", "G", param.g));
            writer.println(String.format("        %-8s=   %s", "DIST", param.dist));
            writer.println(String.format("        %-8s=   %s", "POR", param.por));
            writer.println(String.format("        %-8s=   %s", "ROCK", 0.00));
            writer.println(String.format("        %-8s=   %s", "SMAX", 1.0));
            writer.println(String.format("        %-8s=   %s", "ADF", 0.0));
            writer.println(String.format("        %-8s=   %s", "ALF", 0.8));
            writer.println(String.format("        %-8s=   %s", "BARE", 0.23));
            writer.println(String.format("        %-8s=   %s", "RSP", 1.0));
            writer.println(String.format("        %-8s=   %s", "SPACING", 1.0));
            writer.println(String.format("        %-8s=   %s", "FRACT", param.fract));
            writer.println("END PLANE");
            writer.close();
        } catch (FileNotFoundException ex) {
            LOG.log(Level.SEVERE, "RHEM-01: FileNotFoundException.", ex);
            throw new ServiceException("Problem in generating the parameter file.", ex);
        }
    }

    private void generateStormFile(double Ke, String today) throws ServiceException {

        String cligenFileName = "/" + aoa.stateId.toLowerCase()
                + "/300yr/" + aoa.stateId + "_"
                + aoa.climatestationId + "_300yr.out";

        Client cl = new Client();
        File f = getWorkspaceFile(aoa.stateId + "_" + aoa.climatestationId + ".out");
//        cl.doGET(cligen_db + cligenFileName, f);

        try {
            URLConnection conn = new URL(cligen_db + cligenFileName).openConnection();
            FileUtils.copyInputStreamToFile(conn.getInputStream(), f);

            String tempFileName = "tempfile.pre";
            FileReader fileReader = new FileReader(f);
            long counter = 0;
            try (BufferedReader bufferedReader
                    = new BufferedReader(fileReader)) {
                try (PrintWriter writer
                        = new PrintWriter(new File(getWorkspaceDir() + tempFileName))) {
                    for (int i = 0; i <= 17; i++) {
                        bufferedReader.readLine();
                    }
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        String[] test = line.split("\\s+");
                        double keComparison = Double.parseDouble(test[8]) * (Double.parseDouble(test[5]) / Double.parseDouble(test[6]));
                        if (Ke < keComparison && test.length > 8) {
                            counter++;
                            writer.println(String.format("    %-5s %-5s %-5s %-5s %-5s %-6s %-6s %-6s",
                                    counter, test[2], test[3], test[4], test[5], test[6], test[7], test[8]));
                        }
                    }
                }
                bufferedReader.close();
                appendInfo(tempFileName, today, counter);
            }
        } catch (IOException | ServiceException e) {
            LOG.log(Level.SEVERE, "RHEM-01: Problem in generating the storm file.", e);
            throw new ServiceException("Problem in generating the storm file.", e);
        }
    }

    private void appendInfo(String tempFileName, String today, long counter) throws ServiceException {
        try (PrintWriter writer
                = new PrintWriter(new File(getWorkspaceDir(), stormFileName))) {
            FileReader fileReader = new FileReader(new File(getWorkspaceDir() + tempFileName));
            writer.println("# Storm file for scenario: " + aoa.scenarioName);
            writer.println("# Date built: " + today + " (Version 2.3)");
            writer.println("# State: " + aoa.stateId);
            writer.println("# Climate Station: " + aoa.climatestationId);
            writer.println(counter + " # The number of rain events");
            writer.println("0 # Breakpoint data? (0 for no, 1 for yes)");
            writer.println("#  id     day  month  year  Rain   Dur    Tp     Ip");
            writer.println("#                           (mm)   (h)");
            try (BufferedReader bufferedReader
                    = new BufferedReader(fileReader)) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    writer.println(line);
                }
            }
        } catch (IOException e) {
            throw new ServiceException(e);
        }
    }

    private void generateRunFile() throws ServiceException {
        try (PrintWriter writer = new PrintWriter(new File(getWorkspaceDir(), runFileName))) {
            writer.println(parameterFileName + ", " + stormFileName + ", "
                    + summaryFileName + ", \"" + aoa.scenarioName + "\", 0, 2, y, y, n, n, y");
            writer.close();
        } catch (FileNotFoundException ex) {
            LOG.log(Level.SEVERE, "RHEM-01: FileNotFoundException.", ex);
            throw new ServiceException("Problem in generating the run file.", ex);
        }
    }

    private String runModel() throws ServiceException {

        int run = -1;
        try {
            Executable rh = getResourceExe("rhem");
            rh.setArguments("-b", getWorkspaceFile(runFileName).toPath());
            run = rh.exec();
        } catch (ServiceException | IOException se) {
            LOG.log(Level.SEVERE, "RHEM-01: ", se);
            throw new ServiceException("Problem in running the model.", se);
        }
        return run == 0 ? EXEC_OK : EXEC_FAILED;
    }

    private void appendToSumFile(Connection connection) throws ServiceException {
        double avgYearlyPrecip = 0;
        try (Statement statement = connection.createStatement();) {
            String query = "SELECT avg_yearly_precip_mm FROM rhem.d_rhem_climate_stations_avg_300yr_est_rain WHERE station_id = '" + aoa.climatestationId + "';";
            ResultSet rs = statement.executeQuery(query);
            while (rs.next()) {
                avgYearlyPrecip = rs.getDouble("avg_yearly_precip_mm");
            }
        } catch (SQLException e) {
            throw new ServiceException(e);
        }
        int counter = 0;
        File tempSummaryFile = new File(getWorkspaceDir(), "final_" + summaryFileName);
        File summaryFile = new File(getWorkspaceDir(), summaryFileName);
        try (PrintWriter writer
                = new PrintWriter(tempSummaryFile)) {
            FileReader fileReader = new FileReader(summaryFile);
            writer.println("     -ANNUAL-AVERAGES-");
            writer.println();
            writer.println("Avg-Precipitation(mm/year)=   " + avgYearlyPrecip);
            try (BufferedReader bufferedReader
                    = new BufferedReader(fileReader)) {
                String line;
                for (int i = 0; i < 3; i++) {
                    bufferedReader.readLine();
                    counter++;
                }
                while ((line = bufferedReader.readLine()) != null) {
                    counter++;
//                    writer.println(line);
                    String[] test = line.split("\\s+");
                    for (int i = 1; i < test.length; i++) {
                        switch (counter) {
                            case 13:
                                if (i == 1) {
                                    writer.print(String.format("%-28s", "Precipitation(mm)"));
                                    i = 2;
                                } else {
                                    writer.print(String.format("%-28s", test[i]));
                                }
                                break;
                            default:
                                writer.print(String.format("%-28s", test[i]));
                                break;
                        }
//                        if (counter != 13) {
//                            writer.print(String.format("%-28s", test[i]));
//                        } else {
//                            if (i == 1) {
//                                writer.print(String.format("%-28s", "Precipitation(mm)"));
//                                i = 3;
//                            } else {
//                                writer.print(String.format("%-28s", test[i]));
//                            }
//                        }
                    }
                    writer.println();
                }
                bufferedReader.close();
            }
            summaryFile.delete();
            writer.close();
            tempSummaryFile.renameTo(summaryFile);
        } catch (IOException e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public void postProcess() {
        putResult("AoAID", aoa.aoaId, "Area of Analysis Identifier");
        putResult("rhem_site_id", aoa.rhemSiteId, "RHEM Evaluation Site Identifier");
        putResult("CLEN", parameter.clen);
        putResult("UNITS", "metric");
        putResult("DIAMS", parameter.diams);
        putResult("DENSITY", parameter.density);
        putResult("CHEZY", parameter.chezy);
        putResult("RCHEZY", parameter.chezy);
        putResult("SL", parameter.sl);
        putResult("SX", parameter.sx);
        putResult("KSS", parameter.kss);
        putResult("KE", parameter.ke);
        putResult("G", parameter.g);
        putResult("DIST", parameter.dist);
        putResult("POR", parameter.por);
        putResult("FRACT", parameter.fract);
        putResult(new File(getWorkspaceDir(), parameterFileName), "Parameter input file");
        putResult(new File(getWorkspaceDir(), stormFileName), "Storm input file");
        putResult(new File(getWorkspaceDir(), summaryFileName), "Summary file");
        putResult(new File(getWorkspaceDir(), detailedOutputFileName), "Detailed");
    }

    static class AoA {

        protected int aoaId;
        protected int rhemSiteId;
        protected String scenarioName;
        protected String scenarioDescription;
        protected int unit;
        protected String stateId;
        protected String climatestationId;
        protected String soilTexture;
        protected double slopeLength;
        protected String slopeShape;
        protected double slopeSteepness;
        protected double moisturecontent;
        protected double bunchGgrassCanopyCover;
        protected double forbsCanopyCover;
        protected double shrubsCanopyCover;
        protected double sodGrassCanopyCover;
        protected double basalCover;
        protected double rockCover;
        protected double litterCover;
        protected double cryptogamsCover;

        public AoA(int aoaId, int rhemSiteId, String scenarioName,
                String scenarioDescription, int unit, String stateId,
                String climatestationId, String soilTexture, double slopeLength,
                String slopeShape, double slopeSteepness,
                double bunchGgrassCanopyCover, double forbsCanopyCover,
                double shrubsCanopyCover, double sodGrassCanopyCover, double basalCover,
                double rockCover, double litterCover, double cryptogamsCover) {
            this.aoaId = aoaId;
            this.rhemSiteId = rhemSiteId;
            this.scenarioName = scenarioName;
            this.scenarioDescription = scenarioDescription;
            this.unit = unit;
            this.stateId = stateId;
            this.climatestationId = climatestationId;
            this.soilTexture = soilTexture;
            this.slopeLength = slopeLength;
            this.slopeShape = slopeShape;
            this.slopeSteepness = slopeSteepness / 100.0;
            this.bunchGgrassCanopyCover = bunchGgrassCanopyCover / 100.0;
            this.forbsCanopyCover = forbsCanopyCover / 100.0;
            this.shrubsCanopyCover = shrubsCanopyCover / 100.0;
            this.sodGrassCanopyCover = sodGrassCanopyCover / 100.0;
            this.basalCover = basalCover / 100.0;
            this.rockCover = rockCover / 100.0;
            this.litterCover = litterCover / 100.0;
            this.cryptogamsCover = cryptogamsCover / 100.0;
            moisturecontent = moisturecontent / 100.0;
        }
    }

    static class Parameter {

        protected AoA aoa;
        protected double clen;
        protected String diams;
        protected String density;
        protected double slopeLength;
        protected double chezy;
        protected String sx, sl;
        protected String fract;
        protected double ke;
        protected double kss;

        double g, dist, por;

        public Parameter(AoA aoa) {
            this.aoa = aoa;
        }

        public void computeParameters(Connection connection) throws SQLException {
            // canopy cover for grass
//        double grasscanopycover = aoa.bunchGgrassCanopyCover + aoa.forbsCanopyCover + aoa.sodGrassCanopyCover;
            // TOTAL CANOPY COVER
            double totalcanopycover = aoa.bunchGgrassCanopyCover + aoa.forbsCanopyCover + aoa.shrubsCanopyCover + aoa.sodGrassCanopyCover;
            // TOTAL GROUND COVER
            double totalgroundcover = aoa.rockCover + aoa.basalCover + aoa.litterCover + aoa.cryptogamsCover;

            if (aoa.unit == 2) {
                this.slopeLength = aoa.slopeLength * 0.3048;
            } else {
                this.slopeLength = aoa.slopeLength;
            }

            this.computeChezyValue();
            this.computeSlSxValues();
            this.computeClenValue();
            this.getValuesFmDb(connection);
            this.computeKeValue(totalcanopycover);
            this.computeKssValue(totalcanopycover, totalgroundcover);
        }

        public void computeChezyValue() {
            double ft = (-1 * 0.109) + (1.425 * aoa.litterCover)
                    + (0.442 * aoa.rockCover) + (1.764 * (aoa.basalCover
                    + aoa.cryptogamsCover)) + (2.068 * aoa.slopeSteepness);
            ft = Math.pow(10, ft);

            chezy = Math.pow((8 * 9.8) / ft, 0.5);
        }

        public void computeSlSxValues() {
            switch (aoa.slopeShape) {

                case "Uniform":
                    sl = aoa.slopeSteepness + ", " + aoa.slopeSteepness;
                    sx = 0.00 + ", " + 1.00;
                    break;

                case "Convex":
                    sl = 0.001 + ", " + (aoa.slopeSteepness * 2);
                    sx = 0.00 + ", " + 1.00;
                    break;

                case "Concave":
                    sl = (aoa.slopeSteepness * 2) + ", " + 0.001;
                    sx = 0.00 + ", " + 1.00;
                    break;

                case "S-shaped":
                    sl = 0.001 + ", " + (aoa.slopeSteepness * 2) + ", " + 0.001;
                    sx = 0.00 + ", " + 0.50 + ", " + 1.00;
                    break;
            }
        }

        public void computeClenValue() {
            clen = this.slopeLength * 2.5;
        }

        public void getValuesFmDb(Connection connection) throws SQLException {

            try {
                Statement statement = connection.createStatement();

//                String query = "SELECT clay_diameter, silt_diameter, "
//                        + "small_aggregates_diameter, large_aggregates_diameter, "
//                        + "sand_diameter, clay_specific_gravity, "
//                        + "silt_specific_gravity, small_aggregates_specific_gravity, "
//                        + "large_aggregates_specific_gravity, sand_specific_gravity, "
//                        + "mean_matric_potential, pore_size_distribution, mean_porosity, "
//                        + "clay_fraction, silt_fraction, small_aggregates_fraction, "
//                        + "large_aggregates_fraction, sand_fraction "
//                        + "FROM rhem.soil_texture_table "
//                        + "WHERE class_name ='" + aoa.soilTexture + "';";
                try (ResultSet resultSet = statement.executeQuery(DBQueries.RHEM01Query01(aoa.soilTexture))) {
                    while (resultSet.next()) {
                        double diam1 = resultSet.getDouble("clay_diameter");
                        double diam2 = resultSet.getDouble("silt_diameter");
                        double diam3 = resultSet.getDouble("small_aggregates_diameter");
                        double diam4 = resultSet.getDouble("large_aggregates_diameter");
                        double diam5 = resultSet.getDouble("sand_diameter");
                        diams = diam1 + " " + diam2 + " " + diam3 + " " + diam4 + " " + diam5;
                        double density1 = resultSet.getDouble("clay_specific_gravity");
                        double density2 = resultSet.getDouble("silt_specific_gravity");
                        double density3 = resultSet.getDouble("small_aggregates_specific_gravity");
                        double density4 = resultSet.getDouble("large_aggregates_specific_gravity");
                        double density5 = resultSet.getDouble("sand_specific_gravity");
                        density = density1 + " " + density2 + " " + density3 + " " + density4 + " " + density5;
                        g = resultSet.getDouble("mean_matric_potential");
                        dist = resultSet.getDouble("pore_size_distribution");
                        por = resultSet.getDouble("mean_porosity");
                        double fract1 = resultSet.getDouble("clay_fraction");
                        double fract2 = resultSet.getDouble("silt_fraction");
                        double fract3 = resultSet.getDouble("small_aggregates_fraction");
                        double fract4 = resultSet.getDouble("large_aggregates_fraction");
                        double fract5 = resultSet.getDouble("sand_fraction");
                        fract = fract1 + " " + fract2 + " " + fract3 + " " + fract4 + " " + fract5;
                    }
                }

            } catch (SQLException se) {
                throw new SQLException("SQL problem.", se);
            }
        }

        private void computeKeValue(double totalcanopycover) {
            double Keb = 0;
            switch (aoa.soilTexture) {
                case "Sand":
                    Keb = 24 * Math.exp(0.3483 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Loamy Sand":
                    Keb = 10 * Math.exp(0.8755 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Sandy Loam":
                    Keb = 5 * Math.exp(1.1632 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Loam":
                    Keb = 2.5 * Math.exp(1.5686 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Silt Loam":
                    Keb = 1.2 * Math.exp(2.0149 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Silt":
                    Keb = 1.2 * Math.exp(2.0149 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Sandy Clay Loam":
                    Keb = 0.80 * Math.exp(2.1691 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Clay Loam":
                    Keb = 0.50 * Math.exp(2.3026 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Silty Clay Loam":
                    Keb = 0.40 * Math.exp(2.1691 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Sandy Clay":
                    Keb = 0.30 * Math.exp(2.1203 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Silty Clay":
                    Keb = 0.25 * Math.exp(1.7918 * (aoa.basalCover + aoa.litterCover));
                    break;
                case "Clay":
                    Keb = 0.2 * Math.exp(1.3218 * (aoa.basalCover + aoa.litterCover));
                    break;
            }
            double weightedKe = 0;

            // calculate weighted Ke and Kss values for the vegetation types that have non-zero values
            if (totalcanopycover != 0) {
                weightedKe = weightedKe + ((aoa.shrubsCanopyCover / totalcanopycover) * (Keb * 1.2));
                weightedKe = weightedKe + ((aoa.sodGrassCanopyCover / totalcanopycover) * (Keb * 0.8));
                weightedKe = weightedKe + ((aoa.bunchGgrassCanopyCover / totalcanopycover) * (Keb * 1.0));
                weightedKe = weightedKe + ((aoa.forbsCanopyCover / totalcanopycover) * (Keb * 1.0));
            } else {
                weightedKe = Keb;
            }
            ke = weightedKe;
        }

        public void computeKssValue(double totalcanopycover, double totalgroundcover) {
            // Kss variables
            double Kss_Seg_Bunch, Kss_Seg_Sod, Kss_Seg_Shrub, Kss_Seg_Shrub_0, Kss_Seg_Forbs;
            double Kss_Average, Kss_Final;

            // 1)
            //   a) CALCULATE KSS FOR EACH VEGETATION COMMUNITY USING TOTAL FOLIAR COVER
            //		A)   BUNCH GRASS
            if (totalgroundcover < 0.475) {
                Kss_Seg_Bunch = 4.154 + 2.5535 * aoa.slopeSteepness
                        - 2.547 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Bunch = Math.pow(10, Kss_Seg_Bunch);

                Kss_Seg_Sod = 4.2169 + 2.5535 * aoa.slopeSteepness
                        - 2.547 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Sod = Math.pow(10, Kss_Seg_Sod);

                Kss_Seg_Shrub = 4.2587 + 2.5535 * aoa.slopeSteepness - 2.547 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Shrub = Math.pow(10, Kss_Seg_Shrub);

                Kss_Seg_Forbs = 4.1106 + 2.5535 * aoa.slopeSteepness - 2.547 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Forbs = Math.pow(10, Kss_Seg_Forbs);

                Kss_Seg_Shrub_0 = 4.2587 + 2.5535 * aoa.slopeSteepness - 2.547 * totalgroundcover;
                Kss_Seg_Shrub_0 = Math.pow(10, Kss_Seg_Shrub_0);

            } else {
                Kss_Seg_Bunch = 3.1726975 + 2.5535 * aoa.slopeSteepness
                        - 0.4811 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Bunch = Math.pow(10, Kss_Seg_Bunch);

                Kss_Seg_Sod = 3.2355975 + 2.5535 * aoa.slopeSteepness
                        - 0.4811 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Sod = Math.pow(10, Kss_Seg_Sod);

                Kss_Seg_Shrub = 3.2773975 + 2.5535 * aoa.slopeSteepness - 0.4811 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Shrub = Math.pow(10, Kss_Seg_Shrub);

                Kss_Seg_Forbs = 3.1292975 + 2.5535 * aoa.slopeSteepness - 0.4811 * totalgroundcover - 0.7822 * totalcanopycover;
                Kss_Seg_Forbs = Math.pow(10, Kss_Seg_Forbs);

                Kss_Seg_Shrub_0 = 3.2773975 + 2.5535 * aoa.slopeSteepness - 0.4811 * totalgroundcover;
                Kss_Seg_Shrub_0 = Math.pow(10, Kss_Seg_Shrub_0);
            }
            if (totalcanopycover > 0 && totalcanopycover < 0.02) {

                Kss_Average = totalcanopycover / 0.02 * ((aoa.shrubsCanopyCover / totalcanopycover) * Kss_Seg_Shrub
                        + (aoa.sodGrassCanopyCover / totalcanopycover) * Kss_Seg_Sod
                        + (aoa.bunchGgrassCanopyCover / totalcanopycover) * Kss_Seg_Bunch
                        + (aoa.forbsCanopyCover / totalcanopycover) * Kss_Seg_Forbs)
                        + (0.02 - totalcanopycover) / 0.02 * Kss_Seg_Shrub_0;

            } else {

                Kss_Average = (aoa.shrubsCanopyCover / totalcanopycover) * Kss_Seg_Shrub
                        + (aoa.sodGrassCanopyCover / totalcanopycover) * Kss_Seg_Sod
                        + (aoa.bunchGgrassCanopyCover / totalcanopycover) * Kss_Seg_Bunch
                        + (aoa.forbsCanopyCover / totalcanopycover) * Kss_Seg_Forbs;

            }

            // 3) CALCULATE KSS USED FOR RHEM
            if (totalcanopycover == 0) {
                if (totalgroundcover < 0.475) {
                    Kss_Final = 4.2587 + 2.5535 * aoa.slopeSteepness - 2.547 * totalgroundcover;
                    Kss_Final = Math.pow(10, Kss_Final);
                } else {
                    Kss_Final = 3.2773975 + 2.5535 * aoa.slopeSteepness - 0.4811 * totalgroundcover;
                    Kss_Final = Math.pow(10, Kss_Final);
                }
            } else if (totalgroundcover < 0.475) {
                Kss_Final = totalgroundcover / 0.475 * Kss_Average + (0.475 - totalgroundcover) / 0.475 * Kss_Seg_Shrub;
            } else {
                Kss_Final = Kss_Average;
            }

            Kss_Final = (Kss_Final * 1.3) * 2.0;
            this.kss = Kss_Final;
        }

    }

}