diff artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java @ 8942:11bf13cf0463

Minor changes to tkh calculation. Loading default bed heights form config file.
author gernotbelger
date Fri, 09 Mar 2018 18:47:06 +0100
parents 9c02733a1b3c
children 5d5d482da3e9
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java	Wed Mar 07 17:36:04 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java	Fri Mar 09 18:47:06 2018 +0100
@@ -11,9 +11,14 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.lang.math.NumberRange;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.WINFOArtifact;
 import org.dive4elements.river.artifacts.model.Calculation;
@@ -26,11 +31,13 @@
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder;
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator;
+import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
 import org.dive4elements.river.artifacts.states.WaterlevelData;
 import org.dive4elements.river.exports.WaterlevelDescriptionBuilder;
+import org.dive4elements.river.model.BedHeight;
 import org.dive4elements.river.model.River;
 
 /**
@@ -55,7 +62,8 @@
         final Calculation problems = new Calculation();
 
         /* find relevant bed-heights */
-        final Collection<BedHeightsFinder> bedHeights = BedHeightsFinder.createTkhBedHeights(river, problems, calcRange);
+        final List<BedHeight> defaultBedHeights = new DefaultBedHeights(river).getBedHeights(problems);
+        final Collection<BedHeightsFinder> bedHeights = BedHeightsFinder.createTkhBedHeights(calcRange, defaultBedHeights);
 
         /* misuse winfo-artifact to calculate waterlevels in the same way */
         final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo);
@@ -118,46 +126,77 @@
 
         final WstInfo wstInfo = new WstInfo(wstLabel, wspYear, riverInfoProvider.getReferenceGauge());
 
+        /* build tkh calculators per bedheight */
+        final Map<NumberRange, TkhCalculator> calculatorsByRanges = buildCalculators(calcRange, wkms, bedHeights, problems, riverInfoProvider, wstLabel);
+        if (calculatorsByRanges.isEmpty()) {
+            /* there should already be some problems, so just abort */
+            return null;
+        }
+
         final Collection<TkhResultRow> rows = new ArrayList<>();
 
-        /*
-         * for each separate bed height dataset we do the calculation and put everything into one result, bed heights must not
-         * overlap accordingly
-         */
+        /* using wst-kms as basis, because we know that they are generated wst's with a fixed km-step */
+        // FIXME: das führt dazu, das aktuell die Sohlhöhen beliebig linear interpolierrt werden. ist das immer richtig? z.b.
+        // bei großen abständen?
+
+        final int size = wkms.size();
+        for (int i = 0; i < size; i++) {
+
+            final double station = wkms.getKm(i);
+            final double wst = wkms.getW(i);
+
+            /* find the right calculator (i.e. bedheigh) depending on station, there should only be one maximal */
+            final TkhCalculator tkhCalculator = findCalculator(calculatorsByRanges, station);
+            if (tkhCalculator == null)
+                continue;
+
+            final Tkh tkh = tkhCalculator.getTkh(station, wst);
+
+            final String description = descBuilder.getDesc(wkms);
+            final String gaugeLabel = riverInfoProvider.findGauge(station);
+            final String location = riverInfoProvider.getLocation(station);
+
+            rows.add(new TkhResultRow(tkh, description, gaugeLabel, location));
+        }
+
+        return new TkhCalculationResult(wstLabel, wstInfo, true, rows);
+    }
+
+    private TkhCalculator findCalculator(final Map<NumberRange, TkhCalculator> calculators, final double station) {
+
+        // REMAKR: linear search at this point, put we expect the number of bed heights to be very small (1-2 items)
+        final Set<Entry<NumberRange, TkhCalculator>> x = calculators.entrySet();
+        for (final Entry<NumberRange, TkhCalculator> entry : x) {
+            final NumberRange range = entry.getKey();
+            // FIXME: check if we need comparison with a tolerance
+            if (range.containsDouble(station))
+                return entry.getValue();
+        }
+
+        return null;
+    }
+
+    private Map<NumberRange, TkhCalculator> buildCalculators(final DoubleRange calcRange, final WQKms wkms, final Collection<BedHeightsFinder> bedHeights,
+            final Calculation problems, final RiverInfoProvider riverInfoProvider, final String wstLabel) {
+        final Map<NumberRange, TkhCalculator> calculatorByRanges = new HashMap<>();
         for (final BedHeightsFinder bedHeightsProvider : bedHeights) {
 
+            final BedHeightInfo info = bedHeightsProvider.getInfo();
+
+            final NumberRange range = new NumberRange(info.getFrom(), info.getTo());
+
             final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wkms);
 
             /* initialize tkh calculator */
             final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(true, this.context, problems, wstLabel, riverInfoProvider.getRiver(),
-                    calcRange,
-                    dischargeProvider, bedHeightsProvider);
-            if (tkhCalculator == null) {
-                /* just abort, problems have already been updated by buildTkhCalculator() */
-                return null;
-            }
-
-            /* using wst-kms as basis, because we know that they are generated wst's with a fixed km-step */
-
-            // FIXME: das führt dazu, das aktuell die Sohlhöhen beliebig linear interpolierrt werden. ist das immer richtig? z.b.
-            // bei großen abständen?
+                    calcRange, dischargeProvider, bedHeightsProvider);
 
-            final int size = wkms.size();
-            for (int i = 0; i < size; i++) {
-
-                final double station = wkms.getKm(i);
-                final double wst = wkms.getW(i);
-
-                final Tkh tkh = tkhCalculator.getTkh(station, wst);
-
-                final String description = descBuilder.getDesc(wkms);
-                final String gaugeLabel = riverInfoProvider.findGauge(station);
-                final String location = riverInfoProvider.getLocation(station);
-
-                rows.add(new TkhResultRow(tkh, description, gaugeLabel, location));
+            if (tkhCalculator != null) {
+                /* just ignore null ones, problems have already been updated by buildTkhCalculator() */
+                calculatorByRanges.put(range, tkhCalculator);
             }
         }
 
-        return new TkhCalculationResult(wstLabel, wstInfo, true, rows);
+        return calculatorByRanges;
     }
 }
\ No newline at end of file

http://dive4elements.wald.intevation.org