V1_0.java [src/java/m/wqm/wqm05_nutrientslp] Revision: default Date:
package m.wqm.wqm05_nutrientslp;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import java.util.ArrayList;
import javax.ws.rs.Path;
import csip.annotations.Description;
import csip.annotations.Name;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import csip.utils.JSONUtils;
import java.util.Map;
import org.codehaus.jettison.json.JSONException;
/**
*
* @author Srinivas
* @author Rumpal Sidhu
* @author Shaun Case
*/
@Name("WQM-05: Nutrient Soil Leaching Potential (NutrientSLP)")
@Description("This service computes nutrient soil leaching potential for soil "
+ "components in an area of analysis, and then computes nutrient soil "
+ "leaching potential representing the area of analysis (AoA). The service "
+ "primarily will consume data from the WQM-02 WQMSoilAttributes service "
+ "to compute nutrient soil leaching potentials used later by the WQM-13 "
+ "service to compute threshold treatment level scores.")
@Path("m/nutrient_slp/1.0")
@Deprecated
public class V1_0 extends ModelDataService {
private final String[] nslpList = new String[]{"LOW", "MODERATE", "MODERATELY HIGH", "HIGH"};
//Request
private int aoaId;
private ArrayList<SoilComponent> soilComponentList = new ArrayList<>();
//Result
private String aoaNslp;
@Override
protected void preProcess() throws ServiceException, JSONException {
aoaId = parameter().getInt("AoAId");
}
@Override
protected void doProcess() throws ServiceException, JSONException {
JSONArray groups = parameter().getJSONArray("soilcomponents");
for (int i = 0; i < groups.length(); i++) {
Map<String, JSONObject> group = JSONUtils.preprocess(groups.getJSONArray(i));
SoilComponent input = new SoilComponent(group);
soilComponentList.add(input);
}
computeNSLP();
computeAoaNSLP();
}
@Override
protected void postProcess() throws Exception {
results().put("aoa_id", aoaId, "Area of analysis identifier");
results().put("aoa_nslp", aoaNslp, "Soil leaching potential of the area of analysis");
JSONArray resultArr = new JSONArray();
for (SoilComponent sc : soilComponentList) {
JSONArray array = new JSONArray();
array.put(JSONUtils.dataDesc("cokey", sc.getCokey(), "Soil component key"));
array.put(JSONUtils.dataDesc("comp_nslp", sc.getNslp(), "Soil leaching potential of the soil component"));
resultArr.put(JSONUtils.dataDesc("soil_component", array, "Soil Component"));
}
results().put("soil_components", resultArr, "List of Soil Components");
}
private void computeNSLP() throws ServiceException {
for (SoilComponent ip : soilComponentList) {
int comp_nslp_number = -2; //Preset to error condition of invalid combinations.
// If Histosols OR ( Apparent and wtbl_top_min <= 76cm )
// if (ip.getTaxorder().equals("Histosols") || ((ip.getWtbl().equals("Apparent")
// || ip.getWtbl().equals("Perched")) && (ip.getWtblTopMin() <= 76))) {
if (ip.getTaxorder().equals("Histosols") || ((ip.getWtblTopMin() <= 76))) {
comp_nslp_number = 3;
} else {
// Otherwise we need to look at slope and/or coarse fragmentation for this component's hydrologic group.
switch (ip.getHsg()) {
case "A":
comp_nslp_number = computeNSLPHsgA(ip);
break;
case "B":
comp_nslp_number = computeNSLPHsgB(ip);
break;
case "C":
comp_nslp_number = computeNSLPHsgC(ip);
break;
case "D":
comp_nslp_number = computeNSLPHsgD(ip);
break;
// Any dual/combined hydrologic group is "HIGH"
case "A/D":
case "B/D":
case "C/D":
comp_nslp_number = 3;
break;
//NOTE: There is no default section here because the comp_nslp_number variable is
// being used to mark specific error conditions. If this switch fails through
// then comp_nslp_number will remain set to -2, which is checked below. This should NEVER happen, but
// the check is here just in case...
}
}
//Check for error conditions, and if none, then set the NSLP number for this component.
if (comp_nslp_number != -1 && comp_nslp_number != -2) { // These represent error conditions in this function.
if ((comp_nslp_number >= 0) && (comp_nslp_number <= 3)) {
//Adjust final number by coarseFrag values logic
if (ip.getCoarseFrag() > 30) {
comp_nslp_number += 2;
if (comp_nslp_number > 3) {
comp_nslp_number = 3;
}
} else if (ip.getCoarseFrag() > 10) {
comp_nslp_number += 1;
if (comp_nslp_number > 3) {
comp_nslp_number = 3;
}
} // Otherwise just leave it alone, no adjustments are needed.
ip.setNslpNumber(comp_nslp_number);
ip.setNslp(nslpList[comp_nslp_number]);
} else {
throw new ServiceException("An invalid Soil Leaching Potential value was calculated: " + comp_nslp_number + ". Cannot continue. ");
}
} else if (comp_nslp_number == -1) { // Failed in the embedded Hsg computational functions
throw new ServiceException("Invalid Hsg calculation for this soil for: " + ip.getHsg() + ". Cannot continue with NSLP estimation for component key: " + ip.getCokey() + ". ");
} else if (comp_nslp_number == -2) { //Failed the above switch statement
throw new ServiceException("Invalid Hsg name for this soil component key: " + ip.getCokey()
+ " which is neither Histosols nor (Apparent AND <= 76cm) in Water Table Type. Cannot continue with the NSLP estimations.");
} // No else here because it cannot happen...unless someone edits this code and adds a new "error condition" number to use for
// comp_nslp_number...if you do, then PLEASE add a check for it here and keep to the convention of using a negative integer.
}
}
private int computeNSLPHsgA(SoilComponent ip) {
int nslpNumber = 3;
if (ip.getSlope() > 12) {
nslpNumber = 2;
}
return nslpNumber;
}
private int computeNSLPHsgB(SoilComponent ip) {
int nslpNumber = -1;
if ((ip.getSlope() <= 12 && ip.getKfact() >= 0.24) || (ip.getSlope() > 12)) {
nslpNumber = 1;
} else if ((ip.getSlope() >= 3) && (ip.getSlope() <= 12) && (ip.getKfact() < 0.24)) {
nslpNumber = 2;
} else if ((ip.getSlope() < 3) && (ip.getKfact() < 0.24)) {
nslpNumber = 3;
}
return nslpNumber;
}
private int computeNSLPHsgC(SoilComponent ip) {
int nslpNumber = 1;
return nslpNumber;
}
private int computeNSLPHsgD(SoilComponent ip) {
int nslpNumber = 0;
return nslpNumber;
}
//Compute weighted average nutrient soil leaching potential for the AoA
private void computeAoaNSLP() {
double cumNslpProduct = 0;
double aoaArea = 0;
for (SoilComponent sc : soilComponentList) {
cumNslpProduct += (sc.getNslpNumber() * sc.getArea());
aoaArea += sc.getArea();
}
double aoaNslpFract = ((aoaArea != 0.0) ? (cumNslpProduct / aoaArea) : 0.0);
if (aoaNslpFract <= 0.50) {
aoaNslp = "LOW";
} else if (aoaNslpFract > 0.50 && aoaNslpFract <= 1.50) {
aoaNslp = "MODERATE";
} else if (aoaNslpFract > 1.50 && aoaNslpFract <= 2.50) {
aoaNslp = "MODERATELY HIGH";
} else {
aoaNslp = "HIGH";
}
}
public class SoilComponent {
private String cokey;
private double area;
private String hsg;
private String taxorder;
private double kfact;
private double slope;
private double coarseFrag;
private boolean drained = false;
private String wtbl;
private double wtbl_top_min;
private int nslpNumber;
private String nslp;
private String[] requiredSoilInputs = new String[]{
"cokey",
"aoa_comp_area",
"aoa_comp_hsg",
"aoa_comp_taxorder",
"aoa_comp_kfact",
"aoa_comp_slope",
"aoa_comp_coarse_frag",
"aoa_comp_wtbl",
"aoa_comp_wtbl_top_min"
};
public SoilComponent(Map<String, JSONObject> soilGroup) throws ServiceException, JSONException {
checkSoilComponentInputParameters(soilGroup);
cokey = soilGroup.get("cokey").getString("value");
area = soilGroup.get("aoa_comp_area").getDouble("value");
hsg = soilGroup.get("aoa_comp_hsg").getString("value");
taxorder = soilGroup.get("aoa_comp_taxorder").getString("value");
kfact = soilGroup.get("aoa_comp_kfact").getDouble("value");
slope = soilGroup.get("aoa_comp_slope").getDouble("value");
coarseFrag = soilGroup.get("aoa_comp_coarse_frag").getDouble("value");
wtbl = soilGroup.get("aoa_comp_wtbl").getString("value");
String wtbl_top_min = soilGroup.get("aoa_comp_wtbl_top_min").getString("value");
if ((null == wtbl_top_min) || wtbl_top_min.equalsIgnoreCase("none") || wtbl_top_min.isEmpty()) {
this.wtbl_top_min = 99999.99;
} else {
this.wtbl_top_min = Double.parseDouble(wtbl_top_min);
}
}
private void checkSoilComponentInputParameters(Map<String, JSONObject> soilGroup) throws ServiceException {
for (String requiredSoilInput : requiredSoilInputs) {
if (!soilGroup.containsKey(requiredSoilInput) || soilGroup.get(requiredSoilInput).optString("value", "error").equalsIgnoreCase("error")) {
throw new ServiceException("The input JSON is missing the required soil component value for: " + requiredSoilInput);
}
}
}
//Getter Methods
public String getCokey() {
return cokey;
}
public double getArea() {
return area;
}
public String getHsg() {
return hsg;
}
public String getTaxorder() {
return taxorder;
}
public double getKfact() {
return kfact;
}
public double getSlope() {
return slope;
}
public double getCoarseFrag() {
return coarseFrag;
}
public String getWtbl() {
return wtbl;
}
public double getWtblTopMin() {
return wtbl_top_min;
}
public int getNslpNumber() {
return nslpNumber;
}
public String getNslp() {
return nslp;
}
//Setter Methods
public void setNslpNumber(int number) {
nslpNumber = number;
}
public void setNslp(String value) {
nslp = value;
}
}
}