changeset 9527:7c8d62867876

Cleanup of MainWstValue code. Cache qPositions once determined.
author gernotbelger
date Tue, 02 Oct 2018 13:25:52 +0200
parents 51212d40ff56
children 55c187a0a31e
files artifacts/src/main/java/org/dive4elements/river/artifacts/model/river/MainWstValues.java artifacts/src/main/java/org/dive4elements/river/artifacts/model/river/MainWstValuesCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCrossSectionProcessor.java backend/src/main/java/org/dive4elements/river/model/River.java
diffstat 5 files changed, 149 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/river/MainWstValues.java	Tue Oct 02 13:25:52 2018 +0200
@@ -0,0 +1,102 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.model.river;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.dive4elements.river.artifacts.model.WstValueTable;
+import org.dive4elements.river.artifacts.model.WstValueTable.QPosition;
+import org.dive4elements.river.artifacts.model.WstValueTableFactory;
+import org.dive4elements.river.model.Gauge;
+import org.dive4elements.river.model.MainValue;
+import org.dive4elements.river.model.MainValueType;
+import org.dive4elements.river.model.NamedMainValue;
+import org.dive4elements.river.model.River;
+
+/**
+ * @author Gernot Belger
+ */
+public final class MainWstValues {
+
+    private static final Map<String, MainWstValues> values = new HashMap<>();
+
+    public synchronized static MainWstValues forRiver(final River river) {
+
+        final String riverName = river.getName();
+        if (values.containsKey(riverName))
+            return values.get(riverName);
+
+        /* determine q main values of first upstream gauge */
+        final Gauge gauge = river.firstUpstreamGauge();
+
+        /* determine reference station */
+        // REAMRK: we will be using the station of the gauge (not the start of the range) to determine the q-Position,
+        // because we are using the discharge of the main value of the gauge. Hopefully .wt file and main values are always
+        // synchrone...
+        final BigDecimal referenceStation = gauge.getStation();
+
+        /* determine q-positions for all main values */
+        // REMARK: wst is cached, so we get it when we need it and do not remember it
+        final WstValueTable wst = WstValueTableFactory.getTable(river);
+
+        final Map<String, QPosition> mainValuePositions = new HashMap<>();
+
+        final List<MainValue> mainValues = gauge.getMainValues();
+        for (final MainValue mainValue : mainValues) {
+            final NamedMainValue nmv = mainValue.getMainValue();
+            if (nmv.getType().getName().equals(MainValueType.MainValueTypeKey.Q.getName())) {
+                final BigDecimal discharge = mainValue.getValue();
+                final String name = nmv.getName();
+
+                final QPosition qPosition = wst.getQPosition(referenceStation.doubleValue(), discharge.doubleValue());
+                mainValuePositions.put(name.toUpperCase(), qPosition);
+            }
+        }
+
+        final MainWstValues mainWstValues = new MainWstValues(river.getName(), mainValuePositions);
+        values.put(riverName, mainWstValues);
+        return mainWstValues;
+    }
+
+    private final Map<String, QPosition> mainValuePositions;
+
+    private final String riverName;
+
+    private MainWstValues(final String riverName, final Map<String, QPosition> mainValuePositions) {
+        this.riverName = riverName;
+        this.mainValuePositions = mainValuePositions;
+    }
+
+    public boolean hasPosition(final String mainValueName) {
+
+        final QPosition qPosition = this.mainValuePositions.get(mainValueName.toUpperCase());
+        return qPosition != null;
+    }
+
+    public double getW(final River river, final String mainValueName, final double station) {
+        // REMARK: we do not keep the river, as it is a hibernate object and this instance is statically cached.
+        // However, we need to make sure we are not misused with another river
+        // We also do not look up the river by its name here, because thats a database access
+        if (!river.getName().equals(this.riverName))
+            throw new IllegalStateException();
+
+        // REMARK: wst is cached, so we get it when we need it and do not remember it
+        final WstValueTable wst = WstValueTableFactory.getTable(river);
+
+        final QPosition qPosition = this.mainValuePositions.get(mainValueName.toUpperCase());
+        if (qPosition == null)
+            return Double.NaN;
+
+        return wst.interpolateW(station, qPosition);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/river/MainWstValuesCalculator.java	Mon Oct 01 18:08:31 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-package org.dive4elements.river.artifacts.model.river;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.lang.math.DoubleRange;
-import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.model.WstValueTable;
-import org.dive4elements.river.artifacts.model.WstValueTable.QPosition;
-import org.dive4elements.river.artifacts.model.WstValueTableFactory;
-import org.dive4elements.river.model.Gauge;
-import org.dive4elements.river.model.MainValue;
-import org.dive4elements.river.model.MainValueType.MainValueTypeKey;
-import org.dive4elements.river.model.River;
-
-/**
- * @author Domenico Nardi Tironi
- */
-public final class MainWstValuesCalculator {
-
-    private final WstValueTable wst;
-
-    private final Map<String, MainValueQPosition> positions;
-
-    static class MainValueQPosition {
-
-        public final Map<Gauge, QPosition> gaugePositions = new HashMap<>();
-
-        public QPosition refGaugePositions = null;
-    }
-
-    public static MainWstValuesCalculator forRiver(final CallContext context, final River river, final DoubleRange calcRange, final String... mainValueNames) {
-
-        final RiverInfoProvider info = RiverInfoProvider.forRange(context, river, calcRange);
-
-        return forRiverInfo(info, mainValueNames);
-    }
-
-    public static MainWstValuesCalculator forRiverInfo(final RiverInfoProvider info, final String... mainValueNames) {
-
-        final WstValueTable wst = WstValueTableFactory.getTable(info.getRiver());
-
-        final Map<String, MainValueQPosition> positions = calculatePositions(info, wst, mainValueNames);
-
-        return new MainWstValuesCalculator(wst, positions);
-    }
-
-    private static Map<String, MainValueQPosition> calculatePositions(final RiverInfoProvider info, final WstValueTable wst, final String[] mainValueNames) {
-
-        boolean isFirstGauge = true;
-
-        final Map<String, MainValueQPosition> positions = new HashMap<>();
-
-        for (final String mainValue : mainValueNames)
-            positions.put(mainValue.toUpperCase(), new MainValueQPosition());
-
-        for (final Gauge gauge : info.getGauges()) {
-
-            for (final MainValueQPosition position : positions.values())
-                position.gaugePositions.put(gauge, null);
-
-            final double gaugeKm = gauge.getStation().doubleValue();
-            for (final MainValue mv : MainValue.getValuesOfGaugeAndType(gauge, MainValueTypeKey.Q)) {
-
-                final MainValueQPosition position = positions.get(mv.getMainValue().getName().toUpperCase());
-                if (position != null) {
-                    final QPosition qPosition = wst.getQPosition(gaugeKm, mv.getValue().doubleValue());
-                    position.gaugePositions.put(gauge, qPosition);
-
-                    if (isFirstGauge)
-                        position.refGaugePositions = qPosition;
-                }
-            }
-
-            isFirstGauge = false;
-        }
-
-        return positions;
-    }
-
-    private MainWstValuesCalculator(final WstValueTable wst, final Map<String, MainValueQPosition> positions) {
-        this.wst = wst;
-        this.positions = positions;
-    }
-
-    public boolean hasPosition(final String mainValueName) {
-
-        final MainValueQPosition position = this.positions.get(mainValueName.toUpperCase());
-        if (position == null)
-            throw new IllegalArgumentException();
-
-        return position.refGaugePositions != null;
-    }
-
-    /**
-     * Interpolates the W for a station with a fixed (virtual) wst column position
-     */
-    public double interpolateW(final double station, final String mainValueName) {
-
-        final MainValueQPosition mainValuePosition = this.positions.get(mainValueName.toUpperCase());
-
-        if (mainValuePosition.refGaugePositions == null)
-            return Double.NaN;
-
-        return this.wst.interpolateW(station, mainValuePosition.refGaugePositions);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculator.java	Mon Oct 01 18:08:31 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculator.java	Tue Oct 02 13:25:52 2018 +0200
@@ -19,12 +19,13 @@
 import org.dive4elements.river.artifacts.common.GeneralResultType;
 import org.dive4elements.river.artifacts.common.ResultRow;
 import org.dive4elements.river.artifacts.model.Calculation;
-import org.dive4elements.river.artifacts.model.river.MainWstValuesCalculator;
+import org.dive4elements.river.artifacts.model.river.MainWstValues;
 import org.dive4elements.river.artifacts.model.river.RiverInfoProvider;
 import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper;
 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
 import org.dive4elements.river.artifacts.uinfo.common.UInfoResultType;
 import org.dive4elements.river.artifacts.uinfo.salix.SalixLineAccess.ScenarioType;
+import org.dive4elements.river.model.River;
 
 /**
  * Calculation of the result rows of the u-info salix line calc mode
@@ -56,7 +57,7 @@
             final ScenarioType scenarioType, final String[] scenarioLabels, final String rangeString, final String additionalString,
             final SalixLineCalculationResults results) {
 
-        final MainWstValuesCalculator mainWstValues = fetchGaugeMainValuePositions2(problems);
+        final MainWstValues mainWstValues = fetchWstMainValues(problems);
 
         final WINFOArtifact winfo = new WinfoArtifactWrapper(uinfo);
         winfo.addStringData("ld_mode", "distance");
@@ -87,39 +88,36 @@
         }
     }
 
-    private MainWstValuesCalculator fetchGaugeMainValuePositions2(final Calculation problems) {
-        final MainWstValuesCalculator mainWstValues = MainWstValuesCalculator.forRiverInfo(this.riverInfoProvider, MAIN_VALUE_MQ, MAIN_VALUE_MNQ,
-                MAIN_VALUE_MHQ, MAIN_VALUE_HQ5);
+    private MainWstValues fetchWstMainValues(final Calculation problems) {
 
-        if (!mainWstValues.hasPosition(MAIN_VALUE_MQ))
+        final MainWstValues values = MainWstValues.forRiver(this.riverInfoProvider.getRiver());
+
+        if (!values.hasPosition(MAIN_VALUE_MQ))
             problems.addProblem("uinfo_salix_calc.warning.missing_mq");
         else {
-            if (!mainWstValues.hasPosition(MAIN_VALUE_MHQ))
+            if (!values.hasPosition(MAIN_VALUE_MHQ))
                 problems.addProblem("uinfo_salix_calc.warning.missing_mhq");
-            if (!mainWstValues.hasPosition(MAIN_VALUE_MNQ))
+            if (!values.hasPosition(MAIN_VALUE_MNQ))
                 problems.addProblem("uinfo_salix_calc.warning.missing_mnq");
         }
 
-        return mainWstValues;
+        return values;
     }
 
     /**
      * Create a result row for a station and its gauge, and add w-q-values as selected
      */
-    private ResultRow createRow(final MainWstValuesCalculator mainWstValues, final double station, final NavigableMap<Double, List<Double>> rangeScenarios) {
+    private ResultRow createRow(final MainWstValues mainWstValues, final double station, final NavigableMap<Double, List<Double>> rangeScenarios) {
+
+        final River river = this.riverInfoProvider.getRiver();
 
         final ResultRow row = ResultRow.create();
         row.putValue(GeneralResultType.station, station);
-        // Find station's gauge (obsolete version which calculates gauge-wise)
-        // final Gauge gauge = this.riverInfoProvider.getGauge(station, true);
-        // Interpolate mnw, mw, and mhw
-        // final double mnw = interpolateW(station, this.gaugeMnwPos.get(gauge));
-        // final double mw = interpolateW(station, this.gaugeMwPos.get(gauge));
-        // final double mhw = interpolateW(station, this.gaugeMhwPos.get(gauge));
-        final double mnw = mainWstValues.interpolateW(station, MAIN_VALUE_MNQ);
-        final double mw = mainWstValues.interpolateW(station, MAIN_VALUE_MQ);
-        final double mhw = mainWstValues.interpolateW(station, MAIN_VALUE_MHQ);
-        final double hw5 = mainWstValues.interpolateW(station, MAIN_VALUE_HQ5);
+
+        final double mnw = mainWstValues.getW(river, MAIN_VALUE_MNQ, station);
+        final double mw = mainWstValues.getW(river, MAIN_VALUE_MQ, station);
+        final double mhw = mainWstValues.getW(river, MAIN_VALUE_MHQ, station);
+        final double hw5 = mainWstValues.getW(river, MAIN_VALUE_HQ5, station);
         row.putValue(UInfoResultType.waterlevelMNW, mnw);
         row.putValue(UInfoResultType.waterlevelMW, mw);
         row.putValue(UInfoResultType.waterlevelMHW, mhw);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCrossSectionProcessor.java	Mon Oct 01 18:08:31 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCrossSectionProcessor.java	Tue Oct 02 13:25:52 2018 +0200
@@ -23,7 +23,7 @@
 import org.dive4elements.river.artifacts.D4EArtifact;
 import org.dive4elements.river.artifacts.access.RiverAccess;
 import org.dive4elements.river.artifacts.model.CrossSectionFacetUtils;
-import org.dive4elements.river.artifacts.model.river.MainWstValuesCalculator;
+import org.dive4elements.river.artifacts.model.river.MainWstValues;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.exports.CrossSectionGenerator;
 import org.dive4elements.river.jfree.StripedAreaDataset;
@@ -87,8 +87,8 @@
 
         for (final VegetationZoneServerClientXChange zone : zones) {
 
-            final double lower = uefdToHeight(context, river, currentStation, zone.getLowerFromTo());
-            final double upper = uefdToHeight(context, river, currentStation, zone.getUpperFromTo());
+            final double lower = uefdToHeight(river, currentStation, zone.getLowerFromTo());
+            final double upper = uefdToHeight(river, currentStation, zone.getUpperFromTo());
 
             final Color color = Color.decode(zone.getHexColor());
             final String label = String.format("%s (%dd-%dd)", zone.getZoneName(), zone.getLowerFromTo(), zone.getUpperFromTo());
@@ -116,12 +116,10 @@
         throw new UnsupportedOperationException();
     }
 
-    private static double uefdToHeight(final CallContext context, final River river, final double station, final int uefd) {
+    private static double uefdToHeight(final River river, final double station, final int uefd) {
 
-        // FIXME: cache me
-        final MainWstValuesCalculator mainWstValues = MainWstValuesCalculator.forRiver(context, river, null, MAIN_VALUE_MQ);
-
-        final double mw = mainWstValues.interpolateW(station, MAIN_VALUE_MQ);
+        final MainWstValues mainWstValues = MainWstValues.forRiver(river);
+        final double mw = mainWstValues.getW(river, MAIN_VALUE_MQ, station);
 
         // Üfd = -70,559 ∗ ln((DGM - MW) + 0,5) + 80,711
         final double f1 = -70.559;
--- a/backend/src/main/java/org/dive4elements/river/model/River.java	Mon Oct 01 18:08:31 2018 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/River.java	Tue Oct 02 13:25:52 2018 +0200
@@ -14,6 +14,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.TreeMap;
 
 import javax.persistence.Column;
@@ -427,5 +428,27 @@
         }
         return null;
     }
+    
+    public Gauge firstUpstreamGauge() {
+        final List<Gauge> gauges = getGauges();
+
+        final NavigableMap<BigDecimal, Gauge> byKm = new TreeMap<>();
+
+        for (final Gauge gauge : gauges) {
+            final Range range = gauge.getRange();
+            if (range != null) {
+                final BigDecimal a = range.getA();
+                byKm.put(a, gauge);
+            }
+        }
+
+        if (byKm.isEmpty())
+            return null;
+
+        if (kmUp)
+            return byKm.lastEntry().getValue();
+
+        return byKm.firstEntry().getValue();
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org