Parameter.java [src/java/m/rhem/model] Revision: b4532614e56521e407dbd03a73779498a8516f23  Date: Wed Dec 29 18:55:25 MST 2021
/*
 * 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.model;

import csip.api.server.ServiceException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import m.rhem.DBResources;
import static rhem.utils.RHEMUtils.fmt;
import static rhem.utils.RHEMUtils.formatDouble;

/**
 *
 * @author rumpal
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
public class Parameter {

  private static final double CLEN_MULTIPLIER = 2.5;

  String clen, diams, density;
  String len, chezy, rchezy;
  String sl, sx;
  String cv, sat, kss, komega, kcm, ke, adf, alf, bare;

  String g, dist, por;
  String fract;

  double slopeLength;


  public Parameter(String diams, String density, String len,
      String chezy, String rchezy, String sl, String sx, String cv,
      String sat, String kss, String komega, String kcm, String ke,
      String adf, String alf, String bare, String g, String dist,
      String por, String fract) {
    this.diams = diams;
    this.density = density;
    this.len = len;
    this.chezy = chezy;
    this.rchezy = rchezy;
    this.sl = sl;
    this.sx = sx;
    this.cv = cv;
    this.sat = sat;
    this.kss = kss;
    this.komega = komega;
    this.kcm = kcm;
    this.ke = ke;
    this.adf = adf;
    this.alf = alf;
    this.bare = bare;
    this.g = g;
    this.dist = dist;
    this.por = por;
    this.fract = fract;
    this.clen = String.valueOf(Double.parseDouble(len) * CLEN_MULTIPLIER);
  }


  public Parameter(double slopeLength) throws ServiceException {
    cv = "1.00";
    sat = "0.25";
    komega = "0.000007747";
    kcm = "0.00029936430000";
    adf = "0.0";
    alf = "0.8";
    bare = "0 ! INACTIVE";
    this.slopeLength = slopeLength;
  }


  public void computeParameters(Connection connection, AoA aoa) throws SQLException, ServiceException {

    double totalcanopycover = aoa.bunchGgrassCanopyCover + aoa.forbsCanopyCover
        + aoa.shrubsCanopyCover + aoa.sodGrassCanopyCover;
    double totalgroundcover = aoa.rockCover + aoa.basalCover
        + aoa.litterCover + aoa.cryptogamsCover;

    len = String.valueOf(slopeLength);

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


  private void computeChezyValue(AoA aoa) {
    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);
    if (ft != 0.0) {
      rchezy = chezy = String.valueOf(Math.pow((8 * 9.8) / ft, 0.5));
    } else {
      throw new ArithmeticException("Divide by zero for ft value while computing ChezyValue; Cannot continue.");
    }
  }


  private void computeSlSxValues(AoA aoa) throws ServiceException {
    switch (aoa.slopeShape.toLowerCase()) {
      case "uniform":
        sl = fmt(aoa.slopeSteepness) + ", " + fmt(aoa.slopeSteepness);
        sx = "0.00, 1.00";
        break;
      case "convex":
        sl = "0.001, " + fmt(aoa.slopeSteepness * 2);
        sx = "0.00, 1.00";
        break;
      case "concave":
        sl = fmt(aoa.slopeSteepness * 2) + ", " + 0.001;
        sx = "0.00, 1.00";
        break;
      case "s-shaped":
        sl = "0.001, " + fmt(aoa.slopeSteepness * 2) + ", " + 0.001;
        sx = "0.00, 0.50, 1.00";
        break;
      default:
        throw new ServiceException("Invalid slope shape, " + aoa.slopeShape + ", specified for this AoA; Cannot continue.");
    }
  }

  // format a double and avoid scientific notation for small values.

  private void computeClenValue() {
    clen = String.valueOf(slopeLength * CLEN_MULTIPLIER);
  }


  private void getValuesFmDb(Connection con, AoA aoa) throws SQLException {
    try (Statement st = con.createStatement()) {
      try (ResultSet rs = st.executeQuery(DBResources.RunRHEMQuery01(aoa.soilTexture))) {
        while (rs.next()) {
          diams = formatDouble(rs.getDouble("clay_diameter")) + " "
              + formatDouble(rs.getDouble("silt_diameter")) + " "
              + formatDouble(rs.getDouble("small_aggregates_diameter")) + " "
              + formatDouble(rs.getDouble("large_aggregates_diameter")) + " "
              + formatDouble(rs.getDouble("sand_diameter"));
          density = formatDouble(rs.getDouble("clay_specific_gravity")) + " "
              + formatDouble(rs.getDouble("silt_specific_gravity")) + " "
              + formatDouble(rs.getDouble("small_aggregates_specific_gravity")) + " "
              + formatDouble(rs.getDouble("large_aggregates_specific_gravity")) + " "
              + formatDouble(rs.getDouble("sand_specific_gravity"));
          g = formatDouble(rs.getDouble("mean_matric_potential"));
          dist = formatDouble(rs.getDouble("pore_size_distribution"));
          por = formatDouble(rs.getDouble("mean_porosity"));
          fract = formatDouble(rs.getDouble("clay_fraction")) + " "
              + formatDouble(rs.getDouble("silt_fraction")) + " "
              + formatDouble(rs.getDouble("small_aggregates_fraction")) + " "
              + formatDouble(rs.getDouble("large_aggregates_fraction")) + " "
              + formatDouble(rs.getDouble("sand_fraction"));
        }
      }
    }
  }


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

    double weightedKe = 0;

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


  private void computeKssValue(double totalcanopycover, double totalgroundcover, AoA aoa) {
    double kssSegBunch, kssSegSod, kssSegShrub, kssSegShrub0, kssSegForbs;

    // 1)
    //   a) CALCULATE KSS FOR EACH VEGETATION COMMUNITY USING TOTAL FOLIAR COVER
    //		A)   BUNCH GRASS
    double steepness = 2.5535 * aoa.slopeSteepness;
    double canopy = 0.7822 * totalcanopycover;
    if (totalgroundcover < 0.475) {
      double ground = 2.547 * totalgroundcover;

      kssSegBunch = 4.154 + steepness - ground - canopy;
      kssSegBunch = Math.pow(10, kssSegBunch);

      kssSegSod = 4.2169 + steepness - ground - canopy;
      kssSegSod = Math.pow(10, kssSegSod);

      kssSegShrub = 4.2587 + steepness - ground - canopy;
      kssSegShrub = Math.pow(10, kssSegShrub);

      kssSegForbs = 4.1106 + steepness - ground - canopy;
      kssSegForbs = Math.pow(10, kssSegForbs);

      kssSegShrub0 = 4.2587 + steepness - ground;
      kssSegShrub0 = Math.pow(10, kssSegShrub0);

    } else {
      double ground = 0.4811 * totalgroundcover;
      kssSegBunch = 3.1726975 + steepness - ground - canopy;
      kssSegBunch = Math.pow(10, kssSegBunch);

      kssSegSod = 3.2355975 + steepness - ground - canopy;
      kssSegSod = Math.pow(10, kssSegSod);

      kssSegShrub = 3.2773975 + steepness - ground - canopy;
      kssSegShrub = Math.pow(10, kssSegShrub);

      kssSegForbs = 3.1292975 + steepness - ground - canopy;
      kssSegForbs = Math.pow(10, kssSegForbs);

      kssSegShrub0 = 3.2773975 + steepness - ground;
      kssSegShrub0 = Math.pow(10, kssSegShrub0);
    }

    double kssAverage = 0.0;  //If totalcanopycover is 0, then this value will never be changed, but also not used.
    if (totalcanopycover > 0 && totalcanopycover < 0.02) {
      kssAverage = totalcanopycover / 0.02 * ((aoa.shrubsCanopyCover / totalcanopycover) * kssSegShrub
          + (aoa.sodGrassCanopyCover / totalcanopycover) * kssSegSod
          + (aoa.bunchGgrassCanopyCover / totalcanopycover) * kssSegBunch
          + (aoa.forbsCanopyCover / totalcanopycover) * kssSegForbs)
          + (0.02 - totalcanopycover) / 0.02 * kssSegShrub0;
    } else {
      if (totalcanopycover >= 0.02) {
        kssAverage = (aoa.shrubsCanopyCover / totalcanopycover) * kssSegShrub
            + (aoa.sodGrassCanopyCover / totalcanopycover) * kssSegSod
            + (aoa.bunchGgrassCanopyCover / totalcanopycover) * kssSegBunch
            + (aoa.forbsCanopyCover / totalcanopycover) * kssSegForbs;
      }
      //  Otherwise, see below, if statement in step 3, don't ever use Kss_Average 
      // in this case and won't divide anywhere else by totalcanopycover.            
    }

    // 3) CALCULATE KSS USED FOR RHEM
    double kssFinal;
    if (totalcanopycover == 0.0) {
      if (totalgroundcover < 0.475) {
        kssFinal = 4.2587 + 2.5535 * aoa.slopeSteepness - 2.547 * totalgroundcover;
        kssFinal = Math.pow(10, kssFinal);
      } else {
        kssFinal = 3.2773975 + 2.5535 * aoa.slopeSteepness - 0.4811 * totalgroundcover;
        kssFinal = Math.pow(10, kssFinal);
      }
    } else if (totalgroundcover < 0.475) {
      kssFinal = totalgroundcover / 0.475 * kssAverage + (0.475 - totalgroundcover) / 0.475 * kssSegShrub;
    } else {
      kssFinal = kssAverage;
    }
    // if aoa.sar is 0, the last expr will be 0
    kssFinal = ((kssFinal * 1.3) * 2.0) + (711.0 * aoa.sar);
    kss = String.valueOf(kssFinal);
  }


  public String getClen() {
    return clen;
  }


  public String getDiams() {
    return diams;
  }


  public String getDensity() {
    return density;
  }


  public String getLen() {
    return len;
  }


  public String getChezy() {
    return chezy;
  }


  public String getRchezy() {
    return rchezy;
  }


  public String getSl() {
    return sl;
  }


  public String getSx() {
    return sx;
  }


  public String getCv() {
    return cv;
  }


  public String getSat() {
    return sat;
  }


  public String getKss() {
    return kss;
  }


  public String getKomega() {
    return komega;
  }


  public String getKcm() {
    return kcm;
  }


  public String getKe() {
    return ke;
  }


  public String getAdf() {
    return adf;
  }


  public String getAlf() {
    return alf;
  }


  public String getBare() {
    return bare;
  }


  public String getG() {
    return g;
  }


  public String getDist() {
    return dist;
  }


  public String getPor() {
    return por;
  }


  public String getFract() {
    return fract;
  }

}