Displaying differences for changeset
 
display as  

src/java/m/rse/wepot/V1_1.java

@@ -50,13 +50,18 @@
     private double aoa_cfactor;
     private String aoa_dom_comp;
     private String aoa_dom_compname;
+    private String aoa_dom_wind_comp;
+    private String aoa_dom_wind_compname;
     private double aoa_ifactor;
     private double aoa_tfactor;
+    private double aoa_wind_tfactor;
     private double aoa_lsfactor;
     private double aoa_kfactor;
     private double aoa_wind_ep;
     private double aoa_water_ep;
 
+    private boolean isPalouse;
+
     double cfactorraster = -1;
 
     @Override
@@ -71,10 +76,14 @@
         this.aoa_dom_compname = "";
         this.aoa_ifactor = Const.UNKNOWN_CFACTOR;
         this.aoa_tfactor = Const.UNKNOWN_CFACTOR;
+        this.aoa_dom_wind_comp = "";
+        this.aoa_dom_wind_compname = "";
+        this.aoa_wind_tfactor = Const.UNKNOWN_CFACTOR;
         this.aoa_lsfactor = Const.UNKNOWN_CFACTOR;
         this.aoa_kfactor = Const.UNKNOWN_CFACTOR;
         this.aoa_wind_ep = Const.UNKNOWN_CFACTOR;
         this.aoa_water_ep = Const.UNKNOWN_CFACTOR;
+        this.isPalouse = false;
 
         try {
             //These functions will throw a usuable user message if they cannot find these values.
@@ -88,15 +97,18 @@
 
     @Override
     protected String process() {
+        ArrayList<V1_1.ssurgoAttributes> intersectionAttributes = null;
         try {
 
             if (this.error_msg.isEmpty()) {
                 JSONArray features = this.aoaGeometry.optJSONArray("features");
                 if (this.buildPolygon(features)) {
+
+                    this.polygonData.makeESRIRotation(PGTools.PolygonLatLon.ESRIContourType.outer);
+
                     //Got a valid Polygon now.  
                     //HINT:  You can get the WKT from the PolygonLatLon object to build an SQL query via the "toWKT" funciton, 
                     //       and then encasing that WKT in the typical "geometry::STPolyFromText(<KWT goes here>,4326)", etc.  
-
                     LOG.info("THE POLYGON AS WE KNOW IT IS=" + this.polygonData.toWKT());
                     String cfactor_polygon = "geometry::STPolyFromText(" + this.polygonData.toWKT() + ",4326)";
                     LOG.info("getting centroid for polygon now");
@@ -104,12 +116,21 @@
                     LOG.info("About to get C Factor Raster value for lat=" + centroid.lat + " long=" + centroid.lon + " ");
                     this.aoa_cfactor = PGTools.getCFactorRaster(centroid.lat, centroid.lon, getWorkspaceDir()) / 100.0;
 
-                    //Call SSURGO gemoetry intersect code here ( ssurgo.soilmu_a table )
-                    //Call SSURGO component lookups here ( ssurgo.component table )            
-                    if (this.componentLookup(this.ssurgoIntersect(this.polygonData.toWKT()), this.isPalouseArea(this.polygonData.toWKT()))) {
-                        //Calc wind and water ep here...
-                        this.aoa_wind_ep = this.aoa_cfactor * this.aoa_ifactor / this.aoa_tfactor;
-                        this.aoa_water_ep = this.aoa_kfactor * this.aoa_lsfactor / this.aoa_tfactor;
+                    intersectionAttributes = this.ssurgoIntersect(this.polygonData.toWKT());
+                    this.isPalouse = this.isPalouseArea(this.polygonData.toWKT());
+
+                    if (null != intersectionAttributes) {
+                        if (this.windCriticalComponentLookup(intersectionAttributes)) {
+                            this.aoa_wind_ep = this.aoa_cfactor * this.aoa_ifactor / this.aoa_wind_tfactor;
+
+                            if (this.waterCriticalComponentLookup(intersectionAttributes)) {
+                                this.aoa_water_ep = this.aoa_kfactor * this.aoa_lsfactor / this.aoa_tfactor;
+                            } else {
+                                this.error_msg += " Could not calculate the water erodibility potenial.  Missing component information. ";
+                            }
+                        } else {
+                            this.error_msg += " Could not calculate the wind erodibility potenial.  Missing component information. ";
+                        }
                     }
                 }
             }
@@ -119,8 +140,7 @@
             this.error_msg += "SQL exception getting cfactor:  " + se.getMessage();
         } catch (ServiceException sx) {
             this.error_msg += "Service exception getting cfactor:  " + sx.getMessage();
-        }
-        catch (IOException ioe) {
+        } catch (IOException ioe) {
             this.error_msg += "IO Exception getting cFactor value from raster geotiff layer:  " + ioe.getMessage();
         }
 
@@ -131,11 +151,14 @@
     protected void postProcess() throws Exception {
         if (this.error_msg.isEmpty()) {
             putResult("aoa_id", this.AoAId);
-            putResult("aoa_dom_comp", this.aoa_dom_comp);
-            putResult("aoa_dom_compname", this.aoa_dom_compname);
+            putResult("aoa_dom_water_comp", this.aoa_dom_comp);
+            putResult("aoa_dom_water_compname", this.aoa_dom_compname);
+            putResult("aoa_dom_wind_comp", this.aoa_dom_wind_comp);
+            putResult("aoa_dom_wind_compname", this.aoa_dom_wind_compname);
             putResult("aoa_cfactor", this.aoa_cfactor);
             putResult("aoa_ifactor", this.aoa_ifactor);
             putResult("aoa_tfactor", this.aoa_tfactor);
+            putResult("aoa_wind_tfactor", this.aoa_wind_tfactor);
             putResult("aoa_lsfactor", this.aoa_lsfactor);
             putResult("aoa_kfactor", this.aoa_kfactor);
             putResult("aoa_wind_ep", this.aoa_wind_ep);
@@ -258,37 +281,21 @@
         return ret_val;
     }
 
-    // Returns the intersected mukey with the largest area.
-    private String ssurgoIntersect(String WKTPolygon) {
+    // Returns the intersected mukeys
+    private ArrayList<V1_1.ssurgoAttributes> ssurgoIntersect(String WKTPolygon) {
         HashMap<String, V1_1.ssurgoAttributes> mukeyAttributes;
         ArrayList<V1_1.ssurgoAttributes> attributeList;
-        //String polygonText = " ST_PolygonFromText(" + WKTPolygon + ") ";
 
-        String ret_val = null;
+        ArrayList<V1_1.ssurgoAttributes> ret_val = null;
 
         if (null != WKTPolygon) {
             String query;
             mukeyAttributes = new HashMap<>();
             attributeList = new ArrayList<>();
 
-// postgis sql               
-//      query = "SELECT m.areasymbol, m.musym, m.mukey,"
-//          + "st_area(st_transform(st_intersection(ST_PolygonFromText(" + WKTPolygon + ", 4326), m.the_geom::geography::geometry ),3541))/43560 as sizeIntersectionAcres "
-//          + " FROM ssurgo.soilmu_a as m "
-//          + " WHERE ST_Intersects(" + polygonText + ", m.the_geom ) "
-//          + " AND st_isvalid( m.the_geom) AND st_isvalid(" + polygonText + ");";
-// sql server spatial sql                
             query
-                    = /*        "SELECT areasymbol, musym, mukey, geography::STPolyFromText(" + WKTPolygon + ",4326).MakeValid().ReorientObject().STIntersection(soilpoly).STArea() / 4046.86 as sizeIntersectionAcres "
-            + "FROM "
-            + "(SELECT m.areasymbol, m.musym, m.mukey, geography::STPolyFromText(m.the_geom.STAsText(),4326).MakeValid().ReorientObject() as soilpoly "
-            + "FROM ssurgo.ssurgo.soilmu_a as m "
-            + "WITH (index(geom_sidx)) "
-            + "WHERE m.the_geom.STIntersects(geometry::STPolyFromText(" + WKTPolygon + ",0)) = 1 "
-            + "AND m.the_geom.STIsValid()=1 "
-            + "AND (geometry::STPolyFromText(" + WKTPolygon + ",0).STIsValid())=1) "
-            + "as a;";
-                     */ "SELECT areasymbol, musym, mukey, geography::STGeomFromText(intersectPoly.STAsText(), 4326).MakeValid().STArea() / 4046.86 as sizeIntersectionAcres"
+                    = "SELECT areasymbol, musym, mukey, geography::STGeomFromText(intersectPoly.STAsText(), 4326).MakeValid().STArea() / 4046.86 as sizeIntersectionAcres, "
+                    + " geography::STGeomFromText(" + WKTPolygon + ", 4326).MakeValid().STArea() / 4046.86 as aoaArea"
                     + " FROM"
                     + " (SELECT m.areasymbol, m.musym, m.mukey, "
                     + " m.the_geom.STIntersection(geometry:: STGeomFromText (" + WKTPolygon + ",0)).MakeValid() as intersectPoly"
@@ -323,20 +330,14 @@
                             tAttributes.AoA_Id = results.getString("areasymbol");
                             tAttributes.mukey = results.getString("mukey");
                             tAttributes.gid_area = results.getDouble("sizeIntersectionAcres");
+                            tAttributes.aoa_area = results.getDouble("aoaArea");
 
                             mukeyAttributes.put(tKey, tAttributes);
                             attributeList.add(tAttributes);
                         }
                     }
-                    //  Have a unique set of mukeys now, let's find the largest
-                    double largestArea = 0.0;
 
-                    for (V1_1.ssurgoAttributes tAttribute : attributeList) {
-                        if (largestArea < tAttribute.gid_area) {
-                            largestArea = tAttribute.gid_area;
-                            ret_val = tAttribute.mukey;
-                        }
-                    }
+                    ret_val = attributeList;
                 } else {
                     this.error_msg += "No results from the intersect query for this geometry. ";
                 }
@@ -354,103 +355,233 @@
         return ret_val;
     }
 
-    private Boolean componentLookup(String mukey, boolean isPalouseRegion) {
+    private Boolean windCriticalComponentLookup(ArrayList<V1_1.ssurgoAttributes> intersectionAttributeList) {
+        boolean ret_val = true;
+        String dom_comp = "";
+        String dom_compname = "";
+        double ifact = 0.0;
+        double tfact = 0.0;
+        double sandtotal = 0.0;
+        double area = 0.0;
+
+        for (V1_1.ssurgoAttributes attributes : intersectionAttributeList) {
+            if (attributes.gid_area >= (attributes.aoa_area * 0.10)) {
+                this.componentLookup(attributes, false);
+                if (attributes.horizons.size() > 0) {
+                    for (V1_1.componentAttributes tComponent : attributes.horizons) {
+                        if ((tComponent.sand_pct >= sandtotal) && (tComponent.sand_pct > 0)) {
+                            if (sandtotal == tComponent.sand_pct) {
+                                if (tComponent.area_pct > area) {
+                                    sandtotal = tComponent.sand_pct;
+                                    ifact = tComponent.ifact;
+                                    tfact = tComponent.tfact;
+                                    dom_comp = tComponent.cokey;
+                                    dom_compname = tComponent.compname;
+                                    area = tComponent.area_pct;
+                                }
+                            } else {
+                                sandtotal = tComponent.sand_pct;
+                                ifact = tComponent.ifact;
+                                tfact = tComponent.tfact;
+                                dom_comp = tComponent.cokey;
+                                dom_compname = tComponent.compname;
+                                area = tComponent.area_pct;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        this.aoa_dom_wind_comp = dom_comp;
+        this.aoa_dom_wind_compname = dom_compname;
+        this.aoa_ifactor = ifact;
+        this.aoa_wind_tfactor = tfact;
+
+        if (dom_comp.isEmpty()) {
+            this.error_msg += " Could not find any wind critical components in the database.  No sand found or no components were greater than 10% of the AOI. ";
+            ret_val = false;
+        }
+
+        return ret_val;
+    }
+
+    private Boolean waterCriticalComponentLookup(ArrayList<V1_1.ssurgoAttributes> intersectionAttributeList) {
+        boolean ret_val = true;
+        String dom_comp = "";
+        String dom_compname = "";
+        double ifact = 0.0;
+        double lsfactor = 0.0;
+        double tfactor = 0.0;
+        double kffact = 0.0;
+        double area = 0.0;
+
+        for (V1_1.ssurgoAttributes attributes : intersectionAttributeList) {
+            if (attributes.gid_area >= (attributes.aoa_area * 0.10)) {
+                this.componentLookup(attributes, true);
+                if (attributes.horizons.size() > 0) {
+                    for (V1_1.componentAttributes tComponent : attributes.horizons) {
+                        if ((tComponent.kffact >= kffact) && (tComponent.kffact > 0)) {
+                            if (kffact == tComponent.kffact) {
+                                if (tComponent.area_pct > area) {
+                                    kffact = tComponent.kffact;
+                                    lsfactor = tComponent.lsfact;
+                                    tfactor = tComponent.tfact;
+                                    ifact = tComponent.ifact;
+                                    dom_comp = tComponent.cokey;
+                                    dom_compname = tComponent.compname;
+                                    area = tComponent.area_pct;
+                                }
+                            } else {
+                                kffact = tComponent.kffact;
+                                lsfactor = tComponent.lsfact;
+                                tfactor = tComponent.tfact;
+                                ifact = tComponent.ifact;
+                                dom_comp = tComponent.cokey;
+                                dom_compname = tComponent.compname;
+                                area = tComponent.area_pct;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        this.aoa_dom_comp = dom_comp;
+        this.aoa_dom_compname = dom_compname;
+        this.aoa_lsfactor = lsfactor;
+        this.aoa_tfactor = tfactor;
+        this.aoa_ifactor = ifact;
+        this.aoa_kfactor = kffact;
+
+        if (dom_comp.isEmpty()) {
+            this.error_msg += " Could not find any water critical components in the database.  No kffact found or no components were greater than 10% of the AOI. ";
+            ret_val = false;
+        }
+
+        return ret_val;
+    }
+
+    private Boolean componentLookup(V1_1.ssurgoAttributes attribute, boolean useKFact) {
         String query;
         ResultSet results;
-        Boolean ret_val = false;
+        Boolean ret_val = true;
         double slope_r = 0.0;
         double theta = 0.0;
         double lambda = 0.0;
         double length_m = 0.0;
-        double[] slopeDistance = {200.0, 300.0, 200.0, 180.0, 160.0, 150.0, 140.0, 130.0, 125.0, 120.0, 110.0, 100.0, 90.0, 80.0, 70.0};
-        double[] palouseSlopeDistance = {350.0, 275.0, 225.0, 175.0, 150.0, 125.0, 100.0};
-        boolean palouseRegion = isPalouseRegion;
+        // Look up tables for slope length 
+        double[][] LightleWeesiesSlopeLength = {{0, .75, 100},
+        {.75, 1.5, 200},
+        {1.5, 2.5, 300},
+        {2.5, 3.5, 200},
+        {3.5, 4.5, 180},
+        {4.5, 5.5, 160},
+        {5.5, 6.5, 150},
+        {6.5, 7.5, 140},
+        {7.5, 8.5, 130},
+        {8.5, 9.5, 125},
+        {9.5, 10.5, 120},
+        {10.5, 11.5, 110},
+        {11.5, 12.5, 100},
+        {12.5, 13.5, 90},
+        {13.5, 14.5, 80},
+        {14.5, 15.5, 70},
+        {15.5, 17.5, 60},
+        {17.5, -1, 50}};
 
-        if ((null != mukey) && !mukey.isEmpty()) {
+        double[][] PalouseSlopeLength = {{0, 5.5, 350},
+        {5.5, 10.5, 275},
+        {10.5, 15.5, 225},
+        {15.5, 20.5, 175},
+        {20.5, 25.5, 150},
+        {25.5, 35.5, 125},
+        {35.5, -1, 100}};
+        double[][] slopeLength;
+
+        if ((null != attribute.mukey) && !attribute.mukey.isEmpty()) {
             try (
                     java.sql.Connection conn = PGTools.getConnection("cfactor", LOG);
                     java.sql.Statement statement = conn.createStatement();) {
 
-                query = "SELECT component.cokey, component.compname, component.wei as ifact, component.slope_r, component.slopelenusle_r as lsfact, component.tfact, component.comppct_r "
+                query = "SELECT component.cokey, component.compname, component.wei as ifact, component.slope_r, component.slopelenusle_r as lsfact, component.tfact, component.comppct_r, "
+                        + " chorizon.cokey, chorizon.kffact, chorizon.kwfact, chorizon.sandtotal_r "
                         + " FROM ssurgo.component "
-                        + " WHERE component.mukey='" + mukey + "' "
+                        + " INNER JOIN ssurgo.chorizon on component.cokey=chorizon.cokey "
+                        + " WHERE component.mukey='" + attribute.mukey + "' "
                         + " AND component.slope_r is not null"
-                        + " ORDER BY component.comppct_r DESC;";
+                        + " AND UPPER(component.majcompflag)='YES' "
+                        + " AND chorizon.hzdept_r=0 "
+                        + ((useKFact) ? " AND (chorizon.kffact is not null OR chorizon.kwfact is not null )" : " AND chorizon.sandtotal_r is not null ") + ";";
+
                 LOG.info(" ssurgo query=" + query);
 
                 results = statement.executeQuery(query);
                 LOG.info(" past the query execute");
 
-                if (null != results) {
-                    results.next(); //Only need the first result row, since it will contain the larges comppct_r value, due to the order by clause.
+                attribute.horizons = new ArrayList<>();
 
-                    this.aoa_dom_comp = results.getString("cokey");
-                    this.aoa_dom_compname = results.getString("compname");
-                    this.aoa_ifactor = results.getDouble("ifact");
+                while (results.next()) {
+                    V1_1.componentAttributes tHorizon = new V1_1.componentAttributes();
+
+                    tHorizon.cokey = results.getString("cokey");
+                    tHorizon.compname = results.getString("compname");
+                    tHorizon.ifact = results.getDouble("ifact");
+                    tHorizon.tfact = results.getDouble("tfact");
                     slope_r = results.getDouble("slope_r");
+                    tHorizon.slope_r = slope_r;
+                    tHorizon.area_pct = (results.getDouble("comppct_r") / 100.0) * (attribute.gid_area / attribute.aoa_area);
 
-                    if (!palouseRegion) {
-                        if (slope_r >= 18) {
-                            lambda = 50;
-                        } else if (slope_r >= 16) {
-                            lambda = 60;
-                        } else if (slope_r >= 0 && slope_r < 1.0) {  //maybe should just be <1.0
-                            lambda = 100;
+                    if (useKFact) { // Water Erodibility needed.
+                        if (this.isPalouse) {
+                            slopeLength = PalouseSlopeLength;
                         } else {
-                            lambda = slopeDistance[((int) slope_r) - 1];  // Maybe should be ((int) round(slope_r)) - 1
+                            slopeLength = LightleWeesiesSlopeLength;
                         }
-                    } else if (slope_r < 6) {
-                        lambda = palouseSlopeDistance[0];
-                    } else if (slope_r < 11) {
-                        lambda = palouseSlopeDistance[1];
-                    } else if (slope_r < 16) {
-                        lambda = palouseSlopeDistance[2];
-                    } else if (slope_r < 21) {
-                        lambda = palouseSlopeDistance[3];
-                    } else if (slope_r < 26) {
-                        lambda = palouseSlopeDistance[4];
-                    } else if (slope_r < 36) {
-                        lambda = palouseSlopeDistance[5];
-                    } else if (slope_r < 46) {
-                        lambda = palouseSlopeDistance[6];
-                    }
 
-                    length_m = ((slope_r >= 5.0) ? 0.5 : (slope_r >= 3.5) ? 0.4 : (slope_r >= 1.0) ? 0.3 : 0.2);
-                    theta = Math.atan(slope_r / 100.0);
-
-                    this.aoa_lsfactor = Math.pow((lambda / 72.6), length_m) * (65.41 * Math.pow(Math.sin(theta), 2.0) + 4.56 * Math.sin(theta) + 0.065);  //results.getDouble("lsfact");
-
-                    this.aoa_tfactor = results.getDouble("tfact");
-
-                    results.close();
-
-                    query = "SELECT chorizon.cokey, chorizon.kffact, chorizon.kwfact "
-                            + "FROM ssurgo.chorizon "
-                            + "WHERE ssurgo.chorizon.cokey='" + this.aoa_dom_comp + "'";
-                    LOG.info(" ssurgo query=" + query);
-
-                    results = statement.executeQuery(query);
-                    LOG.info(" past the query execute");
-
-                    if (null != results) {
-                        results.next();
-
-                        this.aoa_kfactor = results.getDouble("kffact");
-                        if (results.wasNull()) {
-                            this.aoa_kfactor = results.getDouble("kwfact");
-                            if (results.wasNull()) {
-                                this.aoa_kfactor = 0.02;
+                        for (int i = 0; i < slopeLength.length; i++) {
+                            if (slopeLength[i][1] != -1) {
+                                if ((slope_r >= slopeLength[i][0]) && (slope_r < slopeLength[i][1])) {
+                                    lambda = slopeLength[i][2];
+                                    break;
+                                } else if (slope_r >= slopeLength[i][0]) {
+                                    lambda = slopeLength[i][2];
+                                    break;
+                                }
                             }
                         }
 
+                        length_m = ((slope_r >= 5.0) ? 0.5 : (slope_r >= 3.5) ? 0.4 : (slope_r >= 1.0) ? 0.3 : 0.2);
+                        theta = Math.atan(slope_r / 100.0);
+
+                        tHorizon.lsfact = Math.pow((lambda / 72.6), length_m) * (65.41 * Math.pow(Math.sin(theta), 2.0) + 4.56 * Math.sin(theta) + 0.065);  //results.getDouble("lsfact");
+                        tHorizon.kffact = results.getDouble("kffact");
+                        if (results.wasNull()) {
+                            tHorizon.kffact = results.getDouble("kwfact");
+                            if (results.wasNull()) {
+                                this.error_msg = "Invalid kffact selected, empty columns in both kffact and kwfact";
+                                ret_val = false;
+                            } else {
+                                attribute.horizons.add(tHorizon);
+                                ret_val = true;
+                            }
+                        } else {
+                            attribute.horizons.add(tHorizon);
+                            ret_val = true;
+                        }
+                    } else {
+                        tHorizon.lsfact = 0.0;
+                        tHorizon.sand_pct = results.getDouble("sandtotal_r");
+                        attribute.horizons.add(tHorizon);
                         ret_val = true;
-                    } else {
-                        this.error_msg += "Could not find a matching cokey for this intersected mapunit in the cHorizon table.";
                     }
+                }
 
-                } else {
-                    this.error_msg += "Could not find a matching cokey for this intersected mapunit.";
+                if (attribute.horizons.size() <= 0) {
+                    ret_val = false;
+                    this.error_msg += "No soil components and/or horizon data found for this mukey: " + attribute.mukey + " .";
                 }
+
             } catch (SQLException | csip.ServiceException ex) {
                 this.error_msg += "Could not continue processing the component lookups for this mapunit intersect:  " + ex.getMessage();
             }
@@ -469,6 +600,44 @@
         public String AoA_Id;
         public String mukey;
         public double gid_area;
+        public double aoa_area;
+        public ArrayList<V1_1.componentAttributes> horizons;
+
+        public ssurgoAttributes() {
+            this.gid = "";
+            this.AoA_Id = "";
+            this.mukey = "";
+            this.gid_area = 0.0;
+            this.aoa_area = 1.0;
+            this.horizons = null;
+        }
+    }
+
+    public static class componentAttributes {
+
+        public String cokey;
+        public String compname;
+        public double ifact;
+        public double slope_r;
+        public double tfact;
+        public double kffact;
+        public double kwfact;
+        public double area_pct;
+        public double lsfact;
+        public double sand_pct;
+
+        public componentAttributes() {
+            this.cokey = "";
+            this.compname = "";
+            this.ifact = 0.0;
+            this.slope_r = 0.0;
+            this.tfact = 0.0;
+            this.kffact = 0.0;
+            this.kwfact = 0.0;
+            this.area_pct = 0.0;
+            this.lsfact = 0.0;
+            this.sand_pct = 0.0;
+        }
     }
 
 }