V1_0.java [src/java/m/rhem/rhem01_runmodel] Revision: 5b3dddef0245d85efaca66b3d2428f5ff8246ae3  Date: Mon Jul 20 17:50:57 MDT 2020
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API, and application suite.
 *
 * 2012-2020, OMSLab, Colorado State University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package m.rhem.rhem01_runmodel;

import csip.Config;
import csip.Executable;
import csip.ModelDataService;
import csip.PayloadParameter;
import csip.ServiceException;
import csip.annotations.Polling;
import csip.annotations.Resource;
import java.io.IOException;
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 javax.ws.rs.Path;
import m.rhem.model.AoA;
import m.rhem.model.Parameter;
import m.rhem.model.RhemModel;
import csip.annotations.Description;
import csip.annotations.Name;
import rhem.utils.DBResources;
import rhem.utils.RhemResources;
import static rhem.utils.RhemResources.RHEM4_EXE;
import static rhem.utils.RhemResources.RHEM4_INTL_EXE;

/**
 * RHEM-01:Run RHEM Model
 *
 * @version 1.0
 * @author Rumpal Sidhu
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
@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(from = RhemResources.class)
public class V1_0 extends ModelDataService {

  private static final int DEFAULT_MOISTURE_CONTENT = 25;
  private static final double DEFAULT_SLOPE_LENGTH_1 = 50.0;
  private static final double DEFAULT_SLOPE_LENGTH_2 = 164.04;
  private static final double DEFAULT_MINIMUM_SLOPE_STEEPNESS = 0.01;

  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");

  RhemModel rhemModel;
  int unit;


  @Override
  public void preProcess() throws ServiceException {
    PayloadParameter parameters = parameter();

    int aoaId = parameters.getInt("AoAID", 0);
    int rhemSiteId = parameters.getInt("rhem_site_id", 0);
    String scenarioName = parameters.getString("scenarioname");
    String scenarioDescription = parameters.getString("scenariodescription");
    unit = parameters.getInt("units");
    String stateId = parameters.getString("stateid");
    String climatestationId = parameters.getString("climatestationid");
    String soilTexture = parameters.getString("soiltexture");
    String slopeShape = parameters.getString("slopeshape");
    double slopeSteepness = parameters.getDouble("slopesteepness", DEFAULT_MINIMUM_SLOPE_STEEPNESS);
    double bunchGgrassCanopyCover = parameters.getDouble("bunchgrasscanopycover", 0.0);
    double forbsCanopyCover = parameters.getDouble("forbscanopycover", 0.0);
    double shrubsCanopyCover = parameters.getDouble("shrubscanopycover", 0.0);
    double sodGrassCanopyCover = parameters.getDouble("sodgrasscanopycover", 0.0);
    double basalCover = parameters.getDouble("basalcover", 0.0);
    double rockCover = parameters.getDouble("rockcover", 0.0);
    double litterCover = parameters.getDouble("littercover", 0.0);
    double cryptogamsCover = parameters.getDouble("cryptogamscover", 0.0);
    double sar = parameters.getDouble("sar", 0.0);

    ///////////////////////////////
    //  BEGIN  Validations of input 
    //The values allowed for the field unit in the request are 1 and 2. 1 is for metric units and 2 is for English units
    if (sar < 0.0 || sar > 50.0) {
      throw new ServiceException("invalid sar (0.0 ... 50.0): " + sar);
    }

    double slopeLength;
    switch (unit) {
      case 1:
        slopeLength = DEFAULT_SLOPE_LENGTH_1;
        break;

      case 2:
        slopeLength = DEFAULT_SLOPE_LENGTH_2;
        break;

      default:
        throw new ServiceException("Unit should be 1-metric or 2-English. The value, " + unit + ", is not valid.");
    }

    if (slopeSteepness <= 0.0) {
      throw new ServiceException("The slopesteepness input parameter must be greater than 0.");
    }

    //  END Validations
    ///////////////////////////////
    aoa = new AoA(aoaId, rhemSiteId, scenarioName,
        scenarioDescription, unit, stateId, climatestationId,
        soilTexture, slopeLength, slopeShape, slopeSteepness,
        bunchGgrassCanopyCover, forbsCanopyCover, shrubsCanopyCover,
        sodGrassCanopyCover, basalCover, rockCover, litterCover,
        cryptogamsCover, DEFAULT_MOISTURE_CONTENT, sar);
  }


  @Override
  public void doProcess() throws Exception {
    SimpleDateFormat sdf = new SimpleDateFormat("MMMM dd, YYYY, hh:mm a");
    String today = sdf.format(new Date());

    String fileName = aoa.getScenarioName();
    if (fileName.length() > 15) {
      fileName = fileName.substring(0, 15);
    }
    fileName = fileName.replace(' ', '_');

    parameterFileName = "scenario_input_" + fileName + ".par";
    stormFileName = "storm_input_" + fileName + ".pre";
    summaryFileName = "scenario_output_summary_" + fileName + ".sum";
    detailedOutputFileName = "scenario_output_summary_" + fileName + ".out";
    runFileName = fileName + ".run";

    parameter = new Parameter(aoa);

    try (Connection connection = resources().getJDBC(DBResources.CRDB);) {
      parameter.computeParameters(connection);
    }

    rhemModel = new RhemModel(aoa.getStateId(), aoa.getClimateStationId(),
        aoa.getScenarioName(), today, getWorkspaceDir(), parameterFileName,
        stormFileName, runFileName, summaryFileName);

    rhemModel.generateParamFile(parameter);
    rhemModel.generateStormFile(cligen_db, Double.parseDouble(parameter.getKe()));
    rhemModel.generateRunFile();

    runModel();

    //If the run is successful then edit the summary file.
    double avgYearlyPrecip = 0.0;
    if (rhemModel.isIntl()) {
      avgYearlyPrecip = rhemModel.getYearlyPrecipIntl();
    } else {
      try (Connection connection = resources().getJDBC(DBResources.CRDB);
          Statement statement = connection.createStatement();) {
        try (ResultSet rs = statement.executeQuery(DBResources.RHEM01Query02(aoa.getClimateStationId()))) {
          while (rs.next()) {
            avgYearlyPrecip = rs.getDouble("avg_yearly_precip_mm");
          }
        }
      }
    }
    rhemModel.appendToSumFile(avgYearlyPrecip);
  }


  private void runModel() throws ServiceException, IOException {
    Executable rh = resources().getExe(rhemModel.isIntl() ? RHEM4_INTL_EXE : RHEM4_EXE);
    rh.setArguments("-b", getWorkspaceFile(runFileName).toPath());
    int run = rh.exec();
    if (run != 0) {
      throw new ServiceException("Error running rhem: " + run);
    }
  }


  @Override
  public void postProcess() {
    results().put("AoAID", aoa.getAoaId(), "Area of Analysis Identifier");
    results().put("rhem_site_id", aoa.getRhemSiteId(), "RHEM Evaluation Site Identifier");
    results().put("CLEN", parameter.getClen(), "characteristic length of hillsope");
    results().put("UNITS", (unit == 1) ? "metric" : "English", "unit of measure, metric or English");
    results().put("DIAMS", parameter.getDiams(), "list of representative soil particle diameters for up to 5 particle classes");
    results().put("DENSITY", parameter.getDensity(), "list of densities corresponding to the DIAMS particle classes");
    results().put("CHEZY", parameter.getChezy(), "overland flow Chezy coefficient");
    results().put("RCHEZY", parameter.getRchezy(), "concentrated flow Chezy coefficient");
    results().put("SL", parameter.getSl(), "slope expressed as fractional rise/run");
    results().put("SX", parameter.getSx(), "normalized distance");
    results().put("KSS", parameter.getKss(), "splash and sheet erodibility coefficient");
    results().put("KE", parameter.getKe(), "effective hydraulic conductivity");
    results().put("G", parameter.getG(), "mean capillary drive");
    results().put("DIST", parameter.getDist(), "pore size distribution index");
    results().put("POR", parameter.getPor(), "porosity");
    results().put("FRACT", parameter.getFract(), "list of particle class fractions");
    results().put("TDS", rhemModel.getTDS(), "total dissolved solids");
    results().put(getWorkspaceFile(parameterFileName), "Parameter input file");
    results().put(getWorkspaceFile(stormFileName), "Storm input file");
    results().put(getWorkspaceFile(summaryFileName), "Summary file");
    results().put(getWorkspaceFile(detailedOutputFileName), "Detailed summary file");
  }
}