changeset 8901:0a900d605d52

S-INFO Flowdepth work on TKH calculation
author mschaefer
date Thu, 22 Feb 2018 17:04:06 +0100
parents d32c22fc686c
children 93e6afa30045
files artifacts/pom.xml artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties artifacts/src/main/resources/messages_de_DE.properties artifacts/src/main/resources/messages_en.properties
diffstat 7 files changed, 74 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/pom.xml	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/pom.xml	Thu Feb 22 17:04:06 2018 +0100
@@ -42,7 +42,7 @@
           </descriptors>
         </configuration>
       </plugin>
-      <plugin>
+      <!--plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
         <version>3.0.0</version>
@@ -63,7 +63,7 @@
             </goals>
           </execution>
         </executions>
-      </plugin>
+      </plugin-->
     </plugins>
   </build>
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java	Thu Feb 22 17:04:06 2018 +0100
@@ -18,15 +18,22 @@
 import org.apache.commons.math.analysis.interpolation.LinearInterpolator;
 import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
 import org.apache.log4j.Logger;
+import org.dive4elements.river.artifacts.math.Utils;
 import org.dive4elements.river.artifacts.model.DateRange;
 import org.dive4elements.river.backend.SedDBSessionHolder;
 import org.dive4elements.river.model.River;
+import org.dive4elements.river.utils.DoubleUtil;
 import org.hibernate.SQLQuery;
 import org.hibernate.Session;
 import org.hibernate.type.StandardBasicTypes;
 
+import gnu.trove.TDoubleArrayList;
+
 /**
- * Searchable sorted km array with parallel bed measurements value array and linear interpolation for km and d50 between the array elements.
+ * Searchable sorted km array with parallel bed measurements value array and linear interpolation for km and d50 between the array elements.<br />
+ * <br />
+ * See comment of SQL command on how the values are filtered and aggregated.
+ * 
  * @author Matthias Schäfer
  *
  */
@@ -154,18 +161,35 @@
     private static final String[] SQL_BED_D50_SELECT_ALIAS = {"km", "mindate", "maxdate", "cnt", "mindepth", "maxdepth", "d50"};
 
     /**
-     * Real linear interpolator for kms and d50 values
+     * Kms of the loaded river range
      */
-    private PolynomialSplineFunction interpolator;
+    private TDoubleArrayList kms;
+    
+    /**
+     * D50 for each km in kms 
+     */
+    private TDoubleArrayList values;
+
     
     /***** METHODS *****/
     
     /**
      * Returns the d50 value interpolated according to a km
-     * @throws ArgumentOutsideDomainException
+     * @return d50 (mm) of the km, or NaN
      */
     public double findD50(double km) throws ArgumentOutsideDomainException {
-        return interpolator.value(km);
+        if ((kms == null) || (kms.size() == 0))
+            return Double.NaN;
+        int i = kms.binarySearch(km);
+        if (i >= 0)
+            return values.get(i);
+        i = -i - 1;
+        if ((i - 1 >= 0) && Utils.epsilonEquals(km, kms.get(i - 1), 0.0001))
+            return values.get(i - 1);
+        else if ((i >= 0) && (i <= kms.size() - 1) && Utils.epsilonEquals(km, kms.get(i), 0.0001))
+            return values.get(i);
+        else
+            return Double.NaN;
     }
     
     /**
@@ -191,18 +215,15 @@
         sqlQuery.setDate("todate", dateRange.getTo());
         @SuppressWarnings("unchecked")
         final List<Object[]> rows = sqlQuery.list();
-        final double[] kms = new double[rows.size()];
-        final double[] values = new double[rows.size()];
+        kms = new TDoubleArrayList();
+        values = new TDoubleArrayList();
         D50Measurement measurement;
-        int i = -1;
         for (Object[] row : rows) {
             measurement = new D50Measurement(row, SQL_BED_D50_SELECT_ALIAS);
-            i++;
-            kms[i] = measurement.getKm();
-            values[i] = measurement.getD50();
-            log.debug(String.format("loadValues km %.3f d50(mm) %.1f count %d", kms[i], values[i], measurement.getCnt()));
+            kms.add(measurement.getKm());
+            values.add(measurement.getD50());
+            log.debug(String.format("loadValues km %.3f d50(mm) %.1f count %d", kms.get(kms.size()-1), values.get(values.size()-1), measurement.getCnt()));
         }
-        interpolator = new LinearInterpolator().interpolate(kms, values);
         return true;
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java	Thu Feb 22 17:04:06 2018 +0100
@@ -27,7 +27,7 @@
 import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.model.DateRange;
 import org.dive4elements.river.artifacts.model.LocationProvider;
-import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.artifacts.model.QKms;
 import org.dive4elements.river.artifacts.model.WKms;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
@@ -111,7 +111,6 @@
         final String wstId = diffPair.getWstId();
 
         final BedHeight bedHeight = loadBedHeight(soundingId);
-        final BedHeight bedHeight = loadBedHeight(soundingId);
         if (bedHeight == null) {
             final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId);
             problems.addProblem(message);
@@ -133,7 +132,7 @@
 
         checkYearDifference(label, waterlevel, bedHeight, problems);
         checkWaterlevelDiscretisation(wstKms, calcRange, problems);
-        // TODO: prüfen, ob sohlhöen die calcRange abdecken/überschneiden
+        // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden
 
         /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */
         final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE);
@@ -147,19 +146,16 @@
 
         final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding);
 
-        // FIXME: nur prüfen/beschaffen wenn TKH Berechnung aktiv
-        /* Abflusswerte vorhanden? */
-        if (!(wstKms instanceof WQKms)) {
+        boolean doCalcTkh = useTkh;
+        if (doCalcTkh && !(wstKms instanceof QKms)) {
             final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
             problems.addProblem(message);
-            // TODO: keine Berechnung TKH
+            doCalcTkh = false;
         }
 
         BedQualityD50KmValueFinder bedMeasurementsFinder = null;
-        if (useTkh)
-            bedMeasurementsFinder = loadBedMeasurements(river, calcRange, sounding.getYear());
-        // FIXME: prüfung ob (genug) werte vorhanden sind? was sind genau die kriterien? falls nein, problem hinzufügen und keine
-        // berechnung tkh
+        if (doCalcTkh)
+            bedMeasurementsFinder = loadBedMeasurements(river, calcRange, sounding.getYear().intValue());
 
         final String bedHeightLabel = bedHeight.getDescription();
         final String wstLabel = wstKms.getName();
@@ -167,9 +163,9 @@
         final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs());
         UnivariateRealFunction qInterpolator = null;
         DoubleRange qRange = null;
-        if (useTkh && (wstKms instanceof WQKms)) {
-            qInterpolator = DoubleUtil.getLinearInterpolator(((WQKms) wstKms).allKms(), ((WQKms) wstKms).allQs());
-            qRange = new DoubleRange( ((WQKms) wstKms).allQs().min(), ((WQKms) wstKms).allQs().max());
+        if (doCalcTkh) {
+            qInterpolator = DoubleUtil.getLinearInterpolator(((QKms) wstKms).allKms(), ((QKms) wstKms).allQs());
+            qRange = new DoubleRange( ((QKms) wstKms).allQs().min(), ((QKms) wstKms).allQs().max());
         }
         
         // FIXME: sort by station first, but in what direction?
@@ -182,13 +178,13 @@
         // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden?
         /* SoilKind lastKind = SoilKind.mobil; */
         SoilKindKmValueFinder soilKindFinder = null;
-        if (useTkh) {
+        if (doCalcTkh) {
             soilKindFinder = new SoilKindKmValueFinder();
             soilKindFinder.loadValues(river, calcRange);
         }
         
         FlowVelocityModelKmValueFinder flowVelocitiesFinder = null;
-        if (useTkh) {
+        if (doCalcTkh) {
             flowVelocitiesFinder = new FlowVelocityModelKmValueFinder();
             flowVelocitiesFinder.loadValues(river, calcRange, qRange);
         }
@@ -208,8 +204,6 @@
 
             if (!calcRange.containsDouble(km))
                 continue;
-            if (!calcRange.containsDouble(km))
-                continue;
 
             try {
                 // FIXME: check out of range
@@ -227,33 +221,38 @@
 
                 // FIXME: calculate tkh
                 double tkh = 0;
-                if (useTkh) {
-                    double d50 = 0;
-                    try {
-                        d50 = bedMeasurementsFinder.findD50(km);
-                    } catch (Exception e) {
+                if (doCalcTkh) {
+                    double d50 = bedMeasurementsFinder.findD50(km);
+                    if (Double.isNaN(d50)) {
                         final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingD50", null, label);
                         problems.addProblem(km, message);
-                        //FIXME: cumulate problems
+                        //FIXME: cumulate problems to one message?
                     }
-                    if (flowVelocitiesFinder.findKmQValues(km, discharge)) {
-                        tkh = calculateTkh(wst - meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), d50, flowVelocitiesFinder.getFindTauFound());
-                        log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f",
-                            km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(), d50*1000, tkh));
+                    if (!Double.isNaN(d50)) {
+                        if (flowVelocitiesFinder.findKmQValues(km, discharge)) {
+                            tkh = calculateTkh(wst - meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), d50, flowVelocitiesFinder.getFindTauFound());
+                            /* log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f",
+                                km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(), d50*1000, tkh)); */
+                        }
+                        else {
+                            final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
+                            problems.addProblem(km, message);
+                            //FIXME: cumulate problems to one message?
+                        }
                     }
                     else
                         tkh = Double.NaN;
                 }
                 
                 // Soil kind
-                SoilKind kind = SoilKind.starr;
-                if (useTkh) {
+                SoilKind kind = SoilKind.mobil;
+                if (doCalcTkh) {
                     try {
                         kind = soilKindFinder.findSoilKind(km);                        
                     } catch (Exception e) {
                         final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
                         problems.addProblem(km, message);
-                        //FIXME: cumulate problems
+                        //FIXME: cumulate problems to one message?
                     }
                 }
                 
--- a/artifacts/src/main/resources/messages.properties	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/src/main/resources/messages.properties	Thu Feb 22 17:04:06 2018 +0100
@@ -773,8 +773,8 @@
 sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 sinfo_calc_flow_depth.warning.waterlevel_discretisation  = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
 sinfo_calc_flow_depth.warning.year_difference = {0}: Sie verwenden als Differenzenpaar eine Wasserspiegellage aus dem Jahr {1} und eine Peilung aus dem Jahr {2}. Dies kann zu unplausiblen Werten f\u00fchren.
-sinfo_calc_flow_depth.warning.missingSoilKind = {0}: no soil kind available
-sinfo_calc_flow_depth.warning.missingD50 = {0}: no d50 available
+sinfo_calc_flow_depth.warning.missingSoilKind = {0}: keine Sohlart vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
+sinfo_calc_flow_depth.warning.missingD50 = {0}: kein D50 vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 
 sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
 sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
--- a/artifacts/src/main/resources/messages_de.properties	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/src/main/resources/messages_de.properties	Thu Feb 22 17:04:06 2018 +0100
@@ -779,8 +779,8 @@
 sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 sinfo_calc_flow_depth.warning.waterlevel_discretisation  = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
 sinfo_calc_flow_depth.warning.year_difference = {0}: Sie verwenden als Differenzenpaar eine Wasserspiegellage aus dem Jahr {1} und eine Peilung aus dem Jahr {2}. Dies kann zu unplausiblen Werten f\u00fchren.
-sinfo_calc_flow_depth.warning.missingSoilKind = {0}: keine Sohlart vorhanden
-sinfo_calc_flow_depth.warning.missingD50 = {0}: kein D50 vorhanden
+sinfo_calc_flow_depth.warning.missingSoilKind = {0}: keine Sohlart vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
+sinfo_calc_flow_depth.warning.missingD50 = {0}: kein D50 vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 
 sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
 sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
--- a/artifacts/src/main/resources/messages_de_DE.properties	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/src/main/resources/messages_de_DE.properties	Thu Feb 22 17:04:06 2018 +0100
@@ -775,6 +775,8 @@
 sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 sinfo_calc_flow_depth.warning.waterlevel_discretisation  = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
 sinfo_calc_flow_depth.warning.year_difference = {0}: Sie verwenden als Differenzenpaar eine Wasserspiegellage aus dem Jahr {1} und eine Peilung aus dem Jahr {2}. Dies kann zu unplausiblen Werten f\u00fchren. 
+sinfo_calc_flow_depth.warning.missingSoilKind = {0}: keine Sohlart vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
+sinfo_calc_flow_depth.warning.missingD50 = {0}: kein D50 vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 
 Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
 
--- a/artifacts/src/main/resources/messages_en.properties	Thu Feb 22 14:11:19 2018 +0100
+++ b/artifacts/src/main/resources/messages_en.properties	Thu Feb 22 17:04:06 2018 +0100
@@ -774,6 +774,8 @@
 sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 sinfo_calc_flow_depth.warning.waterlevel_discretisation  = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
 sinfo_calc_flow_depth.warning.year_difference = {0}: Sie verwenden als Differenzenpaar eine Wasserspiegellage aus dem Jahr {1} und eine Peilung aus dem Jahr {2}. Dies kann zu unplausiblen Werten f\u00fchren.
+sinfo_calc_flow_depth.warning.missingSoilKind = {0}: keine Sohlart vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
+sinfo_calc_flow_depth.warning.missingD50 = {0}: kein D50 vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 
 sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
 sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe

http://dive4elements.wald.intevation.org