V1_0.java [src/java/m/wqm/wqm16_nutappmgtscores] Revision: Date:
package m.wqm.wqm16_nutappmgtscores;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import csip.utils.JSONUtils;
import csip.utils.Dates;
import csip.annotations.Polling;
import csip.annotations.Resource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Map;
import javax.ws.rs.Path;
import csip.annotations.Name;
import csip.annotations.Description;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import java.util.concurrent.TimeUnit;
import org.codehaus.jettison.json.JSONException;
import wqm.utils.DBQueries;
import wqm.utils.DBResources;
import static wqm.utils.DBResources.WQM_ID;
/**
* WQM-16: Nutrient Application Management Scores
*
* @author Rumpal Sidhu
* @version 1.0
*/
@Name("WQM-16: Nutrient Application Management Scores (NutAppMgtScores)")
@Description("This service computes scores for adjusting the rate, timing, "
+ "and method of applying nutrients to mitigate nitrogen leaching, "
+ "and nitrogen and phosphorus runoff loss potential.")
@Path("m/nutappmgtscores/1.0")
@Polling(first = 10000, next = 2000)
@Resource(from = DBResources.class)
public class V1_0 extends ModelDataService {
private int aoaId;
private String pSoilTestResult;
private ArrayList<Crop> cropList = new ArrayList<>();
private double nAppRateScore, pAppRateScore, nleachAppMgtScore, nsurfAppMgtScore, psurfAppMgtScore;
private int appMethodScore = 0, nAppTimingScore = 100, pAppTimingScore = 100;
@Override
protected void preProcess() throws ServiceException, JSONException {
aoaId = parameter().getInt("AoAId", 0);
pSoilTestResult = parameter().getString("p_soil_test_result", null);
JSONArray crops = parameter().getJSONArray("crop_list");
for (int i = 0; i < crops.length(); i++) {
Map<String, JSONObject> mgtCropId = JSONUtils.preprocess(crops.getJSONArray(i));
int id = JSONUtils.getIntParam(mgtCropId, "crop_id", 0);
String plantDate = JSONUtils.getStringParam(mgtCropId, "crop_plant_date", null);
Date cropPlantDate = getDate(plantDate);
double yield = JSONUtils.getDoubleParam(mgtCropId, "crop_yield", 0);
String units = JSONUtils.getStringParam(mgtCropId, "crop_yield_units", null);
ArrayList<NutrientApplication> nutrientApplicationList = new ArrayList<>();
if (JSONUtils.checkKeyExistsB(mgtCropId, "application_list")) {
JSONArray applicationList = JSONUtils.getJSONArrayParam(mgtCropId, "application_list");
for (int j = 0; j < applicationList.length(); j++) {
Map<String, JSONObject> application = JSONUtils.preprocess(applicationList.getJSONArray(j));
String nutrient_application_date = JSONUtils.getStringParam(application, "nutrient_application_date", null);
Date applicationDate = getDate(nutrient_application_date);
boolean incorporated = JSONUtils.getBooleanParam(application, "incorporated", false);
ArrayList<Nutrient> nutrientList = new ArrayList<>();
JSONArray appList = JSONUtils.getJSONArrayParam(application, "application");
for (int k = 0; k < appList.length(); k++) {
Map<String, JSONObject> app = JSONUtils.preprocess(appList.getJSONArray(k));
String nutrientApplied = JSONUtils.getStringParam(app, "nutrient_applied", null);
int applicationRate = JSONUtils.getIntParam(app, "application_rate", 0);
nutrientList.add(new Nutrient(nutrientApplied, applicationRate));
}
nutrientApplicationList.add(new NutrientApplication(applicationDate, incorporated, nutrientList));
}
}
cropList.add(new Crop(id, cropPlantDate, yield, units, nutrientApplicationList));
}
}
@Override
protected void doProcess() throws ServiceException, SQLException {
try (Connection connection = resources().getJDBC(WQM_ID);) {
compute(connection);
}
}
@Override
protected void postProcess() throws JSONException {
results().put("AoAId", aoaId, "Area of Analysis Identifier");
results().put("nleach_app_mgt_score", nleachAppMgtScore, "Nitrogen Application Management Score for Mitigating Leaching Loss Potential");
results().put("nsurf_app_mgt_score", nsurfAppMgtScore, "Nitrogen Application Management Score for Mitigating Surface Runoff Loss Potential");
results().put("psurf_app_mgt_score", psurfAppMgtScore, "Phosphorus Application Management Score for Mitigating Surface Runoff Loss Potential");
results().put("n_app_rate_score", nAppRateScore, "Nitrogen Application Rate Mitigation Score");
results().put("n_app_timing_score", nAppTimingScore, "Nitrogen Application Timing Mitigation Score");
results().put("p_app_rate_score", pAppRateScore, "Phosphorus Application Rate Mitigation Score");
results().put("p_app_timing_score", pAppTimingScore, "Phosphorus Application Timing Mitigation Score");
results().put("app_method_score", appMethodScore, "Nutrient Application Method Mitigation Score");
}
public final Date getDate(String sDate) {
String[] parse = sDate.split("-");
Calendar date = new GregorianCalendar(Integer.parseInt(parse[0]),
Integer.parseInt(parse[1]) - 1, Integer.parseInt(parse[2]));
return date.getTime();
}
private void compute(Connection connection) throws SQLException {
for (Crop crop : cropList) {
if (crop.nutrientApplicationList.isEmpty()) {
computeEmpty(connection);
} else {
computeAppRateScore(connection, crop);
computeAppTimimgScore(connection, crop);
}
nleachAppMgtScore = nAppRateScore + nAppTimingScore + appMethodScore;
nsurfAppMgtScore = nAppRateScore + nAppTimingScore + appMethodScore;
psurfAppMgtScore = pAppRateScore + pAppTimingScore + appMethodScore;
}
}
private void computeEmpty(Connection connection) throws SQLException {
try (Statement statement = connection.createStatement();) {
try (ResultSet resultSet = statement.executeQuery(DBQueries.WQM16Query02("nitrogen", "rate", "none", null, null, null));) {
while (resultSet.next()) {
nAppRateScore = resultSet.getInt("app_mgt_score");
}
}
try (ResultSet resultSet = statement.executeQuery(DBQueries.WQM16Query02("phosphorus", "rate", "none", pSoilTestResult, null, null));) {
while (resultSet.next()) {
pAppRateScore = resultSet.getInt("app_mgt_score");
}
}
}
}
private void computeAppRateScore(Connection connection, Crop crop) throws SQLException {
try (Statement statement = connection.createStatement();) {
String cropType = "";
double ncropAppRateScore = 0, pcropAppRateScore = 0, nRate = 0, pRate = 0;
double cropPctDmat = 0, pctNitrogen = 0, pctPhosphorus = 0;
//Compute N and P application rates for the crop
for (NutrientApplication nutApp : crop.nutrientApplicationList) {
for (Nutrient nutrient : nutApp.nutrientList) {
switch (nutrient.nutrientApplied.toUpperCase()) {
case "NITROGEN":
nRate += nutrient.application_Rate;
break;
case "PHOSPHORUS":
pRate += nutrient.application_Rate;
break;
}
}
}
try (ResultSet resultSet = statement.executeQuery(DBQueries.WQM16Query01(crop.id, null));) {
while (resultSet.next()) {
cropType = resultSet.getString("crop_type");
cropPctDmat = resultSet.getDouble("pct_dmat");
pctNitrogen = resultSet.getDouble("pct_nitrogen");
pctPhosphorus = resultSet.getDouble("pct_phosphorus");
}
}
/**
* 1. Compute N removal ratio for the crop, 2. Compute N application
* management rate score for the crop
*/
double nRemoveRatio = nRate / (crop.yield * cropPctDmat * pctNitrogen);
String query = DBQueries.WQM16Query02("nitrogen", "rate", cropType.equalsIgnoreCase("small grain") ? "small grain" : "other", null, nRemoveRatio, null);
try (ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
ncropAppRateScore = resultSet.getInt("app_mgt_score");
}
}
//Update N application management rate score for the AoA
nAppRateScore += ncropAppRateScore;
/**
* 1. Compute P removal ratio for the crop, 2. Compute P application
* management rate score for the crop
*/
query = null;
double pRemoveratio = pRate / (crop.yield * cropPctDmat * pctPhosphorus);
switch (pSoilTestResult.toUpperCase()) {
case "HIGH":
case "NONE":
if (pRemoveratio >= 1.2) {
pcropAppRateScore = 0;
} else {
query = DBQueries.WQM16Query02("phosphorus", "rate", "app", pSoilTestResult, pRemoveratio, null);
}
break;
case "MEDIUM":
case "LOW":
if (pRemoveratio >= 1.6) {
pcropAppRateScore = 0;
} else {
query = DBQueries.WQM16Query02("phosphorus", "rate", "app", pSoilTestResult, pRemoveratio, null);
}
break;
}
if (query != null) {
try (ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
pcropAppRateScore = resultSet.getInt("app_mgt_score");
}
}
}
//Update P application management rate score for the AoA
pAppRateScore += pcropAppRateScore;
}
}
private void computeAppTimimgScore(Connection connection, Crop crop) throws SQLException {
try (Statement statement = connection.createStatement();) {
int incorporated = 0;
/**
* 1. Compute N and P application timing scores for the crop 2.
* Update timing scores for the AoA
*/
for (NutrientApplication nu : crop.nutrientApplicationList) {
String appType = crop.nutrientApplicationList.size() == 1 ? "nosplit" : "split";
long app_day_diff = Dates.diffInMillis(crop.plantDate, nu.applicationDate);
app_day_diff = TimeUnit.MILLISECONDS.toDays(app_day_diff);
for (Nutrient nutrient : nu.nutrientList) {
try (ResultSet resultSet = statement.executeQuery(DBQueries.WQM16Query02(nutrient.nutrientApplied, "timing", appType, null, null, (int) app_day_diff))) {
Integer score = null;
if (resultSet.next()) {
score = resultSet.getInt("app_mgt_score");
}
switch (nutrient.nutrientApplied.toUpperCase()) {
case "NITROGEN":
if (score == null) {
nAppTimingScore = 0;
} else if (score < nAppTimingScore) {
nAppTimingScore = score;
}
break;
case "PHOSPHORUS":
if (score == null) {
pAppTimingScore = 0;
} else if (score < pAppTimingScore) {
pAppTimingScore = score;
}
break;
}
}
}
if (nu.incorporated) {
incorporated++;
}
}
if (incorporated == crop.nutrientApplicationList.size()) {
try (ResultSet resultSet = statement.executeQuery(DBQueries.WQM16Query02(null, "method", "incorporate", null, null, null));) {
if (resultSet.next()) {
appMethodScore = resultSet.getInt("app_mgt_score");
}
}
}
}
}
static class Crop {
protected int id;
protected Date plantDate;
protected double yield;
protected String yieldUnits;
protected ArrayList<NutrientApplication> nutrientApplicationList;
public Crop(int id, Date date, double yield, String yieldUnits, ArrayList<NutrientApplication> nutrientApplicationList) {
this.id = id;
this.plantDate = date;
this.yield = yield;
this.yieldUnits = yieldUnits;
this.nutrientApplicationList = nutrientApplicationList;
}
}
static class NutrientApplication {
protected Date applicationDate;
protected boolean incorporated;
protected ArrayList<Nutrient> nutrientList;
public NutrientApplication(Date date, boolean incorporated, ArrayList<Nutrient> nutrientList) {
this.applicationDate = date;
this.incorporated = incorporated;
this.nutrientList = nutrientList;
}
}
static class Nutrient {
protected String nutrientApplied;
protected double application_Rate;
public Nutrient(String nutrientApplied, double application_Rate) {
this.nutrientApplied = nutrientApplied;
this.application_Rate = application_Rate;
}
}
}