V1_4.java [src/java/m/weps] Revision: b95b2313f6f8d023985f516581f980c6e921f95e  Date: Tue Apr 11 13:47:28 MDT 2017
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package m.weps;

import c.GIS_DB;
import c.GIS_DB.FileQryResult;
import c.GIS_DB_Factory;
import csip.*;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;
import csip.utils.JSONUtils;
import oms3.annotations.*;
import usda.weru.weps.reports.query.WepsConnection;
import wepsreportdata.WepsReportData;
import java.io.*;
import java.math.RoundingMode;
import java.net.URI;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.Path;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import man2weps.WepsTranslator;
import man2weps.mcrew.ManageData;
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.*;
import static util.ErosionConst.*;
import static m.weps.V1_4.*;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * WEPS Model Service.
 *
 * @author wlloyd, od
 */
@Name("WEPS")
@Description("WEPS. References sdmONLINE. Can use WEPS 1.5.52")
@VersionInfo("1.4")
@Path("m/weps/1.4")
@Polling(first = 25000, next = 2000)

// weps, weps.version is in the csip-conf.file
@Resource(type = EXECUTABLE, file = "/bin/${arch}/${weps.version}/weps.exe", id = WEPS_EXE)

// cligen
@Resource(type = EXECUTABLE, file = "/bin/${arch}/cligen.exe", id = CLIGEN)
@Resource(type = FILE, file = "/data/upd_US_cligen_stations.par", id = STATION_PAR)

// windgen
@Resource(type = EXECUTABLE, file = "/bin/win-x86/wind_gen4.exe", wine = true, id = WINDGEN)
@Resource(type = EXECUTABLE, file = "/bin/${arch}/interpolate.exe", id = INTERPOLATE)
@Resource(type = EXECUTABLE, file = "/bin/${arch}/interp_wdb.exe", id = INTERP_WDB)
@Resource(type = FILE, file = "/data/wind_gen_his_upper_US_NRCS.idx", id = WINDGEN_IDX)
@Resource(type = FILE, file = "/data/wind_gen_his_upper_US.wdb", id = DEFAULT_WIND_STATION_DB)
@Resource(type = FILE, file = "/data/interpolation_boundary.pol", id = BOUNDARY_POL)

// report
@Resource(type = FILE, file = "/data/weps_report.json", id = REPORT_JSON_ID)

// Output
@Resource(type = OUTPUT, file = "stir_energy.out sci_energy.out *stdout.txt *stderr.txt")

public class V1_4 extends ModelDataService {

    static final String REPORT_JSON_ID = "weps_report";
    static final String WEPS_EXE = "weps";
    static final String CLIGEN = "cligen";
    static final String WINDGEN = "windgen";
    static final String INTERPOLATE = "interpolate";
    static final String INTERP_WDB = "interp_wdb";
    static final String WINDGEN_IDX = "windgen.idx";
    static final String BOUNDARY_POL = "boundary.pol";
    static final String WEIGHTS_TXT = "weights.txt";
    static final String DEFAULT_WIND_STATION_DB = "wind_gen_his_upper_US.wdb";
    static final String STATION_PAR = "station_par";
    static final String ROMEDLL = "RomeDLL.dll";
    static final String KEY_COKEY = "cokey";

    //
//    private String binDir = Config.getString("m.bin.dir", "/tmp/csip/bin");
    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 WEPS_MGMT = "wepsmgmt.man";
    static final int NRCS_CYCLE_COUNT = 50;

    // Variables for WEPS model run
    private String soilkey = "";
    private String soilfile = "";
    private int simulationYears = 3 * NRCS_CYCLE_COUNT;
    private JSONObject fieldGeometry = null;
    private JsonRegion field_region = null;
    private JsonRegion barrier_region = null;
    private String soilPtr = "";
    private String soilFilename = "";
    private String windDbPath = "";
    private String sWindgenStation = "";
    private boolean cropCalibrationMode = false;

    private GIS_DB db = null;
    private WepsModelRun wmr = new WepsModelRun();
    public WepsOutput wo = new WepsOutput();
    private File stdout;


    @Override
    public void preProcess() throws Exception {

        // required parameter - at least one of these must exist!
        if (!(JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL))
                && !(JSONUtils.checkKeyExistsB(getParamMap(), WEPS_KEY_SOIL_FILE))) {
            throw new ServiceException("No Value for " + WEPS_KEY_SOIL + " and " + WEPS_KEY_SOIL_FILE + ". At least one is required.");
        }

        // At least one of the two soil params must be populated
        // This version is used by IET
        soilkey = getStringParam(WEPS_KEY_SOIL, "");
        // This version is used by ZedX
        soilfile = getStringParam(WEPS_KEY_SOIL_FILE, "");

        wmr.setLat(getStringParam(WEPS_KEY_LATITUDE));
        wmr.setLongitude(getStringParam(WEPS_KEY_LONGITUDE));

        double fieldLengthInM = getDoubleParam(WEPS_KEY_FIELD_LENGTH) * CONV_FT_TO_M;
        if (fieldLengthInM <= 0) {
            appendMetainfoWarning(WEPS_FIELD_LENGTH_IS_INVALID);
        }
        wmr.setSimYLen(String.valueOf(fieldLengthInM));

        double fieldWidthInM = getDoubleParam(WEPS_KEY_FIELD_WIDTH) * CONV_FT_TO_M;
        if (fieldWidthInM <= 0) {
            appendMetainfoWarning(WEPS_FIELD_WIDTH_IS_INVALID);
        }
        wmr.setSimXLen(String.valueOf(fieldWidthInM));

        JSONUtils.checkKeyExists(getParamMap(), WEPS_KEY_MANAGEMENT);

        // optional parameter
        if (hasParam(WEPS_KEY_ELEVATION)) {
            double elevationInM = getDoubleParam(WEPS_KEY_ELEVATION) * CONV_FT_TO_M;
            wmr.setElevation(String.valueOf(elevationInM));
        } else {
            appendMetainfoWarning(WEPS_ELEVATION_DEFAULT_USED);
        }
        if (hasParam(WEPS_KEY_WATER_EROSION_LOSS)) {
            double waterErosionLoss = getDoubleParam(WEPS_KEY_WATER_EROSION_LOSS) * CONV_TONACRE_TO_KGM2;
            wmr.setWaterErosionLoss(String.valueOf(waterErosionLoss));
        }
        if (hasParam(WEPS_KEY_FIELD_ORIENTATION)) {
            double fieldOrient = getDoubleParam(WEPS_KEY_FIELD_ORIENTATION);
            wmr.setSimRegionAngle(String.valueOf(fieldOrient));
        }
        if (hasParam(WEPS_KEY_SOIL_ROCK_FRAGMENTS)) {
            double rockFragments = getDoubleParam(WEPS_KEY_SOIL_ROCK_FRAGMENTS);
            wmr.setSoilRockFragments(String.valueOf(rockFragments));
        }
        if (hasParam(WEPS_KEY_CROP_CALIBRATION_MODE)) {
            cropCalibrationMode = getBooleanParam(WEPS_KEY_CROP_CALIBRATION_MODE);
        }
        if (hasParam(WEPS_FIELD_BOUNDARY)) {
            appendMetainfoWarning(WEPS_FIELD_BOUNDARY_IGNORED);
        }
    }


    @Override
    protected void doProcess() throws Exception {
        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");
        }

        try {
            // get the mgmt as a json obj and create a WEPS man file using Jim's parser
            String error = loadWepsMgmt();
            if (error != null) {
                LOG.info("ERROR: " + error);
                throw new ServiceException(error);
            }

            // get wind barriers
            getWindBarriers();

            // Get climate info
            getClimate();

            // Get wind info
            generateWindData();

            // Get soils data
            if(Config.getBoolean("sdmONLINE",false))
                getSoilIFC();
            else
                getStaticSoilIfc();

            // The WEPS GUI requires an empty notes.txt file per LEW to run
            FileUtils.writeStringToFile(new File(getWorkspaceDir(), "notes.txt"), "");

            // Always generate Weps Run file from JSON parameters (it is never provided in the model srvc signature)
            LOG.info("creating wepsrun file.");
            WepsRunFileGenerator.GenerateWepsRunFile(wmr, getWorkspaceDir().toString(), "weps.run");

            LOG.info("starting weps process");

            // run WEPS model
            // model call uses the following cmd line args
            // /weps -W1 -u0 -I2 -t1 -P./ >stdout.txt 2>stderr.txt
            Executable exe = getResourceExe(WEPS_EXE);
            exe.setArguments("-W1", "-u0", "-I2", "-t1", "-T1", "-P./");
            if (cropCalibrationMode) {
                // C15 tells WEPS to perform up to 15 calibration cycles for convergence, could do fewer cycles
                // Z50 is required with calibration flag
                exe.addArguments("-C15", "-Z50");
            }

            stdout = exe.stdout();

            boolean handleProgress = Config.getBoolean("weps.progress", false);
            if (handleProgress) {
                exe.setStdoutHandler(new Executable.StdHandler() {
                    @Override
                    public void handle(String out) {
                        if (out == null)
                            return;
                        int idx = out.lastIndexOf("Year");
                        if (idx > -1) {
                            try {
                                String a = out.substring(idx, out.indexOf('\n', idx));
                                setProgress(a);
                            } catch (ServiceException ex) {
                                System.out.println("Error setting progress info.");
                            }
                        }
                    }
                });
            }

            int result = exe.exec();
            if (result != 0) {
                throw new ServiceException("WEPS exit error :" + result);
            }

            // Check standard out for "inpsub" error - occurs when no soil file is available
            if (exe.stdout().exists()) {
                String out = FileUtils.readFileToString(exe.stdout());
                if (out.contains("inpsub error")) {
                    throw new ServiceException("Error in WEPS--Standard output:" + out);
                }
            }
        } catch (Exception e) {
            LOG.log(Level.SEVERE, "ERROR EXECUTING WEPS", e);
            throw e;
        }
    }


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

                WepsTranslator translator = new WepsTranslator();
                translator.setConfigFilename("config/mcrew_start.xml");
                translator.setInputManType(ManageData.InputManType.READ_LMOD_MAN_JSON);
                translator.setOutputMan(true);
                JSONObject mgmtObj = new 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);
                            }
                        } catch (NumberFormatException ex) { // I want to transition the numeric errors to string errors like this
                            LOG.log(Level.SEVERE, "THERE IS AN ERROR: " + error);
                        }
                    }
                } 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;
                }
                // 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 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 {
            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 = getWorkspaceDir().toString();
//            LOG.info("extract cligen to:/bin/" + Binaries.getArch());
//            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" + getWorkspaceDir().toString() + "/cli_gen.cli"};
//            LOG.log(Level.INFO, "cligen args=" + pcCliGen.args.toString());
//            pcCliGen.execute();
            String dbpath = getResourceFile(STATION_PAR).toString();

            Executable cligen = getResourceExe(CLIGEN);
            cligen.setArguments("-S" + cligenStation.state, "-s" + cligenStation.stationId, "-i" + dbpath,
                    "-t5", "-I3", "-F", "-b01", "-y" + simulationYears, "-o" + getWorkspaceDir().toString() + "/cli_gen.cli");
            int ret = cligen.exec();
            if (ret != 0) {
                throw new ServiceException("WEPS error: cligen execution failed :" + ret);
            }

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


    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
            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();
                    windDbPath = getResourceFile(DEFAULT_WIND_STATION_DB).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", 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(getWorkspaceDir(), "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 = getWorkspaceDir().toString();
//                    pcInterpolate.exe = "./interpolate.sh";
//                    pcInterpolate.args = new String[]{};
//                    pcInterpolate.execute();
                    String dbpath = getResourceFile(WINDGEN_IDX).toString();
                    String polygon = getResourceFile(BOUNDARY_POL).toString();

                    Executable interpolate = getResourceExe(INTERPOLATE);
                    interpolate.setArguments("-f", dbpath, "-p", polygon, "-lat", nf.format(countyCentroidLat), "-long", nf.format(countyCentroidLon));
                    int ret = interpolate.exec();
                    if (ret != 0) {
                        throw new ServiceException(" Interpolation execution failed: " + ret);
                    }


                    bInterpolatedWind = true;
                    String interpolateOut = FileUtils.readFileToString(interpolate.stdout());
                    if(interpolateOut.contains("ERROR"))
                        throw new ServiceException("Wind Interpolation Error: \n"+ interpolateOut);
                    WeightsParser wp = new WeightsParser();
//                    wp.weightsFile = pcInterpolate.stdout;
                    //wp.weightsFile = FileUtils.readFileToString(interpolate.stdout());
//                    wp.exitValue = pcInterpolate.exitValue;
                    //wp.exitValue = ret;
//                    wp.weightsErr = pcInterpolate.stderr;
                    wp.weightsErr = FileUtils.readFileToString(interpolate.stderr());
//                    LOG.info("exit value from pcInterpolate execution=" + pcInterpolate.exitValue);
                    // must process this monstrosity 
                    wp.parse(interpolate.stdout());

//                    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", 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.stations[0]);
                        LOG.info("Station1="+station1Db);
                        String station2Db = getWindStationFile(wp.stations[1]);
                        LOG.info("Station2="+station2Db);
                        String station3Db = getWindStationFile(wp.stations[2]);
                        LOG.info("Station3="+station3Db);
                        // Generate shell script to invoke interpolate
//                        File interpwdbsh = new File(getWorkspaceDir(), "interpwdb.sh");
//                        interpwdbsh.setExecutable(true);
                        // 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);
//                        pcInterpWdb.working_dir = getWorkspaceDir().toString();
//                        pcInterpWdb.exe = "./interpwdb.sh";
//                        pcInterpWdb.args = new String[]{};
//                        pcInterpWdb.execute();
                        Executable interp_wdb = getResourceExe(INTERP_WDB);
                        interp_wdb.setArguments("test.wdb", station1Db, wp.weights[0], station2Db, wp.weights[1], station3Db, wp.weights[2]);
                        ret = interp_wdb.exec();
                        if (ret != 0) {
                            throw new ServiceException("Error executing interp_wdb " + ret);
                        }

                        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();
                    windDbPath = getResourceFile(DEFAULT_WIND_STATION_DB).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.findWEPSCounty(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(getWorkspaceDir(), "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 = getWorkspaceDir().toString();
//            String cmd = "./windgen.sh";
//            pcWindGen.args = new String[]{};
//            pcWindGen.exe = cmd;
//            pcWindGen.execute();
            Executable windgen = getResourceExe(WINDGEN);
            // no need to set the wine argument. It is done in the resource definition.
            windgen.setArguments("-f", windDbPath, "-b", "01", "-y", simulationYears, "-o", wmr.getWinFile(), "-s", sWindgenStation);
            int ret = windgen.exec();
            if (ret != 0) {
                throw new ServiceException(" error executing windgen: " + ret);
            }

            //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 filePath = "";
        if(windStationId != 0){
            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, 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 + " ");
            filePath = wmr.getSoilFile();
        }
        return filePath;
    }


    private void getStaticSoilIfc() 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, 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 getSoilIFC() throws JSONException, Exception{

        if(soilkey.length() > 0){
            JSONObject soilsRequest = new JSONObject();
            JSONObject meta = new JSONObject();
            JSONArray paramObj = new JSONArray();
            JSONObject cokeyObj = new JSONObject();
            JSONObject soilsResponse;
            JSONObject responseMeta;
            JSONArray resultArr;
            JSONObject soilObj;
            String soilFileName;
            URI soilURI;
            File soilIFC;
            String error = "";

            soilsRequest.put(KEY_METAINFO, meta);
            soilsRequest.put(KEY_PARAMETER, paramObj);
            paramObj.put(cokeyObj);

            paramObj.put(0,cokeyObj);
            cokeyObj.put(KEY_NAME, KEY_COKEY);
            cokeyObj.put(KEY_VALUE,soilkey);
            LOG.info("SOILS Request: "+soilsRequest.toString());
            soilsResponse = new Client().doPOST(Config.getString("weps.soils","http://csip.engr.colostate.edu:8092/csip-soils/d/soilsIFC/1.0"), soilsRequest);
            LOG.info("SOILS Response: "+soilsResponse.toString());
            responseMeta = soilsResponse.getJSONObject(KEY_METAINFO);
            if(!responseMeta.getString(KEY_STATUS).equalsIgnoreCase("Failed")){
                resultArr = soilsResponse.getJSONArray(KEY_RESULT);
                soilObj = resultArr.getJSONObject(0);
                soilURI = new URI(soilObj.getString(KEY_VALUE));
                soilFileName = soilURI.getPath().substring(soilURI.getPath().lastIndexOf("/")+1,soilURI.getPath().length());
                soilIFC = getWorkspaceFile(soilFileName);
                
                new Client().doGET(soilURI.toString(), soilIFC);
                
                LOG.info("THE SOIL IS =" + soilIFC.getAbsolutePath() + "\n");
                
                wmr.setSoilFile(soilIFC.getName());

            }else{
                error = responseMeta.getString(ERROR);
                LOG.warning(error);
                throw new ServiceException("WEPS error: Soil error: "+ error);
            }
        }else{
            throw new ServiceException("WEPS error: A soilkey must be provided for the sdmONLINE configuration.");
        }
    }

    private void getFile(String url, String filename) throws ServiceException {
        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(getWorkspaceDir(), filename));
            fos.write(soilData);
        } catch (IOException ie) {
            LOG.log(Level.SEVERE, "ERROR GETTING SOILS IFC FILE!:" + ie.toString());
            throw new ServiceException(ie);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception fe) {
                }
            }
        }
    }


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


    @Override
    public JSONArray createResults() throws Exception {
        LOG.info("Create the WEPS results...");
        JSONArray results = new JSONArray();

        String sciEnergyOut;
        try (BufferedReader bfr = new BufferedReader(new FileReader(new File(getWorkspaceDir(), "sci_energy.out")))) {
            sciEnergyOut = "";
            while (bfr.ready()) {
                sciEnergyOut += bfr.readLine();
            }
        }

        wo = SciEnergyParser.parseSciEnergyFile(sciEnergyOut);

        if (wo.bNaN) {
            appendMetainfoWarning(WEPS_FOUND_NAN_IN_OUTPUT);
        }

        getAdvancedOutput();

        // 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(WEPS_CLI_STATION, wmr.getCliStationName()));
        if(sWindgenStation.equals("999999"))
            sWindgenStation = "Interpolated";
        results.put(JSONUtils.data(WEPS_WIND_STATION,sWindgenStation));

        return results;
    }

    private double calculateSTIRFuel(JSONArray fuels) throws JSONException{
        double fuel = 0;
        
        for(int i=0;i<fuels.length();i++)
            fuel += fuels.getDouble(i);
        
        return fuel;
    }
    private void getAdvancedOutput() throws JSONException, Exception {
        JSONArray reportItems = new JSONArray();
        JSONObject item = new JSONObject();
        JSONArray report;
        Map<String, JSONObject> reportValues;
        JSONArray suspen;
        JSONArray salt;
        JSONArray pm10;
        JSONArray fuel;

        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);
        
        item = new JSONObject();
        item.put("name","stir_energy.energy");
        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");
        fuel = JSONUtils.getJSONArrayParam(reportValues, "stir_energy.energy");

        wo.suspension = suspen.getString(suspen.length() - 1);
        wo.saltation = salt.getString(salt.length() - 1);
        wo.pm10 = pm10.getString(pm10.length() - 1);
        wo.dieselEnergy = String.valueOf(calculateSTIRFuel(fuel));
    }


    @Override
    protected JSONArray createReport() throws Exception {
        String workDir = getWorkspaceDir().toString();
        File reportTemplate = getResourceFile(REPORT_JSON_ID);

        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());
        reportdata.loadFiles(getWorkspaceDir().toString(), stdout.getName(),Config.getString("weps.version"));

//        // 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) + "'");
            LOG.info("Trying report value: " + itemName);
            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));
                    LOG.info("Scalar value: " + 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 = getResourceFile(REPORT_JSON_ID);
        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());
        reportdata.loadFiles(getWorkspaceDir().toString(), stdout.getName(),Config.getString("weps.version"));

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