V1_0.java [src/java/m/weppws] Revision: default Date:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package m.weppws;
import csip.utils.Client;
import csip.Config;
import csip.ModelDataService;
import csip.api.server.Executable;
import static csip.ModelDataService.ERROR;
import static csip.ModelDataService.KEY_METAINFO;
import static csip.ModelDataService.KEY_NAME;
import static csip.ModelDataService.KEY_PARAMETER;
import static csip.ModelDataService.KEY_STATUS;
import static csip.ModelDataService.KEY_VALUE;
import csip.annotations.*;
import csip.api.server.ServiceException;
import static csip.annotations.ResourceType.*;
import csip.utils.JSONUtils;
import csip.utils.Validation;
import java.io.*;
import java.util.logging.Level;
import java.util.ArrayList;
import java.util.Set;
import java.net.URI;
import java.util.Map;
import java.util.logging.Logger;
import java.util.HashSet;
import java.util.List;
import java.util.Iterator;
import java.util.Arrays;
import javax.ws.rs.*;
import static m.weppws.ApplicationResources.*;
import org.apache.commons.io.FileUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import util.WEPPHillslopeServiceCall;
import util.Grid;
import static util.WeppConstants.CONFIG_CLIGEN_PRISM_URL;
//import static util.WeppConstants.CONFIG_CONTOURS_URL;
//import static util.WeppConstants.CONFIG_CROPS_URL;
//import static util.WeppConstants.CONFIG_MANAGEMENTS_URL;
//import static util.WeppConstants.CONFIG_OPERATIONS_URL;
//import static util.WeppConstants.CONFIG_RESIDUES_URL;
import static util.WeppConstants.CONFIG_SOIL_URL;
//import static util.WeppConstants.CONFIG_STRIPS_URL;
import static util.WeppConstants.CONFIG_WEPP_HILLSLOPE_URL;
import static util.WeppConstants.NORTH_D8;
import static util.WeppConstants.NORTH_EAST_D8;
import static util.WeppConstants.EAST_D8;
import static util.WeppConstants.SOUTH_EAST_D8;
import static util.WeppConstants.SOUTH_D8;
import static util.WeppConstants.SOUTH_WEST_D8;
import static util.WeppConstants.WEST_D8;
import static util.WeppConstants.NORTH_WEST_D8;
import static util.WeppConstants.buildConfigKey;
import static util.WeppConstants.GridType;
import static util.WeppConstants.CONV_HA_TO_AC;
import static util.WeppConstants.CONV_M_TO_FT;
@Name("weppws")
@Description("WEPPWS - Watershed service for WEPP TauDEM based - 8/14/2023")
@Path("m/weppws/1.0")
@Polling(first = 2000, next = 2000)
@Resource(file = "/bin/${arch}/wepphillslopeservws.exe", id = "weppserv", type = EXECUTABLE)
@Resource(file = "/bin/${arch}/weppws_2020.exe", id = "wepp", type = EXECUTABLE)
@Resource(file = "/bin/${arch}/weppws_2020_64.exe", id = "wepp64", type = EXECUTABLE)
@Resource(file = "/data/channelDatabase.json", id = "channeldatabase")
@Resource(file = "/data/fallow.rot.txt", id = "fallowchannel")
@Resource(file = "/data/grass.rot.txt", id = "grasschannel")
@Resource(file = "/data/impoundmentDatabase.json", id = "impoundmentdatabase")
// This is the main service for runnign a WEPP spatial fiel simulation of
// small watershed simulation. Each subctachment will be simulated using a
// sub-service to try to get better response time.
//
// This service handles reading any data from other databses (soils, climates,
// managements).
//
public class V1_0 extends ModelDataService {
protected String modelVersion = "4.1";
static final String WEPP_PRISM = "usePRISM";
static final String ADJUSTPWW_PWD = "adjustPWW_PWD";
static final String WEPP_RAND_SEED = "randSeed";
static final String WEPP_KEY_CLIMATE_DATA_VERSION = "climateDataVersion";
static final String LATITUDE = "latitude";
static final String LONGITUDE = "longitude";
static final String SIMULATION_TYPE = "simulationType";
static final String SOIL_DICTIONARY = "soilDictionary";
static final String MANAGE_DICTIONARY = "managementDictionary";
static final String D8_GRID = "D8Grid";
static final String FIELD_GRID = "FieldMaskGrid";
static final String CHANNEL_GRID = "ChannelGrid";
static final String SUBCATCHMENT_GRID = "SubcatchmentsGrid";
static final String FLOWPATH_GRID = "LongestFlowpathGrid";
static final String SLOPE_GRID = "SlopeD8Grid";
static final String MANAGE_GRID = "ManagementGrid";
static final String SOIL_GRID = "SoilGrid";
static final String LINK_TABLE = "ChannelLinks";
static final String CRLMOD = "crlmod";
static final String WEPP_KEY_RUN_YEARS = "run_years";
static final String IET_ROTATIONS = "rotationFiles";
static final String STATS_ONLY = "noRunsStatsOnly";
static final String SUBSET = "flowpathSubsetPercentage";
static final String SPLIT_SUBCATCHMENTS = "splitSubcatchments";
static final String CHANNEL_PARMS = "channelParameters";
static final String CHANNEL_ORDERS = "channelOrders";
static final String USE_CHANNELS = "usechannels";
static final String RUNOFF_CALC = "runoffCalculation";
static final String USE_PASSFILES = "usepassfiles";
static final String DETAIL_SUBCATCHMENTS = "detailsubcatchments";
static final String USE_LANDUSE_AS_CHANNEL_MAN = "useLanduseManInChannels";
static final String APPEND_CHANNEL_DB = "appendChannelDatabase";
static final String APPLY_IMPOUNDMENTS = "impoundments";
static final String CHAN_EROD_FLAG = "chanErodFlag";
double longitude;
double latitude;
int subsetPercentage;
boolean usePRISM;
boolean adjustPWW_PWD;
int randomSeedVal;
int run_years;
int climateDataVersion;
String simulationType;
boolean useRepHillslopes;
boolean statsOnly;
String d8Grid;
String fieldMaskGrid;
String channelGrid;
String subcatchmentGrid;
String flowpathGrid;
String slopeGrid;
String manageGrid;
String soilGrid;
String channelLinks;
JSONArray managementDict;
JSONArray managementDictAll;
JSONArray soilDict;
JSONArray soilDictAll;
String[] managementNames;
JSONArray managementsWithData;
int defaultSoil;
int defaultManagement;
JSONArray channelOrderData;
JSONArray channelParameterData;
String rawChannelDatabaseData;
int numChannelsUsed;
boolean use64BitWEPP;
boolean splitSubcatchments; // True if each TauDEM subcatchment should be
// split into 3 areas to emuulate TOPAZ
boolean parallelRuns;
JSONArray usrChannelOrderData;
JSONArray usrChannelParameterData;
boolean clipflag;
int[] usechannels;
int runoffCalculation;
int chanErodFlag;
boolean usePassFiles;
int[] detailsubcatchments;
boolean useLanduseManInChannels;
JSONArray appendChannelDB;
JSONArray impoundments;
JSONArray impoundmentParameterData;
Grid flow_d8_grid;
Grid field_grid;
Grid slope_d8_grid;
Grid man_grid;
Grid soil_grid;
Grid flowpath_grid;
Grid subcatchment_grid;
Grid channel_grid;
Grid outSoilLoss_grid;
Grid outSedYield_grid;
Grid outRunoff_grid;
Grid outFlowpathLoss_grid;
Grid sedWeight_grid;
Grid sub3_grid;
// define how to handle cells in flowpath output where several merge
static final int weightMethod = 0; // 0=weighted based on flowpath length, 1=averaged, 2=maximum
Set<Integer> subs;
Watershed aoi;
protected String soilServiceURL = null;
protected String climateServiceURL;
// protected String contourServiceURL = null;
// protected String manServiceURL = null;
// protected String stripsServiceURL = null;
// protected String cropsURL = null;
// protected String operationsURL = null;
// protected String residueURL = null;
protected String weppHillslopeURL = null;
protected String flowpathURL = null;
protected String queryURL = null;
protected void setURLs() throws ServiceException {
soilServiceURL = getConfigString(buildConfigKey(modelVersion, CONFIG_SOIL_URL));
climateServiceURL = getConfigString(buildConfigKey(modelVersion, CONFIG_CLIGEN_PRISM_URL));
// contourServiceURL = getConfigString(buildConfigKey(modelVersion, CONFIG_CONTOURS_URL));
// manServiceURL = getConfigString(buildConfigKey(modelVersion, CONFIG_MANAGEMENTS_URL));
// stripsServiceURL = getConfigString(buildConfigKey(modelVersion, CONFIG_STRIPS_URL));
// cropsURL = getConfigString(buildConfigKey(modelVersion, CONFIG_CROPS_URL));
// operationsURL = getConfigString(buildConfigKey(modelVersion, CONFIG_OPERATIONS_URL));
// residueURL = getConfigString(buildConfigKey(modelVersion, CONFIG_RESIDUES_URL));
weppHillslopeURL = getConfigString(buildConfigKey(modelVersion, CONFIG_WEPP_HILLSLOPE_URL));
flowpathURL = Config.getString("weppws.flowpath", "");
queryURL = Config.getString("weppws.queryURL", "");
}
protected static String getConfigString(String key) throws ServiceException {
String ret_val = Config.getString(key);
if (ret_val == null)
throw new ServiceException("Configuration parameter, '" + key + "', is missing. Cannot continue.");
return ret_val;
}
/**
* init() Initialize WEPP workspace. This requires creating a couple
* subdirectories. In addition the connections to the sqlite databases are
* verified.
*
*/
private boolean init() throws ServiceException, Exception {
setURLs();
aoi = new Watershed(LOG, workspace().getDir(), simulationType.startsWith("Watershed"), this);
flow_d8_grid = getWSGrid(GridType.INT_GRID, d8Grid, "flowdir_d8.asc");
field_grid = getWSGrid(GridType.INT_GRID, fieldMaskGrid, "field.asc");
slope_d8_grid = getWSGrid(GridType.FLOAT_GRID, slopeGrid, "slope_d8.asc");
flowpath_grid = getWSGrid(GridType.FLOAT_GRID, flowpathGrid, "flowpathlens.asc");
subcatchment_grid = getWSGrid(GridType.INT_GRID, subcatchmentGrid, "subcatchments.asc");
channel_grid = getWSGrid(GridType.INT_GRID, channelGrid, "channels.asc");
man_grid = getWSGrid(GridType.INT_GRID, manageGrid, "managements.asc");
soil_grid = getWSGrid(GridType.INT_GRID, soilGrid, "soils.asc");
File linkfilename = workspace().getFile("channel_links.csv");
if (channelLinks.startsWith("http")) {
URI fileURI = new URI(channelLinks);
new Client().doGET(fileURI.toString(), linkfilename);
} else {
linkfilename = workspace().getFile(channelLinks);
}
readLinksCSV(linkfilename);
readChannelDatabaseJSON(resources().getFile("channeldatabase"));
if (impoundments != null)
readImpoundmentDatabaseJSON(resources().getFile("impoundmentdatabase"));
applyUsrOrderParameters();
applyUsrChannelParameters();
applyAppendChannelDB();
//buildWEPPFormatChannelData();
FileUtils.copyFile(resources().getFile("grasschannel"), workspace().getFile("grass.rot"));
FileUtils.copyFile(resources().getFile("fallowchannel"), workspace().getFile("fallow.rot"));
//setLocalFile(resources().getFile("grasschannel"),"grass.rot");
//setLocalFile(resources().getFile("fallowchannel"),"fallow.rot");
if (slope_d8_grid.verifyFloat(0, 100) == false)
throw new ServiceException("Slope grid contains bad value.");
// check that all grids are the same size
if ((flow_d8_grid.rowCount() != field_grid.rowCount()) || (flow_d8_grid.rowCount() != slope_d8_grid.rowCount())
|| (flow_d8_grid.rowCount() != flowpath_grid.rowCount()) || (flow_d8_grid.rowCount() != subcatchment_grid.rowCount())
|| (flow_d8_grid.rowCount() != channel_grid.rowCount())
|| (flow_d8_grid.rowCount() != man_grid.rowCount()) || (flow_d8_grid.rowCount() != soil_grid.rowCount())
|| (flow_d8_grid.colCount() != field_grid.colCount()) || (flow_d8_grid.colCount() != slope_d8_grid.colCount())
|| (flow_d8_grid.colCount() != flowpath_grid.colCount()) || (flow_d8_grid.colCount() != subcatchment_grid.colCount())
|| (flow_d8_grid.colCount() != channel_grid.colCount())
|| (flow_d8_grid.colCount() != man_grid.colCount()) || (flow_d8_grid.colCount() != soil_grid.colCount())) {
throw new ServiceException("Error: Input grids do not all have the same number of rows and columns.");
}
LOG.info("one col:" + slope_d8_grid.getFloatRowCol(0, 0));
return true;
}
/**
* preProcess() Get input parameters from WEPP request.
*
* @throws Exception
*/
@Override
protected void preProcess() throws Exception {
latitude = parameter().getDouble(LATITUDE);
longitude = parameter().getDouble(LONGITUDE);
usePRISM = parameter().getBoolean(WEPP_PRISM, false);
adjustPWW_PWD = parameter().getBoolean(ADJUSTPWW_PWD, false);
randomSeedVal = parameter().getInt(WEPP_RAND_SEED, -1);
run_years = parameter().getInt(WEPP_KEY_RUN_YEARS, 100);
climateDataVersion = parameter().getInt(WEPP_KEY_CLIMATE_DATA_VERSION, 1992);
simulationType = parameter().getString(SIMULATION_TYPE);
Validation.checkString(simulationType, "Watershed", "Field", "Hillslope", "Watershed-Flowpaths");
statsOnly = parameter().getBoolean(STATS_ONLY, false);
// management dictionary
// soils dictionary
soilDict = parameter().getJSONArray(SOIL_DICTIONARY);
managementDict = parameter().getJSONArray(MANAGE_DICTIONARY);
use64BitWEPP = parameter().getBoolean(USE64BITWEPP, false);
// input grids
d8Grid = parameter().getString(D8_GRID);
fieldMaskGrid = parameter().getString(FIELD_GRID);
channelGrid = parameter().getString(CHANNEL_GRID);
subcatchmentGrid = parameter().getString(SUBCATCHMENT_GRID);
flowpathGrid = parameter().getString(FLOWPATH_GRID);
slopeGrid = parameter().getString(SLOPE_GRID);
manageGrid = parameter().getString(MANAGE_GRID);
soilGrid = parameter().getString(SOIL_GRID);
channelLinks = parameter().getString(LINK_TABLE);
subsetPercentage = parameter().getInt(SUBSET, 100);
splitSubcatchments = parameter().getBoolean(SPLIT_SUBCATCHMENTS, false);
// parallelRuns = parameter().getBoolean(PARALLEL_RUNS, true);
parallelRuns = Config.getBoolean("weppws.parallel", false);
usrChannelOrderData = parameter().getJSONArray(CHANNEL_ORDERS, null);
usrChannelParameterData = parameter().getJSONArray(CHANNEL_PARMS, null);
usechannels = parameter().getIntArray(USE_CHANNELS, new int[0]);
detailsubcatchments = parameter().getIntArray(DETAIL_SUBCATCHMENTS, new int[0]);
usePassFiles = parameter().getBoolean(USE_PASSFILES, false);
useLanduseManInChannels = parameter().getBoolean(USE_LANDUSE_AS_CHANNEL_MAN, false);
appendChannelDB = parameter().getJSONArray(APPEND_CHANNEL_DB, null);
impoundments = parameter().getJSONArray(APPLY_IMPOUNDMENTS, null);
String runCalc = parameter().getString(RUNOFF_CALC, "Modified EPIC");
chanErodFlag = parameter().getInt(CHAN_EROD_FLAG, 0);
switch (runCalc) {
case "Modified EPIC":
runoffCalculation = 1;
break;
case "CREAMS":
runoffCalculation = 2;
break;
case "Kinematic Wave":
runoffCalculation = 3;
break;
case "Muskingum-Cunge(constant)":
runoffCalculation = 4;
break;
case "Muskingum-Cunge(variable)":
runoffCalculation = 5;
break;
default:
throw new IllegalArgumentException("for " + RUNOFF_CALC + ":" + runCalc);
}
defaultSoil = 0;
defaultManagement = 0;
init();
//aoi.dumpChannels();
}
void progress(String msg) {
synchronized (this) {
try {
setProgress(msg);
} catch (ServiceException ex) {
Logger.getLogger(V1_0.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* process() Calls functions to build the WEPP input files and then run WEPP
*
* @throws Exception
*/
@Override
protected void doProcess() throws Exception {
getClimateFile();
getSoilFiles();
getManagementFiles();
findSubcatchmentsInAOI();
findFlowpaths();
findChannels();
aoi.setChannelFlowpaths();
aoi.connectChannels();
if (usechannels.length > 0) {
// only a portion of the field/watershed area is being used so the
// field mask needs to be updated. First determine the ids to include
// in the mask.
aoi.labelWEPPChannelsSubarea(usechannels[0]);
// update the mask to only include the areas identified.
field_grid = aoi.createSubareaMask(field_grid, subcatchment_grid);
} else {
if (simulationType.startsWith("Watershed"))
aoi.labelWEPPChannels();
}
aoi.findMajorComponents(subcatchment_grid, channel_grid, soil_grid, man_grid, field_grid);
// set to include all subcatchments
if (usechannels.length == 0)
aoi.setInuseSubcatchments();
aoi.calcArea(field_grid);
buildWEPPFormatChannelData();
if (splitSubcatchments) {
aoi.setTopazIDs();
sub3_grid = new Grid(subcatchment_grid, GridType.INT_GRID, 0);
aoi.classifyFlowpaths();
LOG.info("Creating sub3 grid.");
aoi.createsub3grid(sub3_grid);
sub3_grid.writeGrid(workspace().getFile("topazSubcatchments.asc"));
aoi.findMajorComponentsTopaz(sub3_grid, soil_grid, man_grid, field_grid);
}
applyImpoundments();
Executable weppserv = resources().getExe("weppserv");
// Run an external program to create all the model inputs and run wepp
// turn on calibration flag
if (simulationType.startsWith("Watershed") || (usechannels.length > 0)) {
weppserv.setArguments(workspace().getDir(),
workspace().getFile("wepp.prw"),
workspace().getFile("output/weppout.txt"),
resources().getFile(use64BitWEPP ? "wepp64" : "wepp"), "0", 0, 0, 1);
} else {
weppserv.setArguments(workspace().getDir(),
workspace().getFile("wepp.prj"),
workspace().getFile("output/weppout.txt"),
resources().getFile(use64BitWEPP ? "wepp64" : "wepp"), "0", 0, 0, 1);
}
switch (simulationType) {
case "Field":
int totalRuns;
if (detailsubcatchments.length == 0) {
totalRuns = aoi.runFlowpaths(weppserv, field_grid, statsOnly, subsetPercentage, parallelRuns);
} else {
totalRuns = aoi.runFlowpathsSubset(weppserv, field_grid, statsOnly, subsetPercentage, parallelRuns, detailsubcatchments);
}
LOG.info("***** Total number of flowpath runs" + totalRuns);
totalRuns = aoi.runRepresentativeHillslopes(weppserv, field_grid, statsOnly, parallelRuns, splitSubcatchments, false);
LOG.info("***** Total number of representative hillslope runs (field simulation): " + totalRuns);
break;
case "Hillslope":
if (usechannels.length == 0) {
totalRuns = aoi.runRepresentativeHillslopes(weppserv, field_grid, statsOnly, parallelRuns, splitSubcatchments, false);
} else {
totalRuns = aoi.runRepresentativeHillslopes(weppserv, field_grid, true, parallelRuns, splitSubcatchments, usePassFiles);
aoi.runWatershedSubarea(weppserv, statsOnly, usechannels[0], usePassFiles);
}
LOG.info("***** Total number of representative hillslope runs (hillslope simulation): " + totalRuns);
break;
case "Watershed":
totalRuns = aoi.runRepresentativeHillslopes(weppserv, field_grid, true, parallelRuns, splitSubcatchments, usePassFiles);
if (usechannels.length == 0) {
aoi.runWatershed(weppserv, statsOnly, usePassFiles);
} else {
aoi.runWatershedSubarea(weppserv, statsOnly, usechannels[0], usePassFiles);
}
LOG.info("***** Total number of representative hillslope runs: " + totalRuns);
break;
case "Watershed-Flowpaths":
// setup watershed inputs for WEPP
totalRuns = aoi.runRepresentativeHillslopes(weppserv, field_grid, true, parallelRuns, splitSubcatchments, usePassFiles);
LOG.info("***** Total number of representative hillslope runs: " + totalRuns);
if (usechannels.length == 0) {
aoi.runWatershed(weppserv, statsOnly, usePassFiles);
} else {
aoi.runWatershedSubarea(weppserv, statsOnly, usechannels[0], usePassFiles);
}
// For flowpaths setup hillslope inputs for WEPP
weppserv.setArguments(workspace().getDir(),
workspace().getFile("wepp.prj"),
workspace().getFile("output/weppout.txt"),
resources().getFile(use64BitWEPP ? "wepp64" : "wepp"), "0", 0, 0, 1);
if (detailsubcatchments.length == 0) {
totalRuns = aoi.runFlowpaths(weppserv, field_grid, statsOnly, subsetPercentage, parallelRuns);
} else {
totalRuns = aoi.runFlowpathsSubset(weppserv, field_grid, statsOnly, subsetPercentage, parallelRuns, detailsubcatchments);
}
LOG.info("***** Total number of watershed flowpath runs: " + totalRuns);
break;
default:
throw new IllegalArgumentException("simulationType: " + simulationType);
}
if (usechannels.length > 0)
aoi.filterSubarea();
if (!statsOnly) {
createOutputGrids();
outSoilLoss_grid.writeGrid(workspace().getFile("rephillslope.asc"));
outSedYield_grid.writeGrid(workspace().getFile("repsedleaving.asc"));
outRunoff_grid.writeGrid(workspace().getFile("reprunoff.asc"));
if (weightMethod == 2) {
// no weighting, just the maximum loss at each cell
outFlowpathLoss_grid.writeGrid(workspace().getFile("flowpathloss.asc"));
} else {
// need to first apply the weight grid to get the actual loss values
outFlowpathLoss_grid.writeWeightedGrid(sedWeight_grid, workspace().getFile("flowpathloss.asc"));
}
}
aoi.writeOutputSummary(workspace().getFile("outputsummary.json"));
aoi.writeInputSummary(workspace().getFile("inputsummary.json"));
aoi.dumpSubcatchments();
removeFiles();
}
/**
* postProcess() Extract some WEPP outputs and include links to model input
* and output files.
*
* @throws Exception
*/
@Override
protected void postProcess() throws Exception {
metainfo().put("WEPPVersion", aoi.weppVersion);
metainfo().put("PreprocessorVersion", aoi.preVersion);
results().put("Precipitation", aoi.precip, "Average Annual Preciptation", "in");
if (simulationType.equals("Hillslope")) {
results().put("Field Irrigation", aoi.irrigation, "Average annual irrigation from all representative hillslopes in field", "ac-in");
results().put("Field Hillslope Erosion", aoi.fieldErosion, "Average annual soil loss from all representative hillslopes in field", "ton/ac/yr");
results().put("Field NRCS Soil Loss", aoi.fieldNRCSErosion, "NRCS Planning soil loss from all representative hillslopes in field", "ton/ac/yr");
results().put("Field Sediment Yield", aoi.fieldSedYield, "Average annual sediment yield from all representative hillslopes in field", "ton/ac/yr");
}
if (simulationType.startsWith("Watershed")) {
results().put("Precipitation Volume", aoi.precipVol, "Average Annual Preciptation Volume", "ft^3");
results().put("Discharge", aoi.discharge, "Average Annual Discharge at Outlet", "in");
results().put("Discharge Volume", aoi.dischargeVol, "Average Annual Discharge Volume at Outlet", "ft^3");
results().put("Sediment Yield", aoi.sedimentYld, "Average Annual Sediment Yield", "ton");
results().put("Sediment Yield Per Acre", aoi.sedimentYldArea, "Average Annual Sediment Yield per Area", "ton/ac");
results().put("Delivery Ratio", aoi.delRatio, "Sediment Delivery Ratio", "");
}
results().put("Area", aoi.area * CONV_HA_TO_AC, "Watershed Area", "ac");
if (simulationType.startsWith("Watershed")) {
JSONArray chans = new JSONArray();
for (int i = 0; i < aoi.channels.size(); i++) {
if (aoi.channels.get(i).weppID > 0) {
JSONObject jo = new JSONObject();
jo.put("TAUDEM_ID", aoi.channels.get(i).id);
jo.put("WEPP_ID", aoi.channels.get(i).weppID);
jo.put("LENGTH_FT", aoi.channels.get(i).length);
jo.put("WIDTH_FT", aoi.channels.get(i).width);
jo.put("SOIL_LOSS_TON", aoi.channels.get(i).loss);
jo.put("SED_YIELD_TON", aoi.channels.get(i).sedYield);
jo.put("DISCHARGE_FT3", aoi.channels.get(i).discharge);
jo.put("INTERSECTS_FIELD", 0);
chans.put(jo);
}
}
results().put("Channels", chans, "Average Annual Channel Sediment Yields and Discharges", "ft,ton,ft^3");
}
JSONArray hills = new JSONArray();
for (int i = 0; i < aoi.subcatchments.size(); i++) {
Subcatchment mysub = aoi.subcatchments.get(i);
if (!splitSubcatchments) {
if (mysub.weppid > 0) {
JSONObject jo = new JSONObject();
jo.put("TAUDEM_ID", mysub.id);
jo.put("WEPP_ID", mysub.weppid);
if (mysub.repHillslopeFlowpath != null) {
jo.put("LENGTH_FT", mysub.repHillslopeFlowpath.totalLengthMeters * CONV_M_TO_FT);
} else {
jo.put("LENGTH_FT", 0);
}
jo.put("WIDTH_FT", mysub.repHillslopeWidth * CONV_M_TO_FT);
jo.put("RUNOFF_IN", mysub.avgRunoff);
jo.put("SOIL_LOSS_TONAC", mysub.avgSoilLoss);
jo.put("SED_YIELD_TONAC", mysub.avgSedYield);
jo.put("NRCSSOILLOSS_TONAC", mysub.nrcssoilloss);
jo.put("IRRIGATION_IN", mysub.irrigation);
jo.put("IRRIGATION_FT3", mysub.irrigationVol);
jo.put("INTERSECTS_FIELD", 0);
hills.put(jo);
}
} else {
SubcatchmentSubarea mysubsub;
for (int j = 0; j < 3; j++) {
if (j == 0) {
mysubsub = mysub.leftsub;
} else if (j == 1) {
mysubsub = mysub.rightsub;
} else {
mysubsub = mysub.topsub;
}
if (mysubsub != null) {
JSONObject jo = new JSONObject();
jo.put("TAUDEM_ID", mysub.id);
jo.put("WEPP_ID", mysubsub.weppid);
jo.put("WEPPALTID", mysubsub.weppAltID);
jo.put("ORIENTATION", mysubsub.getOrientation());
if (mysubsub.repHillslopeFlowpath != null) {
jo.put("LENGTH_FT", mysubsub.repHillslopeFlowpath.totalLengthMeters * CONV_M_TO_FT);
} else {
jo.put("LENGTH_FT", 0);
}
jo.put("WIDTH_FT", mysubsub.repHillslopeWidth * CONV_M_TO_FT);
jo.put("RUNOFF_IN", mysubsub.avgRunoff);
jo.put("SOIL_LOSS_TONAC", mysubsub.avgSoilLoss);
jo.put("SED_YIELD_TONAC", mysubsub.avgSedYield);
jo.put("NRCSSOILLOSS_TONAC", mysub.nrcssoilloss);
jo.put("IRRIGATION_IN", mysub.irrigation);
jo.put("IRRIGATION_FT3", mysub.irrigationVol);
jo.put("INTERSECTS_FIELD", 0);
jo.put("FLOWPATHS_FOUND", mysubsub.numFlowpaths);
jo.put("GRID_CELLS", mysubsub.cells);
hills.put(jo);
}
}
}
}
results().put("Hillslopes", hills, "Average Annual Representative Hillslopes Runoff, Soil Loss and Sediment Yields", "in, ton/ac, ton/ac");
putResultIfFileExist("inputsummary.json", "Watershed/Field Inputs summary");
putResultIfFileExist("outputsummary.json", "Watershed/Field Output summary");
// flowpathloss grid is only available for flowpath runs
if (simulationType.equals("Watershed-Flowpaths") || simulationType.equals("Field"))
putResultIfFileExist("flowpathloss.asc", "Watershed/Field flowpath soil loss results (ton/ac/yr)");
// These grids are available from all simulations
putResultIfFileExist("rephillslope.asc", "Watershed/Field representative hillslope soil loss results (ton/ac/yr)");
putResultIfFileExist("repsedleaving.asc", "Watershed/Field representative hillslope sediment leaving (ton/ac/yr)");
putResultIfFileExist("reprunoff.asc", "Watershed/Field representative hillslope runoff (in/yr)");
if (simulationType.equals("Watershed-Flowpaths") || simulationType.equals("Watershed")) {
putResultIfFileExist("output/loss_pw0.txt", "WEPP model watershed main text output");
}
if (splitSubcatchments)
putResultIfFileExist("topazSubcatchments.asc", "Subcatchments split, TOPAZ emulation");
}
private void putResultIfFileExist(String file, String description) {
File f = workspace().getFile(file);
if (f.exists())
results().put(f, description);
else
LOG.info("Missing: " + file);
}
void removeFiles() {
// only keep files really needed, archive can get too large otherwise
aoi.removeFiles();
}
void createOutputGrids() throws ServiceException {
// create empty grids the same size as the subcatchment grid
outSoilLoss_grid = new Grid(subcatchment_grid, GridType.FLOAT_GRID, -1);
outSedYield_grid = new Grid(subcatchment_grid, GridType.FLOAT_GRID, -1);
outRunoff_grid = new Grid(subcatchment_grid, GridType.FLOAT_GRID, -1);
outFlowpathLoss_grid = new Grid(subcatchment_grid, GridType.FLOAT_GRID, -999);
sedWeight_grid = new Grid(subcatchment_grid, GridType.FLOAT_GRID, 0);
if (!splitSubcatchments) {
aoi.createSoilLossGrid(outSoilLoss_grid, subcatchment_grid);
aoi.createSedYieldGrid(outSedYield_grid, subcatchment_grid);
aoi.createRunoffGrid(outRunoff_grid, subcatchment_grid);
} else {
aoi.createSoilLossGridSubareas(outSoilLoss_grid, sub3_grid);
aoi.createSedYieldGridSubareas(outSedYield_grid, sub3_grid);
aoi.createRunoffGridSubareas(outRunoff_grid, sub3_grid);
}
aoi.createFlowpathLossGrid(outFlowpathLoss_grid, sedWeight_grid);
channel_grid.maskChannels(outSoilLoss_grid, outSedYield_grid, outRunoff_grid, -1);
}
void readLinksCSV(File csvfile) throws ServiceException {
String row;
int line = 0;
int chanIDCol = -1;
int downCol = -1;
int up1Col = -1;
int up2Col = -1;
int lastCol = -1;
int orderCol = -1;
try (BufferedReader csvReader = new BufferedReader(new FileReader(csvfile))) {
while ((row = csvReader.readLine()) != null) {
String[] data = row.split(",");
if (line == 0) {
// header
for (int i = 0; i < data.length; i++) {
if (data[i].equals("LINKNO")) {
chanIDCol = i;
if (i > lastCol) {
lastCol = i;
}
} else if (data[i].equals("DSLINKNO")) {
downCol = i;
if (i > lastCol) {
lastCol = i;
}
} else if (data[i].equals("USLINKNO1")) {
up1Col = i;
if (i > lastCol) {
lastCol = i;
}
} else if (data[i].equals("USLINKNO2")) {
up2Col = i;
if (i > lastCol) {
lastCol = i;
}
} else if (data[i].equals("strmOrder")) {
orderCol = i;
if (i > lastCol) {
lastCol = i;
}
}
}
if ((chanIDCol < 0) || (downCol < 0) || (up1Col < 0) || (up2Col < 0)) {
throw new ServiceException("Channel link file missing one or more required columns: LINKNO,DSLINKNO,USLINKNO1,USLINKNO2");
}
} else {
// regular line of data
if (data.length > (lastCol)) {
int id = Integer.parseInt(data[chanIDCol]);
int downs = Integer.parseInt(data[downCol]);
int up1 = Integer.parseInt(data[up1Col]);
int up2 = Integer.parseInt(data[up2Col]);
// may not have stream order column
int order = (orderCol > 0) ? Integer.parseInt(data[orderCol]) : 1;
Channel ch = new Channel(id, downs, up1, up2, order, this);
aoi.addChannel(ch);
} else {
throw new ServiceException("Missing columns in channel link file.");
}
}
line++;
}
} catch (Exception e) {
throw new ServiceException("Error reading file " + csvfile.getAbsolutePath());
}
}
Grid getWSGrid(GridType type, String gridURL, String localFilename) throws Exception {
File gridfilename;
if (gridURL.startsWith("http")) {
gridfilename = workspace().getFile(localFilename);
URI gridURI = new URI(gridURL);
new Client().doGET(gridURI.toString(), gridfilename);
} else {
gridfilename = workspace().getFile(gridURL);
}
Grid g = new Grid(type, gridfilename.getAbsolutePath());
return g;
}
Set<Integer> findSubcatchmentsInAOI() throws ServiceException {
// need to look in all cells enclosed in field mask and get unique
// values from subcatchments grid.
subs = field_grid.intersect(subcatchment_grid);
int idx = 1;
for (Integer sub : subs) {
Subcatchment s = new Subcatchment(sub, this, idx++);
aoi.addSubcatchment(s);
}
LOG.info("SUBCATCHMENTS>> " + subs.toString());
return subs;
}
int findFlowpaths() throws ServiceException {
int num = 0;
float fdata[][] = flowpath_grid.getFloatData();
int subdata[][] = subcatchment_grid.getIntData();
for (int i = 0; i < flowpath_grid.rowCount(); i++) {
for (int j = 0; j < flowpath_grid.colCount(); j++) {
if (fdata[i][j] == 0) { // start of a flowpath
int whatsub = subdata[i][j];
if (subs.contains(whatsub)) {
// is within area of interest
Subcatchment s = aoi.getSubcatchment(whatsub);
walkFlowpath(s, i, j);
num++;
}
}
}
}
return num;
}
int findChannels() throws ServiceException {
int cdata[][] = channel_grid.getIntData();
int nodata = channel_grid.getNoData();
Set<Integer> hitChans = new HashSet<>();
int num = 0;
for (int i = 0; i < channel_grid.rowCount(); i++) {
for (int j = 0; j < channel_grid.colCount(); j++) {
if (cdata[i][j] != nodata) { // part of a channel
// determine if this channel has already been processed
if (!hitChans.contains(cdata[i][j])) {
// hit a channel cell, find start
findChannelHead(i, j, cdata[i][j]);
// mark this channel as complete
hitChans.add(cdata[i][j]);
num++;
}
}
}
}
return num;
}
void findChannelHead(int r, int c, int id) throws ServiceException {
int cdata[][] = channel_grid.getIntData();
int d8[][] = flow_d8_grid.getIntData();
int row = r;
int col = c;
int lastRow, lastCol;
boolean moved;
boolean addThisChannel;
boolean d8neighbors = true;
int maxrows = flow_d8_grid.rowCount();
int maxcols = flow_d8_grid.colCount();
int d8nodata = flow_d8_grid.getNoData();
// Look at the neighboring cells to see which ones are potential upstream from
// this cell.
while (d8neighbors) {
lastRow = row;
lastCol = col;
moved = false;
if (((row - 1) >= 0) && ((col - 1) >= 0)) {
if (cdata[row - 1][col - 1] == id) {
if (d8[row - 1][col - 1] == SOUTH_EAST_D8) {
row = row - 1;
col = col - 1;
moved = true;
}
}
}
if (moved == false) {
if ((row - 1) >= 0) {
if (cdata[row - 1][col] == id) {
if (d8[row - 1][col] == SOUTH_D8) {
row = row - 1;
moved = true;
}
}
}
}
if (moved == false) {
if (((row - 1) >= 0) && ((col + 1) < maxcols)) {
if (cdata[row - 1][col + 1] == id) {
if (d8[row - 1][col + 1] == SOUTH_WEST_D8) {
row = row - 1;
col = col + 1;
moved = true;
}
}
}
}
if (moved == false) {
if ((col + 1) < maxcols) {
if (cdata[row][col + 1] == id) {
if (d8[row][col + 1] == WEST_D8) {
col = col + 1;
moved = true;
}
}
}
}
if (moved == false) {
if (((row + 1) < maxrows) && ((col + 1) < maxcols)) {
if (cdata[row + 1][col + 1] == id) {
if (d8[row + 1][col + 1] == NORTH_WEST_D8) {
row = row + 1;
col = col + 1;
moved = true;
}
}
}
}
if (moved == false) {
if ((row + 1) < maxrows) {
if (cdata[row + 1][col] == id) {
if (d8[row + 1][col] == NORTH_D8) {
row = row + 1;
moved = true;
}
}
}
}
if (moved == false) {
if (((row + 1) < maxrows) && ((col - 1) >= 0)) {
if (cdata[row + 1][col - 1] == id) {
if (d8[row + 1][col - 1] == NORTH_EAST_D8) {
row = row + 1;
col = col - 1;
moved = true;
}
}
}
}
if (moved == false) {
if ((col - 1) >= 0) {
if (cdata[row][col - 1] == id) {
if (d8[row][col - 1] == EAST_D8) {
col = col - 1;
moved = true;
}
}
}
}
addThisChannel = false;
if (moved == false) {
// reached starting/head cell, none above this cell
addThisChannel = true;
} else {
if ((col < 0) || (row < 0) || (col >= maxcols) || (row >= maxrows)) {
// ran off grid, use last position
addThisChannel = true;
} else {
if (d8[row][col] == d8nodata) {
// ran off edge of field mask, use last position
addThisChannel = true;
}
}
}
if (addThisChannel) {
d8neighbors = false;
// add start position for channel
if ((lastRow == 0) && (lastCol == 0)) {
aoi.setChannelStart(id, -1, -1);
}
aoi.setChannelStart(id, lastRow, lastCol);
}
}
}
void walkFlowpath(Subcatchment s, int row, int col) throws ServiceException {
int cgrid[][] = channel_grid.getIntData();
int d8[][] = flow_d8_grid.getIntData();
float slpgrid[][] = slope_d8_grid.getFloatData();
int sgrid[][] = soil_grid.getIntData();
int mgrid[][] = man_grid.getIntData();
List<Integer> rows = new ArrayList<>();
List<Integer> cols = new ArrayList<>();
List<Float> dist = new ArrayList<>();
List<Float> slp = new ArrayList<>();
List<Integer> man = new ArrayList<>();
List<Integer> soil = new ArrayList<>();
float cellsize = (float) channel_grid.getCellsize();
float cellsizediag = (float) Math.sqrt((double) ((cellsize * cellsize) + (cellsize * cellsize)));
int nodata = channel_grid.getNoData();
int d8nodata = flow_d8_grid.getNoData();
int soilnodata = soil_grid.getNoData();
int mannodata = man_grid.getNoData();
int maxrows = flow_d8_grid.rowCount();
int maxcols = flow_d8_grid.colCount();
boolean walking = true;
while (walking) {
rows.add(row);
cols.add(col);
slp.add(slpgrid[row][col]);
if (sgrid[row][col] == soilnodata) {
soil.add(defaultSoil);
} else {
soil.add(sgrid[row][col]);
}
if (mgrid[row][col] == mannodata) {
man.add(defaultManagement);
} else {
man.add(mgrid[row][col]);
}
switch (d8[row][col]) {
case NORTH_D8:
dist.add(cellsize);
row--;
break;
case NORTH_EAST_D8:
dist.add(cellsizediag);
row--;
col++;
break;
case EAST_D8:
dist.add(cellsize);
col++;
break;
case SOUTH_EAST_D8:
dist.add(cellsizediag);
row++;
col++;
break;
case SOUTH_D8:
dist.add(cellsize);
row++;
break;
case SOUTH_WEST_D8:
dist.add(cellsizediag);
row++;
col--;
break;
case WEST_D8:
dist.add(cellsize);
col--;
break;
case NORTH_WEST_D8:
dist.add(cellsizediag);
row--;
col--;
break;
}
// check if we hit a channel or went out of bounds
if ((row < 0) || (col < 0) || (row >= maxrows) || (col >= maxcols)) {
s.addFlowpath(rows, cols, slp, man, soil, dist, -1, -1, -1);
walking = false;
} else {
if ((cgrid[row][col] != nodata) || (d8[row][col] == d8nodata)) {
s.addFlowpath(rows, cols, slp, man, soil, dist, row, col, cgrid[row][col]);
walking = false;
}
}
}
}
void walkChannelFlowpath(Channel s) throws ServiceException {
int cgrid[][] = channel_grid.getIntData();
int d8[][] = flow_d8_grid.getIntData();
float slpgrid[][] = slope_d8_grid.getFloatData();
int sgrid[][] = soil_grid.getIntData();
int mgrid[][] = man_grid.getIntData();
List<Integer> rows = new ArrayList<>();
List<Integer> cols = new ArrayList<>();
List<Float> dist = new ArrayList<>();
List<Float> slp = new ArrayList<>();
List<Integer> man = new ArrayList<>();
List<Integer> soil = new ArrayList<>();
float cellsize = (float) channel_grid.getCellsize();
float cellsizediag;
int row, col;
int maxrows, maxcols;
int MAX_CELLS_IN_FLOWPATH = 1000;
row = s.startRow;
col = s.startCol;
if ((row == -1) && (col == -1)) {
LOG.info("Channel listed in links.csv not found in channel grid, looking in subcatchment grid");
// see if it listed in the subcatchment grid.
int subgrid[][] = subcatchment_grid.getIntData();
for (int i = 0; i < subcatchment_grid.rowCount(); i++) {
for (int j = 0; j < subcatchment_grid.colCount(); j++) {
if (subgrid[i][j] == s.id) { // part of a channel
s.startRow = i;
s.startCol = j;
row = i;
col = j;
}
}
}
}
if ((row == -1) && (col == -1)) {
LOG.info("Channel Flowpath inconsistent for subcatchment: " + s.id + " links.csv lists channel but none found.");
rows.add(0);
cols.add(0);
slp.add((float)0.001);
soil.add(defaultSoil);
man.add(defaultManagement);
dist.add(cellsize);
s.addFlowpath(rows, cols, slp, man, soil, dist);
LOG.info("Added pseudo channel soil: " + defaultSoil + " " + defaultManagement);
return;
}
maxrows = flow_d8_grid.rowCount();
maxcols = flow_d8_grid.colCount();
boolean walking = true;
cellsizediag = (float) Math.sqrt((double) ((cellsize * cellsize) + (cellsize * cellsize)));
int nodata = channel_grid.getNoData();
int d8nodata = flow_d8_grid.getNoData();
int soilnodata = soil_grid.getNoData();
int mannodata = man_grid.getNoData();
s.addFlowpath(rows, cols, slp, man, soil, dist);
while (walking) {
if (rows.size() > MAX_CELLS_IN_FLOWPATH) {
throw new ServiceException("Channel Flowpath inconsistent for subcatchment: " + s.id + " starting from row: " + s.startRow + " and column: " + s.startCol);
}
rows.add(row);
cols.add(col);
slp.add(slpgrid[row][col]);
if (sgrid[row][col] == soilnodata) {
if (defaultSoil == soilnodata) {
throw new ServiceException("Channel Flowpath soil inconsistent for subcatchment: " + s.id + " starting from row: " + s.startRow + " and column: " + s.startCol);
}
soil.add(defaultSoil);
} else {
soil.add(sgrid[row][col]);
}
if (mgrid[row][col] == mannodata) {
if (defaultManagement == mannodata) {
throw new ServiceException("Channel Flowpath management inconsistent for subcatchment: " + s.id + " starting from row: " + s.startRow + " and column: " + s.startCol);
}
man.add(defaultManagement);
} else {
man.add(mgrid[row][col]);
}
switch (d8[row][col]) {
case NORTH_D8:
dist.add(cellsize);
row--;
break;
case NORTH_EAST_D8:
dist.add(cellsizediag);
row--;
col++;
break;
case EAST_D8:
dist.add(cellsize);
col++;
break;
case SOUTH_EAST_D8:
dist.add(cellsizediag);
row++;
col++;
break;
case SOUTH_D8:
dist.add(cellsize);
row++;
break;
case SOUTH_WEST_D8:
dist.add(cellsizediag);
row++;
col--;
break;
case WEST_D8:
dist.add(cellsize);
col--;
break;
case NORTH_WEST_D8:
dist.add(cellsizediag);
row--;
col--;
break;
}
// check if we hit the end of this channel
if ((row < 0) || (col < 0) || (row >= maxrows) || (col >= maxcols)) {
s.addFlowpath(rows, cols, slp, man, soil, dist);
walking = false;
} else {
if ((cgrid[row][col] != s.id) || (d8[row][col] == d8nodata)) {
s.addFlowpath(rows, cols, slp, man, soil, dist);
walking = false;
}
}
}
}
/**
* Calls the CSIP service to run CLIGEN and return a climate file with
* optional PRISM adjustments.
*
* @throws JSONException parsing JSON errors
* @throws ServiceException CSIP message to return if failed.
* @throws Exception file writing errors
*/
protected void getClimateFile() throws JSONException, ServiceException, Exception {
JSONObject climateRequest = new JSONObject();
JSONObject climateResponse;
JSONObject meta = new JSONObject();
JSONArray paramObj = new JSONArray();
JSONObject inputFeature = new JSONObject();
JSONObject collection = new JSONObject();
JSONArray features = new JSONArray();
JSONObject feature = new JSONObject();
JSONObject properties = new JSONObject();
JSONObject geometry = new JSONObject();
JSONArray coordinates = new JSONArray();
JSONObject prism = new JSONObject();
JSONObject dataVersion = new JSONObject();
JSONObject runYears = new JSONObject();
JSONObject fileName = new JSONObject();
JSONObject jparFile = new JSONObject();
JSONObject adjustProb = new JSONObject();
JSONObject randomSeed = new JSONObject();
URI parUri;
File parFile;
Map<String, JSONObject> resultMap;
meta.put("mode", "sync");
climateRequest.put(KEY_METAINFO, meta);
climateRequest.put(KEY_PARAMETER, paramObj);
paramObj.put(inputFeature);
inputFeature.put(KEY_NAME, "input_zone_features");
inputFeature.put(KEY_VALUE, collection);
collection.put("type", "FeatureCollection");
collection.put("features", features);
features.put(feature);
feature.put("type", "Feature");
feature.put("properties", properties);
properties.put(KEY_NAME, "pt one");
properties.put("gid", 1);
feature.put("geometry", geometry);
geometry.put("type", "Point");
geometry.put("coordinates", coordinates);
coordinates.put(longitude);
coordinates.put(latitude);
if (randomSeedVal > -1) {
randomSeed.put(KEY_NAME, "randSeed");
randomSeed.put(KEY_VALUE, randomSeedVal);
paramObj.put(randomSeed);
}
paramObj.put(prism);
prism.put(KEY_NAME, "usePRISM");
prism.put(KEY_VALUE, usePRISM);
paramObj.put(adjustProb);
adjustProb.put(KEY_NAME, "adjustPWW_PWD");
adjustProb.put(KEY_VALUE, adjustPWW_PWD);
paramObj.put(dataVersion);
// set correct parameter, this chnaged from v1 to v2
if (climateServiceURL.endsWith("cligen_prism/wepp/1.0")) {
dataVersion.put(KEY_NAME, "climateDataVersion");
runYears.put(KEY_NAME, WEPP_KEY_RUN_YEARS);
} else {
dataVersion.put(KEY_NAME, "dataVersion");
runYears.put(KEY_NAME, "duration");
}
dataVersion.put(KEY_VALUE, climateDataVersion);
paramObj.put(runYears);
runYears.put(KEY_VALUE, run_years);
paramObj.put(fileName);
fileName.put(KEY_NAME, "outputFile");
fileName.put(KEY_VALUE, "wepp.cli");
paramObj.put(jparFile);
jparFile.put(KEY_NAME, "returnParFiles");
jparFile.put(KEY_VALUE, "true");
LOG.info("Request URL: " + climateServiceURL);
LOG.info("CLIMATE Request: " + climateRequest.toString());
climateResponse = new Client().doPOST(climateServiceURL, climateRequest);
//LOG.info("CLIMATE Response: " + climateResponse.toString());
JSONObject responseMeta = climateResponse.getJSONObject(KEY_METAINFO);
if (!responseMeta.getString(KEY_STATUS).equalsIgnoreCase("Failed")) {
resultMap = JSONUtils.getResults(climateResponse);
URI climateURI = new URI(JSONUtils.getStringParam(resultMap, "wepp.cli", ""));
String climateFileName = climateURI.getPath().substring(climateURI.getPath().lastIndexOf("/") + 1, climateURI.getPath().length());
File climateFile = workspace().getFile(climateFileName);
new Client().doGET(climateURI.toString(), climateFile);
if (usePRISM) {
parUri = new URI(JSONUtils.getStringParam(resultMap, "cligenRecordPrism.par", ""));
parFile = workspace().getFile("wepp.par");
if (parUri.getHost() == null) {
LOG.severe("CligenRecordPrism.par missing from cligen response.");
parUri = new URI(JSONUtils.getStringParam(resultMap, "cligenRecord.par", ""));
}
if (parUri.getHost() != null) {
new Client().doGET(parUri.toString(), parFile);
} else {
LOG.severe("CligenRecord.par missing from cligen response.");
}
} else {
// get correct result, this name changed from v1 to v2
if (climateServiceURL.endsWith("cligen_prism/wepp/1.0")) {
parUri = new URI(JSONUtils.getStringParam(resultMap, "base.par", ""));
} else {
parUri = new URI(JSONUtils.getStringParam(resultMap, "cligenRecord.par", ""));
}
parFile = workspace().getFile("wepp.par");
new Client().doGET(parUri.toString(), parFile);
}
} else {
String error = responseMeta.getString(ERROR);
throw new ServiceException("Climate service error: " + error);
}
}
protected boolean getManagementFiles() throws Exception {
JSONArray allparms;
JSONObject myRequest;
String manfileURL;
String manfileName;
JSONObject oneRot;
String name;
int id;
JSONObject crlmodobj = parameter().getJSON(CRLMOD);
managementDictAll = new JSONArray();
allparms = new JSONArray();
myRequest = new JSONObject();
JSONArray temp = new JSONArray();
temp.put("0");
allparms = allparms.put(JSONUtils.data("onlyConvertManagements", true));
allparms = allparms.put(JSONUtils.data("latitude", 0));
allparms = allparms.put(JSONUtils.data("longitude", 0));
allparms = allparms.put(JSONUtils.data("length", 100));
allparms = allparms.put(JSONUtils.data("soilPtr", temp));
allparms = allparms.put(JSONUtils.data("crlmod", crlmodobj));
String metainfo = "{\"request-results\" : [ \"SLOPE_DELIVERY\",\"SLOPE_T_VALUE\",\"SLOPE_DEGRAD\"],\"mode\" : \"sync\"}";
JSONObject m = new JSONObject(metainfo);
myRequest = myRequest.put("metainfo", m);
myRequest = myRequest.put("parameter", allparms);
LOG.info("WEPP-HILL REQUEST URL: " + weppHillslopeURL);
LOG.info("WEPP-HILL REQUEST:" + myRequest.toString());
// call the wepp hillslope service to do the management conversion
WEPPHillslopeServiceCall wwe04 = new WEPPHillslopeServiceCall(weppHillslopeURL, m, allparms);
try {
wwe04.call();
} catch (ServiceException ex) {
String metaError = wwe04.getMetaError();
Logger.getLogger(WeppSoil.class.getName()).log(Level.SEVERE, null, ex);
if (!metaError.isEmpty())
throw new ServiceException("Error getting WEPP hillslope management.");
}
JSONArray results = wwe04.getResultSection();
if (results == null)
throw new ServiceException("Error getting WEPP hillslope management. - Results are null.");
LOG.info(results.toString());
for (int i = 0; i < results.length(); i++) {
try {
manfileName = results.getJSONObject(i).getString("name");
manfileURL = results.getJSONObject(i).getString("value");
} catch (Exception ex) {
throw new ServiceException("Error getting WEPP hillslope management.");
}
boolean rotInDict = false;
String mparts[];
for (int j = 0; j < managementDict.length(); j++) {
oneRot = managementDict.getJSONObject(j);
name = oneRot.getString("name") + ".rot";
id = oneRot.getInt("id");
if (j == 0) {
defaultManagement = id;
LOG.info("Setting default management: " + id);
}
mparts = manfileName.split("_", 2);
if (name.equals(mparts[1])) {
// make sure the name corresponds to the index that will be
// in the grid file.
manfileName = Integer.toString(id) + "_" + name;
rotInDict = true;
int cellCount = man_grid.cellCountWithMask(id, field_grid);
oneRot.put("cells", cellCount);
managementDictAll.put(oneRot);
break;
}
}
// use the dictionary to define what managements are needed
if (rotInDict) {
File manFile = workspace().getFile(manfileName);
try {
new Client().doGET(manfileURL, manFile);
} catch (IOException ex) {
throw new ServiceException("Cannot create the management files locally with the returned data from WEPP Hillslope: " + ex.getMessage(), ex);
}
}
}
return true;
}
protected void getSoilFiles() throws JSONException, ServiceException, Exception {
soilDictAll = new JSONArray();
for (int i = 0; i < soilDict.length(); i++) {
JSONObject soil = soilDict.getJSONObject(i);
String onecokey = soil.getString("cokey");
if (!onecokey.isEmpty()) {
int id = soil.getInt("id");
String idxFilename = workspace().getFile(Integer.toString(id) + "_" + onecokey + ".sol").toString();
File idxFilenameFile = workspace().getFile(Integer.toString(id) + "_" + onecokey + ".sol");
File onecokeyFile = workspace().getFile(onecokey + ".sol");
if (onecokeyFile.exists()) {
// Already got this soil, copy to table specific name
FileUtils.copyFile(onecokeyFile, idxFilenameFile);
} else {
LOG.info("Request saving soil to: " + workspace().getDir().toString() + "/" + onecokey + ".sol");
buildSoilInput(idxFilename, onecokey);
FileUtils.copyFile(idxFilenameFile, onecokeyFile);
}
int cellCount = soil_grid.cellCountWithMask(id, field_grid);
soil.put("cells", cellCount);
soilDictAll.put(soil);
if (defaultSoil == 0) {
defaultSoil = id;
LOG.info("Setting default soil: " + id);
}
} else {
throw new ServiceException("Cannot create the soil file locally for soil, missing COKEY: " + soil.getInt("id") + " named: " + soil.getString("name"));
}
}
}
/**
* This calls functions to build the WEPP soil files.
*
* @param file Name of soil file where output is written
* @param soilid SSURGO soil ID in the format mukey:cokey or cokey
* @throws JSONException JSON
* @throws Exception any errors parsing numbers.
*
*/
protected void buildSoilInput(String file, String soilid) throws JSONException, Exception {
// Need to use the soil id from the request to create a soil file with
// WeppSoil
int cokey = Integer.parseInt(soilid);
LOG.info("SOIL SERVICE CALL: " + soilServiceURL + " " + soilid);
WeppSoil theSoil = new WeppSoil(LOG, soilServiceURL);
if (theSoil.getSoilCSIP(metainfo().toString(), cokey, workspace().getDir(), file) == false) {
// Updated - push the error up by throwing an exception, let the calling code
// or user interface decide how to handle this condition.
String msg = "The cokey " + soilid + " provided does not exist in the Soils Data Mart.<br>"
+ "Soil identifier information in project may not be up to date.<br><br>"
+ "Data returned from the WEPPSoilInput service did not contain the expected results. ";
throw new ServiceException(msg);
}
}
public String soilIndexToName(int idx) throws JSONException {
for (int i = 0; i < soilDict.length(); i++) {
JSONObject soil = soilDict.getJSONObject(i);
String onecokey = soil.getString("cokey");
int id = soil.getInt("id");
if (id == idx)
return Integer.toString(id) + "_" + onecokey + ".sol";
}
return "";
}
public String soilIndexToShortName(int idx) throws JSONException {
for (int i = 0; i < soilDict.length(); i++) {
JSONObject soil = soilDict.getJSONObject(i);
int id = soil.getInt("id");
if (id == idx)
return soil.getString("name");
}
return "???";
}
public String manIndexToName(int idx) throws JSONException {
for (int i = 0; i < managementDict.length(); i++) {
JSONObject oneRot = managementDict.getJSONObject(i);
int id = oneRot.getInt("id");
if (id == idx)
return Integer.toString(id) + "_" + oneRot.getString("name") + ".rot";
}
return "";
}
public String manIndexToShortName(int idx) throws JSONException {
for (int i = 0; i < managementDict.length(); i++) {
JSONObject oneRot = managementDict.getJSONObject(i);
int id = oneRot.getInt("id");
if (id == idx)
return oneRot.getString("name");
}
return "???";
}
public String manNameToRot(String name) throws JSONException {
for (int i = 0; i < managementDict.length(); i++) {
JSONObject oneRot = managementDict.getJSONObject(i);
if (name.equals(oneRot.getString("name")))
return Integer.toString(oneRot.getInt("id")) + "_" + name + ".rot";
}
// check if it is one of built-in managements fallow or grass
if (name.equals("fallow") || (name.equals("grass"))) {
return name + ".rot";
}
return "ERROR missing management: " + name;
}
void buildWEPPFormatChannelData() throws JSONException {
// from the channel parameter JSON refromat to what WEPP expects.
StringBuilder chandbdata = new StringBuilder();
numChannelsUsed = 0;
for (int i = 0; i < channelParameterData.length(); i++) {
JSONObject chan = channelParameterData.getJSONObject(i);
if (aoi.usesChannelParms(chan.getString("id"))) {
chandbdata.append(chan.getString("id")).append(" 0\n");
chandbdata.append(chan.getString("name")).append("\n");
chandbdata.append(chan.getString("Comment")).append("\n");
chandbdata.append("comment line 2\n");
chandbdata.append("comment line 3\n");
chandbdata.append(chan.getInt("ishape")).append(" ");
chandbdata.append(chan.getInt("icntrl")).append(" ");
chandbdata.append(chan.getInt("ienslp")).append(" ");
chandbdata.append(chan.getInt("flgout")).append("\n");
chandbdata.append(chan.getDouble("chnz")).append(" ");
chandbdata.append(chan.getDouble("chnnbr")).append("\n");
chandbdata.append(chan.getDouble("chnn")).append(" ");
chandbdata.append(chan.getDouble("chnk")).append(" ");
chandbdata.append(chan.getDouble("chntcr")).append(" ");
chandbdata.append(chan.getDouble("chnedm")).append(" ");
chandbdata.append(chan.getDouble("chneds")).append("\n");
chandbdata.append(chan.getDouble("ctlslp")).append(" ");
chandbdata.append(chan.getDouble("ctlz")).append(" ");
chandbdata.append(chan.getDouble("ctln")).append("\n");
chandbdata.append(chan.getDouble("rccoeff")).append(" ");
chandbdata.append(chan.getDouble("rcexp")).append(" ");
chandbdata.append(chan.getDouble("rcoset")).append("\n");
chandbdata.append("\"").append(chan.getString("management")).append(".rot\"\n\n");
numChannelsUsed++;
}
}
chandbdata.insert(0, "99.1\n" + numChannelsUsed + "\n");
rawChannelDatabaseData = chandbdata.toString();
}
void writeWEPPFormatChannelData(String filename) throws IOException {
File chanFile = workspace().getFile(filename);
FileUtils.writeStringToFile(chanFile, rawChannelDatabaseData, "UTF-8");
}
void buildWEPPFormatImpoundmentData(String filename) throws JSONException, IOException {
File impFile = workspace().getFile(filename);
StringBuilder impbdata = new StringBuilder();
int count;
count = 0;
for (int i = 0; i < impoundmentParameterData.length(); i++) {
JSONObject imp = impoundmentParameterData.getJSONObject(i);
LOG.info("--->Checking impoundment " + imp.getString("id"));
if (aoi.usesImpoundmentParms(imp.getString("id"))) {
impbdata.append(buildWEPPFormatSingleImpoundment(imp, count));
count++;
} else {
LOG.info("Not using impoundment " + imp.getString("id"));
}
}
String header = "99.1\n" + String.valueOf(count) + "\n";
impbdata.insert(0, header);
FileUtils.writeStringToFile(impFile, impbdata.toString(), "UTF-8");
}
String buildWEPPFormatSingleImpoundment(JSONObject imp, int idx) throws JSONException {
StringBuilder myimp = new StringBuilder();
String thisimp;
thisimp = "# impoundment " + String.valueOf(idx + 1) + "\n";
myimp.append(thisimp);
myimp.append(imp.getString("id")).append(" 0\n");
myimp.append(imp.getString("name")).append("\n");
myimp.append(imp.getString("comments")).append("\n");
myimp.append("created by weppws service\n");
myimp.append("----\n");
// output the type line
if (imp.has("dropspillway")) {
myimp.append("1\n");
} else if (imp.has("culverts")) {
myimp.append("2\n");
} else if (imp.has("rockfilldam")) {
myimp.append("3\n");
} else if (imp.has("emergencyspillway")) {
myimp.append("4\n");
} else if (imp.has("filterfence")) {
myimp.append("5\n");
} else if (imp.has("perforatedriser")) {
myimp.append("6\n");
} else {
myimp.append("0\n");
}
// output drop spillway section
if (imp.has("dropspillway")) {
JSONObject sw = imp.getJSONObject("dropspillway");
int stype = sw.getInt("type");
myimp.append(stype).append("\n");
switch (stype) {
case 1:
myimp.append(String.format("%f %f %f %f\n", sw.getDouble("diars"), sw.getDouble("hrs"), sw.getDouble("coefw"), sw.getDouble("coefo")));
myimp.append(String.format("%f %f %f %f %f\n", sw.getDouble("diabl"), sw.getDouble("hrh"), sw.getDouble("lbl"), sw.getDouble("sbl"), sw.getDouble("hblot")));
break;
case 2:
myimp.append(String.format("%f %f %f %f %f\n", sw.getDouble("lenrs"), sw.getDouble("widrs"), sw.getDouble("hrs"), sw.getDouble("coefw"), sw.getDouble("coefo")));
myimp.append(String.format("%f %f %f %f %f\n", sw.getDouble("diabl"), sw.getDouble("hrh"), sw.getDouble("lbl"), sw.getDouble("sbl"), sw.getDouble("hblot")));
break;
case 3:
myimp.append(String.format("%f %f %f %f %f\n", sw.getDouble("lenrs"), sw.getDouble("widrs"), sw.getDouble("hrs"), sw.getDouble("coefw"), sw.getDouble("coefo")));
myimp.append(String.format("%f %f %f %f %f %f\n", sw.getDouble("hitbl"), sw.getDouble("widbl"), sw.getDouble("hrh"), sw.getDouble("lbl"), sw.getDouble("sbl"), sw.getDouble("hblot")));
break;
}
myimp.append(String.format("%f %f %f\n", sw.getDouble("ke"), sw.getDouble("kb"), sw.getDouble("kc")));
} else {
myimp.append("0\n");
}
// output culvert section
if (imp.has("culverts")) {
JSONArray culs = imp.getJSONArray("culverts");
for (int i = 0; i < culs.length(); i++) {
JSONObject cul = culs.getJSONObject(i);
myimp.append(String.format("%d\n%d\n", i + 1, i + 1)); // culvert is present
myimp.append(String.format("%f %f %f %f %f %f\n", cul.getDouble("arcv"), cul.getDouble("hitcv"), cul.getDouble("hcv"), cul.getDouble("lcv"), cul.getDouble("scv"), cul.getDouble("hcvot")));
myimp.append(String.format("%f %f %f\n", cul.getDouble("ke"), cul.getDouble("kb"), cul.getDouble("kc")));
}
if (culs.length() < 2) {
myimp.append("0\n"); // only 1 culvert, 0 for second
}
} else {
myimp.append("0\n0\n"); // there are options for 2 culverts, 0 indicates no culverts for both
}
// output rock fill checkdam section
if (imp.has("rockfilldam")) {
myimp.append("1\n"); // rockfill checkdam is present
JSONObject rd = imp.getJSONObject("rockfilldam");
myimp.append(String.format("%f %f %f %f %f\n", rd.getDouble("lnrf"), rd.getDouble("hrf"), rd.getDouble("hotrf"), rd.getDouble("wdrf"), rd.getDouble("diarf")));
} else {
myimp.append("0\n");
}
// output emergency spillway section
if (imp.has("emergencyspillway")) {
JSONObject es = imp.getJSONObject("emergencyspillway");
int stype = es.getInt("type");
myimp.append(stype).append("\n");
switch (stype) {
case 1:
myimp.append(String.format("%f %f %f %f %f\n", es.getDouble("bwes"), es.getDouble("sses"), es.getDouble("nes"), es.getDouble("hes"), es.getDouble("hmxes")));
myimp.append(String.format("%f %f %f %f %f\n", es.getDouble("ses1"), es.getDouble("les1"), es.getDouble("ses2"), es.getDouble("les2"), es.getDouble("ses3")));
break;
case 2:
JSONArray hest = imp.getJSONArray("hest");
myimp.append(String.format("%d\n%f\n", hest.length(), es.getDouble("hes")));
for (int i = 0; i < hest.length(); i++) {
myimp.append(String.format("%f\n", hest.getDouble(i)));
}
JSONArray qes = imp.getJSONArray("qes");
for (int i = 0; i < qes.length(); i++) {
myimp.append(String.format("%f\n", qes.getDouble(i)));
}
break;
}
} else {
myimp.append("0\n");
}
// output filter fence section
if (imp.has("filterfence")) {
JSONObject ff = imp.getJSONObject("filterfence");
int stype = ff.getInt("type");
myimp.append(stype).append("\n");
myimp.append(String.format("%f %f %f %f\n", ff.getDouble("vsl"), ff.getDouble("wdff"), ff.getDouble("hff"), ff.getDouble("hotff")));
} else {
myimp.append("0\n");
}
// output perorated riser section
if (imp.has("perforatedriser")) {
myimp.append("1\n");
JSONObject pr = imp.getJSONObject("perforatedriser");
myimp.append(String.format("%f %f %f %f %f %f %f\n", pr.getDouble("hr"), pr.getDouble("hb"), pr.getDouble("hs"), pr.getDouble("hd"), pr.getDouble("diar"), pr.getDouble("as"), pr.getDouble("diab")));
myimp.append(String.format("%f %f %f %f %f %f %f %f\n", pr.getDouble("hrh"), pr.getDouble("lbl"), pr.getDouble("sbl"), pr.getDouble("diabl"), pr.getDouble("cb"), pr.getDouble("coefw"), pr.getDouble("coefo"), pr.getDouble("cs")));
myimp.append(String.format("%f %f %f\n", pr.getDouble("ke"), pr.getDouble("kb"), pr.getDouble("kc")));
} else {
myimp.append("0\n");
}
// output miscellaneous and stage-area-length data that all types share
JSONObject misc = imp.getJSONObject("misc");
myimp.append(String.format("%f %f %f %f %f\n", misc.getDouble("htop"), misc.getDouble("hfull"), misc.getDouble("h"), misc.getDouble("deltat"), misc.getDouble("qinf")));
myimp.append(String.format("%d %d\n", misc.getInt("isize"), misc.getInt("ndiv")));
JSONArray hal = misc.getJSONArray("hal");
myimp.append(String.format("%d\n", hal.length()));
myimp.append(String.format("%f %f %f\n", misc.getDouble("hmin"), misc.getDouble("a0"), misc.getDouble("l0")));
for (int i = 0; i < hal.length(); i++) {
myimp.append(String.format("%f\n", hal.getDouble(i)));
}
JSONArray area = misc.getJSONArray("area");
for (int i = 0; i < area.length(); i++) {
myimp.append(String.format("%f\n", area.getDouble(i)));
}
JSONArray length = misc.getJSONArray("length");
for (int i = 0; i < length.length(); i++) {
myimp.append(String.format("%f\n", length.getDouble(i)));
}
return myimp.toString();
}
void setAllChannelOrderNames(String name) throws JSONException {
for (int j = 0; j < channelOrderData.length(); j++) {
JSONObject ch = channelOrderData.getJSONObject(j);
ch.put("name", name);
}
}
void setAllChannelOrderWidths(int width) throws JSONException {
for (int j = 0; j < channelOrderData.length(); j++) {
JSONObject ch = channelOrderData.getJSONObject(j);
ch.put("width", width);
}
}
static final List<String> ckeysStrs = Arrays.asList("comment", "management");
static final List<String> ckeysInts = Arrays.asList("ishape", "icntrl", "ienslp", "flgout", "width");
static final List<String> ckeysDbl = Arrays.asList("chnz", "chnnbr", "chnn", "chnk", "chntcr",
"chnedm", "chneds", "ctlslp", "ctlz", "ctln", "rccoeff", "rcexp", "rcoset");
void modifyChannelRecord(String id, JSONObject chdata) throws JSONException {
for (int j = 0; j < channelParameterData.length(); j++) {
JSONObject ch = channelParameterData.getJSONObject(j);
if (ch.getString("id").equals(id)) {
Iterator it = chdata.keys();
while (it.hasNext()) {
String pname = it.next().toString();
if (ckeysStrs.contains(pname)) {
ch.put(pname, chdata.getString(pname));
} else if (ckeysInts.contains(pname)) {
ch.put(pname, chdata.getInt(pname));
} else if (ckeysDbl.contains(pname)) {
ch.put(pname, chdata.getDouble(pname));
}
}
}
}
}
boolean findChannelSet(String id) throws JSONException {
for (int j = 0; j < channelParameterData.length(); j++) {
JSONObject ch = channelParameterData.getJSONObject(j);
if (ch.getString("id").equals(id))
return true;
}
return false;
}
void applyUsrChannelParameters() throws JSONException {
// merge data for channel parameters contained in the request into
// the channel parameter JSON bundled with the service.
if (usrChannelParameterData != null) {
for (int i = 0; i < usrChannelParameterData.length(); i++) {
JSONObject uch = usrChannelParameterData.getJSONObject(i);
if (uch.has("id")) {
// this applies to a channel data record which will
// modify all channels that reference this id
if (findChannelSet(uch.getString("id"))) {
// this applies to a single channel data record which will
// modify all channels that reference this id
modifyChannelRecord(uch.getString("id"), uch);
} else {
// this applies to s single channel with TauDEM identifier specified
// by "id". Currently only the width and parameter set can be
// changed for indivisual channels. TBD - need to add the
// ability to modify other parameters
aoi.modifySingleChannel(uch.getString("id"), uch);
}
}
}
}
}
void applyUsrOrderParameters() throws JSONException {
// merge data for channel orders contained in the request into
// the channel order JSON bundled with the service.
if (usrChannelOrderData != null) {
for (int i = 0; i < usrChannelOrderData.length(); i++) {
JSONObject uch = usrChannelOrderData.getJSONObject(i);
int order = uch.getInt("order");
// find this entry in the loaded channel order database
for (int j = 0; j < channelOrderData.length(); j++) {
JSONObject ch = channelOrderData.getJSONObject(j);
if (order == ch.getInt("order")) {
// found entry
if (uch.has("id"))
ch.put("id", uch.getString("id"));
if (uch.has("width"))
ch.put("width", uch.getInt("width"));
}
}
}
}
}
void applyAppendChannelDB() throws JSONException {
// create new channel parameter sets based on existing names
if (appendChannelDB != null) {
for (int i = 0; i < appendChannelDB.length(); i++) {
JSONObject uch = appendChannelDB.getJSONObject(i);
String def = uch.getString("def");
String base = uch.getString("base");
// find this entry in the loaded channel order database
for (int j = 0; j < channelParameterData.length(); j++) {
JSONObject ch = channelParameterData.getJSONObject(j);
if (base.equals(ch.getString("id"))) {
// found entry
JSONObject newobj = new JSONObject(ch.toString());
newobj.put("id", def);
channelParameterData.put(newobj);
modifyChannelRecord(def, uch);
}
}
}
}
}
void readChannelDatabaseJSON(File dbFile) throws ServiceException {
try {
String chandata = FileUtils.readFileToString(dbFile, "UTF-8");
JSONObject st = new JSONObject(chandata);
JSONObject chdb = st.getJSONObject("channelDatabase");
channelOrderData = chdb.getJSONArray("channelOrders");
channelParameterData = chdb.getJSONArray("channels");
} catch (IOException | JSONException e) {
throw new ServiceException("Could not read channel database file: " + dbFile.getName());
}
}
void readImpoundmentDatabaseJSON(File dbFile) throws ServiceException {
try {
// read in the JSON data for channel orders
String impounddata = FileUtils.readFileToString(dbFile, "UTF-8");
JSONObject st = new JSONObject(impounddata);
impoundmentParameterData = st.getJSONArray("impoundments");
} catch (IOException | JSONException e) {
throw new ServiceException("Could not read impoundment database file: " + dbFile.getName());
}
}
String getChannelName(int order) {
try {
for (int i = 0; i < channelOrderData.length(); i++) {
JSONObject chan = channelOrderData.optJSONObject(i);
if (chan.getInt("order") == order)
return chan.getString("id");
}
} catch (JSONException ex) {
System.out.println("Error " + ex);
}
return null;
}
int getChannelWidth(int order) {
try {
for (int i = 0; i < channelOrderData.length(); i++) {
JSONObject chan = channelOrderData.optJSONObject(i);
if (chan.getInt("order") == order)
return chan.getInt("width");
}
} catch (JSONException ex) {
System.out.println("Error " + ex);
}
return -1;
}
void applyImpoundments() throws ServiceException {
if (impoundments == null) {
return;
}
try {
for (int i = 0; i < impoundments.length(); i++) {
JSONObject imp = impoundments.optJSONObject(i);
int chanid = imp.getInt("id");
Impoundment istruct = new Impoundment(i + 1, chanid, imp.getString("def"), imp.getString("position"), aoi);
aoi.addImpoundment(istruct);
}
} catch (JSONException ex) {
System.out.println("Error " + ex);
}
}
}