changeset 9451:fd6621f47a72

Bundu bzws density calculation completed
author mschaefer
date Thu, 23 Aug 2018 10:57:40 +0200
parents 7e1fb8d0cb0d
children 9e471031cc1e
files artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/BunduResultType.java artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BedQualityCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java artifacts/src/main/java/org/dive4elements/river/utils/Formatter.java
diffstat 4 files changed, 85 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/BunduResultType.java	Wed Aug 22 19:12:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/BunduResultType.java	Thu Aug 23 10:57:40 2018 +0200
@@ -404,7 +404,7 @@
         }
     };
 
-    public static final BunduResultType missStationRangeFrom = new BunduResultType(I18NStrings.UNIT_KM, "bundu.export.bezugswst.csv.meta.miss.mass.km_from") {
+    public static final BunduResultType missStationRangeFrom = new BunduResultType(I18NStrings.UNIT_KM, "bundu.export.bezugswst.csv.meta.miss.km_from") {
 
         private static final long serialVersionUID = 1L;
 
@@ -420,7 +420,7 @@
         }
     };
 
-    public static final BunduResultType missStationRangeTo = new BunduResultType(I18NStrings.UNIT_KM, "bundu.export.bezugswst.csv.meta.miss.mass.km_to") {
+    public static final BunduResultType missStationRangeTo = new BunduResultType(I18NStrings.UNIT_KM, "bundu.export.bezugswst.csv.meta.miss.km_to") {
 
         private static final long serialVersionUID = 1L;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BedQualityCalculator.java	Wed Aug 22 19:12:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BedQualityCalculator.java	Thu Aug 23 10:57:40 2018 +0200
@@ -11,10 +11,14 @@
 package org.dive4elements.river.artifacts.bundu.bezugswst;
 
 import java.util.Date;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.TreeMap;
 
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.access.BedQualityAccess;
 import org.dive4elements.river.artifacts.bundu.BUNDUArtifact;
+import org.dive4elements.river.artifacts.math.Linear;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.Calculation.Problem;
 import org.dive4elements.river.artifacts.model.CalculationResult;
@@ -35,16 +39,19 @@
 
     private final BUNDUArtifact bundu;
 
+    private final NavigableMap<Double, Double> densities;
 
     public BedQualityCalculator(final CallContext context, final BUNDUArtifact bundu) {
         this.context = context;
         this.bundu = bundu;
+        this.densities = new TreeMap<>();
     }
 
+
     /**
      * Calculates the river bed sublayer densities for an array of kms and a time period of measurements
      */
-    public double[][] execute(final Calculation problems, final River river, final double[] kms, final Date startDay, final Date endDay) {
+    public void execute(final Calculation problems, final River river, final double[] kms, final Date startDay, final Date endDay) {
         final BedQualityCalculation bqCalc = new BedQualityCalculation();
         final BedQualityAccess access = createBqAccess(kms[0], kms[kms.length - 1], startDay, endDay);
         final CalculationResult bqCalcResult = bqCalc.calculate(access);
@@ -55,7 +62,52 @@
         final BedQualityResult[] results = (BedQualityResult[]) bqCalcResult.getData();
         final BedQualityResult result = results[0];
         final BedQualityResultValue bqResValue = result.getValue("density", "sublayer");
-        return bqResValue.getDataInterpolated(kms);
+        final double[][] kmdensities = bqResValue.getDataInterpolated(kms);
+        this.densities.clear();
+        for (int i = 0; i <= kmdensities[0].length - 1; i++)
+            this.densities.put(Double.valueOf(kmdensities[0][i]), Double.valueOf(kmdensities[1][i]));
+    }
+
+    /**
+     * Searches the density of a station in the active calculation result
+     */
+    public double getDensity(final double station) {
+        return interpolateDensity(station);
+    }
+
+    /**
+     * Searches and interpolates a density value for a km
+     */
+    private double interpolateDensity(final double km) {
+
+        if (this.densities.containsKey(km)) {
+            final Double value = this.densities.get(km);
+            return (value == null) ? Double.NaN : value.doubleValue();
+        }
+
+        final Entry<Double, Double> floorEntry = this.densities.floorEntry(km);
+        final Entry<Double, Double> ceilingEntry = this.densities.ceilingEntry(km);
+
+        if ((floorEntry == null) || (ceilingEntry == null))
+            return Double.NaN;
+
+        final double floorKm = floorEntry.getKey().doubleValue();
+        final double ceilKm = ceilingEntry.getKey().doubleValue();
+
+        // report once if the interpolation distance exceeds 1000m
+        // if ((Math.abs(floorKm - ceilKm) > MAX_DISTANCE_KM) && (this.problems != null)) {
+        // this.problems.addProblem(km, "linearInterpolator.maxdistance", MAX_DISTANCE_KM * 1000);
+        // this.problems = null;
+        // return Double.NaN;
+        // }
+
+        final Double floorHeight = floorEntry.getValue();
+        final Double ceilingHeight = ceilingEntry.getValue();
+
+        if (floorHeight == null || ceilingHeight == null)
+            return Double.NaN;
+
+        return Linear.linear(km, floorKm, ceilKm, floorHeight, ceilingHeight);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java	Wed Aug 22 19:12:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java	Thu Aug 23 10:57:40 2018 +0200
@@ -38,6 +38,7 @@
 import org.dive4elements.river.exports.WaterlevelDescriptionBuilder;
 import org.dive4elements.river.model.BedHeightValueType;
 import org.dive4elements.river.model.River;
+import org.dive4elements.river.utils.DoubleUtil;
 import org.dive4elements.river.utils.Formatter;
 
 class BezugswstCalculation {
@@ -120,14 +121,8 @@
         // Compute the missing volumes
         if (access.isCalculateMissingValue()) {
             computeMissingVolumes(problems);
-            final BedQualityCalculator bqCalculator = new BedQualityCalculator(this.context, bunduartifact);
-            final double[] kms = new double[] { this.missKmFrom.doubleValue(), this.missKmTo.doubleValue() };
-            final Calendar endDay = Calendar.getInstance();
-            endDay.set(access.getBezugsJahr().intValue(), 11, 31);
-            final Calendar startDay = Calendar.getInstance();
-            startDay.set(endDay.get(Calendar.YEAR) - 20, 0, 1);
-            // TODO final double[][] kmDensities = bqCalculator.execute(problems, river, kms, startDay.getTime(), endDay.getTime());
-            computeMissingMasses(problems);
+            final BedQualityCalculator bqCalculator = computeDensities(problems, bunduartifact, access, river);
+            computeMissingMasses(problems, bqCalculator);
         }
 
         // Add the result to the results collection
@@ -388,15 +383,33 @@
     }
 
     /**
+     * Create a density calculator and compute the densities of the missing volume km range and time period according to the
+     * reference year
+     */
+    private BedQualityCalculator computeDensities(final Calculation problems, final BUNDUArtifact bunduartifact, final BunduAccess access, final River river) {
+        final BedQualityCalculator bqCalculator = new BedQualityCalculator(this.context, bunduartifact);
+        // 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());
+        return bqCalculator;
+    }
+
+    /**
      * Computes the missing masses
      */
-    private void computeMissingMasses(final Calculation problems) {
+    private void computeMissingMasses(final Calculation problems, final BedQualityCalculator densityFinder) {
         for (final ResultRow row : this.rows) {
             @SuppressWarnings("unchecked")
             final List<Double> volumes = (List<Double>) row.getValue(BunduResultType.missVolumeFields);
             if ((volumes == null) || Double.isNaN(volumes.get(0)))
                 continue;
-            final double density = getDensity(row.getDoubleValue(GeneralResultType.station));
+            final double density = getDensity(row.getDoubleValue(GeneralResultType.station), densityFinder);
             final List<Double> masses = new ArrayList<>();
             double kmTotal = 0.0;
             for (int j = BedHeightValueType.FIELD_FIRST_INDEX; j <= BedHeightValueType.FIELD_LAST_INDEX; j++) {
@@ -470,8 +483,11 @@
         return missRows;
     }
 
-    private double getDensity(final double km) {
-        return 1.73; // TODO
+    /**
+     * Gets the density of a km from the densities calculation
+     */
+    private double getDensity(final double km, final BedQualityCalculator densityFinder) {
+        return densityFinder.getDensity(km);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/utils/Formatter.java	Wed Aug 22 19:12:51 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/utils/Formatter.java	Thu Aug 23 10:57:40 2018 +0200
@@ -449,7 +449,7 @@
     }
 
     public static NumberFormat getCurrencyFormat(final CallContext context) {
-        final NumberFormat nf = getFormatter(context.getMeta(), 0, 0);
+        final NumberFormat nf = getFormatter(context.getMeta(), 2, 2);
         nf.setGroupingUsed(true);
         return nf;
     }

http://dive4elements.wald.intevation.org