V1_3.java [src/java/m/weps] Revision: eb5986b2c84408f910ddb9b407fc0082ebaba65d  Date: Wed May 11 13:30:24 MDT 2016
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package m.weps;

import c.GIS_DB;
import c.PostGIS;
import c.GIS_DB.FileQryResult;
import c.GIS_DB_Factory;
import csip.Config;
import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.Polling;
import csip.utils.Binaries;
import csip.utils.JSONUtils;
import java.io.*;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
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.JSONException;
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")
@Polling(first = 25000, next = 2000)
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 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 GIS_DB db = null;
    private String binDir = "";
    private String soilPtr = "";
    private String soilFilename = "";
    private String windDbPath = "";
    private String sWindgenStation = "";
    private boolean cropCalibrationMode = false;


    @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
    protected String process() throws Exception {
        String error = null;
        ProcessComponent pc = new ProcessComponent();
        try {
            db = GIS_DB_Factory.createGISEngine();
        } catch (Exception e) {
            LOG.severe("Error obtaining DB connection in WEPS run!");
            throw new ServiceException("WEPS error: Cannot obtain geospatial db connection", e);
        }

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

            // 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
            error = loadWepsMgmt();
            LOG.info("ERROR: " + error);
            if (error == null) {
                // Get field geometry
                getFieldGeometry();

                // get wind barriers
                getWindBarriers();

                // Get climate info
                getClimate();

                // Get wind info
                generateWindData();

                // Get soils data
                getSoilIfc();

                // run WEPS model
                try {
                    // The WEPS GUI requires an empty notes.txt file per LEW to run
                    String emptyString = "";
                    File notes_txt = new File(sessionWorkDir + "/notes.txt");
                    FileUtils.writeStringToFile(notes_txt, emptyString);

                    // 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
                    LOG.info("starting process");
                    pc = new ProcessComponent();

                    // linux based WEPS
                    pc.exe = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/weps.exe", new File(binDir)).toString();
                    // C15 tells WEPS to perform up to 15 calibration cycles for convergence, could do fewer cycles
                    // Z50 is required with calibration flag
                    String[] wepsArgs = (cropCalibrationMode ? new String[]{"-W1", "-u0", "-I2", "-t1", "-T1", "-P./", "-C15", "-Z50"}
                            : new String[]{"-W1", "-u0", "-I2", "-t1", "-T1", "-P./"});
                    pc.args = wepsArgs;
                    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);
                }
                return pc.exitValue == 0 ? EXEC_OK : EXEC_FAILED;
            } else {
                return error;
            }
        } catch (Exception e) {
            LOG.log(Level.SEVERE, "ERROR EXECUTING WEPS", e);
            throw new ServiceException("WEPS error: unknown error executing WEPS model>", e);
        }
    }


    /*
     * Checks for the existence of required WEPS parameters.
     * Loads them into proper variables for running the model.
     */
    private void loadRequiredParameters() throws ServiceException {
        try {
            LOG.info("SOIL_KEY");
            if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL)) {
                soilkey = JSONUtils.getValue(getParamMap().get(WEPS_KEY_SOIL));
            }
            LOG.info("SOIL_FILE");
            if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL_FILE)) {
                soilfile = JSONUtils.getValue(getParamMap().get(WEPS_KEY_SOIL_FILE));
            }
            LOG.info("SET_LAT");
            if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_LATITUDE)) {
                wmr.setLat(JSONUtils.getValue(getParamMap().get(WEPS_KEY_LATITUDE)));
            }
            LOG.info("SET_LONG");
            if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_LONGITUDE)) {
                wmr.setLongitude(JSONUtils.getValue(getParamMap().get(WEPS_KEY_LONGITUDE)));
            }
            LOG.info("SET_ELEVATION");
            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));
            }
            LOG.info("SET_LENGTH");
            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));
            }
            LOG.info("WIDTH");
            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));
            }
            LOG.info("EROSION_LOSS");
            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));
            }
            LOG.info("ORIENTATION");
            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));
            }

            LOG.info("SOIL_ROCK_FRAGMENTS");
            if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL_ROCK_FRAGMENTS)) {
                double rockFragments = Double.parseDouble(JSONUtils.getValue(getParamMap().get(WEPS_KEY_SOIL_ROCK_FRAGMENTS)));
                wmr.setSoilRockFragments(String.valueOf(rockFragments));
            }

            LOG.info("WEPS Crop Calibration Mode");
            if (JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_CROP_CALIBRATION_MODE)) {
                cropCalibrationMode = Boolean.parseBoolean(JSONUtils.getValue(getParamMap().get(WEPS_KEY_CROP_CALIBRATION_MODE)));
            }

        } catch (Exception e) {
            throw new ServiceException("WEPS error: error processing model run parameters.", e);
        }
    }


    /*
     * Uses's Jim Lyon's LMOD to WEPS mgmt translator to create a WEPS mgmt file
     */
    private String loadWepsMgmt() throws ServiceException {
        String error = null;
        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);
                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 {
                    error = translator.Translate();
                    LOG.log(Level.INFO, "OUTPUT FROM THE TRANSLATOR ='" + error + "'");
                    if (error != null) {
                        try {
                            if (Integer.parseInt(error) != 1) {
                                LOG.log(Level.SEVERE, "THERE IS AN ERROR CODE RETURNED FROM THE MAN2WEPS TRANSLATOR. Code=" + error);
                                throw new ServiceException("THERE IS AN ERROR CODE RETURNED FROM THE MAN2WEPS TRANSLATOR.");
                            }
                        } catch (NumberFormatException ex) { // I want to transition the numeric errors to string errors like this
                            LOG.log(Level.SEVERE, "THERE IS AN ERROR: ", ex);
                            throw new ServiceException("LMOD management translation error executing WEPS", ex);
                        }
                    }
                } catch (Exception e) {
                    LOG.log(Level.SEVERE, "FLAT UP EXPLOSION FROM THE WEPS TRANSLATOR:", e);
                    throw new ServiceException("LMOD management translation error executing WEPS", e);
                    //return WEPS_ERROR_LMOD_TRANSLATION_ERROR;
                }
//                if (error != null)
//                {
                // Set these values no matter what
                wmr.setRunCycle(Integer.toString(translator.getRotationYears()));
                LOG.log(Level.INFO, "*****************************************************set run cycle=" + wmr.getRunCycle());
                simulationYears = Integer.parseInt(wmr.getRunCycle()) * NRCS_CYCLE_COUNT;
                wmr.setNumYears(Integer.toString(simulationYears));
//                }
            }
        } catch (Exception e) {
            LOG.log(Level.SEVERE, "LMOD TRANSLATOR ERROR:", e);
            throw new ServiceException("WEPS error: error translating WEPS mgmt from LMOD.", e);
        }
        LOG.log(Level.INFO, "*****************************************************LEAVING loadWepsMgmt");
        LOG.log(Level.INFO, "*****************************************************set run cycle=" + wmr.getRunCycle());
        LOG.log(Level.INFO, "*****************************************************set num years=" + wmr.getNumYears());
        return error;
    }


    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.log(Level.SEVERE, "Error with wind barriers: ", e);
            throw new ServiceException("WEPS error: error processing wind barriers information: ", e);
        }
    }


    private void getClimate() throws ServiceException {
        try {
            if (db != null) {
                double latitude = Double.parseDouble(wmr.getLat());
                double longitude = Double.parseDouble(wmr.getLongitude());
                GIS_DB.StationResult cligenStation = null;

                // check if the field lat/long intersects any cli station geometries first- and use it if so
                GIS_DB.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);
                        LOG.info("***************************************************************set cligen station 1=" + cligenStation.name);

                    } else {
                        // use the cli station found by intersecting the climate station geometries
                        cligenStation = cliStation;
                        LOG.info("***************************************************************set cligen station 2=" + cligenStation.name);

                    }
                } 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()));
                    LOG.info("***************************************************************set cligen station 3=" + cligenStation.name);

                }
                // generate cli file using this station
                LOG.info("***************************************************************using cligen station=" + cligenStation.name);
                if (wmr.getElevation().equals(WepsModelRun.UNSET_ELEVATION)) {
                    wmr.setElevation(cligenStation.elevation);
                }

                // populate cli gen station parameters in weps.run file
                wmr.setCliStationLong(cligenStation.stationX);
                wmr.setCliStationLat(cligenStation.stationY);
                wmr.setCliStationStateFips(cligenStation.state);
                wmr.setCliStationC1(cligenStation.stationId);
                wmr.setCliStationName(cligenStation.name);
                wmr.setCliStationEleM(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.exe", 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 + "/cli_gen.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) {
            LOG.log(Level.SEVERE, "Error", e);
            throw new ServiceException("WEPS error: error generating climate data:", e);
        }
    }


    private void generateWindData() throws ServiceException {
        try {
            boolean bInterpolatedWind = false;
            GIS_DB.County wepsCounty = null;
            GIS_DB.StationResult windStationForWepsRunFile = null;
            wmr.setWinFile("win_gen.win");
            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
                GIS_DB.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();
                        windStationForWepsRunFile = windStation;
                        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
                        wmr.setWinFile("interpolate.win");

                        // Generate weights file
                        ProcessComponent pcInterpolate = new ProcessComponent();

                        // linux
                        String exepath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/interpolate.exe", 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
                        wepsCounty = db.countyCentroid(latitude, longitude);

                        // Generate shell script to invoke interpolate
                        File interpolatesh = new File(sessionWorkDir + "/interpolate.sh");
                        NumberFormat nf = DecimalFormat.getInstance();
                        int windInterpolationDecimalDigits = Config.getInt("weps.wind_interpolate_precision", 2);
                        nf.setMaximumFractionDigits(windInterpolationDecimalDigits);
                        nf.setMinimumFractionDigits(windInterpolationDecimalDigits);
                        nf.setRoundingMode(RoundingMode.HALF_UP);
                        double countyCentroidLat = Double.parseDouble(wepsCounty.county_centroid_Y);
                        double countyCentroidLon = Double.parseDouble(wepsCounty.county_centroid_X);
                        LOG.log(Level.INFO, "***county centroid lat=" + countyCentroidLat + " lon=" + countyCentroidLon);
                        // linux
                        String invokeInterpolate = exepath + " -f " + dbpath + " -p " + polygon + " -lat " + nf.format(countyCentroidLat) + " -long " + nf.format(countyCentroidLon);
                        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);

                        bInterpolatedWind = true;
                        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();

                            // linux
                            exepath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/interp_wdb.exe", 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");
                            // windows
                            //String invokeInterpWdb = "wine " + exepath + " test.wdb" + " " + station1Db + wp.weight1 + " " + station2Db + wp.weight2 + " " + station3Db + wp.weight3;
                            // linux
                            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!
                        }

                        // for wind interpolation, report the nearest wind gen station in the weps.run file for now
                        // check with Fred to verify if this is correct behavior for the weps gui
                        windStationForWepsRunFile = db.findWindgenStation(Double.parseDouble(wmr.getLat()), Double.parseDouble(wmr.getLongitude()));
                        // to do
                        // in this case, we are getting the wind gen station from the "wingen_stations" table which does not provide
                        // lat long values, so we are using the model run's coordinates.  We will need to include wind gen station coordinate data
                        // in the database in order to provide it.
                        windStationForWepsRunFile.stationX = wmr.getLongitude();
                        windStationForWepsRunFile.stationY = wmr.getLat();
                    }

                    // 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());

                        GIS_DB.StationResult windgenStation = db.findWindgenStation(Double.parseDouble(wmr.getLat()), Double.parseDouble(wmr.getLongitude()));
                        LOG.info("windgen station is=" + windgenStation.stationId);
                        sWindgenStation = windgenStation.stationId.trim();
                        windStationForWepsRunFile = windgenStation;
                        // to do
                        // in this case, we are getting the wind gen station from the "wingen_stations" table which does not provide
                        // lat long values, so we are using the model run's coordinates.  We will need to include wind gen station coordinate data
                        // in the database in order to provide it.
                        windStationForWepsRunFile.stationX = wmr.getLongitude();
                        windStationForWepsRunFile.stationY = wmr.getLat();

                        windDbPath = Binaries.unpackResource("/bin/" + Binaries.getArch() + "/" + DEFAULT_WIND_STATION_DB, new File(binDir)).toString();
                    }
                }

                // populate wind gen station parameters in the weps.run file 
                wmr.setWinWindLat(windStationForWepsRunFile.stationY);
                wmr.setWinWindLong(windStationForWepsRunFile.stationX);
                wmr.setWinWindStation(windStationForWepsRunFile.stationId);
                wmr.setWinWindCountry(windStationForWepsRunFile.country);
                wmr.setWinWindState(windStationForWepsRunFile.state);
                wmr.setWinWindStationName(windStationForWepsRunFile.name);
                wmr.setWinWindDescriptionString("|" + wmr.getWinWindStation() + "|" + wmr.getWinWindCountry() + "|" + wmr.getWinWindState() + "|" + wmr.getWinWindStationName());

                // make adjustments if wind is interpolated in weps.run
                if (bInterpolatedWind) {
                    wmr.setWinWindGenProgram("interpolated");
                    if (wepsCounty != null) {
                        wmr.setWinWindLat(wepsCounty.county_centroid_Y);
                        wmr.setWinWindLong(wepsCounty.county_centroid_X);
                    }
                    LOG.log(Level.INFO, "*******************************************WIND IS INTERPOLATED-SETTING DESC STRING TO EMPTY!");
                    wmr.setWinWindDescriptionString("");
                }

                // populate state and county code params in the weps.run file
                GIS_DB.County cnty = db.findCounty(latitude, longitude);
                wmr.setStateSite(cnty.st_abbr);
                wmr.setCountySite(cnty.county_code);
                LOG.log(Level.INFO, "*******************************************AS SET IN WMR county site=" + wmr.getCountySite());
                LOG.log(Level.INFO, "*******************************************AS SET IN WMR state site=" + wmr.getStateSite());

                // generate win file using this station (or interpolated one)
                ProcessComponent pcWindGen = new ProcessComponent();
                String winexepath = Binaries.unpackResource("/bin/win-x86/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 " + wmr.getWinFile() + " -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", e);
        }
    }


    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");
        GIS_DB.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", e);
        }
    }


    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());
            throw new RuntimeException(ie);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception fe) {
                }
            }
        }
    }


    private String trimBrackets(String sText) {
        return sText.substring(1, sText.length() - 1);
    }


    @Override
    protected void postProcess() throws Exception {
        putResult(new File(getWorkspaceDir(), "stir_energy.out"));
        putResult(new File(getWorkspaceDir(), "sci_energy.out"));
        putResult(new File(getWorkspaceDir(), "stdout.txt"));
        putResult(new File(getWorkspaceDir(), "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);
        }

        getAdvancedOutput(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));

        return results;
    }


    private void getAdvancedOutput(WepsOutput wOutput) throws JSONException, Exception {
        JSONArray reportItems = new JSONArray();
        JSONObject item = new JSONObject();
        JSONArray report;
        Map<String, JSONObject> reportValues;
        JSONArray suspen;
        JSONArray salt;
        JSONArray pm10;

        item.put("name", "output.suspen");
        reportItems.put(item);

        item = new JSONObject();
        item.put("name", "output.crp_salt");
        reportItems.put(item);

        item = new JSONObject();
        item.put("name", "output.pm10");
        reportItems.put(item);

        report = createReport(reportItems);

        reportValues = JSONUtils.preprocess(report);

        suspen = JSONUtils.getJSONArrayParam(reportValues, "output.suspen");
        salt = JSONUtils.getJSONArrayParam(reportValues, "output.crp_salt");
        pm10 = JSONUtils.getJSONArrayParam(reportValues, "output.pm10");

        wo.suspension = suspen.getString(suspen.length() - 1);
        wo.saltation = salt.getString(salt.length() - 1);
        wo.pm10 = pm10.getString(pm10.length() - 1);
    }


    @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;
    }


    /**
     * This is an overloaded method for createReport that allows you to only
     * query a set of item in a report
     * @param reportItems items you want returned in the report
     * @return The report data
     * @throws Exception
     */
    private JSONArray createReport(JSONArray reportItems) 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");
        if (reportItems == null || reportItems.length() == 0) {
            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;
    }
}