V5_0_OMSPayload.java [src/java/m/prms/model] Revision:   Date:
package m.prms.model;

import csip.api.server.Executable;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;
import java.io.File;
import java.io.FileWriter;
import java.util.Calendar;
import java.util.logging.Level;
import javax.ws.rs.Path;
import org.apache.commons.io.FileUtils;
import static m.prms.model.V5_0_OMSPayload.PRMS5_EXE;
import oms3.Conversions;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

/**
 * PRMS Service. Execution of the original PRMS model.
 *
 * @author od
 */
@Name("PRMS")
@Description("Precipitation Runoff Modeling System.")
@State(State.UNSTABLE)
@Author(org = "USGS")
@Author(org = "CSU")
@Category("Hydrology")
@Path("m/prms-ewsf/5.0")
@Polling(first = 5000, next = 2000)
@Resource(type = EXECUTABLE, file = "/bin/lin-amd64/prms-5.0", id = PRMS5_EXE)
@Resource(type = OUTPUT, file = "*-stdout.txt *-stderr.txt recharge.* output/*")
public class V5_0_OMSPayload extends ModelDataService {

  static final String PRMS5_EXE = "prms";

  static final String PARMS_FILE = "params.csv";
  static final String DATA_RUNOFF_FILE = "runoff_data-sta.csv";
  static final String DATA_TMIN_FILE = "tmin_data-hru.csv";
  static final String DATA_TMAX_FILE = "tmax_data-hru.csv";
  static final String DATA_PRECIP_FILE = "precip_data-hru.csv";
  static final String CONTROL_FILE = "run.control";
  static final String OUTPUT_FILE = "output.statvar";
  static final String CONTROL_FILE_VM = "m/prms/model/control.vm";

  private static VelocityEngine velocity;


  @Override
  protected void doProcess() throws Exception {
    // parameter file conversion
    File csv = formdata().getFile(PARMS_FILE);
    params = Utils.convertToPRMSParam(csv);

    // data file conversion
    // split into runoff, precip, tmin, tmax
    File f = formdata().getFile(DATA_RUNOFF_FILE);
    data = Utils.convertCSVToData(f, null);
    f = formdata().getFile(DATA_TMIN_FILE);
    data_tmin = Utils.convertCSVToData(f, null);
    f = formdata().getFile(DATA_TMAX_FILE);
    data_tmax = Utils.convertCSVToData(f, null);
    f = formdata().getFile(DATA_PRECIP_FILE);
    data_prcp = Utils.convertCSVToData(f, null);
    
    // create the control file
    createControlFile(workspace().getFile(CONTROL_FILE));

    Executable e = resources().getExe(PRMS5_EXE);
    e.setArguments(CONTROL_FILE);
    if (0 != e.exec()) {
      throw new ServiceException("Error Executing prms: "
          + FileUtils.readFileToString(e.stderr(), "utf-8"));
    }

    // output handling
    File csv_output = Utils.convertStatvarToCSV(output);
    results().put(csv_output);
    
    // Add raw run.out for basinsum.csv. I could preprocess it here, but for now
    //   will rely on the client to parse out what it needs.
    results().put(workspace().getFile("run.out"));
  }


  void populateProperties() throws ServiceException {
    st = Conversions.convert(parameter().getString("start_time"), Calendar.class);
    en = Conversions.convert(parameter().getString("end_time"), Calendar.class);
    output = workspace().getFile(OUTPUT_FILE);
  }


  String createControlFile(File controlfile) throws Exception {
    populateProperties();

    VelocityContext context = new VelocityContext();
    context.put("service", this);

    FileWriter w = new FileWriter(controlfile);
    _velocity().getTemplate(CONTROL_FILE_VM, "utf-8").merge(context, w);
    w.close();

    if (LOG.isLoggable(Level.INFO)) {
      LOG.info("Created: " + CONTROL_FILE);
      LOG.info("\n" + FileUtils.readFileToString(workspace().getFile(CONTROL_FILE), "utf-8"));
    }
    return CONTROL_FILE;
  }


  static synchronized VelocityEngine _velocity() {
    if (velocity == null) {
      velocity = new VelocityEngine();
      velocity.setProperty("file.resource.loader.class",
          ClasspathResourceLoader.class.getName());
      velocity.setProperty("runtime.log", "/tmp/velocity.log");
      velocity.init();
    }
    return velocity;
  }

  /////////////////////////////////////////////// Properties for control file
  Calendar st;
  Calendar en;
  File params;
  // runoff station data
  File data;
  File data_tmin;
  File data_tmax;
  File data_prcp;
  File output;


  public int getStartYear() {
    return st.get(Calendar.YEAR);
  }


  public int getStartMonth() {
    return st.get(Calendar.MONTH) + 1;
  }


  public int getStartDay() {
    return st.get(Calendar.DAY_OF_MONTH);
  }


  public int getEndYear() {
    return en.get(Calendar.YEAR);
  }


  public int getEndMonth() {
    return en.get(Calendar.MONTH) + 1;
  }


  public int getEndDay() {
    return en.get(Calendar.DAY_OF_MONTH);
  }


  public String getParamsFile() {
    return params.getName();
  }


  public String getDataFile() {
    return data.getName();
  }


  public String getTminDataFile() {
    return data_tmin.getName();
  }


  public String getTmaxDataFile() {
    return data_tmax.getName();
  }


  public String getPrcpDataFile() {
    return data_prcp.getName();
  }


  public String getOutputFile() {
    return output.getName();
  }

}