[PATCH 3 of 3] Further work on SINFO-FlowDepth
Wald Commits
scm-commit at wald.intevation.org
Fri Feb 9 18:07:31 CET 2018
# HG changeset patch
# User gernotbelger
# Date 1518196042 -3600
# Node ID a536e1aacf0f6e2823561b4b705ecb211eada515
# Parent f762fadc5313ec4d61f6f08a1533e8c45f3856b1
Further work on SINFO-FlowDepth
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixRealizingCalculationExtended.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixRealizingCalculationExtended.java Fri Feb 09 18:07:22 2018 +0100
@@ -0,0 +1,45 @@
+/** 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.fixings;
+
+import java.util.Date;
+import java.util.List;
+
+import org.dive4elements.river.artifacts.access.FixRealizingAccess;
+import org.dive4elements.river.artifacts.model.FixingsOverview;
+import org.dive4elements.river.artifacts.model.FixingsOverviewFactory;
+
+/**
+ * REMARK: this inheritance is only needed, beause changing the orignal calculation will probably break the
+ * serialization of the artifact....
+ *
+ * @author Gernot Belger
+ */
+public class FixRealizingCalculationExtended extends FixRealizingCalculation {
+ private static final long serialVersionUID = 1L;
+
+ public FixRealizingCalculationExtended(final FixRealizingAccess fixAccess) {
+ super(fixAccess);
+ }
+
+ // FIXME: implement
+ // FIXME: check if this breaks serialization
+ public int determineMeanYear() {
+ final FixingsOverview overview = FixingsOverviewFactory.getOverview(this.river);
+ final ColumnCache cc = new ColumnCache();
+
+ final List<Column> columns = getEventColumns(overview, cc);
+ for (final Column column : columns) {
+ final Date date = column.getDate();
+ }
+
+ return 1999;
+ }
+}
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightStationComparator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightStationComparator.java Fri Feb 09 18:07:22 2018 +0100
@@ -0,0 +1,27 @@
+/** 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.sinfo.flowdepth;
+
+import java.util.Comparator;
+
+import org.dive4elements.river.model.BedHeightValue;
+
+/**
+ * @author Gernot Belger
+ */
+public class BedHeightStationComparator implements Comparator<BedHeightValue> {
+
+ @Override
+ public int compare(final BedHeightValue o1, final BedHeightValue o2) {
+ final Double s1 = o1.getStation();
+ final Double s2 = o2.getStation();
+ return Double.compare(s1, s2);
+ }
+}
\ No newline at end of file
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Fri Feb 09 18:07:22 2018 +0100
@@ -9,9 +9,13 @@
*/
package org.dive4elements.river.artifacts.sinfo.flowdepth;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.dive4elements.artifacts.ArtifactDatabase;
import org.dive4elements.artifacts.CallContext;
import org.dive4elements.river.artifacts.BedHeightsArtifact;
@@ -26,8 +30,10 @@
import org.dive4elements.river.artifacts.states.WaterlevelData;
import org.dive4elements.river.artifacts.states.WaterlevelFetcher;
import org.dive4elements.river.model.BedHeight;
+import org.dive4elements.river.model.BedHeightValue;
import org.dive4elements.river.model.Gauge;
import org.dive4elements.river.model.River;
+import org.dive4elements.river.utils.DoubleUtil;
import org.dive4elements.river.utils.GaugeIndex;
import org.dive4elements.river.utils.RiverUtils;
@@ -107,11 +113,13 @@
}
final WKms wstKms = waterlevel.getWkms();
+ final String wspLabel = wstKms.getName();
+ final String soundingLabel = bedHeight.getDescription();
+ final String label = String.format("%s - %s", wspLabel, soundingLabel);
+
+ checkYearDifference(label, waterlevel, bedHeight, problems);
checkWaterlevelDiscretisation(wstKms, problems);
- // FIXME: woher bekommen?
- final int wspYear = 0;
-
/* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */
final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE,
CSV_NOT_IN_GAUGE_RANGE);
@@ -119,22 +127,14 @@
final Gauge refGauge = waterlevel.findReferenceGauge(river);
final String refGaugeName = refGauge == null ? notinrange : refGauge.getName();
- final String wspLabel = wstKms.getName();
- final String soundingLabel = bedHeight.getDescription();
- final String label = String.format("%s - %s", wspLabel, soundingLabel);
-
final BedHeightInfo sounding = BedHeightInfo.from(bedHeight);
+ final int wspYear = waterlevel.getYear();
final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, refGaugeName);
final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding);
- // TODO: Berechnung der Transportkörperhöhen
- // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht
- // einmal berechnen und in db ablegen?
-
- // Benötigte Daten
- // - Abfluss / Station
- // - kein Abfluss --> Fehler
+ // FIXME: nur prüfen/beschaffen wenn TKH Berechnung aktiv
+ /* Abflusswerte vorhanden? */
if (!(wstKms instanceof QKms)) {
final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ",
null, label);
@@ -145,42 +145,115 @@
// - Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
// - Abhängig von Peiljahr
// - kein D50 vorhanden --> Fehler
+
// - Art der Gewässersohle (starr/mobil)
final String bedHeightLabel = bedHeight.getDescription();
final String wstLabel = wstKms.getName();
- // FIXME: basis der diskretisierung ist bedHeight, die wspl werden interpoliert
- for (int i = 0; i < wstKms.size(); i++) {
+ final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(),
+ wstKms.allWs());
- final double km = wstKms.getKm(i);
- final double wst = wstKms.getW(i);
- // FIXME: interpolate from bedheights?
- final double meanBedHeight = 79.32;
+ // FIXME: sort by station first, but in what direction?
+ final List<BedHeightValue> values = bedHeight.getValues();
- final double flowDepth = wst - meanBedHeight;
+ final List<BedHeightValue> sortedValues = new ArrayList<>(values);
+ Collections.sort(sortedValues, new BedHeightStationComparator());
- final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN;
+ for (final BedHeightValue bedHeightValue : sortedValues) {
- // FIXME: calculate tkh
- final double tkh = 0;
- final double flowDepthTkh = flowDepth - tkh;
+ final Double station = bedHeightValue.getStation();
+ if (station == null || station.isNaN())
+ continue;
- // REMARK: access the location once only during calculation
- final String location = LocationProvider.getLocation(river.getName(), km);
+ final Double meanBedHeightDbl = bedHeightValue.getHeight();
+ if (meanBedHeightDbl == null || meanBedHeightDbl.isNaN())
+ continue;
- // REMARK: access the gauge once only during calculation
- final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km);
+ final double km = station;
+ final double meanBedHeight = meanBedHeightDbl;
- final String gaugeLabel = gauge == null ? notinrange : gauge.getName();
+ try {
+ // FIXME: check out of range
+ final double wst = wstInterpolator.value(km);
- resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight,
- bedHeightLabel, location);
+ final double flowDepth = wst - meanBedHeight;
+
+ // FIXME: piecewise constant interpolation?
+ // final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN;
+ final double discharge = Double.NaN;
+
+ // FIXME: calculate tkh
+ final double tkh = 0;
+ final double flowDepthTkh = flowDepth - tkh;
+
+ // REMARK: access the location once only during calculation
+ final String location = LocationProvider.getLocation(river.getName(), km);
+
+ // REMARK: access the gauge once only during calculation
+ final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km);
+
+ final String gaugeLabel = gauge == null ? notinrange : gauge.getName();
+
+ resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight,
+ bedHeightLabel, location);
+ }
+ catch (final FunctionEvaluationException e) {
+ /* should only happen if out of range */
+ e.printStackTrace();
+ /* simply ignore */
+ }
+
}
return resultData;
}
+ /**
+ * Checks the year difference between waterlevels and sounding, and issues a warning if too big.
+ *
+ * Zeitraum Zeitliche Differenz [a]
+ * X ≥ 1998 ± 3
+ * 1958 ≤ X < 1998 ± 6
+ * 1918 ≤ X < 1958 ± 12
+ * X < 1918 ± 25
+ */
+ private void checkYearDifference(final String label, final WaterlevelData waterlevel, final BedHeight sounding,
+ final Calculation problems) {
+
+ final Integer soundingYear = sounding.getYear();
+ if (soundingYear == null)
+ return;
+
+ final int wstYear = waterlevel.getYear();
+ if (wstYear < 0)
+ return;
+
+ final int maxDifference = getMaxDifferenceYears(soundingYear);
+
+ final int difference = Math.abs(soundingYear - wstYear);
+ if (difference > maxDifference) {
+ final String message = Resources.getMsg(this.context.getMeta(),
+ "sinfo_calc_flow_depth.warning.year_difference", null, label, difference);
+ problems.addProblem(message);
+ }
+ }
+
+ private int getMaxDifferenceYears(final int year) {
+
+ if (year < 1918)
+ return 25;
+
+ if (1918 <= year && year < 1958)
+ return 12;
+
+ if (1958 <= year && year < 1998)
+ return 6;
+
+ /* >= 1998 */
+ return 3;
+ }
+
private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex,
final double km) {
@@ -216,7 +289,7 @@
private BedHeight loadBedHeight(final String soundingId, final double from, final double to) {
- // FIXME: absolutely unbelievable....
+ // REMARK: absolutely unbelievable....
// The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type
// throughout flys.
// The knowledge on how to parse the datacage-ids is spread through the complete code-base...
@@ -228,17 +301,17 @@
final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context);
final Integer bedheightId = artifact.getDataAsInteger("height_id");
- // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the
+ // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the
// other type means)
// Luckily, the requirement is to only access 'single' data here.
// final String bedheightType = artifact.getDataAsString("type");
- // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight
- // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via
+ // REMARK: BedDifferences uses this, but we also need the metadata of the BedHeight
+ // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via
// hibernate stuff
// BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes.
// return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to);
return BedHeight.getBedHeightById(bedheightId);
}
-}
\ No newline at end of file
+}
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelData.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelData.java Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelData.java Fri Feb 09 18:07:22 2018 +0100
@@ -23,20 +23,23 @@
private final String name;
+ private final int year;
+
/** If <code>true</code>, tabular export will show gauges for every station, else only for the first gauge */
private final boolean showAllGauges;
- public WaterlevelData(final WKms wkms) {
- this(wkms, false);
+ public WaterlevelData(final WKms wkms, final int year) {
+ this(wkms, year, false);
}
- public WaterlevelData(final WKms wkms, final boolean showAllGauges) {
- this(null, wkms, showAllGauges);
+ public WaterlevelData(final WKms wkms, final int year, final boolean showAllGauges) {
+ this(null, wkms, year, showAllGauges);
}
- public WaterlevelData(final String name, final WKms wkms, final boolean showAllGauges) {
+ private WaterlevelData(final String name, final WKms wkms, final int year, final boolean showAllGauges) {
this.name = name;
this.wkms = wkms;
+ this.year = year;
this.showAllGauges = showAllGauges;
}
@@ -46,11 +49,11 @@
}
final WKms filteredWkms = this.wkms.filteredKms(from, to);
- return new WaterlevelData(filteredWkms);
+ return new WaterlevelData(this.name, filteredWkms, this.year, this.showAllGauges);
}
public WaterlevelData withName(final String nameToSet) {
- return new WaterlevelData(nameToSet, this.wkms, this.showAllGauges);
+ return new WaterlevelData(nameToSet, this.wkms, this.year, this.showAllGauges);
}
public String getName() {
@@ -81,4 +84,8 @@
return new double[] { from, to };
}
+
+ public int getYear() {
+ return this.year;
+ }
}
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelFetcher.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelFetcher.java Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelFetcher.java Fri Feb 09 18:07:22 2018 +0100
@@ -23,6 +23,7 @@
import org.dive4elements.river.artifacts.model.Segment;
import org.dive4elements.river.artifacts.model.WKms;
import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.artifacts.model.fixings.FixRealizingCalculationExtended;
import org.dive4elements.river.artifacts.model.fixings.FixRealizingResult;
import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
import org.dive4elements.river.utils.RiverUtils;
@@ -86,7 +87,11 @@
final WKms wkms = staticWKms.getWKms(idx, from, to);
if (wkms != null)
- return new WaterlevelData(wkms);
+ {
+ // FIXME: woher bekommen?: eventuell zusammenhang mit tabelle 'time_intervals'
+ final int year = -1;
+ return new WaterlevelData(wkms, year);
+ }
log.error("No WKms from Static artifact for this range.");
return null;
@@ -100,7 +105,11 @@
final WQKms wkms = staticWKms.getWQKms(from, to);
if (wkms != null)
- return new WaterlevelData(wkms);
+ {
+ // FIXME: woher bekommen?: eventuell zusammenhang mit tabelle 'time_intervals'
+ final int year = -1;
+ return new WaterlevelData(wkms, year);
+ }
log.error("No WKms from Static artifact for this range.");
return null;
@@ -122,7 +131,9 @@
return null;
}
- return new WaterlevelData(wkms[idx]).filterByRange(from, to);
+ // REAMRK: W_INFO results does not know any 'year'
+ final int year = -1;
+ return new WaterlevelData(wkms[idx], year).filterByRange(from, to);
}
private WaterlevelData fetchFixationArtifactWaterlevel(final CallContext context,
@@ -138,9 +149,13 @@
final List<Segment> segments = fixAccess.getSegments();
final boolean isFixRealize = (segments != null && !segments.isEmpty());
+ /* ugly but necessary to keep this logic at least a bit inside the FixRealizing stuff */
+ final FixRealizingCalculationExtended calculation = new FixRealizingCalculationExtended(fixAccess);
+ final int year = calculation.determineMeanYear();
+
// REMARK: same logic as in WaterlevelExporter
final boolean showAllGauges = isFixRealize;
- return new WaterlevelData(frR.getWQKms()[idx], showAllGauges).filterByRange(from, to);
+ return new WaterlevelData(frR.getWQKms()[idx], year, showAllGauges).filterByRange(from, to);
}
-}
+}
\ No newline at end of file
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/resources/messages.properties
--- a/artifacts/src/main/resources/messages.properties Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/resources/messages.properties Fri Feb 09 18:07:22 2018 +0100
@@ -772,6 +772,7 @@
sinfo_calc_flow_depth=Flie\u00dftiefen
sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
sinfo_calc_flow_depth.warning.waterlevel_discretisation = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
+sinfo_calc_flow_depth.warning.year_difference = {0}: Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/resources/messages_de.properties
--- a/artifacts/src/main/resources/messages_de.properties Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/resources/messages_de.properties Fri Feb 09 18:07:22 2018 +0100
@@ -778,6 +778,7 @@
sinfo_calc_flow_depth=Flie\u00dftiefen
sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
sinfo_calc_flow_depth.warning.waterlevel_discretisation = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
+sinfo_calc_flow_depth.warning.year_difference = {0}: Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/resources/messages_de_DE.properties
--- a/artifacts/src/main/resources/messages_de_DE.properties Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/resources/messages_de_DE.properties Fri Feb 09 18:07:22 2018 +0100
@@ -774,6 +774,7 @@
sinfo_calc_flow_depth=Flie\u00dftiefen
sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
sinfo_calc_flow_depth.warning.waterlevel_discretisation = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
+sinfo_calc_flow_depth.warning.year_difference = {0}: Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
diff -r f762fadc5313 -r a536e1aacf0f artifacts/src/main/resources/messages_en.properties
--- a/artifacts/src/main/resources/messages_en.properties Fri Feb 09 16:11:47 2018 +0100
+++ b/artifacts/src/main/resources/messages_en.properties Fri Feb 09 18:07:22 2018 +0100
@@ -773,6 +773,7 @@
sinfo_calc_flow_depth=Flie\u00dftiefen
sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
sinfo_calc_flow_depth.warning.waterlevel_discretisation = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
+sinfo_calc_flow_depth.warning.year_difference = {0}: Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
More information about the Dive4Elements-commits
mailing list