V1_3.java [src/java/m/weps] Revision: c74837374670f76d3cc2468383e7a8dfb5f35f59 Date: Thu Sep 03 02:53:25 MDT 2015
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package m.weps;
import c.PostGIS;
import c.PostGIS.FileQryResult;
import csip.Config;
import csip.ModelDataService;
import csip.ServiceException;
import csip.utils.Binaries;
import csip.utils.JSONUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import javax.ws.rs.Path;
import man2weps.WepsTranslator;
import man2weps.mcrew.ManageData;
import oms3.annotations.Description;
import oms3.annotations.Name;
import oms3.annotations.VersionInfo;
import oms3.util.ProcessComponent;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import usda.weru.weps.reports.query.WepsConnection;
import util.ErosionConst;
import static util.ErosionConst.*;
import wepsreportdata.WepsReportData;
/**
* WEPS
*
* @author wlloyd, od
*/
@Name("WEPS")
@Description("WEPS")
@VersionInfo("1.3")
@Path("m/weps/1.3")
public class V1_3 extends ModelDataService {
String sessionWorkDir = "";
static final String SOIL_FILE_EXT = ".ifc";
static final String WIND_STATIONS_DIR = "windstations";
static final String WIND_STATION_FILE_EXT = ".wdb";
static final String DEFAULT_WIND_STATION_DB = "wind_gen_his_upper_US.wdb";
static final String DUMMY_MGMT = "dummy.man";
static final String REPORT_JSON_FILENAME = "weps_report.json";
static final String WEPS_MGMT = "wepsmgmt.man";
static final int NRCS_CYCLE_COUNT = 50;
public WepsOutput wo = new WepsOutput();
// Variables for WEPS model run
private String soilkey = "";
private String soilfile = "";
private WepsModelRun wmr = new WepsModelRun();
private int simulationYears = 3 * NRCS_CYCLE_COUNT;
private JSONObject fieldGeometry = null;
private JsonRegion field_region = null;
private JsonRegion barrier_region = null;
private PostGIS db = null;
private String binDir = "";
private String soilPtr = "";
private String soilFilename = "";
private String windDbPath = "";
private String sWindgenStation = "";
@Override
public void preprocess() throws Exception {
JSONUtils.checkKeyExists(getParamMap(), WEPS_KEY_MANAGEMENT);
JSONUtils.checkKeyExists(getParamMap(), WEPS_KEY_FIELD_LENGTH);
JSONUtils.checkKeyExists(getParamMap(), WEPS_KEY_FIELD_WIDTH);
JSONUtils.checkKeyExists(getParamMap(), WEPS_KEY_LATITUDE);
JSONUtils.checkKeyExists(getParamMap(), WEPS_KEY_LONGITUDE);
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_FIELD_BOUNDARY))
{
appendMetainfoWarning(WEPS_FIELD_BOUNDARY_IGNORED);
}
if (!JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_ELEVATION))
{
appendMetainfoWarning(WEPS_ELEVATION_DEFAULT_USED);
}
if ((!JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL)) &&
(!JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL_FILE)))
{
throw new ServiceException("No SOIL component key or soil file pointer provided! Cannot run WEPS.");
}
// if ((!JSONUtils.checkKeyExistsB(getParamMap(), WEPS_FIELD_BOUNDARY))
// && !((JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_LATITUDE))
// && (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_LONGITUDE))
// && (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_FIELD_WIDTH))
// && (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_FIELD_LENGTH)))) {
// throw new ServiceException("No WEPS Field specification available: geometry or paramters: latitude, longitude, field_width, field_length ");
// }
}
@Override
public Callable<String> createCallable() throws Exception {
return new Callable<String>() {
// to do
// refactor & make smaller
@Override
public String call() throws Exception {
ProcessComponent pc = new ProcessComponent();
try {
db = PostGIS.singleton();
} catch (Exception e) {
LOG.severe("Error obtaining DB connection in WEPS run!");
throw new ServiceException("WEPS error: Cannot obtain geospatial db connection");
}
LOG.info("The default CISP WEPS user dir is=" + System.getProperty("user.dir"));
try {
File workDir = getWorkspaceDir();
sessionWorkDir = workDir.toString();
binDir = Config.getString("m.bin.dir", "/tmp/csip/bin");
// Unpack the dummy mgmt
String dummyMgmt = Binaries.unpackResourceAbsolute("/bin/" + Binaries.getArch() + "/" + DUMMY_MGMT, sessionWorkDir + "/" + DUMMY_MGMT).toString();
wmr.setMgmtFile(DUMMY_MGMT); // the default mgmt, if none provided
// check that required parameters exist. populate them in wmr data object
loadRequiredParameters();
// get the mgmt as a json obj and create a WEPS man file using Jim's parser
loadWepsMgmt();
// Get field geometry
getFieldGeometry();
// get wind barriers
getWindBarriers();
// Get climate info
getClimate();
// Get wind info
generateWindData();
// Get soils data
getSoilIfc();
// run WEPS model
try {
// Always generate Weps Run file from JSON parameters (it is never provided in the model srvc signature)
LOG.log(Level.INFO, "wepsrun file does not exist, creating it.");
String wepsrunFile = "weps.run";
WepsRunFileGenerator.GenerateWepsRunFile(wmr, sessionWorkDir, wepsrunFile);
// Our WEPS model call uses the following cmd line args
// /weps -W1 -u0 -I2 -t1 -P./ >stdout.txt 2>stderr.txt
pc = new ProcessComponent();
pc.exe = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/weps", new File(binDir)).toString();
pc.args = new String[]{"-W1", "-u0", "-I2", "-t1", "-T1", "-P./"};
pc.working_dir = sessionWorkDir;
pc.execute();
// Check standard out for "inpsub" error - occurs when no soil file is available
if (pc.stdout.contains("inpsub error"))
throw new Exception("ERROR RUNNING WEPS--Standard output:" + pc.stdout);
FileUtils.write(new File(workDir, "stdout.txt"), pc.stdout);
FileUtils.write(new File(workDir, "stderr.txt"), pc.stderr);
// Generate report output
String reportJSON = Binaries.unpackResourceAbsolute("/bin/" + Binaries.getArch() + "/" + REPORT_JSON_FILENAME, sessionWorkDir + "/" + REPORT_JSON_FILENAME).toString();
} catch (Exception e) {
throw new ServiceException("WEPS error: error running WEPS model binary:" + e.toString());
}
return pc.exitValue == 0 ? EXEC_OK : EXEC_FAILED;
} catch (Exception e) {
LOG.log(Level.SEVERE, "ERROR EXECUTING WEPS!!!");
// LOG.log(Level.SEVERE, e.getStackTrace().toString());
for (StackTraceElement ste : e.getStackTrace()) {
LOG.log(Level.SEVERE, "class=" + ste.getClassName() + " method=" + ste.getMethodName() + " |" + ste.toString());
}
throw new ServiceException("WEPS error: unknown error executing WEPS model>" + e.toString());
}
}
};
}
/*
* Checks for the existence of required WEPS parameters.
* Loads them into proper variables for running the model.
*/
private void loadRequiredParameters() throws ServiceException {
try {
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL)) {
soilkey = JSONUtils.getValue(getParamMap().get(WEPS_KEY_SOIL));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL_FILE)) {
soilfile = JSONUtils.getValue(getParamMap().get(WEPS_KEY_SOIL_FILE));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_LATITUDE)) {
wmr.setLat(JSONUtils.getValue(getParamMap().get(WEPS_KEY_LATITUDE)));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_LONGITUDE)) {
wmr.setLongitude(JSONUtils.getValue(getParamMap().get(WEPS_KEY_LONGITUDE)));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_ELEVATION)) {
double elevationInM = Double.parseDouble(JSONUtils.getValue(getParamMap().get(WEPS_KEY_ELEVATION))) * CONV_FT_TO_M;
wmr.setElevation(String.valueOf(elevationInM));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_FIELD_LENGTH)) {
double fieldLengthInM = Double.parseDouble(JSONUtils.getValue(getParamMap().get(WEPS_KEY_FIELD_LENGTH))) * CONV_FT_TO_M;
if (fieldLengthInM <= 0)
appendMetainfoWarning(ErosionConst.WEPS_FIELD_LENGTH_IS_INVALID);
wmr.setSimYLen(String.valueOf(fieldLengthInM));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_FIELD_WIDTH)) {
double fieldWidthInM = Double.parseDouble(JSONUtils.getValue(getParamMap().get(WEPS_KEY_FIELD_WIDTH))) * CONV_FT_TO_M;
if (fieldWidthInM <= 0)
appendMetainfoWarning(ErosionConst.WEPS_FIELD_WIDTH_IS_INVALID);
wmr.setSimXLen(String.valueOf(fieldWidthInM));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_WATER_EROSION_LOSS)) {
double waterErosionLoss = Double.parseDouble(JSONUtils.getValue(getParamMap().get(WEPS_KEY_WATER_EROSION_LOSS))) * CONV_TONACRE_TO_KGM2;
wmr.setWaterErosionLoss(String.valueOf(waterErosionLoss));
}
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_FIELD_ORIENTATION)) {
double fieldOrient = Double.parseDouble(JSONUtils.getValue(getParamMap().get(WEPS_KEY_FIELD_ORIENTATION)));
wmr.setSimRegionAngle(String.valueOf(fieldOrient));
}
} catch (Exception e) {
throw new ServiceException("WEPS error: error processing model run parameters.");
}
}
/*
* Uses's Jim Lyon's LMOD to WEPS mgmt translator to create a WEPS mgmt file
*/
private void loadWepsMgmt() throws ServiceException {
try {
LOG.info("WEPS MGMT exisitence check=" + JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_MANAGEMENT));
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_MANAGEMENT)) {
LOG.info("Attempting to translate WEPS management JSON from LMOD to MAN file");
JSONObject mgmt = JSONUtils.getJSONObjectParam(getParamMap(), WEPS_KEY_MANAGEMENT);
// No longer necessary to change the key names below
// JSONArray params = mgmt.getJSONObject("lmod_file").getJSONObject("params").getJSONArray("param");// I think this is wrong
// Map<String,JSONObject> mgmtParams = JSONUtils.preprocess(params);
// JSONObject op_file = mgmtParams.get(RES_OP_PTR);
// if(op_file == null){
// LOG.info("=======op_file is null");
// }
// LOG.info("gof op object");
// JSONObject veg_file = mgmtParams.get(RES_VEG_PTR);
// LOG.info("got veg object");
//
// op_file.put(KEY_NAME, "OP_PTR:file_key");
// LOG.info("put op");
// veg_file.put(KEY_NAME,"VEG_PTR:file_key");
// LOG.info("put veg");
//
// LOG.info("========================THE NEW JSON PARAMS :"+mgmt.toString());
//
// //LOG.info("The WEPS mgmt is");
// //LOG.info(mgmt.toString());
// LOG.info("setting up translator");
WepsTranslator translator = new WepsTranslator();
translator.setConfigFilename("config/mcrew_start.xml");
translator.setInputManType(ManageData.InputManType.READ_LMOD_MAN_JSON);
translator.setOutputMan(true);
org.json.JSONObject mgmtObj = new org.json.JSONObject(mgmt.toString());
translator.setInputJSONObject(mgmtObj);
translator.setOutputFilename(getWorkspaceDir().toString() + "/" + WEPS_MGMT);
if (translator != null) {
LOG.log(Level.INFO, "input filename =" + translator.getInputFilename());
LOG.log(Level.INFO, "output filename =" + translator.getOutputFilename());
LOG.log(Level.INFO, "rotation years =" + translator.getRotationYears());
LOG.log(Level.INFO, "JSON to translate=" + translator.getInputJSONObject());
}
try {
String error = translator.Translate();
if(error != null)
{
if (Integer.parseInt(error) != 1)
{
LOG.log(Level.SEVERE, "THERE IS AN ERROR CODE RETURNED FROM THE MAN2WEPS TRANSLATOR. Code=" + error);
throw new ServiceException(error);
}
}
} catch (Exception e) {
LOG.log(Level.SEVERE, "FLAT UP EXPLOSION FROM THE WEPS TRANSLATOR:" + e.toString());
if (translator != null) {
//LOG.log(Level.INFO, translator.)
} else {
LOG.log(Level.INFO, "TRANSLATOR IS NULL!");
}
for (StackTraceElement ste : e.getStackTrace()) {
LOG.log(Level.SEVERE, "class=" + ste.getClassName() + " method=" + ste.getMethodName() + " |" + ste.toString());
}
throw new ServiceException("LMOD management translation error executing WEPS");
//return WEPS_ERROR_LMOD_TRANSLATION_ERROR;
}
wmr.setRunCycle(Integer.toString(translator.getRotationYears()));
simulationYears = Integer.parseInt(wmr.getRunCycle()) * NRCS_CYCLE_COUNT;
wmr.setNumYears(Integer.toString(simulationYears));
wmr.setMgmtFile(WEPS_MGMT);
}
} catch (Exception e) {
LOG.log(Level.SEVERE, "STACK TRACE FROM LMOD TRANSLATOR ERROR:");
for (StackTraceElement ste : e.getStackTrace()) {
LOG.log(Level.SEVERE, "class=" + ste.getClassName() + " method=" + ste.getMethodName() + " |" + ste.toString());
}
throw new ServiceException("WEPS error: error translating WEPS mgmt from LMOD.");
}
}
private void getFieldGeometry() throws ServiceException {
// try {
// if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_FIELD_BOUNDARY)) {
// fieldGeometry = JSONUtils.getJSONObjectGeometry(getParamMap(), WEPS_FIELD_BOUNDARY);
// LOG.info("field boundary geometry json obj=" + fieldGeometry);
// String field_json_in = fieldGeometry.toString();
// org.json.JSONTokener field_json_tok = new org.json.JSONTokener(field_json_in);
// org.json.JSONObject field_json_object = new org.json.JSONObject(field_json_tok);
// field_region = new JsonRegion(field_json_object);
// // override provided lat long with centroid of field if available
// // which is then used for wind and climate queries
// wmr.setLat(String.valueOf(field_region.center_y));
// wmr.setLongitude(String.valueOf(field_region.center_x));
// wmr.setSimRegionAngle(String.valueOf(field_region.region_angle));
// //wmr.simXLen = String.valueOf(field_region.getWidth());
// //wmr.simYLen = String.valueOf(field_region.getHeight());
// }
// } catch (Exception e) {
// throw new ServiceException("WEPS error: error processing field geometry");
// }
}
private void getWindBarriers() throws ServiceException {
try {
String barrierdir = "";
if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_BARRIERS)) {
JSONArray barriers = JSONUtils.getJSONArrayParam(getParamMap(), WEPS_KEY_BARRIERS);
if ((barriers != null) && (barriers.length() > 0)) {
LinkedList<Barrier> lstBarriers = new LinkedList<Barrier>();
for (int i = 0; i < barriers.length(); i++) {
Barrier b = new Barrier();
JSONObject barrier = barriers.getJSONObject(i);
LOG.info("barrier obj " + i + "=" + barrier.toString());
JSONObject barriervalue = barrier.optJSONObject("value");
if (barriervalue != null) {
JSONObject lmodfile = barriervalue.optJSONObject("lmod_file");
JSONObject properties = barrier.optJSONObject("properties");
JSONObject barrierGeometry = barrier.optJSONObject(WEPS_GEOMETRY); // pass to Jim's code
if (barrierGeometry != null) {
LOG.info("barrier geometry=" + barrierGeometry.toString());
String barrier_json_in = barrierGeometry.toString();
org.json.JSONTokener barrier_json_tok = new org.json.JSONTokener(barrier_json_in);
org.json.JSONObject barrier_json_object = new org.json.JSONObject(barrier_json_tok);
barrier_region = new JsonRegion(barrier_json_object);
}
// Get barrier values from lmod mgmt json first
LOG.info("lmodfile obj=" + lmodfile.toString());
JSONObject barrierParamObj = lmodfile.optJSONObject("params");
b.type = lmodfile.getString("name");
LOG.info("barrierParamObj=" + barrierParamObj.toString());
JSONArray barrierParams = barrierParamObj.optJSONArray("param");
LOG.info("barrierParams array=" + barrierParams.toString());
for (int j = 0; j < barrierParams.length(); j++) {
JSONObject barrierp = barrierParams.getJSONObject(j);
LOG.info("barrierparam[" + j + "]=" + barrierp.toString());
String thisparam = barrierp.getString("name");
if (thisparam.equals(WEPS_BARRIERPARAM_WIDTH)) {
b.width = trimBrackets(barrierp.getString("data"));
}
if (thisparam.equals(WEPS_BARRIERPARAM_HEIGHT)) {
b.height = trimBrackets(barrierp.getString("data"));
}
if (thisparam.equals(WEPS_BARRIERPARAM_NUM_ROWS)) {
b.number = trimBrackets(barrierp.getString("data"));
}
if (thisparam.equals(WEPS_BARRIERPARAM_POROSITY)) {
b.porosity = trimBrackets(barrierp.getString("data"));
}
}
// check if barrier geometry is available and if so prefer these values instead
//if (field_region != null)
if (barrier_region != null) {
LOG.info("barrier_region obj=" + barrier_region.toString());
barrierdir = barrier_region.getCompassDir(field_region);
b.height = String.valueOf(barrier_region.getHeight());
b.width = String.valueOf(barrier_region.getWidth());
} else {
// The weps barrier location (n s e w) is described based on how coordinates are specified
barrierdir = properties.getString("placement");
}
if (barrierdir.equals(WEPS_BARRIER_NORTH)) {
b.x1 = "0";
b.y1 = wmr.getSimYLen();
b.x2 = wmr.getSimXLen();
b.y2 = Double.toString(Double.parseDouble(wmr.getSimYLen()) + Double.parseDouble(b.width));
}
if (barrierdir.equals(WEPS_BARRIER_SOUTH)) {
b.x1 = "0";
b.y1 = Double.toString(-Double.parseDouble(b.width));
b.x2 = wmr.getSimXLen();
b.y2 = "0";
}
if (barrierdir.equals(WEPS_BARRIER_EAST)) {
b.x1 = wmr.getSimXLen();
b.y1 = "0";
b.x2 = Double.toString(Double.parseDouble(wmr.getSimXLen()) + Double.parseDouble(b.width));
b.y2 = wmr.getSimYLen();
}
if (barrierdir.equals(WEPS_BARRIER_WEST)) {
b.x1 = Double.toString(-Double.parseDouble(b.width));
b.y1 = "0";
b.x2 = "0";
b.y2 = wmr.getSimYLen();
}
lstBarriers.add(b);
}
}
wmr.setNumBarriers(Integer.toString(lstBarriers.size()));
for (int ij = 0; ij < Integer.parseInt(wmr.getNumBarriers()); ij++) {
Barrier b = lstBarriers.get(ij);
LOG.info("Barrier #" + ij + " x1=" + b.x1 + " x2=" + b.x2 + " y1=" + b.y1 + " y2=" + b.y2 + " width=" + b.width + " height=" + b.height + " number=" + b.number + " type=" + b.type + " porosity=" + b.porosity);
}
// A blank dummy barrier is required in the weps.run file if there are none
if (lstBarriers.size() == 0) {
LOG.info("THIS WEPS RUN HAS NO BARRIERS!");
Barrier b = new Barrier();
lstBarriers.add(b);
}
wmr.setBarriers(lstBarriers);
}
}
} catch (Exception e) {
// Handle error in processing barriers
LOG.severe("Error with wind barriers: " + e.toString());
String stackTrace = "";
for (StackTraceElement ste : e.getStackTrace()) {
stackTrace += ste.toString();
}
LOG.severe("stack trace=" + stackTrace);
throw new ServiceException("WEPS error: error processing wind barriers information: " + e.toString());
}
}
private void getClimate() throws ServiceException {
try {
if (db != null)
{
double latitude = Double.parseDouble(wmr.getLat());
double longitude = Double.parseDouble(wmr.getLongitude());
PostGIS.StationResult cligenStation = null;
// check if the field lat/long intersects any cli station geometries first- and use it if so
PostGIS.StationResult cliStation = db.cliGeomIntersect(latitude, longitude);
if (cliStation != null)
{
LOG.info("The cliStation name is '" + cliStation.name + "'");
if (cliStation.name.contentEquals("Out"))
{
// in the mountain west polygon - use the nearest cligen station
cligenStation = db.findCligenStation(latitude, longitude);
}
else
{
// use the cli station found by intersecting the climate station geometries
cligenStation = cliStation;
}
}
else
{
// get climate station for this lat / long
LOG.info("FIND NEAREST CLIGEN STATION!");
LOG.info("lat=" + wmr.getLat());
LOG.info("long=" + wmr.getLongitude());
// not in the mountain west polygon, did not intersect any climate station, use the nearest station
cligenStation = db.findCligenStation(Double.parseDouble(wmr.getLat()), Double.parseDouble(wmr.getLongitude()));
}
// generate cli file using this station
LOG.info("using cligen station=" + cligenStation.stationId);
if (wmr.getElevation().equals(WepsModelRun.UNSET_ELEVATION))
{
wmr.setElevation(cligenStation.elevation);
}
ProcessComponent pcCliGen = new ProcessComponent();
pcCliGen.working_dir = sessionWorkDir;
LOG.info("extract cligen to:/bin/" + Binaries.getArch());
LOG.info("binDir is=" + binDir);
pcCliGen.exe = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/cligen", new File(binDir)).toString();
LOG.info("extract climate db");
String dbpath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/upd_US_cligen_stations.par", new File(binDir)).toString();
pcCliGen.args = new String[]{"-S" + cligenStation.state, "-s" + cligenStation.stationId, "-i" + dbpath, "-t5", "-I3", "-F", "-b01", "-y" + simulationYears, "-o" + sessionWorkDir + "/cligen.cli"};
LOG.log(Level.INFO, "cligen args=" + pcCliGen.args.toString());
pcCliGen.execute();
// prefer lat/long generated climates file for weps run
//wmr.cliFile = "cligen.cli";
}
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException("WEPS error: error generating climate data:" + e.toString());
}
}
private void generateWindData() throws ServiceException {
try {
sWindgenStation = null;
// Always generate wind data for lat / long using wingen and possible interpolate program
if (db != null) {
double latitude = Double.parseDouble(wmr.getLat());
double longitude = Double.parseDouble(wmr.getLongitude());
// check if the field lat/long intersects any wind station geometries first- and use it if so
PostGIS.StationResult windStation = db.windGeomIntersect(latitude, longitude);
if (windStation != null)
{
LOG.info("The intersected windStation name is '" + windStation.name + "'");
// Check for Out or INT polygons - these are not wind stations, just filler polygons
if ((windStation.name.contentEquals("Out")) || (windStation.name.contentEquals("INT")))
{
sWindgenStation = null;
}
else
{
sWindgenStation = windStation.stationId.trim();
windDbPath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/" + DEFAULT_WIND_STATION_DB, new File(binDir)).toString();
}
}
// Do we still need to populate the windgen station???
if (sWindgenStation == null)
{
// next check if in the interpolation boundary shape, if so, interpolate 3 nearest wind stations
// to generate an interpolated station
LOG.log(Level.INFO, "Check if lat/long is in interpolation boundary");
if (db.IsInInterpolateBoundary(latitude, longitude)) {
LOG.log(Level.INFO, "YES! lat/long is in interpolation boundary");
// Generate wind station interpolation
// Generate weights file
ProcessComponent pcInterpolate = new ProcessComponent();
String exepath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/interpolate", new File(binDir)).toString();
String dbpath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/wind_gen_his_upper_US_NRCS.idx", new File(binDir)).toString();
String polygon = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/interpolation_boundary.pol", new File(binDir)).toString();
// Get the county centroid for wind interpolation
PostGIS.County wepsCounty = db.countyCentroid(latitude, longitude);
// Generate shell script to invoke interpolate
File interpolatesh = new File(sessionWorkDir + "/interpolate.sh");
String invokeInterpolate = exepath + " -f " + dbpath + " -p " + polygon + " -lat " + wepsCounty.county_centroid_Y + " -long " + wepsCounty.county_centroid_X;
FileUtils.writeStringToFile(interpolatesh, invokeInterpolate);
interpolatesh.setExecutable(true);
pcInterpolate.working_dir = sessionWorkDir;
pcInterpolate.exe = "./interpolate.sh";
pcInterpolate.args = new String[]{};
pcInterpolate.execute();
// Added small delay because occasionally the stdout was incomplete upon parsing
Thread.sleep(300);
WeightsParser wp = new WeightsParser();
wp.weightsFile = pcInterpolate.stdout;
wp.exitValue = pcInterpolate.exitValue;
wp.weightsErr = pcInterpolate.stderr;
LOG.info("exit value from pcInterpolate execution=" + pcInterpolate.exitValue);
// must process this monstrosity
wp.parse();
if ((wp.station1 > 0) & (wp.station2 > 0) && (wp.station3 > 0)) {
// If there are wind stations then, generate interpolate wind station wdb file
// Note the interp_wdb program is ancient Fortran and can not handle file paths of any length
// therefore everything has to be extracted to the workdir and done locally there.
// This is BAD (inefficient) because it is extra work to always extract wind station wdb's for every model run!
ProcessComponent pcInterpWdb = new ProcessComponent();
exepath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/interp_wdb", new File(binDir)).toString();
// String station1Db = BinUtils.unpackResourceAbsolute("/bin/" + BinUtils.getArch() + "/windstations/" + wp.station1 + ".wdb", sessionWorkDir + "/" + wp.station1 + ".wdb").toString();
// String station2Db = BinUtils.unpackResourceAbsolute("/bin/" + BinUtils.getArch() + "/windstations/" + wp.station2 + ".wdb", sessionWorkDir + "/" + wp.station2 + ".wdb").toString();
// String station3Db = BinUtils.unpackResourceAbsolute("/bin/" + BinUtils.getArch() + "/windstations/" + wp.station3 + ".wdb", sessionWorkDir + "/" + wp.station3 + ".wdb").toString();
String station1Db = getWindStationFile(wp.station1);
String station2Db = getWindStationFile(wp.station2);
String station3Db = getWindStationFile(wp.station3);
// Generate shell script to invoke interpolate
File interpwdbsh = new File(sessionWorkDir + "/interpwdb.sh");
String invokeInterpWdb = exepath + " test.wdb" + " " + station1Db + wp.weight1 + " " + station2Db + wp.weight2 + " " + station3Db + wp.weight3;
FileUtils.writeStringToFile(interpwdbsh, invokeInterpWdb);
interpwdbsh.setExecutable(true);
pcInterpWdb.working_dir = sessionWorkDir;
pcInterpWdb.exe = "./interpwdb.sh";
pcInterpWdb.args = new String[]{};
pcInterpWdb.execute();
windDbPath = "test.wdb";
sWindgenStation = "999999"; // this is the magic number indicating its an interpolated wind station!
}
}
// otherwise, just use data from nearest wind station:
// If this is not using an interpolated wind station, then use the default closest one...
if (windDbPath.length() == 0) {
LOG.log(Level.INFO, "NO! lat/long is NOT in interpolation boundary");
// get wind generation station for this lat / long
LOG.info("FIND NEAREST WIND STATION!");
LOG.info("lat=" + wmr.getLat());
LOG.info("long=" + wmr.getLongitude());
PostGIS.StationResult windgenStation = db.findWindgenStation(Double.parseDouble(wmr.getLat()), Double.parseDouble(wmr.getLongitude()));
LOG.info("windgen station is=" + windgenStation.stationId);
sWindgenStation = windgenStation.stationId.trim();
windDbPath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/" + DEFAULT_WIND_STATION_DB, new File(binDir)).toString();
}
}
// generate win file using this station (or interpolated one)
ProcessComponent pcWindGen = new ProcessComponent();
String exepath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/wind_gen4", new File(binDir)).toString();
String winexepath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/wind_gen4.exe", new File(binDir)).toString();
LOG.log(Level.INFO, "Using wind database:" + windDbPath);
// Generate shell script to invoke windgen
File windgensh = new File(sessionWorkDir + "/windgen.sh");
//String invokeWinGen = exepath + " -f " + windDbPath + " -b 01 -y " + simulationYears + " -o thewind.win -s " + sWindgenStation;
String invokeWinGen = "wine " + winexepath + " -f " + windDbPath + " -b 01 -y " + simulationYears + " -o thewind.win -s " + sWindgenStation;
FileUtils.writeStringToFile(windgensh, invokeWinGen);
windgensh.setExecutable(true);
pcWindGen.working_dir = sessionWorkDir;
String cmd = "./windgen.sh";
pcWindGen.args = new String[]{};
pcWindGen.exe = cmd;
pcWindGen.execute();
//wmr.winFile = "thewind.win";
}
} catch (Exception e) {
throw new ServiceException("WEPS error: error generating wind data");
}
}
private String getWindStationFile(int windStationId) throws ServiceException {
String wepsdb = Config.getString("weps.db", "http://oms-db.engr.colostate.edu/weps");
String windStation = WIND_STATIONS_DIR + "/" + windStationId + WIND_STATION_FILE_EXT;
// Get wind station file and write to temp space
String fileToGet = wepsdb + "/" + windStation;
LOG.log(Level.INFO, "wind station file to get=" + fileToGet);
getFile(fileToGet, sessionWorkDir, windStationId + WIND_STATION_FILE_EXT);
// Return file name of retrieved wind station
// An extra space is appended for interp_wdb.exe use on command line
wmr.setSoilFile(windStationId + WIND_STATION_FILE_EXT + " ");
return wmr.getSoilFile();
}
private void getSoilIfc() throws ServiceException {
String wepsdb = Config.getString("weps.db", "http://oms-db.engr.colostate.edu/weps");
PostGIS.FileQryResult soil = null;
try {
// Use user provided soil key to look up and acquire soils file
LOG.log(Level.INFO, "WEPS soilkey=" + soilkey);
LOG.log(Level.INFO, "WEPS soilfile=" + soilfile);
if ((soilfile == null) || ((soilfile != null) && (soilfile.length() < 1)))
{
LOG.log(Level.INFO, "Not using WEPS soilfile pointer for soil");
if (db != null)
{
LOG.log(Level.INFO, "Get WEPS soils using database");
if ((soilkey != null) && (soilkey.length() > 0))
{
LOG.log(Level.INFO, "USING provided WEPS soil component key=" + soilkey);
soil = db.findSoilsWepsByCokey(soilkey, Double.parseDouble(wmr.getLongitude()));
}
else
{
LOG.log(Level.INFO, "Attempting to resolve WEPS soil by lat=" + wmr.getLat() + " and long=" + wmr.getLongitude());
soil = db.findSoilsWeps(Double.parseDouble(wmr.getLat()), Double.parseDouble(wmr.getLongitude()));
}
if (soil == null)
{
LOG.log(Level.WARNING, "No soil for lat=" + wmr.getLat() + "\nfor long=" + wmr.getLongitude() + "\n");
soilPtr = "";
if ((soilkey != null) && (soilkey.length() > 0)) {
throw new ServiceException("WEPS error: no soil available for cokey");
} else {
throw new ServiceException("WEPS error: no soil available for provided lat/long coordinates");
}
}
else
soilPtr = soil.file_path + "/" + soil.file_name + SOIL_FILE_EXT;
}
}
else
{
// use provided soil file pointer
LOG.log(Level.INFO, "USING provided WEPS soil ptr=" + soilPtr);
soilPtr = soilfile + SOIL_FILE_EXT;
File soil_file = new File(soilfile);
soil = new FileQryResult();
soil.file_name = soil_file.getName();
soil.file_path = soil_file.getAbsolutePath();
}
// Get soil file and write to temp space
String fileToGet = wepsdb + "/" + soilPtr;
LOG.log(Level.INFO, "soils file to get=" + fileToGet);
LOG.log(Level.INFO, "soils file name=" + soil.file_name);
LOG.log(Level.INFO, "soils file path=" + soil.file_path);
getFile(fileToGet, sessionWorkDir, soil.file_name + SOIL_FILE_EXT);
// Prefer lat/long retrieved soils file
wmr.setSoilFile(soil.file_name + SOIL_FILE_EXT);
} catch (Exception e) {
throw new ServiceException("WEPS error: error retrieiving soil data");
}
}
private void getFile(String url, String destDir, String filename) {
FileOutputStream fos = null;
try {
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpResponse response = client.execute((HttpUriRequest) httpget);
byte[] soilData = IOUtils.toByteArray(response.getEntity().getContent());
fos = new FileOutputStream(new File(destDir + "/" + filename));
fos.write(soilData);
fos.close();
} catch (IOException ie) {
LOG.log(Level.SEVERE, "ERROR GETTING SOILS IFC FILE!:" + ie.toString());
} finally {
if (fos != null) {
try {
fos.close();
} catch (Exception fe) {
}
}
}
}
private String trimBrackets(String sText) {
return sText.substring(1, sText.length() - 1);
}
@Override
protected File[] postprocess() throws Exception {
File simDir = getWorkspaceDir();
return new File[] {
new File(simDir, "stir_energy.out"),
new File(simDir, "sci_energy.out"),
new File(simDir, "stdout.txt"),
new File(simDir, "stderr.txt")
};
}
@Override
public JSONArray createResults() throws Exception {
LOG.info("Create the WEPS results...");
JSONArray results = new JSONArray();
String outUrl = Config.getString("m.results.url", "http://localhost:8084/csip/q/");
String baseUrl = outUrl + getSUID();
FileReader fr = new FileReader(sessionWorkDir + "/sci_energy.out");
BufferedReader bfr = new BufferedReader(fr);
String sciEnergyOut = "";
while (bfr.ready()) {
sciEnergyOut += bfr.readLine();
}
bfr.close();
fr.close();
wo = SciEnergyParser.parseSciEnergyFile(sciEnergyOut);
if (wo.bNaN)
appendMetainfoWarning(ErosionConst.WEPS_FOUND_NAN_IN_OUTPUT);
FileReader fr2 = new FileReader(sessionWorkDir +"/gui1_data.out");
BufferedReader bfr2 = new BufferedReader(fr2);
String guiString = "";
while(bfr2.ready()){
guiString += bfr2.readLine();
}
bfr2.close();
fr2.close();
GUI1Parser.parseGUI1(guiString, wo);
// Special unit conversions for Phacil
double dieselEnergy_gallonsPerAcre = Double.parseDouble(wo.dieselEnergy) * CONV_LITERHECTATRE_TO_GALLONACRE;
double averageBiomass_tonAcreYear = Double.parseDouble(wo.averageBiomass) * CONV_KGM2_TONACRE;
double windEros_tonAcreYear = Double.parseDouble(wo.windEros) * CONV_KGM2_TONACRE;
double waterEros_tonAcreYear = Double.parseDouble(wo.waterEros) * CONV_KGM2_TONACRE;
results.put(JSONUtils.dataDesc(WEPS_RES_SOIL_COND_INDEX, wo.soilConditioningIndex, "total SCI (soil conditioning index)"));
results.put(JSONUtils.dataDesc(WEPS_RES_SCI_OM_FACTOR, wo.sciOmFactor, "SCI Organic Matter subfactor"));
results.put(JSONUtils.dataDesc(WEPS_RES_SCI_ER_FACTOR, wo.sciErFactor, "SCI Erosion Rate subfactor"));
results.put(JSONUtils.dataDesc(WEPS_RES_SCI_FO_FACTOR, wo.sciFoFactor, "SCI Field Operations subfactor"));
results.put(JSONUtils.dataUnitDesc(WEPS_RES_DIESEL_ENERGY, dieselEnergy_gallonsPerAcre, "gallon(Diesel)/acre", "energy used by management operations, expressed as fuel consumption equivalent"));
results.put(JSONUtils.dataUnitDesc(WEPS_RES_AVG_BIOMASS, averageBiomass_tonAcreYear, "ton/acre/year", "Average biomass"));
results.put(JSONUtils.dataUnitDesc(WEPS_RES_WIND_EROS, windEros_tonAcreYear, "ton/acre/year", "Wind erosion (computed by WEPS)"));
results.put(JSONUtils.dataUnitDesc(WEPS_RES_WATER_EROS, waterEros_tonAcreYear, "ton/acre/year", "Water erosion (external input)"));
results.put(JSONUtils.dataDesc(WEPS_RES_AVG_ALL_STIR, wo.avgAllStir, "Average STIR"));
results.put(JSONUtils.data(WEPS_SALTATION, wo.saltation));
results.put(JSONUtils.data(WEPS_SUSPENSION, wo.suspension));
results.put(JSONUtils.data(WEPS_PM10, wo.pm10));
// results.put(JSONUtils.data("sci", baseUrl + "/sci_energy.out"));
// results.put(JSONUtils.data("stir", baseUrl + "/strir_energy.out"));
// results.put(JSONUtils.data("stdout", baseUrl + "/stdout.txt"));
// results.put(JSONUtils.data("stderr", baseUrl + "/stderr.txt"));
return results;
}
// @Override
// public String getModelName() {
// return "weps/1.2";
// }
@Override
public long getNextPoll() {
return 2000; // poll every 2 seconds after the first poll
}
@Override
protected long getFirstPoll() {
// to do
// this should be based on the number of years of the weps run
return 25000; // wait 25 seconds for the first poll.
}
// @Override
// protected JSONObject describe() throws JSONException {
//
// JSONArray p = new JSONArray();
//
// JSONObject metainfo = new JSONObject();
////// metainfo.put(KEY_REQUEST_RESULTS, new JSONArray(potResults));
//
// JSONObject model = new JSONObject();
// model.put(KEY_PARAMETER, p);
// model.put(KEY_METAINFO, metainfo);
// return model;
// }
@Override
protected JSONArray createReport() throws Exception {
String workDir = getWorkspaceDir().toString();
File reportTemplate = new File(workDir + "/" + REPORT_JSON_FILENAME);
String sReportJSON = FileUtils.readFileToString(reportTemplate);
//JSONObject reportObj = new JSONObject(sReportJSON);
//JSONArray reportItems = reportObj.getJSONArray("WEPSreport");
JSONArray reportItems = new JSONArray(sReportJSON);
WepsConnection con = new WepsConnection();
// Create an instance of this class to do the actual loading.
WepsReportData reportdata = new WepsReportData(con);
// Set the location of the folder to translate files in.
String sInputDirectory = workDir;
if (!reportdata.setInputDirectory(sInputDirectory)) {
// Print a usage message and quit
LOG.severe("error: WEPS reports input directory doesn't exist.");
throw new ServiceException("Error create WEPS reports. Report directory does not exist.");
}
// @todo set configuration options.
reportdata.m_sUnits = "US";
// Load the file data.
LOG.info("WorkingDir: "+ getWorkspaceDir().toString());
reportdata.loadFiles(getWorkspaceDir().toString());
// // Dump the loaded data as text for debugging purposes.
// LOG.info("hash map output=" + con.toString());
//
// LOG.info("Original Report JSON obj=" + reportObj.toString());
HashMap<String, ArrayList<Object>> m_reportdata = con.getParamValues();
for (int i = 0; i < reportItems.length(); i++) {
JSONObject obj = (JSONObject) reportItems.get(i);
String itemName = obj.getString(REPORT_NAME);
//LOG.info("COMPARISON for scalars: itemname='" + itemName + "'");
//if (itemName.length() >= 5) LOG.info("COMPARISON for scalars: itemname 0,5='" + itemName.substring(0,5) + "'");
//if (itemName.length() >= 11) LOG.info("COMPARISON for scalars: itemname 0,11='" + itemName.substring(0,11) + "'");
if ((itemName != null) && ((((itemName.length()) >= 5) && (itemName.substring(0, 5).contentEquals("runs.")))
|| (((itemName.length()) >= 11) && (itemName.substring(0, 11).contentEquals("sci_energy."))))) {
// Scalar values
//LOG.info("look up " + itemName + " in report hash table for scalar output.");
ArrayList<Object> scalar = m_reportdata.get(itemName);
if (scalar != null) {
//LOG.info("putting to jsonobj=" + scalar.get(0));
obj.put(REPORT_VALUE, scalar.get(0));
reportItems.put(i, obj);
} else {
LOG.warning("WEPS report generatioin: Scalar parameter has no data in hashmap=" + itemName);
}
} else {
// Array values
//LOG.info("look up " + itemName + " in report hash table for array output.");
LinkedList coll = new LinkedList();
ArrayList<Object> array = m_reportdata.get(itemName);
if (array != null) {
for (int j = 0; j < array.size(); j++) {
coll.add(array.get(j));
}
obj.put(REPORT_VALUE, (Collection) coll);
reportItems.put(i, obj);
} else {
LOG.warning("WEPS report generation: Array parameter has no data in hashmap=" + itemName);
}
}
obj.remove(REPORT_TYPE);
}
//LOG.info("Updated Report JSON obj=" + reportObj.toString());
return reportItems;
}
}