NASIS.java [src/java/d/dataNodes] 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 d.dataNodes;
import d.soils.wwe02_wepssoilinput.StratifiedTextures;
import csip.SessionLogger;
import d.util.OrganicSoilException;
import d.util.ConfigData;
import d.util.SoilUtil;
import d.util.Utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import javax.measure.Measure;
import javax.measure.quantity.Length;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
/**
*
* @author brad
*/
public class NASIS {
private SessionLogger LOG;
private static boolean estimateNullValues = true;
private static final String STRATIFIED_LAYER_KEY = "SR";
private String textureChk[] = {"by", "cem", "ce", "dur", "frag", "gyp", "hpm", "ind", "marl", "mat",
"mpm", "muck", "mpt", "or", "opwd",
"peat", "pc", "pf", "pgp", "pum", "spm", "st", "udom",
"u", "uwb", "var", "w", "wb", "cem-", "pf-"};
private static final String[] ORGANIC_TEXTURES = {"mpm", "mpt", "muck", "peat", "spm", "udom", "pdom", "hpm"};
private String errIncFile = "";
private String state = "";
private String county = "";
private String ssaname = "";
private String ssaid = "";
private String musym = "";
private String compname = "";
private String comppct = "";
private String taxorder = "";
private String localphase = "";
private double losstolerance = 0.0;
private double slope = 0.0;
private double albedodry = 0.0;
private int numlay = 0;
private int adjlay = 0;
private double hzdept[];
private double hzdepb[];
private double hzthk[];
private String texture[];
private boolean stratified[];
private boolean rv[];
private double claytotal[];
private double sandtotal[];
private double silttotal[];
private double sandvco[];
private double sandco[];
private double sandmed[];
private double sandfine[];
private double sandvf[];
private double dbthirdbar[];
private double wtenthbar[];
private double wthirdbar[];
private double w15thbar[];
private double ksat[];
private double cec7[];
private double ecec[];
private double om[];
private double caco3[];
private double ph1to1h2o[];
private double ph01mcacl2[];
private double fragvol[];
private double lep[];
private double bedrockDepth;
private double impermiableDepth;
private static double omFractionThreshold;
private enum SoilElementTestAction {
IGNORE, ERROR, ESTIMATE
}
public NASIS(int inpnumlay,SessionLogger log) {
LOG = log;
numlay = inpnumlay;
if (numlay == 0) {
return;
}
hzdept = new double[numlay];
hzdepb = new double[numlay];
hzthk = new double[numlay];
texture = new String[numlay];
stratified = new boolean[numlay];
rv = new boolean[numlay];
claytotal = new double[numlay];
sandtotal = new double[numlay];
silttotal = new double[numlay];
sandvco = new double[numlay];
sandco = new double[numlay];
sandmed = new double[numlay];
sandfine = new double[numlay];
sandvf = new double[numlay];
dbthirdbar = new double[numlay];
wtenthbar = new double[numlay];
wthirdbar = new double[numlay];
w15thbar = new double[numlay];
ksat = new double[numlay];
cec7 = new double[numlay];
ecec = new double[numlay];
om = new double[numlay];
caco3 = new double[numlay];
ph1to1h2o = new double[numlay];
ph01mcacl2 = new double[numlay];
fragvol = new double[numlay];
lep = new double[numlay];
}
public SessionLogger getLOG() {
return LOG;
}
public void setLOG(SessionLogger LOG) {
this.LOG = LOG;
}
public static boolean isEstimateNullValues() {
return estimateNullValues;
}
public static void setEstimateNullValues(boolean estimateNullValues) {
NASIS.estimateNullValues = estimateNullValues;
}
public String[] getTextureChk() {
return textureChk;
}
public void setTextureChk(String[] textureChk) {
this.textureChk = textureChk;
}
public String getErrIncFile() {
return errIncFile;
}
public void setErrIncFile(String errIncFile) {
this.errIncFile = errIncFile;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
public String getSsaname() {
return ssaname;
}
public void setSsaname(String ssaname) {
this.ssaname = ssaname;
}
public String getSsaid() {
return ssaid;
}
public void setSsaid(String ssaid) {
this.ssaid = ssaid;
}
public String getMusym() {
return musym;
}
public void setMusym(String musym) {
this.musym = musym;
}
public String getCompname() {
return compname;
}
public void setCompname(String compname) {
this.compname = compname;
}
public String getComppct() {
return comppct;
}
public void setComppct(String comppct) {
this.comppct = comppct;
}
public String getTaxorder() {
return taxorder;
}
public void setTaxorder(String taxorder) {
this.taxorder = taxorder;
}
public String getLocalphase() {
return localphase;
}
public void setLocalphase(String localphase) {
this.localphase = localphase;
}
public double getLosstolerance() {
return losstolerance;
}
public void setLosstolerance(double losstolerance) {
this.losstolerance = losstolerance;
}
public double getSlope() {
return slope;
}
public void setSlope(double slope) {
this.slope = slope;
}
public double getAlbedodry() {
return albedodry;
}
public void setAlbedodry(double albedodry) {
this.albedodry = albedodry;
}
public int getNumlay() {
return numlay;
}
public void setNumlay(int numlay) {
this.numlay = numlay;
}
public int getAdjlay() {
return adjlay;
}
public void setAdjlay(int adjlay) {
this.adjlay = adjlay;
}
public double[] getHzdept() {
return hzdept;
}
public void setHzdept(double[] hzdept) {
this.hzdept = hzdept;
}
public double[] getHzdepb() {
return hzdepb;
}
public void setHzdepb(double[] hzdepb) {
this.hzdepb = hzdepb;
}
public double[] getHzthk() {
return hzthk;
}
public void setHzthk(double[] hzthk) {
this.hzthk = hzthk;
}
public String[] getTexture() {
return texture;
}
public void setTexture(String[] texture) {
this.texture = texture;
}
public boolean[] getStratified() {
return stratified;
}
public void setStratified(boolean[] stratified) {
this.stratified = stratified;
}
public boolean[] getRv() {
return rv;
}
public void setRv(boolean[] rv) {
this.rv = rv;
}
public double[] getClaytotal() {
return claytotal;
}
public void setClaytotal(double[] claytotal) {
this.claytotal = claytotal;
}
public double[] getSandtotal() {
return sandtotal;
}
public void setSandtotal(double[] sandtotal) {
this.sandtotal = sandtotal;
}
public double[] getSilttotal() {
return silttotal;
}
public void setSilttotal(double[] silttotal) {
this.silttotal = silttotal;
}
public double[] getSandvco() {
return sandvco;
}
public void setSandvco(double[] sandvco) {
this.sandvco = sandvco;
}
public double[] getSandco() {
return sandco;
}
public void setSandco(double[] sandco) {
this.sandco = sandco;
}
public double[] getSandmed() {
return sandmed;
}
public void setSandmed(double[] sandmed) {
this.sandmed = sandmed;
}
public double[] getSandfine() {
return sandfine;
}
public void setSandfine(double[] sandfine) {
this.sandfine = sandfine;
}
public double[] getSandvf() {
return sandvf;
}
public void setSandvf(double[] sandvf) {
this.sandvf = sandvf;
}
public double[] getDbthirdbar() {
return dbthirdbar;
}
public void setDbthirdbar(double[] dbthirdbar) {
this.dbthirdbar = dbthirdbar;
}
public double[] getWtenthbar() {
return wtenthbar;
}
public void setWtenthbar(double[] wtenthbar) {
this.wtenthbar = wtenthbar;
}
public double[] getWthirdbar() {
return wthirdbar;
}
public void setWthirdbar(double[] wthirdbar) {
this.wthirdbar = wthirdbar;
}
public double[] getW15thbar() {
return w15thbar;
}
public void setW15thbar(double[] w15thbar) {
this.w15thbar = w15thbar;
}
public double[] getKsat() {
return ksat;
}
public void setKsat(double[] ksat) {
this.ksat = ksat;
}
public double[] getCec7() {
return cec7;
}
public void setCec7(double[] cec7) {
this.cec7 = cec7;
}
public double[] getEcec() {
return ecec;
}
public void setEcec(double[] ecec) {
this.ecec = ecec;
}
public double[] getOm() {
return om;
}
public void setOm(double[] om) {
this.om = om;
}
public double[] getCaco3() {
return caco3;
}
public void setCaco3(double[] caco3) {
this.caco3 = caco3;
}
public double[] getPh1to1h2o() {
return ph1to1h2o;
}
public void setPh1to1h2o(double[] ph1to1h2o) {
this.ph1to1h2o = ph1to1h2o;
}
public double[] getPh01mcacl2() {
return ph01mcacl2;
}
public void setPh01mcacl2(double[] ph01mcacl2) {
this.ph01mcacl2 = ph01mcacl2;
}
public double[] getFragvol() {
return fragvol;
}
public void setFragvol(double[] fragvol) {
this.fragvol = fragvol;
}
public double[] getLep() {
return lep;
}
public void setLep(double[] lep) {
this.lep = lep;
}
public double getBedrockDepth() {
return bedrockDepth;
}
public void setBedrockDepth(double bedrockDepth) {
this.bedrockDepth = bedrockDepth;
}
public double getImpermiableDepth() {
return impermiableDepth;
}
public void setImpermiableDepth(double impermiableDepth) {
this.impermiableDepth = impermiableDepth;
}
public static double getOmFractionThreshold() {
return omFractionThreshold;
}
public static void setOmFractionThreshold(double omFractionThreshold) {
NASIS.omFractionThreshold = omFractionThreshold;
}
public boolean loadSQL(Connection con, String cokey) {
try {
String mukey = null;
String lkey = null;
String chkey = null;
Statement stmt = con.createStatement();
// String query = new String("SELECT * FROM component WHERE cokey = '"+cokey+"'");
String query = "SELECT compname,comppct_r,taxorder,slope_r,albedodry_r,mukey,localphase,"
+ "tfact FROM component WHERE cokey = '" + cokey + "'";
ResultSet rs = stmt.executeQuery(query);
boolean tmp = rs.next();
if (!tmp)
return false;
copyComponent(rs);
//can test taxorder now to see if organic
// We have our own organic test later so just go through with this
// if (ConfigData.getDefault(LOG).getSoilTestOrganic()) {
// if ("histosols".equalsIgnoreCase(taxorder)) {
// throw new OrganicSoilException();
// }
// }
mukey = rs.getString("mukey");
rs.close();
query = "SELECT musym,lkey FROM mapunit WHERE mukey = '" + mukey + "'";
rs = stmt.executeQuery(query);
tmp = rs.next();
copyMapUnit(rs);
lkey = rs.getString("lkey");
rs.close();
//Bedrock Depth
query = "SELECT brockdepmin AS brockdepmin_r FROM muaggatt WHERE mukey = '" + mukey + "'";
rs = stmt.executeQuery(query);
tmp = rs.next();
copyMuAggatt(rs);
rs.close();
//Restritive Depth
query = "SELECT Min(resdept_r) AS resdeptmin_r FROM corestrictions WHERE cokey='" + cokey + "' GROUP BY cokey";
rs = stmt.executeQuery(query);
tmp = rs.next();
copyCoRestrictions(rs);
rs.close();
try {
query = "SELECT areaname,areasymbol,cordate,ssurgoarchived,"
+ "tabularversion FROM legend WHERE lkey = '" + lkey + "'";
rs = stmt.executeQuery(query);
} catch (SQLException sqle) {
query = "SELECT areaname,areasymbol,cordate,ssurgoarchived FROM legend WHERE lkey = '" + lkey + "'";
rs = stmt.executeQuery(query);
}
tmp = rs.next();
copyLegend(rs);
rs.close();
Statement stmtFrags = con.createStatement();
Statement stmtTexture = con.createStatement();
// query = new String("SELECT * FROM chorizon WHERE cokey = '"+cokey+"'");
String[] hrzFlds = {"hzdept", "hzdepb", "claytotal", "sandtotal", "silttotal",
"sandvc", "sandco", "sandmed", "sandfine",
"sandvf", "dbthirdbar", "wtenthbar",
"wthirdbar", "wfifteenbar", "cec7", "ecec", "om",
"caco3", "ph1to1h2o", "ph01mcacl2", "lep", "ksat"};
StringBuilder sb = new StringBuilder("SELECT ");
for (String hrzFld : hrzFlds) {
sb.append(hrzFld + "_r,");
sb.append(hrzFld + "_l,");
sb.append(hrzFld + "_h,");
}
//hzdept_r, (hzdept_l + hzdept_h) / 2
sb.append("chkey, desgnmaster, hzname FROM chorizon WHERE cokey = '" + cokey + "' ORDER BY hzdept_r ASC");
// Order by depth to make sure layers are in the correct order.
String chorizonQuery = sb.toString();
rs = stmt.executeQuery(chorizonQuery);
int layerNum = 0;
int i = 0;
boolean foundAMineralLayer = false;
//up to this amount is allowed to be ignored
double maxOrganicDepth = ConfigData.getDefault(LOG).getSoilMaxOrganicDepth().doubleValue(SI.MILLIMETER);
//as we loop over the layers, we add up how much organic layer has been ignored
double usedOrganicDepth = 0;
while (rs.next()) {
chkey = rs.getString("chkey");
String chtexturegrpQuery = "SELECT texture, stratextsflag, rvindicator FROM chtexturegrp WHERE chkey = '"
+ chkey + "'";
try (ResultSet rsTexture = stmtTexture.executeQuery(chtexturegrpQuery)) {
//do we ignore an organic surface?
if (ConfigData.getDefault(LOG).isSkipOrganicSoilSurfaceLayers()
&& !foundAMineralLayer && usedOrganicDepth <= maxOrganicDepth) {
String hzname = getValueFromRS(rs, "hzname", null);
String desgnmaster = getValueFromRS(rs, "desgnmaster", null);
double om = getValueFromRS(rs, "om");
//convert from percent to fraction
om = om / 100d;
String text = getValueFromRS(rsTexture, "texture", null);
boolean organic = isLayerOrganic(hzname, desgnmaster, text, om);
if (organic) {
//data mart is in cm not mm
double thicknessMiliMeter
= getValueFromRS(rs, "hzthk", getValueFromRS(rs, "hzdepb", Double.NaN)) * 10;
usedOrganicDepth += thicknessMiliMeter;
if (usedOrganicDepth <= maxOrganicDepth) {
//still allowed to ignore
LOG.log(Level.INFO,"Organic layer ignored.");
continue;
} else {
Measure<Double, Length> max = Measure.valueOf(maxOrganicDepth, SI.MILLIMETER);
Measure<Double, Length> used = Measure.valueOf(usedOrganicDepth, SI.MILLIMETER);
NumberFormat format = DecimalFormat.getNumberInstance();
boolean isSIUnits = Utils.SIUnits.equals(ConfigData.getDefault(LOG).getData(ConfigData.Units));
Unit<Length> units = isSIUnits ? SI.MILLIMETER : NonSI.INCH;
if (i == 0) {
throw new OrganicSoilException(
"The organic surface layer depth exceeded the maximum ignorable depth.\n"
+ format.format(used.doubleValue(units)) + units + " > "
+ format.format(max.doubleValue(units)) + units);
} else {
throw new OrganicSoilException(
"The soil layer below the ignored organic layer is still organic.");
}
}
} else {
//not organic, so we're good to go
foundAMineralLayer = true;
}
}
copyHorizon(rs, layerNum);
String chfragsQuery = "SELECT fragvol_r,fragvol_h,fragvol_l FROM chfrags WHERE chkey = '" + chkey + "'";
ResultSet rsFrags = stmtFrags.executeQuery(chfragsQuery);
copyFrags(rsFrags, layerNum);
rsFrags.close();
//already executed the query for the organic tests
copyTexture(rsTexture, layerNum);
layerNum++;
} finally {
i++;
}
}
rs.close();
this.numlay = layerNum;
//If the config option is set, average the stratified layers.
if (ConfigData.getDefault(LOG).isAverageStratifiedSoilLayers()) {
averageStratifiedLayers();
}
fixUpData();
testData();
} catch (SQLException e) {
e.printStackTrace();
// for (; e != null; e = e.getNextException()) {
// //System.err.println("\n" + e);
// e.printStackTrace();
// }
}
return true;
}
public void fixUpData() {
for (adjlay = 1; adjlay < numlay; adjlay++) {
// stop if layer is identified as rock, peat, etc.
if (chkTexture(texture[adjlay])) {
break;
}
// stop if both sand and clay are missing or zero
if ((Double.isNaN(claytotal[adjlay]) || claytotal[adjlay] == 0.0)
&& (Double.isNaN(sandtotal[adjlay]) || sandtotal[adjlay] == 0.0)) {
break;
}
// stop if layer does not have wet bulk density
if (Double.isNaN(dbthirdbar[adjlay]) || dbthirdbar[adjlay] == 0.0) {
break;
}
}
}
public void testData() {
SoilElementTestAction ignore = SoilElementTestAction.IGNORE;
SoilElementTestAction ignore2 = SoilElementTestAction.IGNORE;
SoilElementTestAction estimate = SoilElementTestAction.ESTIMATE;
SoilElementTestAction error = SoilElementTestAction.ERROR;
if (!estimateNullValues) {
//We don't want to estimate
estimate = error;
ignore2 = error;
//Test values that must be present in surgo
state = testStringSoilElement(state, "State", "state", SoilElementTestAction.IGNORE, "unknown");
}
//Errors
if (numlay <= 0) {
LOG.log(Level.SEVERE, "No layers found in soil record.");
}
//Soil Components
compname = testStringSoilElement(compname, "Component Name", "compname", ignore, "unknown");
comppct = testStringSoilElement(comppct, "Component Percent", "comppct_r", ignore, "unknown");
taxorder = testStringSoilElement(taxorder, "Taxonomic Order", "taxorder", ignore, "unknown");
localphase = testStringSoilElement(localphase, "Local Phase", "localphase", ignore, "unknown");
losstolerance = testNumericSoilElement(losstolerance, "t/ac/yr",
1, 5, "Soil Loss Tolerance", "losstolerance", ignore, -1);
slope = testNumericSoilElement(slope, "fraction", 0, 999, "Slope Gradient", "slope", ignore, -1);
albedodry = testNumericSoilElement(albedodry, "fraction", 0, 1, "Dry Soil Albedo",
"albedodry", estimate, 0.6 / Math.exp(0.4 * om[0]));
//End Soil Components
//Map Unit
musym = testStringSoilElement(musym, "Map Symbol", "musym", ignore2, "no map symbol");
//End Map Unit
//MuAggatt
bedrockDepth = testNumericSoilElement(bedrockDepth, "cm", 0, 9999, "Bedrock Depth", "bedrockDepth", ignore, 9999);
//End MuAggatt
//CoRestrictions
impermiableDepth = testNumericSoilElement(impermiableDepth, "", 0, 9999,
"Impermiable/Restrictive Depth", "resdept_r_min", ignore, 9999);
//End CoRestrictions
//Legend
ssaname = testStringSoilElement(ssaname, "Area Name/Area State", "areaname", ignore2, "no area name, no area state");
ssaid = testStringSoilElement(ssaid, "Area Symbol", "areasymbol", ignore2, "no area symbol");
//End Legend
//Test Soil Layers, only tests layers that were not dropped for texture reasons.
if (adjlay <= numlay) {
for (int layer = 0; layer < adjlay; layer++) {
hzdept[layer] = testNumericSoilElement(hzdept[layer], "cm", 0, 999,
"Layer Depth Top", "hzdept", error, Double.NaN, layer);
hzdepb[layer] = testNumericSoilElement(hzdepb[layer], "cm", 0, 999,
"Layer Depth Bottom", "hzdepb", error, Double.NaN, layer);
hzthk[layer] = hzdepb[layer] - hzdept[layer];
hzthk[layer] = testNumericSoilElement(hzthk[layer], "cm", 0.01, 1000,
"Layer Thickness", "hzthk", estimate, hzdept[layer] - hzdepb[layer], layer);
claytotal[layer] = testNumericSoilElement(claytotal[layer], "weight %",
0, 100, "Total Clay Content", "claytotal", error, Double.NaN, layer);
sandtotal[layer] = testNumericSoilElement(sandtotal[layer], "weight %",
0, 100, "Total Sand Content", "sandtotal", error, Double.NaN, layer);
double calculatedSiltTotal = 100 - (claytotal[layer] + sandtotal[layer]);
silttotal[layer] = testNumericSoilElement(silttotal[layer], "weight %",
calculatedSiltTotal * 0.999, calculatedSiltTotal * 1.001,
"Total Silt Content", "silttotal", SoilElementTestAction.ESTIMATE, calculatedSiltTotal, layer);
sandvf[layer] = testNumericSoilElement(sandvf[layer], "weight %", 0, 100,
"Very Fine Sand", "sandvf", error, Double.NaN, layer);
dbthirdbar[layer] = testNumericSoilElement(dbthirdbar[layer], "g/cm3", .02, 2.60,
"1/3 Bar Bulk Density", "dbthirdbar", error, Double.NaN, layer);
//the value will be estimated by ifc
wthirdbar[layer] = testNumericSoilElement(wthirdbar[layer], "volume %", 0, 80,
"1/3 bar water ", "wthirdbar", ignore, Double.NaN, layer);
om[layer] = testNumericSoilElement(om[layer], "weight %", 0, 100,
"Organic Matter Content", "om", error, Double.NaN, layer);
caco3[layer] = testNumericSoilElement(caco3[layer], "weight %", 0, 110,
"CaCO3 Equivalent", "caco3", error, Double.NaN, layer);
//cec7[layer] = testNumericSoilElement(cec7[layer], "weight %", 0, 110,
//"CEC7 or ECEC", "cec7", error, Double.NaN, layer);
if (Double.isNaN(cec7[layer]) && Double.isNaN(ecec[layer])) {
LOG.log(Level.SEVERE,"CEC7 and ECEC values are missing from layer " + (layer + 1) + ".");
}
//total sand and total clay can not be greater than 100% combined.
if (claytotal[layer] + sandtotal[layer] > 100) {
LOG.log(Level.SEVERE, "Total Clay and Sand content for layer " + (layer + 1) + " exceeds 100%.");
}
// fractionRock = (double[]) nasinp.fragvol.clone(); // rock %
// veryCoarseSandFraction = (double[]) nasinp.sandvco.clone(); // coarseSandFraction
// coarseSandFraction = (double[]) nasinp.sandco.clone(); // coarseSandFraction
// mediumSandFraction = (double[]) nasinp.sandmed.clone(); // mediumSandFraction
// fineSandFraction = (double[]) nasinp.sandfine.clone(); // fineSandFraction
// veryFineSandFraction = (double[]) nasinp.sandvf.clone();
if (!estimateNullValues) {
//Test values per layer
if (Double.isNaN(ph1to1h2o[layer]) && Double.isNaN(ph01mcacl2[layer])) {
LOG.log(Level.SEVERE, "pH 1:1 H2O and 0.01 MCaCl2 values are missing from layer " + (layer + 1) + ".");
}
ksat[layer] = testNumericSoilElement(ksat[layer], "um/s", 0, 705, "Ksat", "ksat", error, Double.NaN, layer);
w15thbar[layer] = testNumericSoilElement(w15thbar[layer], "volume %", 0, 70,
"15 bar water (wp)", "wfifteenbar", ignore, Double.NaN, layer);
}
//Special case for LEP
if (Double.isNaN(lep[layer])) {
if (estimateNullValues) {
//Estimate a value
double bsd = SoilUtil.estimateSettledBulkDensity(claytotal[layer], sandtotal[layer], om[layer]);
if (wthirdbar[layer] > bsd) {
bsd = wthirdbar[layer];
String msgText = "Settled bulk density adjusted: Set to wet bulk density.";
LOG.log(Level.WARNING, msgText);
} else {
String msgText = "Settled bulk density estimated: " + Utils.formatDouble(bsd, 4);
LOG.log(Level.WARNING, msgText);
}
double lepc = SoilUtil.estimateLinearExtensibility(bsd, wthirdbar[layer]);
lep[layer] = testNumericSoilElement(lep[layer], "%", 0, 30,
"Linear Extensibility", "lep", estimate, lepc, layer);
} else {
if (om[layer] > omFractionThreshold) {
lep[layer] = testNumericSoilElement(lep[layer], "%", 0, 30,
"Linear Extensibility", "lep", estimate, 0.0d, layer);
} else {
lep[layer] = testNumericSoilElement(lep[layer], "%", 0, 30,
"Linear Extensibility", "lep", error, Double.NaN, layer);
}
}
} else {
lep[layer] = testNumericSoilElement(lep[layer], "%", 0, 30, "Linear Extensibility",
"lep", error, Double.NaN, layer);
}
}
}
}
private String testStringSoilElement(String value, String name, String header,
SoilElementTestAction action, String actionValue) {
//1. Test is not null
if (value == null || value.length() == 0) {
switch (action) {
case IGNORE:
logSubstitutionMessage(Level.WARNING, name, header, actionValue);
return actionValue;
case ESTIMATE:
logEstimatedMessage(Level.WARNING, name, header, actionValue);
return actionValue;
case ERROR:
logMessage(Level.SEVERE, name + " (" + header + ") is missing.");
return actionValue;
}
}
return value;
}
private double testNumericSoilElement(double value, String units, double minimum,
double maximum, String name, String header, SoilElementTestAction action, double actionValue) {
return testNumericSoilElement(value, units, minimum, maximum, name, header, action, actionValue, -1);
}
private double testNumericSoilElement(double value, String units, double minimum,
double maximum, String name, String header, SoilElementTestAction action, double actionValue, int layer) {
String layerTag = "";
if (layer > -1) {
layerTag = " from layer " + (layer + 1);
}
//1. Test is not null
if (Double.isNaN(value)) {
switch (action) {
case IGNORE:
logSubstitutionMessage(Level.WARNING, name, header, actionValue, layer);
return actionValue;
case ESTIMATE:
logEstimatedMessage(Level.WARNING, name, header, actionValue, layer);
return actionValue;
case ERROR:
logMessage(Level.SEVERE, name + " (" + header + ") is missing" + layerTag + ".");
return actionValue;
}
}
//2. Test in range if needed
boolean outOfRange = false;
if (!Double.isNaN(minimum) && value < minimum) {
outOfRange = true;
}
if (!Double.isNaN(maximum) && value > maximum) {
outOfRange = true;
}
if (outOfRange) {
switch (action) {
case IGNORE:
logSubstitutionMessage(Level.WARNING, name, header, Double.toString(actionValue) + " " + units, layer);
return actionValue;
case ESTIMATE:
logEstimatedMessage(Level.WARNING, name, header, Double.toString(actionValue) + " " + units, layer);
return actionValue;
case ERROR:
logMessage(Level.SEVERE, name + " (" + header + ")" + layerTag
+ " is outside the acceptable range (" + Double.toString(minimum)
+ " to " + Double.toString(maximum) + ").");
return actionValue;
}
}
return value;
}
public void averageStratifiedLayers() {
StratifiedTextures st = null;//StratifiedTextures.getInstance(LOG);
Layers:
for (int i = 0; i < numlay; i++) {
String layerTexture = texture[i];
if (stratified[i] && rv[i] && layerTexture.trim().toUpperCase().startsWith(STRATIFIED_LAYER_KEY)) {
//This layer is stratified
String[] textures = layerTexture.split(" ", -1);
boolean first = true;
double sand = 0;
double clay = 0;
double vsf = 0;
int count = 0;
for (String subTexture : textures) {
subTexture = subTexture.trim();
if (first) {
//skip the sr marker
first = false;
continue;
}
if (st.isTextureValid(subTexture)) {
count++;
sand += st.getSand(subTexture);
sand /= count;
clay += st.getClay(subTexture);
clay /= count;
vsf += st.getVeryFineSand(subTexture);
vsf /= count;
} else {
//can't fix up this layer
continue Layers;
}
}
if (sand + clay > 1) {
//TODO: log error
continue Layers;
}
double silt = 1 - sand - clay;
sandtotal[i] = sand * 100;
silttotal[i] = silt * 100;
claytotal[i] = clay * 100;
sandvf[i] = vsf * 100;
LOG.log(Level.INFO, "Averaged stratified layer values on layer " + String.valueOf(i + 1) + ".");
}
}
}
private boolean chkTexture(String texture) {
String tmp = texture.toLowerCase();
for (String textureChk1 : textureChk) {
if (tmp.indexOf(textureChk1) >= 0) {
int tdx = tmp.indexOf(textureChk1); // check if token
if (tdx > 0) {
if (!Character.isWhitespace(tmp.charAt(tdx - 1))) {
continue;
}
if (tmp.charAt(tdx - 1) != '-') {
continue;
}
}
if (tdx + textureChk1.length() < tmp.length()) {
if (!Character.isWhitespace(tmp.charAt(tdx + textureChk1.length()))) {
continue;
}
}
LOG.log(Level.WARNING, "Layer dropped for texture " + texture + ".");
return true;
}
}
return false;
}
private static boolean isLayerOrganic(String hzname, String desgnmaster, String texture, double organicMatter) {
//horizon name
if (hzname != null && hzname.startsWith("O")) {
return true;
}
if (desgnmaster != null && desgnmaster.startsWith("O")) {
return true;
}
for (String organicTexture : ORGANIC_TEXTURES) {
if (organicTexture.equals(texture)) {
return true;
}
}
if (organicMatter > omFractionThreshold) {
return true;
}
//aka, a mineral layer
return false;
}
private void copyComponent(ResultSet rs) {
compname = getValueFromRS(rs, "compname", null);
comppct = getValueFromRS(rs, "comppct_r", null);
taxorder = getValueFromRS(rs, "taxorder", null);
localphase = getValueFromRS(rs, "localphase", "");
String temp = getValueFromRS(rs, "tfact", "0");
if (temp.trim().length() == 0) {
temp = "0";
}
losstolerance = Integer.parseInt(temp);
// losstolerance = getValueFromRS(rs, "tfact");
slope = getValueFromRS(rs, "slope");
albedodry = getValueFromRS(rs, "albedodry");
}
protected void copyMapUnit(ResultSet rs) {
musym = getValueFromRS(rs, "musym", null);
}
/**
*
* @param rs
*/
protected void copyMuAggatt(ResultSet rs) {
bedrockDepth = getValueFromRS(rs, "brockdepmin");
}
/**
*
* @param rs
*/
protected void copyCoRestrictions(ResultSet rs) {
impermiableDepth = getValueFromRS(rs, "resdeptmin");
}
/********************************************************************** wjr
* @param rs */
protected void copyLegend(ResultSet rs) {
ssaname = getValueFromRS(rs, "areaname", null);
ssaid = getValueFromRS(rs, "areasymbol", null);
Date cordate = getDateValueFromRS(rs, "cordate");
Date archiveddate = getDateValueFromRS(rs, "ssurgoarchived");
String tabularVersion = getStringValueFromRS(rs, "tabularversion");
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
if (cordate != null) {
LOG.log(Level.INFO, "Correlation Date: " + format.format(cordate));
}
if (archiveddate != null) {
LOG.log(Level.INFO, "SSURGO Archived Date: " + format.format(archiveddate));
}
if (tabularVersion != null && tabularVersion.trim().length() > 0) {
LOG.log(Level.INFO, "Tabular Version: " + tabularVersion);
}
String[] parts = ssaname.split(",", -1);
if (parts.length == 0) {
state = null;
county = "";
} else if (parts.length == 1) {
state = parts[0].trim();
county = "";
} else {
county = parts[0].trim();
state = parts[1].trim();
}
}
protected void copyHorizon(ResultSet rs, int idx) {
this.hzdept[idx] = getValueFromRS(rs, "hzdept");
this.hzdepb[idx] = getValueFromRS(rs, "hzdepb");
this.claytotal[idx] = getValueFromRS(rs, "claytotal");
this.sandtotal[idx] = getValueFromRS(rs, "sandtotal");
this.silttotal[idx] = getValueFromRS(rs, "silttotal");
sandvco[idx] = getValueFromRS(rs, "sandvc", 0);
sandco[idx] = getValueFromRS(rs, "sandco", 0);
this.sandmed[idx] = getValueFromRS(rs, "sandmed", 0);
this.sandfine[idx] = getValueFromRS(rs, "sandfine", 0);
this.sandvf[idx] = getValueFromRS(rs, "sandvf");
this.dbthirdbar[idx] = getValueFromRS(rs, "dbthirdbar");
// this.dbovendry[idx] = getValueFromRS(rs, "dbovendry");
// this.wtenthbar[idx] = getValueFromRS(rs, "wtenthbar");
//this.wtenthbar[idx] = -9.9;
this.wthirdbar[idx] = getValueFromRS(rs, "wthirdbar");
this.w15thbar[idx] = getValueFromRS(rs, "wfifteenbar");
this.ksat[idx] = getValueFromRS(rs, "ksat");
this.cec7[idx] = getValueFromRS(rs, "cec7");
this.ecec[idx] = getValueFromRS(rs, "ecec");
// I think my error checking will work - it compiles :-)
// However, my test case error is not because both fields are null,
// but that one is null for one layer and the other is null for another and
// the NASIS(SSURGO) to IFC code can't handle that correctly (yet) - LEW
//if ((this.cec7[idx] < 0.0) && (this.ecec[idx] < 0.0))
//System.err.println("NASIS_copyHorizon: cec7 or ecec fields not populated ");
//if ((this.cec7[idx] < 0.0) && (this.ecec[idx] < 0.0)) throw new FieldNotPopulated("cec7 and ecec");
this.om[idx] = getValueFromRS(rs, "om");
this.caco3[idx] = getValueFromRS(rs, "caco3");
this.ph1to1h2o[idx] = getValueFromRS(rs, "ph1to1h2o");
this.ph01mcacl2[idx] = getValueFromRS(rs, "ph01mcacl2");
this.lep[idx] = getValueFromRS(rs, "lep");
}
protected void copyTexture(ResultSet rs, int idx) {
this.texture[idx] = "";
try {
rs.next();
String temp = rs.getString("texture");
temp = (temp == null) ? "" : temp;
temp = temp.replace("-", "_");
this.texture[idx] = temp;
String stratifiedString = rs.getString("stratextsflag");
stratified[idx] = stratifiedString != null ? (stratifiedString.trim().equalsIgnoreCase("yes")) : false;
String rvString = rs.getString("rvindicator");
rv[idx] = rvString != null ? (rvString.trim().equalsIgnoreCase("yes")) : false;
} catch (SQLException e) {
}
}
/********************************************************************** wjr
* @param rs
* @param idx */
protected void copyFrags(ResultSet rs, int idx) {
this.fragvol[idx] = 0.0;
try {
while (rs.next()) {
double tempFragVol = getValueFromRS(rs, "fragvol");
this.fragvol[idx] += (Double.isNaN(tempFragVol)) ? 0.0 : tempFragVol;
}
} catch (SQLException e) {
}
}
protected String getStringValueFromRS(ResultSet rs, String fieldName) {
try {
return rs.getString(fieldName);
} catch (SQLException e) {
return null;
}
}
/**
*
* @param rs
* @param fieldName
* @return
*/
protected int getIntergerValueFromRS(ResultSet rs, String fieldName) {
try {
return rs.getInt(fieldName);
} catch (SQLException e) {
return Integer.MIN_VALUE;
}
}
/**
*
* @param rs
* @param fieldName
* @return
*/
protected Date getDateValueFromRS(ResultSet rs, String fieldName) {
try {
return rs.getDate(fieldName);
} catch (SQLException e) {
return null;
}
}
/**
*
* @param rs
* @param fieldName
* @return
*/
protected double getValueFromRS(ResultSet rs, String fieldName) {
return getValueFromRS(rs, fieldName, Double.NaN);
}
/**
*
* @param rs
* @param fieldName
* @param defaultValue
* @return
*/
protected double getValueFromRS(ResultSet rs, String fieldName, double defaultValue) {
try {
String rtnStr = rs.getString(fieldName + "_r");
if (rtnStr == null) {
throw new SQLException();
}
try {
return Double.parseDouble(rtnStr);
} catch (NumberFormatException g) {
throw new SQLException();
}
} catch (SQLException e) {
try {
String rtn_l = rs.getString(fieldName + "_l");
String rtn_h = rs.getString(fieldName + "_h");
if (rtn_l == null || rtn_h == null) {
throw new SQLException();
}
try {
return (Double.parseDouble(rtn_l) + Double.parseDouble(rtn_h)) / 2;
} catch (NumberFormatException h) {
throw new SQLException();
}
} catch (SQLException f) {
return defaultValue;
}
} catch (NullPointerException npe) {
return defaultValue;
}
}
/**
*
* @param resultSet
* @param fieldName
* @param defaultValue
* @return
*/
protected String getValueFromRS(ResultSet resultSet, String fieldName, String defaultValue) {
try {
String temp = resultSet.getString(fieldName);
return temp != null ? temp : defaultValue;
} catch (Exception e) {
// todo: it looks like this catch clause is always activated
return defaultValue;
}
}
private void logSubstitutionMessage(Level severity,
String dataElement, String header, Object newValue) {
logSubstitutionMessage(severity, dataElement, header, newValue, -1);
}
private void logSubstitutionMessage(Level severity,
String dataElement, String header, Object newValue, int layer) {
String layerTag = "";
if (layer > -1) {
layerTag = " from layer " + (layer + 1);
}
String tempMessage = dataElement + " ("
+ header + ") is missing" + layerTag + ". Null value was substituted with '" + newValue.toString() + "'.";
LOG.log(severity, tempMessage);
}
private void logMessage(Level severity, String message) {
LOG.log(severity, message);
}
private void logEstimatedMessage(Level severity,
String dataElement, String header, Object newValue) {
logEstimatedMessage(severity, dataElement, header, newValue, -1);
}
private void logEstimatedMessage(Level severity,
String dataElement, String header, Object newValue, int layer) {
String layerTag = "";
if (layer > -1) {
layerTag = " from layer " + (layer + 1);
}
String tempMessage = dataElement
+ " (" + header + ") is missing" + layerTag
+ ". Value was estimated to '" + newValue.toString() + "'.";
LOG.log(severity, tempMessage);
}
}