Flowpath.java [src/java/m/weppws] Revision: default Date:
package m.weppws;
import csip.utils.Client;
import csip.api.server.Executable;
import static csip.ModelDataService.KEY_METAINFO;
import static csip.ModelDataService.KEY_PARAMETER;
import csip.api.client.ModelDataServiceCall;
import csip.api.server.ServiceException;
import csip.SessionLogger;
import csip.utils.JSONUtils;
import csip.utils.ZipFiles;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.json.JSONException;
import org.json.XML;
import java.io.Writer;
import java.nio.file.Files;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static m.weppws.ApplicationResources.USE64BITWEPP;
import org.codehaus.jettison.json.JSONArray;
import util.Grid;
import util.WeppConstants;
/**
*
* Represents a single flowpath, can have multiple managements or soils. Child
* of a subcatchment or channel.
*
*/
public class Flowpath {
int id;
float[] distance; // distance between cell centers for each cell in path
float[] slope; // D8 slope between each cell on path
int[] rows; // row coordinate of each cell
int[] cols; // column coordinate of each cell
int[] soils; // soil ids for each cell
int[] managements; // management ids for each cell
float[] soilLoss; // soil loss at each cell
List<Double> soilOFELengths = new ArrayList<>();
List<Integer> soilOFETypes = new ArrayList<>();
List<Double> manOFELengths = new ArrayList<>();
List<Integer> manOFETypes = new ArrayList<>();
float totalLengthMeters; // total flowpath length
float avgSoilLoss;
float avgRunoff;
float avgSedYield;
float avgIrrigation;
boolean simulationDone;
static int weightMethod;
Channel parc;
int chnEndRow;
int chnEndCol;
int chnEnd;
String posString;
WeppConstants.Orientation relativePosition;
V1_0 par;
Flowpath(int id, int rows[], int cols[], float slope[], int man[], int soil[],
float dist[], V1_0 par, int chnEndRow, int chnEndCol, int chnEnd) {
this.rows = rows;
this.cols = cols;
this.slope = slope;
distance = dist;
managements = man;
soils = soil;
this.id = id;
this.par = par;
this.chnEndRow = chnEndRow;
this.chnEndCol = chnEndCol;
this.chnEnd = chnEnd;
totalLengthMeters = 0;
avgSoilLoss = 0;
avgSedYield = 0;
avgRunoff = 0;
avgIrrigation = 0;
parc = null;
relativePosition = WeppConstants.Orientation.UNKNOWN;
posString = "?-?-?";
// convert slope from 0-1 to range 0-100%
for (int i = 0; i < slope.length; i++) {
slope[i] = ((float) ((int) (slope[i] * 10000))) / 100;
if (slope[i] < 0.1) {
slope[i] = (float) 0.1;
}
distance[i] = ((float) ((int) (distance[i] * 100))) / 100;
totalLengthMeters += distance[i];
}
simulationDone = false;
weightMethod = 0; // weighted average, gives more wieght to longer flowpaths when they merge
//weightMethod = 1; // average - all flowpaths that merege are averaged
//weightMethod = 2; // maximum - the highest loss at a cell is used for merged cells
}
WeppConstants.Orientation getDir() {
return relativePosition;
}
void print(Writer outfile) throws IOException, JSONException {
outfile.write(String.format("{\"id\":%d,", id));
switch (relativePosition) {
case UNKNOWN:
outfile.write(String.format("{\"DIR\":%s-%s,", "UNK", posString));
break;
case NOTFOUND:
outfile.write(String.format("{\"DIR\":%s-%s,", "BAD", posString));
break;
case TOP:
outfile.write(String.format("{\"DIR\":%s-%s,", "TOP",posString));
break;
case LEFT:
outfile.write(String.format("{\"DIR\":%s-%s,", "LEFT",posString));
break;
case RIGHT:
outfile.write(String.format("{\"DIR\":%s-%s,", "RIGHT",posString));
break;
}
outfile.write(String.format("\"rows\":%s,", Arrays.toString(rows)));
outfile.write(String.format("\"cols\":%s,", Arrays.toString(cols)));
outfile.write(String.format("\"soils\":%s,", Arrays.toString(soils)));
outfile.write(String.format("\"mans\":%s,", Arrays.toString(managements)));
if (soilLoss != null) {
outfile.write(String.format("\"loss\":%s,", Arrays.toString(soilLoss)));
}
String line = "\"dist\":[";
for (int i = 0; i < distance.length; i++) {
if (i > 0) {
line = line + "," + distance[i];
} else {
line = line + distance[i];
}
}
line = line + "],";
outfile.write(line);
line = "\"slope\":[";
for (int i = 0; i < slope.length; i++) {
if (i > 0) {
line = line + "," + slope[i]; //String.format(",%f",slope[i]*100);
} else {
line = line + slope[i]; //String.format("%f",slope[i]*100);
}
}
line = line + "],";
line = line + "\"soilLoss\":" + avgSoilLoss + "}\n";
outfile.write(line);
}
//
// runFlowpath1()
//
// Run WEPP model directly, no service URL is started.
//
JSONObject runFlowpathLocal(File workspace, Executable weppserv,
Watershed wspar, double cellsize, boolean usePassFiles) throws ServiceException, IOException, Exception {
boolean skip_runs = false;
buildSlopeInput(new File(workspace, "wepp.slp"), cellsize);
buildProjectInput(new File(workspace, "wepp.prj"), usePassFiles);
// reset soilloss
soilLoss = new float[rows.length];
simulationDone = true;
if (!skip_runs) {
int ret = weppserv.exec();
if (ret != 0) {
throw new ServiceException("WEPP run error: " + ret);
} else {
parseOutputs(new File(workspace, "output/weppout.txt"), new File(workspace, "output/plot_0.txt"), wspar);
}
// if you reuse the weppservobject, you need to reinit the
// output streams, or call getRessourceExe again.
weppserv.redirectDefaults();
} else {
avgSoilLoss = avgSedYield = avgRunoff = avgIrrigation = (float) -999;
wspar.precip = (float) -999;
wspar.weppVersion = "???";
wspar.preVersion = "???";
}
return null;
}
//
// runFlowpath()
//
// Run the flowpath service, flowpath URL services are started upto a maximum
// and then waits for some to finish before starting any new ones.
//
// JSONObject runFlowpath(File workspace, Executable weppserv,
// Watershed wspar, double cellsize, boolean usePassFiles) throws ServiceException, IOException, Exception {
//// boolean skip_runs = false;
//// String flowpathServiceURL = wspar.par.flowpathURL;
//
// buildSlopeInput(new File(workspace, "wepp.slp"), cellsize);
// buildProjectInput(new File(workspace, "wepp.prj"), usePassFiles);
//
// // reset soilloss
// soilLoss = new float[rows.length];
//
// simulationDone = true;
//
// JSONObject res = runFlowpathService(workspace, wspar);
// return res;
// }
//
//
// Starts parallel runs of flowpaths using CSIP service in separate workspaces.
//
ModelDataServiceCall runFlowpathService(File workspace, Watershed wspar, double cellsize, boolean usePassFiles)
throws JSONException, ServiceException, Exception {
File fp_ws = new File(workspace, Integer.toString(id));
if (!fp_ws.exists())
fp_ws.mkdirs();
buildSlopeInput(new File(fp_ws, "wepp.slp"), cellsize);
buildProjectInput(new File(fp_ws, "wepp.prj"), usePassFiles);
// reset soilloss
soilLoss = new float[rows.length];
List<File> files = new ArrayList<>();
files.add(new File(fp_ws, "wepp.prj"));
files.add(new File(workspace, "wepp.cli"));
files.add(new File(fp_ws, "wepp.slp"));
Set<Integer> uniqueSoils = new HashSet<>();
for (int i = 0; i < soilOFETypes.size(); i++) {
if (!uniqueSoils.contains(soilOFETypes.get(i))) {
uniqueSoils.add(soilOFETypes.get(i));
files.add(new File(workspace, soilIndexToName(soilOFETypes.get(i))));
}
}
Set<Integer> uniqueManagements = new HashSet<>();
for (int i = 0; i < manOFETypes.size(); i++) {
if (!uniqueManagements.contains(manOFETypes.get(i))) {
uniqueManagements.add(manOFETypes.get(i));
files.add(new File(workspace, manIndexToName(manOFETypes.get(i))));
}
}
File zipFiles = ZipFiles.zip(new File(fp_ws, "weppfiles.zip"), files);
ModelDataServiceCall res = new ModelDataServiceCall()
.withDefaultLogger()
.url(wspar.par.flowpathURL)
.putMeta("csip.archive.enabled", "false")
.put(USE64BITWEPP, wspar.par.use64BitWEPP)
.put("id", id)
.attach(zipFiles)
.call();
simulationDone = true;
if (res.serviceFinished()) {
avgSoilLoss = (float) res.getDouble("SoilLoss", -999);
avgSedYield = (float) res.getDouble("SedimentYield", -999);
avgRunoff = (float) res.getDouble("Runoff", -999);
avgIrrigation = (float) res.getDouble("Irrigation", -999);
wspar.precip = (float) res.getDouble("Precipitation", -999); // the same for all FP?
wspar.weppVersion = res.getMetaString("WEPPVersion");
wspar.preVersion = res.getMetaString("PreprocessorVersion");
String cellOutputs = res.getString("SoilLossCells", "???");
readLossPlotData(cellOutputs);
}
FileUtils.deleteDirectory(fp_ws);
return res;
}
// JSONObject runFlowpathService(File workspace, Watershed wspar) throws JSONException, ServiceException, Exception {
//
//// String sessionWorkDir = workspace.getAbsolutePath();
// String flowpathServiceURL = wspar.par.flowpathURL;
// JSONObject responseMeta = null;
//
// List<File> files = new ArrayList<>();
// files.add(new File(workspace, "wepp.prj"));
// files.add(new File(workspace, "wepp.cli"));
// files.add(new File(workspace, "wepp.slp"));
//
// Set<Integer> uniqueSoils = new HashSet<>();
// for (int i = 0; i < soilOFETypes.size(); i++) {
// if (!uniqueSoils.contains(soilOFETypes.get(i))) {
// uniqueSoils.add(soilOFETypes.get(i));
// File f = new File(workspace, soilIndexToName(soilOFETypes.get(i)));
// if (f.exists()) {
// files.add(f);
// } else {
// throw new ServiceException("Could not find local file for WEPP: " + f.getName());
// }
// }
// }
//
// Set<Integer> uniqueManagements = new HashSet<>();
// for (int i = 0; i < manOFETypes.size(); i++) {
// if (!uniqueManagements.contains(manOFETypes.get(i))) {
// uniqueManagements.add(manOFETypes.get(i));
// File f = new File(workspace, manIndexToName(manOFETypes.get(i)));
// if (f.exists()) {
// files.add(f);
// } else {
// throw new ServiceException("Could not find local file for WEPP: " + f.getName());
// }
// }
// }
//
// File zipFiles = ZipFiles.zip(new File(workspace, "weppfiles.zip"), files);
//
// try {
// JSONObject flowpathRequest = new JSONObject();
// JSONObject fpResponse;
// String names[] = new String[1];
// File filesz[] = new File[1];
// JSONObject meta = new JSONObject();
// JSONArray paramObj = new JSONArray();
// meta.put("mode", "async");
// flowpathRequest.put(KEY_METAINFO, meta);
//
// if (wspar.par.use64BitWEPP) {
// JSONObject opt = new JSONObject();
// opt.put("name", "use64BitWEPP");
// opt.put("value", true);
// paramObj.put(opt);
// }
//
// flowpathRequest.put(KEY_PARAMETER, paramObj);
//
// Map<String, JSONObject> resultMap;
//
// names[0] = "weppfiles.zip";
//// files[0] = new File(sessionWorkDir + "/weppfiles.zip");
// filesz[0] = zipFiles;
//
// wspar.LOG.info("flowpathServiceURL: " + flowpathServiceURL);
//
// //wspar.LOG.info("flowpath request: " + flowpathRequest.toString());
//
// fpResponse = new Client(300).doPOST(flowpathServiceURL, flowpathRequest, filesz, names);
//
// responseMeta = fpResponse.getJSONObject(KEY_METAINFO);
//
// } catch (JSONException e) {
// e.printStackTrace();
// throw new ServiceException("Process failed to start: " + id);
// } catch (ServiceException e) {
// e.printStackTrace();
// throw new ServiceException("Process failed to start: " + id);
// } catch (Exception e) {
// e.printStackTrace();
// throw new ServiceException("Process failed to start: " + id);
// }
// return responseMeta;
// //return 0;
// }
public JSONObject checkProgress(SessionLogger LOG, JSONObject res, File workspace, Watershed wspar) throws Exception {
JSONObject status = null;
JSONObject fpResponse;
JSONObject responseMeta;
String resp;
String state;
String queryURL = wspar.par.queryURL;
Map<String, JSONObject> resultMap;
String suid = "";
try {
suid = res.getString("suid");
queryURL = queryURL + suid;
resp = new Client(10).doGET(queryURL);
fpResponse = new JSONObject(resp);
responseMeta = fpResponse.getJSONObject(KEY_METAINFO);
state = responseMeta.getString("status");
if (state.equals("Running")) {
return fpResponse;
} else {
if (state.equals("Finished")) {
resultMap = JSONUtils.getResults(fpResponse);
LOG.info("Done : " + responseMeta.toString(2));
parseOutputResp(resultMap, wspar);
} else {
if (state.equals("Failed")) {
throw new ServiceException("Process failed for flowpath with SUID: " + suid);
} else {
throw new ServiceException("Process uknown state returned for flowpath with SUID: " + suid + " state= " + state);
}
}
}
} catch (JSONException ex) {
throw new ServiceException("Could not find process information for flowpath with SUID: " + suid);
}
return status;
}
public void writeToZipFile(File path, ZipOutputStream zipStream)
throws FileNotFoundException, IOException {
System.out.println("Writing file : '" + path + "' to zip file");
FileInputStream fis = new FileInputStream(path);
ZipEntry zipEntry = new ZipEntry(path.getName());
zipStream.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipStream.write(bytes, 0, length);
}
zipStream.closeEntry();
fis.close();
}
protected String buildSlopeInput(File slpfile, double slopeWidth) throws IOException {
StringBuilder output = new StringBuilder();
double slopeAspect = 180;
if (slpfile != null) {
output.append("97.5\n#\n");
output.append("#\n1\n");
}
output.append(slopeAspect);
output.append(' ');
output.append(slopeWidth);
output.append('\n');
if (distance.length < 100) {
output.append(distance.length);
} else {
output.append("100");
}
output.append(' ');
output.append(totalLengthMeters);
output.append('\n');
double slpDist = 0;
double distPerc;
if (distance.length > 1) {
if (distance.length < WeppConstants.MAX_WEPP_SLOPE_POINTS) {
for (int i = 0; i < distance.length; i++) {
distPerc = slpDist / totalLengthMeters;
if (i > 0) {
output.append(", ");
// make sure last point is at end of slope
if (i == distance.length - 1) {
distPerc = 1.0;
}
}
output.append(String.format("%.3f %.3f", distPerc, slope[i] / 100));
slpDist = slpDist + distance[i];
}
} else {
// Too many cells to use a 1-to-1 mapping for the slope file, instead take
// selected points along the profile.
double stepSize = totalLengthMeters / WeppConstants.MAX_WEPP_SLOPE_POINTS;
double pos = 0;
int idx = 0;
for (int i = 0; i < WeppConstants.MAX_WEPP_SLOPE_POINTS; i++) {
distPerc = pos / totalLengthMeters;
if (i > 0) {
output.append(", ");
if (i == (WeppConstants.MAX_WEPP_SLOPE_POINTS - 1)) {
distPerc = 1.0;
}
}
output.append(String.format("%.3f %.3f", distPerc, slope[idx] / 100));
pos = pos + stepSize;
while ((slpDist < pos) && (idx < (distance.length - 1))) {
idx++;
slpDist = slpDist + distance[idx];
}
}
}
} else {
// only one point
output.append(String.format("0.0 %.3f 1.0 %.3f", slope[0] / 100, slope[0] / 100));
}
if (slpfile != null) {
FileUtils.writeStringToFile(slpfile, output.toString(), "UTF-8");
return null;
} else {
return output.toString();
}
}
protected void createOFELists(List<Double> lens, List<Integer> types, int dat[]) {
lens.clear();
types.clear();
int prevType = dat[0];
float totalLength = distance[0];
lens.add(Double.valueOf(totalLength));
types.add(prevType);
for (int i = 1; i < dat.length; i++) {
if (dat[i] == prevType) {
// same soil or management, increase length of this OFE
int idx = lens.size() - 1;
lens.set(idx, lens.get(idx) + distance[i]);
} else {
// new OFE starts here
totalLength = distance[i];
prevType = dat[i];
lens.add(Double.valueOf(totalLength));
types.add(prevType);
}
}
}
protected void buildProjectInput(File prjFile, boolean usePassFiles) throws IOException, ServiceException {
int years = par.run_years;
createOFELists(soilOFELengths, soilOFETypes, soils);
createOFELists(manOFELengths, manOFETypes, managements);
StringBuilder output = new StringBuilder();
output.append("Version = 98.6\n");
output.append("Name = csip-weppws\n");
output.append("Comments {\n}\n");
output.append("Units = English\n");
output.append("Landuse = 1\n");
output.append("Length = ");
output.append(totalLengthMeters);
output.append("\n");
output.append("Profile {\n");
output.append(" File = \"wepp.slp\"\n");
output.append("}\n");
output.append("Climate {\n");
output.append(" File = \"wepp.cli\"\n");
output.append("}\n");
output.append("Soil {\n");
int ofes = soilOFETypes.size() - 1;
output.append(" Breaks = " + ofes + "\n");
for (int i = 0; i < soilOFETypes.size(); i++) {
output.append(" Soil-");
output.append(i);
output.append(" {\n");
output.append(" Distance = ");
output.append(soilOFELengths.get(i));
output.append("\n");
output.append(" File = \"");
output.append(soilIndexToName(soilOFETypes.get(i)));
output.append("\"\n");
output.append(" }\n");
}
output.append("}\n");
output.append("Management {\n");
ofes = soilOFETypes.size() - 1;
output.append(" Breaks = " + ofes + "\n");
for (int i = 0; i < manOFETypes.size(); i++) {
output.append(" Management-");
output.append(i);
output.append(" {\n");
output.append(" Distance = ");
output.append(manOFELengths.get(i));
output.append("\n");
output.append(" File = \"");
output.append(manIndexToName(manOFETypes.get(i)));
output.append("\"\n");
output.append(" }\n");
}
output.append("}\n");
output.append("RunOptions {\n");
output.append(" Version = 1\n");
output.append(" SoilLossOutputType = 1\n");
output.append(" SoilLossOutputFile = AutoName\n");
output.append(" PlotFile = AutoName\n");
if (usePassFiles) {
output.append(" HillSlopePassFile = AutoName\n");
}
output.append(" SimulationYears = ");
output.append(years);
output.append("\n");
output.append(" Model = weppsm_2012\n");
output.append(" SmallEventByPass = 1\n");
output.append("}");
FileUtils.writeStringToFile(prjFile, output.toString(), "UTF-8");
}
String soilIndexToName(int idx) throws ServiceException {
String name;
try {
name = par.soilIndexToName(idx);
if (name.equals("")) {
throw new ServiceException("Could not find soil to match index: " + Integer.toString(idx));
}
} catch (JSONException je) {
throw new ServiceException("Could not find soil to match index: " + Integer.toString(idx));
}
return name;
}
String manIndexToName(int idx) throws ServiceException {
String name;
try {
name = par.manIndexToName(idx);
if (name.equals("")) {
throw new ServiceException("Could not find management to match index: " + Integer.toString(idx));
}
} catch (JSONException je) {
throw new ServiceException("Could not find management to match index: " + Integer.toString(idx));
}
return name;
}
void readLossPlotData(String cellOutputs) throws ServiceException {
if (!cellOutputs.equals("???")) {
String lines[] = cellOutputs.split("\\r?\\n");
float distArr[] = new float[lines.length];
float lossArr[] = new float[lines.length];
int j = 0;
int validLen = 0;
// skip first 4 lines, header
for (int i = 4; i < lines.length; i++) {
String[] vals = lines[i].trim().split("\\s+");
if (vals.length == 3) {
// first value is distance (m) from top of flowpath, last value is soil loss (kg/m^2)
distArr[j] = Float.parseFloat(vals[0]);
lossArr[j++] = Float.parseFloat(vals[2]) * (float) 4.4609; // convert kg/m^2 to ton/Ac
validLen = j;
}
}
float endingDist = 0;
for (int i = 0; i < distance.length; i++) {
soilLoss[i] = getLossData(endingDist, endingDist + distance[i], distArr, lossArr, validLen);
endingDist += distance[i];
}
}
}
public void parseOutputResp(Map<String, JSONObject> resultMap, Watershed wspar) throws ServiceException {
String cellOutputs = "???";
try {
wspar.precip = (float) JSONUtils.getDoubleParam(resultMap, "Precipitation", -999);
avgSoilLoss = (float) JSONUtils.getDoubleParam(resultMap, "SoilLoss", -999);
avgSedYield = (float) JSONUtils.getDoubleParam(resultMap, "SedimentYield", -999);
avgRunoff = (float) JSONUtils.getDoubleParam(resultMap, "Runoff", -999);
avgIrrigation = (float) JSONUtils.getDoubleParam(resultMap, "Irrigation", -999);
wspar.weppVersion = JSONUtils.getStringParam(resultMap, "WEPPVersion", "???");
wspar.preVersion = JSONUtils.getStringParam(resultMap, "PreprocessorVersion", "???");
cellOutputs = JSONUtils.getStringParam(resultMap, "SoilLossCells", "???");
} catch (Exception ex) {
throw new ServiceException("No results from flowpath: " + Integer.toString(id));
}
readLossPlotData(cellOutputs);
}
float getLossData(float start, float end, float X[], float loss[], int len) throws ServiceException {
float winBeg = 0;
float winEnd = X[0];
float total = 0;
float cells = 0;
float frac;
int idx = 0;
while ((start > winEnd) && (idx < len)) {
idx++;
if (idx < X.length) {
winBeg = winEnd;
winEnd = X[idx];
}
}
cells = 0;
while ((end > winBeg) && (idx < len)) {
if ((winEnd < end) && (winBeg >= start)) {
total += loss[idx];
cells = cells + 1;
} else {
if (winBeg < start) {
frac = (winEnd - start) / (winEnd - winBeg);
total += (loss[idx] * frac);
cells = cells + frac;
} else {
if (winBeg < end) {
frac = (end - winBeg) / (winEnd - winBeg);
total += (loss[idx] * frac);
cells = cells + frac;
} else {
// should not get here...
throw new ServiceException("Error resampling soil loss to flowpath");
}
}
}
winBeg = winEnd;
idx++;
if (idx < len) {
winEnd = X[idx];
}
}
return total / cells;
}
/**
* After a WEPP run a brief put file lists the main 4 outputs which as read
* and saved.
*
* @param resultsFile WEPP results
* @throws IOException error reading file
*/
public void parseOutputs(File resultsFile, File plotFile, Watershed wspar) throws IOException {
float precip, sedYield, runoff;
StringBuilder fileContents = new StringBuilder();
String cellOutputs;
try (BufferedReader reader = new BufferedReader(new FileReader(resultsFile))) {
String line = null;
while ((line = reader.readLine()) != null) {
fileContents.append(line);
}
reader.close();
String restring = XML.toJSONObject(fileContents.toString()).toString();
JSONObject results = new JSONObject(restring);
if (results == null || !results.has("RESULTS")) {
throw new IOException("The format of the results output file could not be read. Contents missing or \"RESULTS\" xml tag not found.");
}
results = results.optJSONObject("RESULTS");
wspar.precip = (float) results.optDouble("PRECIP");
avgSoilLoss = (float) results.optDouble("LOSS");
avgSedYield = (float) results.optDouble("SEDYIELD");
avgRunoff = (float) results.optDouble("RUNOFF");
avgIrrigation = (float) results.optDouble("IRRIGATION");
wspar.weppVersion = results.getString("WEPP_VERSION");
wspar.preVersion = results.getString("PREPROCESSOR_VERSION");
wspar.LOG.info("Flowpath: " + id + " " + avgSoilLoss);
cellOutputs = new String(Files.readAllBytes(plotFile.toPath()));
readLossPlotData(cellOutputs);
} catch (Exception e) {
precip = avgSoilLoss = avgSedYield = avgRunoff = avgIrrigation = (float) -999;
}
}
void updateWeightedLossGrid(Grid lossGrid, Grid sedWeight) {
if (simulationDone) {
if (weightMethod == 1) {
// plain average, all cells that merge are averages
lossGrid.updatePathWeightedLoss(soilLoss, rows, cols, 1);
sedWeight.updatePathWeight(rows, cols, 1);
}
if (weightMethod == 0) {
// cell value is weighted based on total flowpath length
float weight = totalLengthMeters;
lossGrid.updatePathWeightedLoss(soilLoss, rows, cols, weight);
sedWeight.updatePathWeight(rows, cols, weight);
}
if (weightMethod == 2) {
// cell value is always the maximum loss
lossGrid.updatePathMaxLoss(soilLoss, rows, cols);
}
}
}
boolean intersectsField(Grid field) {
boolean rc = false;
try {
int fld[][] = field.getIntData();
for (int i = 0; i < rows.length; i++) {
int r = rows[i];
int c = cols[i];
if (fld[r][c] == 1) {
rc = true;
break;
}
}
} catch (ServiceException ex) {
throw new RuntimeException("Propagated:", ex);
}
return rc;
}
void updateRepProfile(double cellsize, float repProfileSlopes[], float repProfileWeights[]) {
double weight = totalLengthMeters;
int cnt = (int) (totalLengthMeters / cellsize);
float resample[] = new float[cnt];
for (int i = 0; i < cnt; i++) {
float lower = (float) (i * cellsize);
float upper = (float) (lower + cellsize);
resample[i] = interpolateSlope(lower, upper);
}
for (int i = resample.length - 1; i >= 0; i--) {
repProfileWeights[i] += weight;
repProfileSlopes[i] += (weight * resample[i]);
}
}
float interpolateSlope(float lower, float upper) {
float newslope = 0;
int last = distance.length - 1;
int idx = last;
float win1 = distance[last];
// find first cell
while (lower > win1) {
win1 += distance[idx];
idx--;
}
float start = win1 - distance[idx];
if ((start >= lower) && (win1 >= upper)) {
// completely contained in original cell
newslope = slope[idx];
} else {
// somewhere between two slope points
if (idx < last) {
float win2 = win1 + distance[idx + 1];
float frac1 = (win1 - lower) / (upper - lower);
float frac2 = (win2 - upper) / (upper - lower);
newslope = (slope[idx] * frac1) + (slope[idx + 1] * frac2);
} else {
// just use last value
newslope = slope[last];
}
}
if (newslope > 1) {
//TODO: check this?
newslope = newslope;
}
return newslope;
}
String printProfile(double width) {
try {
return buildSlopeInput(null, width);
} catch (Exception e) {
return "";
}
}
int getPrevDir(int r, int c) throws ServiceException {
int prev = 0;
for (int i=0; i< rows.length; i++) {
if ((rows[i] == r) && (cols[i] == c)) {
if (i > 0) {
int d8[][] = par.flow_d8_grid.getIntData();
prev = d8[rows[i-1]][cols[i-1]];
} else {
prev = 0; // first cell of flowpath
}
break;
}
}
return prev;
}
int fillsub3grid(Grid sub3, int subid) throws ServiceException {
int id3 = subid;
int cellsFilled = 0;
if (relativePosition == WeppConstants.Orientation.LEFT) {
id3 = id3 + 1;
} else if (relativePosition == WeppConstants.Orientation.RIGHT) {
id3 = id3 + 2;
} else if (relativePosition == WeppConstants.Orientation.TOP) {
id3 = id3 + 3;
} else if (relativePosition == WeppConstants.Orientation.UNKNOWN) {
id3 = -10;
} else if (relativePosition == WeppConstants.Orientation.NOTFOUND) {
id3 = -20;
}
int sub[][];
sub = sub3.getIntData();
for (int i=0; i< rows.length; i++) {
sub[rows[i]][cols[i]] = id3;
cellsFilled = cellsFilled + 1;
}
return cellsFilled;
}
int fillsub3gridChannel(Grid sub3, int subid) throws ServiceException {
int sub[][];
sub = sub3.getIntData();
int cellsFilled = 0;
for (int i=0; i< rows.length; i++) {
sub[rows[i]][cols[i]] = subid;
cellsFilled = cellsFilled + 1;
}
return cellsFilled;
}
void classifyFlowpath(int order) throws ServiceException {
int d8nodata = par.flow_d8_grid.getNoData();
int d8[][] = par.flow_d8_grid.getIntData();
int chan[][] = par.channel_grid.getIntData();
if ((chnEndRow >= 0) && (chnEndCol >= 0)) {
int prevChnDir = par.aoi.findPrevChannelCellDir(chnEnd, chnEndRow, chnEndCol);
int curChnDir = d8[chnEndRow][chnEndCol];
int lastRow = rows[rows.length-1];
int lastCol = cols[cols.length-1];
int flowDir = d8[lastRow][lastCol];
if (prevChnDir > 0) {
relativePosition = determineOrientation(prevChnDir, curChnDir, flowDir);
} else {
if (prevChnDir == 0) {
if (order <= 1) {
relativePosition = WeppConstants.Orientation.TOP;
} else {
relativePosition = WeppConstants.Orientation.NOTFOUND;
}
posString = Integer.toString(curChnDir) + "-" + Integer.toString(prevChnDir) + "-" + Integer.toString(flowDir);
} else {
relativePosition = WeppConstants.Orientation.NOTFOUND;
posString = Integer.toString(curChnDir) + "-" + Integer.toString(prevChnDir) + "-" + Integer.toString(flowDir);
}
}
} else {
relativePosition = WeppConstants.Orientation.NOTFOUND;
}
if ((relativePosition == WeppConstants.Orientation.NOTFOUND) || (relativePosition == WeppConstants.Orientation.UNKNOWN)) {
// TBD - may want to handlle this and try to assign a defaut position
}
}
WeppConstants.Orientation determineOrientation(int prevChnDir, int curChnDir, int flowDir) {
WeppConstants.Orientation pos;
pos = lookupDir(Integer.toString(curChnDir) + "-" + Integer.toString(prevChnDir), flowDir);
posString = Integer.toString(curChnDir) + "-" + Integer.toString(prevChnDir) + "-" + Integer.toString(flowDir);
return pos;
}
WeppConstants.Orientation lookupDir(String seq, int f) {
WeppConstants.Orientation pos;
pos = WeppConstants.Orientation.LEFT; // assume left side
switch (seq) {
case "1-1": // E
if ((f == 2) || (f == 3) || (f == 4)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "1-2": // E
if ((f == 3) || (f == 4)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "1-3": // E
if (f == 4) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "1-4": // E
break; // everything is LEFT
case "1-5": // E
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "1-6": // E
pos = WeppConstants.Orientation.RIGHT;
break; // everything is on RIGHT
case "1-7": // E
if (f != 6) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "1-8": // E
if (f <= 4 ) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "2-1": // NE
if ((f == 2) || (f == 3) || (f == 4) || (f ==5)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "2-2": // NE
if ((f == 3) || (f == 4) || (f == 5)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "2-3": // NE
if ((f == 4) || (f == 5)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "2-4": // NE
if (f == 5) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "2-5": // NE
// all LEFT
break;
case "2-6": // NE
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "2-7": // NE
pos = WeppConstants.Orientation.RIGHT;
break; // everything is on RIGHT
case "2-8": // NE
if ((f <= 5)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "3-1": // N
if ((f == 2) || (f == 3) || (f == 4) || (f == 5) || (f == 6)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "3-2": // N
if ((f == 3) || (f == 4) || (f == 5) || (f == 6)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "3-3": // N
if ((f == 4) || (f == 5) || (f == 6)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "3-4": // N
if ((f == 5) || (f == 6)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "3-5": // N
if (f == 6) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "3-6": // N
// all LEFT
break;
case "3-7": // N
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "3-8": // N
// all RIGHT
pos = WeppConstants.Orientation.RIGHT;
break;
case "4-1": // NW
// all RIGHT
pos = WeppConstants.Orientation.RIGHT;
break;
case "4-2": // NW
if ((f == 3) || (f == 4) || (f == 5) || (f == 6) || (f ==7)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "4-3": // NW
if ((f == 4) || (f == 5) || (f == 6) || (f ==7)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "4-4": // NW
if ((f == 5) || (f == 6) || (f ==7)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "4-5": // NW
if ((f == 6) || (f ==7)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "4-6": // NW
if (f ==7) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "4-7": // NW
// all LEFT
break;
case "4-8": // NW
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "5-1": // W
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "5-2": // W
// all RIGHT
pos = WeppConstants.Orientation.RIGHT;
break;
case "5-3": // W
if ((f == 4) || (f == 5) || (f == 6) || (f ==7) || (f ==8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "5-4": // W
if ((f == 5) || (f == 6) || (f ==7) || (f ==8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "5-5": // W
if ((f == 6) || (f ==7) || (f ==8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "5-6": // W
if ((f ==7) || (f ==8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "5-7": // W
if (f ==8) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "5-8": // W
// all LEFT
break;
case "6-1": // SW
// all LEFT
break;
case "6-2": // SW
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "6-3": // SW
// all right
pos = WeppConstants.Orientation.RIGHT;
break;
case "6-4": // SW
if ((f == 1) || (f == 5) || (f == 6) || (f == 7) || (f == 8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "6-5": // SW
if ((f == 1) || (f == 6) || (f == 7) || (f == 8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "6-6": // SW
if ((f == 1) || (f == 7) || (f == 8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "6-7": // SW
if ((f == 1) || (f == 8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "6-8": // SW
if (f == 1) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "7-1": // S
if (f == 2) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "7-2": // S
// all LEFT
break;
case "7-3": // S
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "7-4": // S
// all RIGHT
pos = WeppConstants.Orientation.RIGHT;
break;
case "7-5": // S
if ((f == 1) || (f == 2) || (f == 8) || (f == 7) || (f == 6)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "7-6": // S
if ((f == 1) || (f == 2) || (f == 8) || (f == 7)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "7-7": // S
if ((f == 1) || (f == 2) || (f == 8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "7-8": // S
if ((f == 1) || (f == 2)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "8-1": // SE
if ((f == 2) || (f == 3)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "8-2": // SE
if (f == 3) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "8-3": // SE
// all LEFT
break;
case "8-4": // SE
pos = WeppConstants.Orientation.UNKNOWN;
break; // does not make sense, revert to unknown
case "8-5": // SE
// all RIGHT
pos = WeppConstants.Orientation.RIGHT;
break;
case "8-6": // SE
if ((f == 1) || (f == 2) || (f == 3) || (f == 8) || (f == 7)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "8-7": // SE
if ((f == 1) || (f == 2) || (f == 3) || (f == 8)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
case "8-8": // SE
if ((f == 1) || (f == 2) || (f == 3)) {
pos = WeppConstants.Orientation.RIGHT;
}
break;
}
return pos;
}
}