V1_3.java [src/java/m/weps] Revision: b34d99dfb923f2fc296a4154868f8a32dbc081dc  Date: Tue Apr 11 13:35:44 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.SqlGIS;
import csip.Config;
import csip.Executable;
import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.Polling;
import csip.annotations.Resource;
import static csip.annotations.ResourceType.*;
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 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;

import static m.weps.V1_3.*;

/**
 * WEPS
 *
 * @author wlloyd, od
 */
@Name("WEPS")
@Description("WEPS")
@VersionInfo("1.3")
@Path("m/weps/1.3")
@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)
@Resource(type = EXECUTABLE, file = "/bin/${arch}/1.3.9/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 = "/bin/${arch}/wind_gen_his_upper_US_NRCS.idx", id = WINDGEN_IDX)
@Resource(type = FILE, file = "/bin/${arch}/wind_gen_his_upper_US.wdb", id = DEFAULT_WIND_STATION_DB)
@Resource(type = FILE, file = "/bin/${arch}/interpolation_boundary.pol", id = BOUNDARY_POL)

// report
@Resource(type = FILE, file = "/bin/${arch}/weps_report.json", id = REPORT_JSON_ID)

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

// database
@Resource(type = JDBC, file = "${conservation_resources.db}", id = DB)

public class V1_3 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 KEY_COKEY = "cokey";
    static final String DB = "csip.erosion.sqlsvr";

    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 WEPS_MGMT = "wepsmgmt.man";
    static final int NRCS_CYCLE_COUNT = 50;
    private WepsOutput wo = new WepsOutput();
    private WepsModelRun wmr = new WepsModelRun();

    // 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 GIS_DB db;
    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.");
        }
    }


    @Override
    protected void doProcess() throws Exception {
        db = new SqlGIS(getResourceJDBC(DB));
        LOG.info("The default CISP WEPS user dir is=" + System.getProperty("user.dir"));
        try {
            sessionWorkDir = getWorkspaceDir().toString();

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

            // get wind barriers
            getWindBarriers();

            // Get climate info
            getClimate();

            // Get wind info
            generateWindData();

            // Get soils data
            getSoilIfc();

            // run WEPS model
            // 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.log(Level.INFO, "wepsrun file does not exist, creating it.");
            String wepsrunFile = "weps.run";
            WepsRunFileGenerator.GenerateWepsRunFile(wmr, sessionWorkDir, wepsrunFile);

            LOG.info("starting WEPS");

            // Our WEPS 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");
            }

            // copy them back to the old names.
//            FileUtils.copyFile(exe.stdout(), new File(exe.stdout().getParentFile(), "stdout.txt"));
//            FileUtils.copyFile(exe.stdout(), new File(exe.stderr().getParentFile(), "stderr.txt"));
            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: (insub error)");
                }
            }
        } catch (Exception e) {
            LOG.log(Level.SEVERE, "ERROR EXECUTING WEPS", e);
            throw new ServiceException("WEPS error: error executing WEPS model>", e);
        } finally {
            db.close();
        }
    }


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

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

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

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

                        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;
                        WeightsParser1 wp = new WeightsParser1();
                        wp.weightsFile = FileUtils.readFileToString(interpolate.stdout());
                        LOG.info("exit value from pcInterpolate execution=" + ret);
                        // 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!
                            String station1Db = getWindStationFile(wp.station1);
                            String station2Db = getWindStationFile(wp.station2);
                            String station3Db = getWindStationFile(wp.station3);

                            Executable interp_wdb = getResourceExe(INTERP_WDB);
                            interp_wdb.setArguments("test.wdb", station1Db, wp.weight1, station2Db, wp.weight2, station3Db, wp.weight3);
                            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 = 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.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)
                LOG.log(Level.INFO, "Using wind database:" + windDbPath);

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

    class WeightsParser1 {

        String weightsFile;

        int station1 = 0;
        double weight1 = 0.0;
        int station2 = 0;
        double weight2 = 0.0;
        int station3 = 0;
        double weight3 = 0.0;


        void parse() {
            if (LOG.isLoggable(Level.INFO)) {
                LOG.info("weights file: " + weightsFile);
            }
            // Find where point is described
            String sPattern = "point:";
            int start = weightsFile.lastIndexOf(sPattern);
            int end = weightsFile.indexOf('\n', start) + 1;
            // skip this line
            weightsFile = weightsFile.substring(end);
            if (LOG.isLoggable(Level.INFO)) {
                LOG.info("new filesubset=" + weightsFile);
            }
            end = weightsFile.indexOf('\n') + 1;
            // skip next line
            weightsFile = weightsFile.substring(end);
            end = weightsFile.indexOf('\n') + 1;
            // skip all comment lines
            String line = "#";
            do {
                weightsFile = weightsFile.substring(end);
                end = weightsFile.indexOf('\n') + 1;
                line = weightsFile.substring(0, end).trim();
            } while (line.charAt(0) == '#');
            // waste an extra line
            weightsFile = weightsFile.substring(end);
            end = weightsFile.indexOf('\n') + 1;
            line = weightsFile.substring(0, end).trim();
            if (LOG.isLoggable(Level.INFO)) {
                LOG.info("line=" + line);
            }
            station1 = Integer.parseInt(line.substring(0, line.indexOf(' ')));
            weight1 = Double.parseDouble(line.substring(line.indexOf(' ')));
            // next line
            weightsFile = weightsFile.substring(end);
            end = weightsFile.indexOf('\n') + 1;
            line = weightsFile.substring(0, end).trim();
            if (LOG.isLoggable(Level.INFO)) {
                LOG.info("line=" + line);
            }
            station2 = Integer.parseInt(line.substring(0, line.indexOf(' ')));
            weight2 = Double.parseDouble(line.substring(line.indexOf(' ')));
            // last line
            weightsFile = weightsFile.substring(end);
            end = weightsFile.indexOf('\n') + 1;
            line = weightsFile.substring(0, end).trim();
            if (LOG.isLoggable(Level.INFO)) {
                LOG.info("line=" + line);
            }
            station3 = Integer.parseInt(line.substring(0, line.indexOf(' ')));
            weight3 = Double.parseDouble(line.substring(line.indexOf(' ')));

            if (LOG.isLoggable(Level.INFO)) {
                LOG.info("station1=" + station1 + " weight1=" + weight1);
                LOG.info("station2=" + station2 + " weight2=" + weight2);
                LOG.info("station3=" + station3 + " weight3=" + weight3);
            }
        }
    }


    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
    public JSONArray createResults() throws Exception {
        LOG.info("Create the WEPS results...");
        JSONArray results = new JSONArray();

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

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

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