V1_0.java [src/java/m/svap/svap03_svaplanduse] Revision: default Date:
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API, and application suite.
*
* 2012-2017, OMSLab, Colorado State University.
*
* OMSLab licenses this file to you under the MIT license.
* See the LICENSE file in the project root for more information.
*/
package m.svap.svap03_svaplanduse;
import csip.Config;
import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.utils.JSONUtils;
import gisobjects.GISObjectException;
import gisobjects.raster.GISRaster;
import java.io.IOException;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.HashMap;
import javax.ws.rs.Path;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import svap.utils.HUC12;
import svap.utils.NLCD_Clip;
/**
* SVAP-03: Get Land Use for Watershed Description
*
* This service accepts a GeoJSON lat/long, finds the intersecting HUC-12
* boundary and sends it to the CSIP-NLCD clip service, then parses the results.
*
* @author Robert Streetman
* @author Shaun Case
* @version 1.0
*/
@Name("SVAP-03: Get Land Use for Watershed Description")
@Description("This service gets the NLCD land use data for the HUC-12 and converts it to NRCS land use percentages")
@Path("m/svap/svaplanduse/1.0")
public class V1_0 extends ModelDataService {
private final String NLCD_CLIP_URL = "https://csip.erams.com/csip-nlcd/m/clip/1.0";
public static final String USGS_HUC_URL = "https://services.nationalmap.gov/arcgis/rest/services/wbd/MapServer/7/query";
private static final HashMap<Integer, String> landuseMapNLCD;
private static final HashMap<Integer, String> landuseMapNRCS;
private HashMap<Integer, Integer> histogramNRCS;
private HashMap<Double, Integer> histogramNLCD;
private JSONObject assessmentLocation;
private String huc12Number, huc12Name;
private int assessmentId;
private double binCount = 0, binCountNRCS = 0;
static {
landuseMapNLCD = new HashMap();
landuseMapNLCD.put(11, "Water;Water");
landuseMapNLCD.put(12, "Water;Water");
landuseMapNLCD.put(21, "Developed Land;Developed");
landuseMapNLCD.put(22, "Developed Land;Developed");
landuseMapNLCD.put(23, "Developed Land;Developed");
landuseMapNLCD.put(24, "Developed Land;Developed");
landuseMapNLCD.put(31, "Other Rural Land;Barren");
landuseMapNLCD.put(41, "Forest;Forest");
landuseMapNLCD.put(42, "Forest;Forest");
landuseMapNLCD.put(43, "Forest;Forest");
landuseMapNLCD.put(51, "Range;Shrubland");
landuseMapNLCD.put(52, "Range;Shrubland");
landuseMapNLCD.put(71, "Range;Herbaceous");
landuseMapNLCD.put(72, "Range;Herbaceous");
landuseMapNLCD.put(73, "Range;Herbaceous");
landuseMapNLCD.put(74, "Range;Herbaceous");
landuseMapNLCD.put(81, "Pasture;Planted/Cultivated");
landuseMapNLCD.put(82, "Crop;Planted/Cultivated");
landuseMapNLCD.put(90, "Other Rural;Wetlands");
landuseMapNLCD.put(95, "Other Rural;Wetlands");
landuseMapNRCS = new HashMap();
landuseMapNRCS.put(0, "KW;Undetermined");
landuseMapNRCS.put(1, "CR;Crop");
landuseMapNRCS.put(2, "FO;Forest");
landuseMapNRCS.put(3, "RA;Range");
landuseMapNRCS.put(4, "PA;Pasture");
landuseMapNRCS.put(5, "PR;Protected");
landuseMapNRCS.put(6, "HQ;Farmstead");
landuseMapNRCS.put(7, "UR;Developed Land");
landuseMapNRCS.put(8, "WA;Water");
landuseMapNRCS.put(9, "OR;Other Rural Land");
landuseMapNRCS.put(10, "AL;Associated Land Ag");
}
@Override
protected void preProcess() throws ServiceException {
//TODO: Change this to a GISObject...
assessmentLocation = parameter().getJSON("assessment_location");
assessmentId = parameter().getInt("assessment_id");
}
@Override
protected void doProcess() throws ServiceException, SQLException, GISObjectException, JSONException, IOException, URISyntaxException, Exception {
HUC12 huc12 = getHUC12Data();
if (huc12.getDataLength() > 0) {
huc12Number = huc12.getPropertyValue(0, "HUC12");
huc12Name = huc12.getPropertyValue(0, "NAME");
if (null != huc12Number) {
if (null != huc12Name) {
translateRasterHistogram(getNLCDRaster(huc12.toJSON()));
} else {
throw new ServiceException("USGS WBD service [HUC_12] returned no value for the HUC_12 name.");
}
} else {
throw new ServiceException("USGS WBD service [HUC_12] returned no value for the HUC_12 Id number.");
}
} else {
throw new ServiceException("Invalid return data from USGS WBD service [HUC_12]. Returned data length is zero.");
}
}
@Override
protected void postProcess() throws ServiceException, JSONException {
results().put("assessment_id", assessmentId, "Assessment identifier.");
results().put("huc_12_id", huc12Number, "HUC12 identifier.");
results().put("huc_name", huc12Name, "HUC12 name.");
if (histogramNLCD != null && binCount > 0) {
JSONArray histArr = new JSONArray();
for (int key : histogramNRCS.keySet()) {
binCountNRCS += histogramNRCS.get(key);
String[] nrcsString = landuseMapNRCS.get(key).split(";");
JSONArray nlcdLanduseArr = new JSONArray();
nlcdLanduseArr.put(JSONUtils.dataDesc("land_use_id", key, "NRCS land use id."));
nlcdLanduseArr.put(JSONUtils.dataDesc("land_use_code", nrcsString[0], "NRCS land use code."));
nlcdLanduseArr.put(JSONUtils.dataDesc("land_use_name", nrcsString[1], "NRCS land use name."));
nlcdLanduseArr.put(JSONUtils.dataDesc("land_use_bin_count", histogramNRCS.get(key), "NRCS land use pixel count."));
nlcdLanduseArr.put(JSONUtils.data("land_use_pct", ((double) histogramNRCS.get(key) / binCount) * 100.0, "NRCS land use percentage.", "Percent"));
histArr.put(JSONUtils.data("land_use_nrcs", nlcdLanduseArr, "NRCS land use summary."));
}
histArr.put(JSONUtils.data("land_use_total_percent", (((double) binCountNRCS / binCount) * 100.0), "Total percentage of NRCS land use", "Percent"));
histArr.put(JSONUtils.data("land_use_total_pixels", binCountNRCS, "Total number of pixels of valid land use."));
histArr.put(JSONUtils.data("land_use_total_bins", binCount, "Total number of pixels in all bins (even non-valid)"));
results().put("huc12_histogram", histArr, "HUC-12 histogram of land use.");
}
}
protected GISRaster getNLCDRaster(JSONObject geometry) throws ServiceException, Exception {
NLCD_Clip nlcdService = new NLCD_Clip(geometry, Config.getString("service.erams.nlcd_clip.uri", NLCD_CLIP_URL), new JSONObject(metainfo().toString()));
nlcdService.call();
return nlcdService.getRaster();
}
protected void translateRasterHistogram(GISRaster raster) throws GISObjectException {
histogramNLCD = new HashMap();
histogramNLCD.putAll(raster.createRasterHistogram());
histogramNRCS = new HashMap();
//Loop through all land use ids in NLCD clip service histogram
histogramNLCD.forEach((key, val) -> {
int k = key.intValue();
binCount += val;
//Map to NLCD histogram if valid id
if (landuseMapNLCD.containsKey(k)) {
//Has this NRCS land use been initialized?
if (histogramNRCS.containsKey(nrcsLandUseId(k))) {//Y
int newBinSum = val + histogramNRCS.get(nrcsLandUseId(k));
histogramNRCS.replace(nrcsLandUseId(k), newBinSum);
} else {//N
histogramNRCS.put(nrcsLandUseId(k), val);
}
}
});
}
public HUC12 getHUC12Data() throws JSONException, URISyntaxException, IOException, ServiceException, GISObjectException {
String longitude = assessmentLocation.getJSONArray("coordinates").get(0).toString();
String latitude = assessmentLocation.getJSONArray("coordinates").get(1).toString();
HUC12 huc12 = new HUC12();
huc12.setOutFields("HUC12, NAME");
huc12.setFormat("geojson");
huc12.fillHUC12Data(longitude + ", " + latitude);
return huc12;
}
private int nrcsLandUseId(int nlcd) {
int nrt = -1;
switch (nlcd) {
case 11:
case 12:
nrt = 8;
break;
case 21:
case 22:
case 23:
case 24:
nrt = 7;
break;
case 31:
case 90:
case 95:
nrt = 9;
break;
case 41:
case 42:
case 43:
nrt = 2;
break;
case 51:
case 52:
case 71:
case 72:
case 73:
case 74:
nrt = 3;
break;
case 81:
nrt = 4;
break;
case 82:
nrt = 1;
break;
}
return nrt;
}
}