# HG changeset patch # User gernotbelger # Date 1538479552 -7200 # Node ID 7c8d6286787627cc14e138d3bdcb64b7c8415752 # Parent 51212d40ff56788e61a4b36847da20adc079fb46 Cleanup of MainWstValue code. Cache qPositions once determined. diff -r 51212d40ff56 -r 7c8d62867876 artifacts/src/main/java/org/dive4elements/river/artifacts/model/river/MainWstValues.java --- /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 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 mainValuePositions = new HashMap<>(); + + final List 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 mainValuePositions; + + private final String riverName; + + private MainWstValues(final String riverName, final Map 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 diff -r 51212d40ff56 -r 7c8d62867876 artifacts/src/main/java/org/dive4elements/river/artifacts/model/river/MainWstValuesCalculator.java --- 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 positions; - - static class MainValueQPosition { - - public final Map 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 positions = calculatePositions(info, wst, mainValueNames); - - return new MainWstValuesCalculator(wst, positions); - } - - private static Map calculatePositions(final RiverInfoProvider info, final WstValueTable wst, final String[] mainValueNames) { - - boolean isFirstGauge = true; - - final Map 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 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 diff -r 51212d40ff56 -r 7c8d62867876 artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/salix/SalixLineCalculator.java --- 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> rangeScenarios) { + private ResultRow createRow(final MainWstValues mainWstValues, final double station, final NavigableMap> 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); diff -r 51212d40ff56 -r 7c8d62867876 artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/vegetationzones/VegetationZonesCrossSectionProcessor.java --- 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; diff -r 51212d40ff56 -r 7c8d62867876 backend/src/main/java/org/dive4elements/river/model/River.java --- 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 gauges = getGauges(); + + final NavigableMap 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 :