changeset 9598:17414e70746e

Softwaretests...20181219 10.1/10.2/10.5/10.9: corrected computation of missing volume and excavation volume, date range for density queries as in Sinfo/Tkh, empty values instead of 0 if computation not possible
author mschaefer
date Tue, 05 Feb 2019 15:51:35 +0100
parents 5395c6d4ca50
children 4c73fe16533d 6c8d1d2d44b3
files artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java
diffstat 1 files changed, 132 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java	Tue Feb 05 15:47:58 2019 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java	Tue Feb 05 15:51:35 2019 +0100
@@ -11,7 +11,6 @@
 package org.dive4elements.river.artifacts.bundu.bezugswst;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
 
 import org.dive4elements.artifacts.CallContext;
@@ -24,6 +23,7 @@
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.Calculation.Problem;
 import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.DateRange;
 import org.dive4elements.river.artifacts.model.WQKms;
 import org.dive4elements.river.artifacts.model.fixings.FixRealizingCalculation;
 import org.dive4elements.river.artifacts.model.fixings.FixRealizingResult;
@@ -32,6 +32,7 @@
 import org.dive4elements.river.artifacts.services.DynamicMainValuesTimeRangeDeterminationService;
 import org.dive4elements.river.artifacts.services.DynamicMainValuesTimeRangeDeterminationService.GaugeInfoResult;
 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
+import org.dive4elements.river.artifacts.sinfo.tkhstate.BedQualityD50TimeRangeConfig;
 import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper;
 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
@@ -56,6 +57,8 @@
      */
     private final static double EXPENSE_PER_CBM = 12.0; // REMARK Sollte von außen einstellbar sein
 
+    private final static double KM_TO_M = 1000.0;
+
     private final CallContext context;
 
     private final List<ResultRow> rows;
@@ -116,7 +119,7 @@
 
         // Fetch the bed levels of the selected sounding
         final Integer bedHeightId = access.getBedHeightID();
-        final BedHeightsFinder bedHeightsFinder = (bedHeightId != null) ? BedHeightsFinder.forId(problems, bedHeightId, access.getRange())
+        final BedHeightsFinder bedHeightsFinder = (bedHeightId != null) ? BedHeightsFinder.forId(problems, bedHeightId, access.getRange(), false)
                 : BedHeightsFinder.NullFinder();
 
         // Fetch the river channel data
@@ -135,7 +138,8 @@
                 return new CalculationResult(results, problems);
             computeMissingVolumes(problems);
             final BedQualityCalculator bqCalculator = computeDensities(problems, bunduartifact, access, river);
-            computeMissingMasses(problems, bqCalculator);
+            if (bqCalculator != null)
+                computeMissingMasses(problems, bqCalculator);
         }
 
         // Add the result to the results collection
@@ -225,7 +229,9 @@
         final double channelWidth = channelFinder.getWidth(station);
         row.putValue(BunduResultType.channelWidth, channelWidth);
         if (!Double.isNaN(channelHeight)) {
-            if (msh > channelHeight + 0.001)
+            if (Double.isNaN(msh))
+                row.putValue(BunduResultType.missDepthMeanBed, Double.NaN);
+            else if (msh > channelHeight + 0.001)
                 row.putValue(BunduResultType.missDepthMeanBed, msh - channelHeight);
             else
                 row.putValue(BunduResultType.missDepthMeanBed, 0.0);
@@ -242,7 +248,11 @@
             final double h = bedHeightsFinder.getFieldHeight(station, i);
             fieldHeights.add(Double.valueOf(h));
             fieldDepths.add(Double.valueOf(w - h));
-            if (h > channelHeight + 0.001) {
+            if (Double.isNaN(h)) {
+                fieldMissDepths.add(Double.NaN);
+                fieldMissWidths.add(Double.NaN);
+            }
+            else if (h > channelHeight + 0.001) {
                 missFieldCnt++;
                 fieldMissDepths.add(Double.valueOf(h - channelHeight));
                 fieldMissWidths.add(Double.valueOf(channelWidth / BedHeightValueType.FIELD_LAST_INDEX));
@@ -252,7 +262,7 @@
             }
             fieldNulls.add(Double.NaN);
         }
-        if (isKmInMissingVolumeRange(station)) {
+        if (!Double.isNaN(msh) && isKmInMissingVolumeRange(station)) {
             row.putValue(BunduResultType.missDepthFields, fieldMissDepths);
             row.putValue(BunduResultType.missWidthFields, fieldMissWidths);
             row.putValue(BunduResultType.hasMissingDepth, (missFieldCnt >= 1));
@@ -303,19 +313,24 @@
                 break;
             if (km > this.missKmTo.doubleValue() - 0.0001)
                 last = i;
+            if (this.rows.get(i).getValue(BunduResultType.hasMissingDepth) == null)
+                continue;
+            final double chDepth = this.rows.get(i).getDoubleValue(BunduResultType.channelDepth) + EXCAVATION_DEPTH;
             final List<Double> areas = new ArrayList<>();
             final List<Double> volumes = new ArrayList<>();
             double vTotal = 0.0;
             double vExcav = 0.0;
             for (int j = BedHeightValueType.FIELD_FIRST_INDEX; j <= BedHeightValueType.FIELD_LAST_INDEX; j++) {
                 if (getFieldValue(i, BunduResultType.missDepthFields, j) > 0.0001) {
-                    computeMissingVolume(volumes, areas, i, first, last, j);
+                    computeMissingVolume(volumes, areas, i, first, last, j, ActualMissingHeightComputer.Instance);
                     vTotal += volumes.get(j - 1);
-                    vExcav += volumes.get(j - 1) + areas.get(j - 1) * EXCAVATION_DEPTH;
                 } else {
                     volumes.add(Double.valueOf(0.0));
                     areas.add(Double.valueOf(0.0));
                 }
+                if (chDepth - getFieldValue(i, BunduResultType.depthFields, j) > 0.0001) {
+                    vExcav += computeMissingVolume(null, null, i, first, last, j, ExcavationMissingAreaComputer.Instance);
+                }
             }
             final double[] meanBedVolumeArea = computeMeanBedMissingAreaAndVolume(i, first, last);
             this.rows.get(i).putValue(BunduResultType.missVolumeMeanBed, meanBedVolumeArea[0]);
@@ -331,33 +346,80 @@
     /**
      * Computes the missing volume of a field of a km row
      */
-    private void computeMissingVolume(final List<Double> volumes, final List<Double> areas, final int current, final int first, final int last,
-            final int field) {
+    private double computeMissingVolume(final List<Double> volumes, final List<Double> areas, final int current, final int first, final int last,
+            final int field, final MissingHeightComputer heightcomputer) {
 
-        final double areaCurr = missingArea(current, first, last, field);
-        final double areaPrev = missingArea(current - 1, first, last, field);
-        final double areaNext = missingArea(current + 1, first, last, field);
+        final double dhCurr = heightcomputer.missingHeight(this.rows.get(current), current, first, last, field);
+        final double dhPrev = heightcomputer.missingHeight(this.rows.get(current - 1), current - 1, first, last, field);
+        final double dhNext = heightcomputer.missingHeight(this.rows.get(current + 1), current + 1, first, last, field);
         final double kmCurr = missingKm(current);
         final double kmPrev = missingKm(current - 1);
         final double kmNext = missingKm(current + 1);
-        final double area1 = Double.isNaN(kmPrev) ? 0.0 : 0.5 * (areaCurr + areaPrev);
-        final double area2 = Double.isNaN(kmNext) ? 0.0 : 0.5 * (areaCurr + areaNext);
-        final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * 500 * area1) + (Math.abs(kmNext - kmCurr) * 500 * area2));
-        volumes.add(volume);
-        if (!Double.isNaN(volume))
-            areas.add(Double.valueOf(area1 + area2));
-        else
-            areas.add(Double.NaN);
+        final double width = getFieldValue(current, BunduResultType.missWidthFields, field);
+        final double area1 = Double.isNaN(kmPrev) ? 0.0 : (0.25 * dhPrev + 0.75 * dhCurr) * width;
+        final double area2 = Double.isNaN(kmNext) ? 0.0 : (0.75 * dhCurr + 0.25 * dhNext) * width;
+        final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * KM_TO_M / 2 * area1) + (Math.abs(kmNext - kmCurr) * KM_TO_M / 2 * area2));
+        if (volumes != null)
+            volumes.add(volume);
+        if (areas != null) {
+            if (!Double.isNaN(volume))
+                areas.add(Double.valueOf(area1 + area2));
+            else
+                areas.add(Double.NaN);
+        }
+        return volume;
     }
 
     /**
-     * Gets the missing area of a field and a row if in range, otherwise 0.0
+     * Interface for the function that computes the missing height of a field
      */
-    private double missingArea(final int rowIndex, final int first, final int last, final int fieldIndex) {
-        if ((first <= rowIndex) && (rowIndex <= last))
-            return getFieldValue(rowIndex, BunduResultType.missDepthFields, fieldIndex) * getFieldValue(rowIndex, BunduResultType.missWidthFields, fieldIndex);
-        else
-            return 0.0;
+    private interface MissingHeightComputer {
+        /**
+         * Gets the missing area of a field and a row if in range, otherwise 0.0
+         */
+        double missingHeight(final ResultRow row, final int rowIndex, final int first, final int last, final int fieldIndex);
+    }
+
+    /**
+     * Computation of the actual missing height of a field
+     */
+    private static class ActualMissingHeightComputer implements MissingHeightComputer {
+        public static MissingHeightComputer Instance = new ActualMissingHeightComputer();
+
+        /**
+         * Gets the missing height of a field and a row if in range, otherwise 0.0
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public double missingHeight(final ResultRow row, final int rowIndex, final int first, final int last, final int fieldIndex) {
+            if ((first <= rowIndex) && (rowIndex <= last)) {
+                return ((List<Double>) row.getValue(BunduResultType.missDepthFields)).get(fieldIndex - 1).doubleValue();
+            }
+            else
+                return 0.0;
+        }
+    }
+
+    /**
+     * Computation of the excavation height of a field
+     */
+    private static class ExcavationMissingAreaComputer implements MissingHeightComputer {
+        public static MissingHeightComputer Instance = new ExcavationMissingAreaComputer();
+
+        /**
+         * Gets the excavation height of a field and a row if in range, otherwise 0.0
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public double missingHeight(final ResultRow row, final int rowIndex, final int first, final int last, final int fieldIndex) {
+            if ((first <= rowIndex) && (rowIndex <= last)) {
+                final double channeldepth = row.getDoubleValue(BunduResultType.channelDepth) + EXCAVATION_DEPTH;
+                final double fielddepth = ((List<Double>) row.getValue(BunduResultType.depthFields)).get(fieldIndex - 1).doubleValue();
+                return (channeldepth - fielddepth);
+            }
+            else
+                return 0.0;
+        }
     }
 
     /**
@@ -365,30 +427,31 @@
      */
     private double[] computeMeanBedMissingAreaAndVolume(final int current, final int first, final int last) {
 
-        final double areaCurr = meanBedMissingArea(current, first, last);
-        if (areaCurr < 0.0001)
+        final double dhCurr = meanBedMissingHeight(current, first, last);
+        if (dhCurr < 0.0001)
             return new double[] { 0.0, 0.0 };
-        final double areaPrev = meanBedMissingArea(current - 1, first, last);
-        final double areaNext = meanBedMissingArea(current + 1, first, last);
+        final double dhPrev = meanBedMissingHeight(current - 1, first, last);
+        final double dhNext = meanBedMissingHeight(current + 1, first, last);
         final double kmCurr = missingKm(current);
         final double kmPrev = missingKm(current - 1);
         final double kmNext = missingKm(current + 1);
-        final double area1 = Double.isNaN(kmPrev) ? 0.0 : 0.5 * (areaCurr + areaPrev);
-        final double area2 = Double.isNaN(kmNext) ? 0.0 : 0.5 * (areaCurr + areaNext);
-        final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * 500 * area1) + (Math.abs(kmNext - kmCurr) * 500 * area2));
+        final double width = this.rows.get(current).getDoubleValue(BunduResultType.channelWidth);
+        final double area1 = Double.isNaN(kmPrev) ? 0.0 : (0.25 * dhPrev + 0.75 * dhCurr) * width;
+        final double area2 = Double.isNaN(kmNext) ? 0.0 : (0.75 * dhCurr + 0.25 * dhNext) * width;
+        final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * KM_TO_M / 2 * area1) + (Math.abs(kmNext - kmCurr) * KM_TO_M / 2 * area2));
         final double area = Double.isNaN(volume) ? Double.NaN : Double.valueOf(area1 + area2);
         return new double[] { volume, area };
     }
 
     /**
-     * Gets the missing area of the mean bed level and a row if in range, otherwise 0.0
+     * Gets the missing height of the mean bed level and a row if in range, otherwise 0.0
      */
-    private double meanBedMissingArea(final int rowIndex, final int first, final int last) {
+    private double meanBedMissingHeight(final int rowIndex, final int first, final int last) {
         if ((first <= rowIndex) && (rowIndex <= last)) {
             final double dh = this.rows.get(rowIndex).getDoubleValue(BunduResultType.channelDepth)
                     - this.rows.get(rowIndex).getDoubleValue(BunduResultType.flowdepthMeanBed);
             if (dh > 0.0)
-                return dh * this.rows.get(rowIndex).getDoubleValue(BunduResultType.channelWidth);
+                return dh;
             return 0.0;
         }
         return 0.0;
@@ -398,7 +461,7 @@
      * Gets the km of a row if within range, otherwise NaN
      */
     private double missingKm(final int rowIndex) {
-        if ((0 <= rowIndex) && (rowIndex <= this.rows.size() - 1))
+        if ((0 <= rowIndex) && (rowIndex <= this.rows.size() - 1) && (this.rows.get(rowIndex).getValue(BunduResultType.hasMissingDepth) != null))
             return this.rows.get(rowIndex).getDoubleValue(GeneralResultType.station);
         return Double.NaN;
     }
@@ -412,12 +475,10 @@
         // REMARK 10km tolerance at start and end to enable interpolation there
         final double[] kms = DoubleUtil.explode(access.getMissingVolFrom().doubleValue() - 10.0, access.getMissingVolTo().doubleValue() + 10.0,
                 access.getStep().doubleValue() / 1000);
-        final Calendar endDay = Calendar.getInstance();
-        endDay.set(access.getBezugsJahr().intValue(), 11, 31);
-        final Calendar startDay = Calendar.getInstance();
-        // TODO Spezialregelung für den Rhein (bis 1999, 2000 bis 2009, ab 2010)
-        startDay.set(endDay.get(Calendar.YEAR) - 20, 0, 1);
-        bqCalculator.execute(problems, river, kms, startDay.getTime(), endDay.getTime());
+        final DateRange dateRange = BedQualityD50TimeRangeConfig.getDefaults(river, access.getBezugsJahr().intValue(), problems);
+        if (dateRange == null)
+            return null;
+        bqCalculator.execute(problems, river, kms, dateRange.getFrom(), dateRange.getTo());
         return bqCalculator;
     }
 
@@ -433,12 +494,17 @@
             final double density = getDensity(row.getDoubleValue(GeneralResultType.station), densityFinder);
             final List<Double> masses = new ArrayList<>();
             double kmTotal = 0.0;
+            int mcnt = 0;
             for (int j = BedHeightValueType.FIELD_FIRST_INDEX; j <= BedHeightValueType.FIELD_LAST_INDEX; j++) {
                 final double m = volumes.get(j - 1) * density;
                 masses.add(m);
-                if (!Double.isNaN(m))
+                if (!Double.isNaN(m)) {
                     kmTotal += m;
+                    mcnt += 1;
+                }
             }
+            if (mcnt == 0)
+                kmTotal = Double.NaN;
             row.putValue(BunduResultType.density, density);
             row.putValue(BunduResultType.missMassFields, masses);
             row.putValue(BunduResultType.missMassTotal, kmTotal);
@@ -469,18 +535,36 @@
         double mTotal = 0.0;
         double eTotal = 0.0;
         double cTotal = 0.0;
+        int vcnt = 0;
+        int mcnt = 0;
+        int ecnt = 0;
         for (final ResultRow row : this.rows) {
             final double volume = row.getDoubleValue(BunduResultType.missVolumeTotal);
             final double mass = row.getDoubleValue(BunduResultType.missMassTotal);
+            if (!Double.isNaN(volume)) {
+                vTotal += volume;
+                vcnt++;
+                if (!Double.isNaN(mass)) {
+                    mTotal += mass;
+                    mcnt++;
+                }
+            }
             final double excavation = row.getDoubleValue(BunduResultType.excavationVolume);
             final double costs = row.getDoubleValue(BunduResultType.excavationCosts);
-            if (!Double.isNaN(volume) && !Double.isNaN(mass)) {
-                vTotal += volume;
-                mTotal += mass;
+            if (!Double.isNaN(excavation)) {
                 eTotal += excavation;
                 cTotal += costs;
+                ecnt++;
             }
         }
+        if (vcnt == 0)
+            vTotal = Double.NaN;
+        if (mcnt == 0)
+            mTotal = Double.NaN;
+        if (ecnt == 0) {
+            eTotal = Double.NaN;
+            cTotal = Double.NaN;
+        }
         final ResultRow sumRow = ResultRow.create();
         sumRow.putValue(BunduResultType.missStationRangeFrom, Double.valueOf(this.missKmFrom));
         sumRow.putValue(BunduResultType.missStationRangeTo, Double.valueOf(this.missKmTo));

http://dive4elements.wald.intevation.org