Subcatchment.java [src/java/m/weppws] Revision: default Date:
package m.weppws;
import csip.Config;
import csip.api.server.Executable;
import csip.api.server.ServiceException;
import csip.SessionLogger;
import csip.utils.Parallel;
import csip.utils.Parallel.Run;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import util.Grid;
import util.WeppConstants;
/**
* Represents a WEPP and TauDEM subcatchment. This can be modeled as flowpaths
* or combined into a representative hillslope.
*
*/
public class Subcatchment {
int id;
int weppid;
int topazid;
int topid, leftid, rightid;
int lastFlowpathID;
int topRow; // bounding box of this subcatchment
int botRow; // bounding box of this subcatchment
int leftCol; // bounding box of this subcatchment
int rightCol; // bounding box of this subcatchment
int majorSoil;
int majorLanduse;
int order;
List<Flowpath> flowpaths = new ArrayList<>(); // all flowpaths in this subcatchment
V1_0 service;
SubcatchmentSubarea topsub;
SubcatchmentSubarea leftsub;
SubcatchmentSubarea rightsub;
float repProfileWeights[];
float repProfileSlopes[];
float avgSoilLoss; // representative soil loss based on all flowpaths
float avgRunoff; // representative runoff based on all flowpaths
float avgSedYield; // representative sediment yld based on all flowpaths
float nrcssoilloss; // NRCS soil loss for planning based on represtative hillslope
float irrigation; // irrigation based on representative hillslope
float irrigationVol; // irrigation volume based on representative hillslope
double area;
int cells;
Flowpath repHillslopeFlowpath; // representative hillslope of all orientations
double repHillslopeWidth;
int flowpathsRun;
boolean inUse;
int weppAltID;
String impoundmentAtEnd;
Subcatchment(int id, V1_0 par, int idx) {
this.id = id;
this.service = par;
weppid = idx;
repHillslopeFlowpath = null;
inUse = false;
order = 0;
weppAltID = 0;
impoundmentAtEnd = "";
}
Subcatchment(int id, V1_0 par, int idx, WeppConstants.SubcatchmentType type, Subcatchment par2) {
this.id = id;
this.service = par;
weppid = idx;
repHillslopeFlowpath = null;
inUse = false;
order = 0;
}
int addFlowpath(List<Integer> rows, List<Integer> cols,
List<Float> slp, List<Integer> man, List<Integer> soil, List<Float> dist,
int chnEndRow, int chnEndCol, int chan) {
int r[] = new int[rows.size()];
int c[] = new int[cols.size()];
float sl[] = new float[slp.size()];
int s[] = new int[soil.size()];
int m[] = new int[man.size()];
float d[] = new float[dist.size()];
lastFlowpathID++;
for (int i = 0; i < rows.size(); i++) {
r[i] = rows.get(i);
c[i] = cols.get(i);
sl[i] = slp.get(i);
s[i] = soil.get(i);
m[i] = man.get(i);
d[i] = dist.get(i);
}
flowpaths.add(new Flowpath(lastFlowpathID, r, c, sl, m, s, d, service, chnEndRow, chnEndCol, chan));
return lastFlowpathID;
}
int writeFlowpaths(File baseDir) throws IOException, JSONException {
File fileName = new File(baseDir, "flowpaths_" + Integer.toString(id));
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
for (int i = 0; i < flowpaths.size(); i++) {
flowpaths.get(i).print(writer);
}
writer.close();
}
return flowpaths.size();
}
String summarizeInput() throws JSONException {
JSONObject so = new JSONObject()
.put("id", id)
.put("weppid", weppid)
.put("topid", topid)
.put("leftid", leftid)
.put("rightid", rightid)
.put("Area (ac)", area * WeppConstants.CONV_HA_TO_AC)
.put("Grid cells", cells)
.put("Major Soil", service.soilIndexToShortName(majorSoil))
.put("Major Soil id", majorSoil)
.put("Major Landuse", service.manIndexToShortName(majorLanduse))
.put("Major Landuse id", majorLanduse)
.put("Percentage of total area", ((double) cells / (double) service.aoi.getArea()) * 100);
return so.toString(2);
}
String summarizeOutput(SessionLogger log) throws JSONException {
double avgRunoffVol;
try {
avgRunoffVol = (repHillslopeFlowpath.totalLengthMeters * WeppConstants.CONV_M_TO_FT)
* (repHillslopeWidth * WeppConstants.CONV_M_TO_FT) * (avgRunoff / 12.0);
} catch (Exception e) {
avgRunoffVol = -999;
log.info(e.toString());
if (repHillslopeFlowpath != null) {
log.info(repHillslopeFlowpath.toString());
} else {
log.info("No representative hillslope created for subcatchment " + id);
log.info("Number of flowpaths: " + flowpaths.size());
JSONObject so = new JSONObject()
.put("id", id)
.put("weppid", weppid)
.put("inuse", inUse)
.put("Area (ac)", area * WeppConstants.CONV_HA_TO_AC)
.put("Grid cells", cells)
.put("Major Soil", service.soilIndexToShortName(majorSoil))
.put("Major Soil id", majorSoil)
.put("Major Landuse", service.manIndexToShortName(majorLanduse))
.put("Major Landuse id", majorLanduse)
.put("Percentage of total area", ((double) cells / (double) service.aoi.getArea()) * 100)
.put("Representative Hillslope Length (ft)", -999)
.put("Representative Hillslope Width (ft)", -999)
.put("Soil Loss (ton/yr)", -999)
.put("Soil Loss per Area (ton/ac/yr)", -999)
.put("NRCS Soil Loss for Conservation Planning (ton/ac/yr)", -999)
.put("Sediment Yield (ton/yr)", -999)
.put("Sediment Yield per Area (ton/ac/yr)", -999)
.put("Runoff (in/yr)", -999)
.put("Runoff Volume (ft^3/yr)", -999)
.put("Irrigation (in/yr)", -999)
.put("Irrigation Volume (ft3/yr)", -999)
.put("Flowpaths within subcatchment", flowpaths.size())
.put("Message", "No flowpaths calculated in subcatchment");
return so.toString(2);
}
}
JSONObject so = new JSONObject()
.put("id", id)
.put("weppid", weppid)
.put("inuse", inUse)
.put("Area (ac)", area * WeppConstants.CONV_HA_TO_AC)
.put("Grid cells", cells)
.put("Major Soil", service.soilIndexToShortName(majorSoil))
.put("Major Soil id", majorSoil)
.put("Major Landuse", service.manIndexToShortName(majorLanduse))
.put("Major Landuse id", majorLanduse)
.put("Percentage of total area", ((double) cells / (double) service.aoi.getArea()) * 100)
.put("Representative Hillslope Length (ft)", repHillslopeFlowpath.totalLengthMeters * WeppConstants.CONV_M_TO_FT)
.put("Representative Hillslope Width (ft)", repHillslopeWidth * WeppConstants.CONV_M_TO_FT)
.put("Soil Loss (ton/yr)", avgSoilLoss)
.put("Soil Loss per Area (ton/ac/yr)", avgSoilLoss / (area * WeppConstants.CONV_HA_TO_AC))
.put("NRCS Soil Loss for Conservation Planning (ton/ac/yr)", nrcssoilloss)
.put("Sediment Yield (ton/yr)", avgSedYield)
.put("Sediment Yield per Area (ton/ac/yr)", avgSedYield / (area * WeppConstants.CONV_HA_TO_AC))
.put("Runoff (in/yr)", avgRunoff)
.put("Runoff Volume (ft^3/yr)", avgRunoffVol)
.put("Irrigation (in/yr)", irrigation)
.put("Irrigation Volume (ft3/yr)", irrigationVol)
.put("Flowpaths within subcatchment", flowpaths.size())
.put("Message", "");
return so.toString(2);
}
//
// runFlowpaths0()
//
// Uses CSIP services to make parallel WEPP runs.
//
int runFlowpaths0(SessionLogger LOG, File workspace, Grid field, boolean statsOnly) throws Exception {
LOG.info("Parallel Flowpath runs for subcatchment " + id);
AtomicInteger numRun = new AtomicInteger();
int nthreads = Config.getInt("weppws.fp.par", 16);
if (!flowpaths.isEmpty()) {
Parallel.run(nthreads, flowpaths.size(), new Function<Integer, Run>() {
@Override
public Run apply(Integer t) {
System.out.println("Created FP Run: " + t);
service.progress("Running " + id + "/" + t);
return () -> {
Flowpath fp = flowpaths.get(t);
if (!statsOnly && fp.intersectsField(field)) {
System.out.println("Running FP: >>>>>>>>>>>>>>>>> " + t);
fp.runFlowpathService(workspace, service.aoi, service.flow_d8_grid.getCellsize(), false);
numRun.incrementAndGet();
}
};
}
});
}
return flowpathsRun = numRun.get();
}
//
// runFlowpaths1()
//
// Runs all, or a subset percentage, of the flowpaths in a the subcatchment.
// The runs are done by calling the local executable, a service call is not
// done to run WEPP. Every call must wait until the previous run is complete.
//
int runFlowpathsLocal(SessionLogger LOG, File workspace, Executable weppserv, Grid field,
boolean statsOnly, int subsetPercentage) throws ServiceException, IOException, Exception {
LOG.info("Exe Flowpath runs for subcatchment " + id);
int numRun = 0;
double div = ((double) subsetPercentage) / (double) 100;
int freq = (int) (1.0 / div);
flowpathsRun = 0;
int i = 0;
while (i < flowpaths.size()) {
if (flowpaths.get(i).intersectsField(field)) {
LOG.info(">>> Starting flowpath: " + i);
if (statsOnly == false) {
// may only be running a subset of the flowpaths
if ((subsetPercentage == 100) || ((i % freq) == 0)) {
flowpaths.get(i).runFlowpathLocal(workspace, weppserv,
service.aoi, service.flow_d8_grid.getCellsize(), false);
numRun++;
}
} else {
numRun++;
}
}
i++;
}
flowpathsRun = numRun;
return numRun;
}
//
// runFlowpaths()
//
// Original version before CSIP parallel version. Makes a service call to run
// each flowpath WEPP model run. At most 16 instances of WEPP are running at
// once, new run requests will block until a slot opens up.
// @deprecated
//
//
// int runFlowpaths(SessionLogger LOG, File workspace, Executable weppserv, Grid field,
// boolean statsOnly, int subsetPercentage) throws ServiceException, IOException, Exception {
//
// LOG.info("Non-Parallel Flowpath runs for subcatchment " + id);
// int numRun = 0;
// double div = ((double) subsetPercentage) / (double) 100;
// int freq = (int) (1.0 / div);
// int concurrentMax = 16; // maximum number of flowpath runs at a time
// int concount = 0; // current number of running flowpaths
//
// List<JSONObject> runningFlowpaths = new ArrayList<>();
// List<Integer> runningIndex = new ArrayList<>();
//
// flowpathsRun = 0;
// int i = 0;
// while (i < flowpaths.size()) {
// if (flowpaths.get(i).intersectsField(field)) {
// LOG.info(">>> Starting flowpath: " + i);
// if (statsOnly == false) {
// // may only be running a subse of the flowpaths
// if ((subsetPercentage == 100) || ((i % freq) == 0)) {
// // only start a run if we are running less than the maximum instances
// if (concount < concurrentMax) {
// JSONObject resp = flowpaths.get(i).runFlowpath(workspace, weppserv,
// service.aoi, service.flow_d8_grid.getCellsize(), false);
// // a response other than null indicates this was done as an async and
// // needs to polled in the future.
// if (resp != null) {
// runningFlowpaths.add(resp);
// runningIndex.add(i);
// concount++;
// }
// numRun++;
// i++;
// } else {
// // need to wait till some runs finish before continuing to add new simulations
// // need to have a timeout if this fails
// while (concount >= concurrentMax) {
// Thread.sleep(2000);
// // check the status of all running flowpaths
// int removed = 0;
// int curIdx = 0;
// for (int j = 0; j < concount; j++) {
// if (curIdx < runningFlowpaths.size()) {
// if (runningFlowpaths.get(curIdx) != null) {
// JSONObject resp = flowpaths.get(runningIndex.get(curIdx)).
// checkProgress(LOG, runningFlowpaths.get(curIdx), workspace, service.aoi);
// if (resp == null) {
// // run completed, remove from list
// runningIndex.remove(curIdx);
// runningFlowpaths.remove(curIdx);
// removed++;
// } else {
// curIdx = curIdx + 1;
// }
// } else {
// curIdx = curIdx + 1;
// }
// }
// }
// concount = concount - removed;
// }
// }
// } else {
// i++;
// }
// } else {
// numRun++;
// i++;
// }
// } else {
// i++;
// }
// }
// // it may be that there are still some runs waiting to complete
// while (concount > 0) {
// Thread.sleep(2000);
// // check the status of all running flowpaths
// int removed = 0;
// int curIdx = 0;
// for (int j = 0; j < concount; j++) {
// if (curIdx < runningFlowpaths.size()) {
// if (runningFlowpaths.get(curIdx) != null) {
// JSONObject resp = flowpaths.get(runningIndex.get(curIdx))
// .checkProgress(LOG, runningFlowpaths.get(curIdx), workspace, service.aoi);
// if (resp == null) {
// // run completed, remove from list
// runningIndex.remove(curIdx);
// runningFlowpaths.remove(curIdx);
// removed++;
// } else {
// curIdx = curIdx + 1;
// }
// } else {
// curIdx = curIdx + 1;
// }
// }
// }
// concount = concount - removed;
// }
// flowpathsRun = numRun;
// return numRun;
// }
void makeRepresentativeHillslopeNoData(float cellSize) {
int[] r = {0};
int[] c = {0};
float[] sl = {(float) 0.001};
int[] s = {majorSoil};
int[] m = {majorLanduse};
float[] d = {(float) cellSize};
repHillslopeFlowpath = new Flowpath(id, r, c, sl, m, s, d, service, -1, -1, -1);
repHillslopeWidth = cellSize;
}
void makeRepresentativeHillslope(float cellSize) {
float longest = 0;
for (int i = 0; i < flowpaths.size(); i++) {
if (flowpaths.get(i).totalLengthMeters > longest) {
longest = flowpaths.get(i).totalLengthMeters;
}
}
int cellsNeeded = (int) ((double) longest / cellSize);
repProfileWeights = new float[cellsNeeded];
repProfileSlopes = new float[cellsNeeded];
for (int i = 0; i < flowpaths.size(); i++) {
flowpaths.get(i).updateRepProfile(cellSize, repProfileSlopes, repProfileWeights);
}
for (int i = 0; i < repProfileSlopes.length; i++) {
repProfileSlopes[i] = repProfileSlopes[i] / repProfileWeights[i];
}
int r[] = new int[cellsNeeded];
int c[] = new int[cellsNeeded];
float sl[] = new float[cellsNeeded];
int s[] = new int[cellsNeeded];
int m[] = new int[cellsNeeded];
float d[] = new float[cellsNeeded];
for (int i = 0; i < cellsNeeded; i++) {
r[i] = 0;
c[i] = 0;
sl[i] = repProfileSlopes[i] / (float) 100.0; // slopes were calculated as %, need to be 0-1 for constructor
s[i] = majorSoil;
m[i] = majorLanduse;
d[i] = (float) cellSize;
}
repHillslopeFlowpath = new Flowpath(id, r, c, sl, m, s, d, service, -1, -1, -1);
repHillslopeWidth = (area * 10000) / repHillslopeFlowpath.totalLengthMeters;
}
int runRepresentativeHillslope0(File workspace, Executable weppserv,
Grid field, boolean statsOnly, boolean splitArea, boolean usePassFiles) throws ServiceException, IOException, Exception {
if (splitArea == false) {
makeRepresentativeHillslope((float) field.getCellsize());
if (repHillslopeFlowpath == null) {
avgSoilLoss = 0;
avgRunoff = 0;
avgSedYield = 0;
irrigation = 0;
return 0;
}
if (statsOnly == false) {
repHillslopeFlowpath.runFlowpathService(workspace, service.aoi, repHillslopeWidth, usePassFiles);
avgSoilLoss = repHillslopeFlowpath.avgSoilLoss;
avgRunoff = repHillslopeFlowpath.avgRunoff;
avgSedYield = repHillslopeFlowpath.avgSedYield;
irrigation = repHillslopeFlowpath.avgIrrigation;
}
return 1;
} else {
int runs = 0;
if (topsub != null) {
runs += topsub.runRepresentativeHillslope0(workspace, weppserv, field, statsOnly, usePassFiles);
}
if (leftsub != null) {
runs += leftsub.runRepresentativeHillslope0(workspace, weppserv, field, statsOnly, usePassFiles);
}
if (rightsub != null) {
runs += rightsub.runRepresentativeHillslope0(workspace, weppserv, field, statsOnly, usePassFiles);
}
return runs;
}
}
//
// runRepresentativeHillslope()
//
// Runs the flowpath that is an aggregation of all flowpaths in a subcatchment.
// Calls to either run the simulation as a service or directly (runflowpath1).
//
JSONObject runRepresentativeHillslope(SessionLogger log, File workspace, Executable weppserv,
Grid field, boolean statsOnly, boolean splitArea, boolean usePassFiles) throws ServiceException, IOException, Exception {
JSONObject resp = null;
if (splitArea == false) {
makeRepresentativeHillslope((float) field.getCellsize());
if (repHillslopeFlowpath == null) {
avgSoilLoss = 0;
avgRunoff = 0;
avgSedYield = 0;
irrigation = 0;
return null;
}
if (statsOnly == false) {
//if (service.flowpathURL.length() > 0) {
// resp = repHillslopeFlowpath.runFlowpath(workspace, weppserv, service.aoi, repHillslopeWidth);
// if (resp != null) {
// avgSoilLoss = repHillslopeFlowpath.avgSoilLoss;
// avgRunoff = repHillslopeFlowpath.avgRunoff;
// avgSedYield = repHillslopeFlowpath.avgSedYield;
// }
//} else {
resp = repHillslopeFlowpath.runFlowpathLocal(workspace, weppserv, service.aoi, repHillslopeWidth, usePassFiles);
avgSoilLoss = repHillslopeFlowpath.avgSoilLoss;
avgRunoff = repHillslopeFlowpath.avgRunoff;
avgSedYield = repHillslopeFlowpath.avgSedYield;
irrigation = repHillslopeFlowpath.avgIrrigation;
//}
}
return resp;
} else {
log.info("*** runRepresentativeHillslope " + id);
if (topsub != null) {
log.info("*** runRepresentativeHillslope-TOP " + id);
topsub.runRepresentativeHillslope(log, workspace, weppserv, field, statsOnly, usePassFiles);
}
if (leftsub != null) {
log.info("*** runRepresentativeHillslope-LEFT " + id);
leftsub.runRepresentativeHillslope(log, workspace, weppserv, field, statsOnly, usePassFiles);
}
if (rightsub != null) {
log.info("*** runRepresentativeHillslope-RIGHT " + id);
rightsub.runRepresentativeHillslope(log, workspace, weppserv, field, statsOnly, usePassFiles);
}
return null;
}
}
//
// checkProgress()
//
// Checksif the representaive hillslope run is complete if it was started from a
// service call.
//
JSONObject checkProgress(SessionLogger LOG, JSONObject resp, File workspace)
throws ServiceException, IOException, Exception {
JSONObject resp2 = repHillslopeFlowpath.checkProgress(LOG, resp, workspace, service.aoi);
if (resp2 == null) {
avgSoilLoss = repHillslopeFlowpath.avgSoilLoss;
avgRunoff = repHillslopeFlowpath.avgRunoff;
avgSedYield = repHillslopeFlowpath.avgSedYield;
irrigation = repHillslopeFlowpath.avgIrrigation;
}
return resp2;
}
float getAvgSoilLoss() {
return avgSoilLoss;
}
float getAvgRunoff() {
return avgRunoff;
}
float getAvgSedYield() {
return avgSedYield;
}
float getAvgIrrigation() {
return irrigation;
}
Grid outputFlowpaths(Grid lossGrid, Grid sedWeightGrid) {
for (int i = 0; i < flowpaths.size(); i++) {
flowpaths.get(i).updateWeightedLossGrid(lossGrid, sedWeightGrid);
}
return lossGrid;
}
void setMajorSoil(int val) {
majorSoil = val;
}
void setMajorLanduse(int val) {
majorLanduse = val;
}
double calcArea(Grid subcatchments, Grid bound) throws ServiceException {
cells = subcatchments.cellCountWithMask(id, bound);
area = (cells * subcatchments.getCellsize() * subcatchments.getCellsize()) / 10000; // total area in ha
return area;
}
double getAreasOfSubs() {
double area2 = 0;
if (topsub != null) {
area2 += topsub.area;
}
if (leftsub != null) {
area2 += leftsub.area;
}
if (rightsub != null) {
area2 += rightsub.area;
}
return area2;
}
String printProfile() {
if (repHillslopeFlowpath != null) {
return repHillslopeFlowpath.printProfile(repHillslopeWidth);
} else {
return ("Representative profile not set for hillslope." + String.valueOf(id));
}
}
String soilIndexToName(int idx) throws ServiceException {
String name;
try {
name = service.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 = service.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;
}
Grid fillsub3grid(SessionLogger LOG,Grid sub3) throws ServiceException {
WeppConstants.Orientation mydir;
int cellsFilled = 0;
for (int i = 0; i < flowpaths.size(); i++) {
cellsFilled = flowpaths.get(i).fillsub3grid(sub3, topazid);
if (cellsFilled <= 0) {
LOG.info(">>> Flowpath has no cells: " + id + " " + topazid);
}
mydir = flowpaths.get(i).getDir();
if (mydir == WeppConstants.Orientation.TOP) {
if (topsub == null) {
topsub = new SubcatchmentSubarea(topazid + 3, service, weppid, WeppConstants.SubcatchmentType.TOP, this);
}
} else if (mydir == WeppConstants.Orientation.LEFT) {
if (leftsub == null) {
leftsub = new SubcatchmentSubarea(topazid + 1, service, weppid, WeppConstants.SubcatchmentType.LEFT, this);
}
} else if (mydir == WeppConstants.Orientation.RIGHT) {
if (rightsub == null) {
rightsub = new SubcatchmentSubarea(topazid + 2, service, weppid, WeppConstants.SubcatchmentType.RIGHT, this);
}
} else if (mydir == WeppConstants.Orientation.UNKNOWN) {
LOG.info(">>> Flowpath UNKNOWN subgrid3 cells: " + id + " " + Integer.toString(topazid) + " (" + cellsFilled + ")");
LOG.info(">>> Unknown Coord: " + flowpaths.get(i).rows[0] + " " + flowpaths.get(i).cols[0]);
} else if (mydir == WeppConstants.Orientation.NOTFOUND) {
LOG.info(">>> Flowpath NOTFOUND subgrid3 cells: " + id + " " + Integer.toString(topazid) + " (" + cellsFilled + ")");
LOG.info(">>> Unknown Coord: " + flowpaths.get(i).rows[0] + " " + flowpaths.get(i).cols[0]);
}
}
return sub3;
}
void classifyFlowpaths(SessionLogger LOG) {
int valid = 0;
int invalid = 0;
for (int i = 0; i < flowpaths.size(); i++) {
try {
flowpaths.get(i).classifyFlowpath(order);
if ((flowpaths.get(i).relativePosition == WeppConstants.Orientation.NOTFOUND) || (flowpaths.get(i).relativePosition == WeppConstants.Orientation.UNKNOWN)) {
LOG.info(">Flowpath orientation error in subcatchment: " + id);
invalid = invalid + 1;
} else {
valid = valid + 1;
}
} catch (ServiceException ex) {
System.out.println("ServiceException: " + ex.toString());
}
}
LOG.info(">Classified Flowpaths for subcatchment: " + id + " valid: " + valid + " invalid: " + invalid);
}
double getRepHillslopeWidth() {
return repHillslopeWidth;
}
double getRepHillslopeLength() {
return repHillslopeFlowpath.totalLengthMeters;
}
String majorLanduseName() throws ServiceException {
return manIndexToName(majorLanduse);
}
String majorSoilName() throws ServiceException {
return soilIndexToName(majorSoil);
}
void setInuse(boolean val) {
inUse = val;
}
boolean getInuse() {
return inUse;
}
void setWeppID(int val) {
weppid = val;
}
void setTopazID(int val) {
topazid = val;
}
void setOrder(int val) {
order = val;
}
int numTopazareas() {
int areas = 0;
if (inUse) {
if (topsub != null) {
areas++;
}
if (leftsub != null) {
areas++;
}
if (rightsub != null) {
areas++;
}
}
return areas;
}
void setWeppAltID(int val) {
weppAltID = val;
}
int getCells() {
return cells;
}
double getPercentageArea() {
return ((double) cells / (double) service.aoi.getArea()) * 100;
}
}