[PATCH] Refaktoring of flow depth calculation, extracting tkh part. First implementation of tkh calculation
Wald Commits
scm-commit at wald.intevation.org
Wed Feb 28 18:14:04 CET 2018
# HG changeset patch
# User gernotbelger
# Date 1519835235 -3600
# Node ID d9dbf0b74bc2cece4128146ba60fc3a7096ec3c5
# Parent e3519c3e7a0a91e03ad877e17588489942469b60
Refaktoring of flow depth calculation, extracting tkh part. First implementation of tkh calculation.
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/doc/conf/artifacts/sinfo.xml
--- a/artifacts/doc/conf/artifacts/sinfo.xml Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/doc/conf/artifacts/sinfo.xml Wed Feb 28 17:27:15 2018 +0100
@@ -118,7 +118,7 @@
<condition data="calculation_mode" value="sinfo_calc_transport_bodies_heights" operator="equal"/>
</transition>
- <state id="state.sinfo.transport_bodies_heights" description="state.sinfo.transport_bodies_heights" state="org.dive4elements.river.artifacts.sinfo.tkh.TkhState" helpText="help.state.sinfo.transport_bodies_heights">
+ <state id="state.sinfo.transport_bodies_heights" description="state.sinfo.transport_bodies_heights" state="org.dive4elements.river.artifacts.sinfo.tkhstate.TkhState" helpText="help.state.sinfo.transport_bodies_heights">
<outputmodes>
<!-- <outputmode name="sinfo_flow_depth" description="output.flow_depth" mime-type="image/png" type="chart"> <facets> <facet name="sinfo_flow_depth.filtered" description="Facet for mean flow depth, filtered by current zoom state"/> <facet name="sinfo_flow_depth.tkh.filtered" description="Facet for mean flow depth including tkh, filtered by current zoom state"/> <facet name="sinfo_flow_depth.tkh" description="Facet for tkh"/> <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
</facets> </outputmode> <outputmode name="sinfo_flowdepth_export" description="output.sinfo_flowdepth_export" mime-type="text/plain" type="export"> <facets> <facet name="csv" description="facet.sinfo_flowdepth_export.csv"/> <facet name="pdf" description="facet.sinfo_flowdepth_export.pdf"/> </facets> </outputmode> <outputmode name="sinfo_flowdepth_report" description="output.sinfo_flowdepth_report" mime-type="text/xml" type="report"> <facets> <facet name="report" description="facet.sinfo_flowdepth_report"/>
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,134 @@
+/** 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.common;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.SoilKind;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+
+import gnu.trove.TDoubleArrayList;
+
+/**
+ * @author Gernot Belger
+ */
+public abstract class AbstractSInfoCalculationResult<ROW extends AbstractSInfoResultRow> implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Collection<ROW> rows;
+
+ private final String label;
+
+ private final boolean hasTkh;
+
+ private final WstInfo wst;
+
+ public AbstractSInfoCalculationResult(final String label, final WstInfo wst, final boolean hasTkh, final Collection<ROW> rows) {
+ this.label = label;
+ this.wst = wst;
+ this.hasTkh = hasTkh;
+ this.rows = new ArrayList<>(rows);
+ }
+
+ public final String getLabel() {
+ return this.label;
+ }
+
+ public final boolean hasTkh() {
+ return this.hasTkh;
+ }
+
+ public final WstInfo getWst() {
+ return this.wst;
+ }
+
+ public final void addRow(final ROW resultRow) {
+ this.rows.add(resultRow);
+ }
+
+ public final Collection<ROW> getRows() {
+ return Collections.unmodifiableCollection(this.rows);
+ }
+
+ public final double[][] getTkhUpPoints() {
+ final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+ final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+ final List<SoilKind> kinds = new ArrayList<>(this.rows.size());
+
+ for (final ROW row : this.rows) {
+ xPoints.add(row.getStation());
+ yPoints.add(row.getTkhUp());
+ kinds.add(row.getTkhKind());
+ }
+
+ return adjustTkhVisualization(xPoints, yPoints, kinds);
+ }
+
+ public final double[][] getTkhDownPoints() {
+ final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+ final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+ final List<SoilKind> kinds = new ArrayList<>(this.rows.size());
+
+ for (final ROW row : this.rows) {
+ xPoints.add(row.getStation());
+ yPoints.add(row.getTkhDown());
+ kinds.add(row.getTkhKind());
+ }
+
+ return adjustTkhVisualization(xPoints, yPoints, kinds);
+ }
+
+ /**
+ * the up and down points must be further adjusted for visualization, see Mail Hr. Reiß
+ * basically we need to introduce extra points when the kind changes, so we get vertical lines in that case
+ */
+ private double[][] adjustTkhVisualization(final TDoubleArrayList xPoints, final TDoubleArrayList yPoints, final List<SoilKind> kinds) {
+
+ final TDoubleArrayList adjustedX = new TDoubleArrayList(xPoints.size());
+ final TDoubleArrayList adjustedY = new TDoubleArrayList(yPoints.size());
+
+ adjustedX.add(xPoints.get(0));
+ adjustedY.add(yPoints.get(0));
+
+ for (int i = 1; i < xPoints.size(); i++) {
+
+ final SoilKind kind1 = kinds.get(i - 1);
+ final SoilKind kind2 = kinds.get(i);
+
+ if (kind1 != kind2) {
+ /* introduce two extra points in order to create a vertical line in the middle of the two adjacent points */
+ final double x1 = xPoints.get(i - 1);
+ final double y1 = yPoints.get(i - 1);
+ final double x2 = xPoints.get(i);
+ final double y2 = yPoints.get(i);
+
+ final double middleX = (x1 + x2) / 2;
+
+ // REMARK: we can't produce a 100% vertical line, as the area-renderer will not work correctly
+ adjustedX.add(middleX - 0.0001);
+ adjustedY.add(y1);
+
+ adjustedX.add(middleX + 0.0001);
+ adjustedY.add(y2);
+ }
+
+ /* always add the real point now */
+ adjustedX.add(xPoints.get(i));
+ adjustedY.add(yPoints.get(i));
+ }
+
+ return new double[][] { adjustedX.toNativeArray(), adjustedY.toNativeArray() };
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,83 @@
+/** 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.common;
+
+import java.io.Serializable;
+
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.SoilKind;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
+
+/**
+ * Contains common result data of flow-depth- and tkh-calculations.
+ *
+ * @author Gernot Belger
+ */
+public abstract class AbstractSInfoResultRow implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final Tkh tkh;
+
+ private final String waterlevelLabel;
+
+ private final String gauge;
+
+ private final String location;
+
+ public AbstractSInfoResultRow(final Tkh tkh, final String waterlevelLabel, final String gauge, final String location) {
+ this.tkh = tkh;
+ this.waterlevelLabel = waterlevelLabel;
+ this.gauge = gauge;
+ this.location = location;
+ }
+
+ public final double getStation() {
+ return this.tkh.getStation();
+ }
+
+ public final SoilKind getTkhKind() {
+ return this.tkh.getKind();
+ }
+
+ public final double getTkh() {
+ return this.tkh.getTkh();
+ }
+
+ public final double getTkhUp() {
+ return this.tkh.getUp();
+ }
+
+ public final double getTkhDown() {
+ return this.tkh.getDown();
+ }
+
+ public final double getWaterlevel() {
+ return this.tkh.getWaterlevel();
+ }
+
+ public final double getDischarge() {
+ return this.tkh.getDischarge();
+ }
+
+ public final String getWaterlevelLabel() {
+ return this.waterlevelLabel;
+ }
+
+ public final String getGauge() {
+ return this.gauge;
+ }
+
+ public final double getMeanBedHeight() {
+ return this.tkh.getMeanBedHeight();
+ }
+
+ public final String getLocation() {
+ return this.location;
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/RiverInfoProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/RiverInfoProvider.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,116 @@
+/** 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.common;
+
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.model.LocationProvider;
+import org.dive4elements.river.artifacts.model.WKms;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.states.WaterlevelData;
+import org.dive4elements.river.model.Gauge;
+import org.dive4elements.river.model.River;
+import org.dive4elements.river.utils.GaugeIndex;
+
+/**
+ * @author Gernot Belger
+ *
+ */
+public final class RiverInfoProvider {
+
+ private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range";
+
+ private final River river;
+ private final GaugeIndex gaugeIndex;
+ private final Gauge refGauge;
+ private final boolean showAllGauges;
+ private final String notinrange;
+
+ public static RiverInfoProvider forRange(final CallContext context, final River river, final DoubleRange calcRange) {
+
+ final List<Gauge> gauges = river.determineGauges(calcRange.getMinimumDouble(), calcRange.getMaximumDouble());
+ final GaugeIndex gaugeIndex = new GaugeIndex(gauges);
+
+ final String notinrange = Resources.getMsg(context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE);
+
+ return new RiverInfoProvider(notinrange, river, false, gaugeIndex, null);
+ }
+
+ private RiverInfoProvider(final String notinrange, final River river, final boolean showAllGauges, final GaugeIndex gaugeIndex, final Gauge refGauge) {
+ this.notinrange = notinrange;
+ this.river = river;
+ this.showAllGauges = showAllGauges;
+ this.gaugeIndex = gaugeIndex;
+ this.refGauge = refGauge;
+ }
+
+ public RiverInfoProvider forWaterlevel(final WaterlevelData waterlevel) {
+ final WKms wstKms = waterlevel.getWkms();
+ final Gauge waterlevelRefGauge = findReferenceGauge(wstKms);
+ final boolean waterlevelShowAllGauges = waterlevel.isShowAllGauges();
+
+ return new RiverInfoProvider(this.notinrange, this.river, waterlevelShowAllGauges, this.gaugeIndex, waterlevelRefGauge);
+ }
+
+ /**
+ * Re-determines the reference gauge, in the same way as the WaterlevelArtifact would do it
+ */
+ private Gauge findReferenceGauge(final WKms wkms) {
+
+ final double[] wstFromTo = findWstFromTo(wkms);
+ return this.river.determineRefGauge(wstFromTo, true);
+ }
+
+ private static double[] findWstFromTo(final WKms wkms) {
+
+ final double from = wkms.getKm(0);
+ final double to = wkms.getKm(wkms.size() - 1);
+
+ final boolean waterIncreasing = wkms.guessWaterIncreasing();
+ if (waterIncreasing)
+ return new double[] { to, from };
+
+ return new double[] { from, to };
+ }
+
+ public String getLocation(final double km) {
+ return LocationProvider.getLocation(this.river.getName(), km);
+ }
+
+ public String findGauge(final double km) {
+ // REMARK: access the gauge once only during calculation
+ final Gauge gauge = getGauge(km);
+
+ return gauge == null ? this.notinrange : gauge.getName();
+ }
+
+ private Gauge getGauge(final double km) {
+
+ // REMARK: using same logic as in WaterlevelExporter here
+
+ if (this.showAllGauges)
+ return this.gaugeIndex.findGauge(km);
+
+ if (this.refGauge.getRange().contains(km))
+ return this.refGauge;
+
+ return null;
+ }
+
+ public String getReferenceGauge() {
+ return this.refGauge == null ? this.notinrange : this.refGauge.getName();
+ }
+
+ public River getRiver() {
+ return this.river;
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightStationComparator.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedHeightStationComparator.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +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.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 e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,235 +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.sinfo.flowdepth;
-
-import java.util.Date;
-import java.util.List;
-
-import org.apache.commons.lang.math.DoubleRange;
-import org.apache.commons.math.ArgumentOutsideDomainException;
-import org.apache.commons.math.analysis.interpolation.LinearInterpolator;
-import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
-import org.apache.log4j.Logger;
-import org.dive4elements.river.artifacts.math.Utils;
-import org.dive4elements.river.artifacts.model.DateRange;
-import org.dive4elements.river.backend.SedDBSessionHolder;
-import org.dive4elements.river.model.River;
-import org.dive4elements.river.utils.DoubleUtil;
-import org.hibernate.SQLQuery;
-import org.hibernate.Session;
-import org.hibernate.type.StandardBasicTypes;
-
-import gnu.trove.TDoubleArrayList;
-
-/**
- * Searchable sorted km array with parallel bed measurements value array and linear interpolation for km and d50 between the array elements.<br />
- * <br />
- * See comment of SQL command on how the values are filtered and aggregated.
- *
- * @author Matthias Schäfer
- *
- */
-public class BedQualityD50KmValueFinder {
-
- /***** INNER CLASSES *****/
-
- /**
- * A bed measurements aggregate with its d50 characteristic grain diameter
- */
- private class D50Measurement {
- private double km;
- public double getKm() {
- return km;
- }
- private Date mindate;
- public Date getMinDate() {
- return mindate;
- }
- private Date maxdate;
- public Date getMaxDate() {
- return maxdate;
- }
- private int cnt;
- public int getCnt() {
- return cnt;
- }
- private double mindepth;
- public double getMinDepth() {
- return mindepth;
- }
- private double maxdepth;
- public double getMaxDepth() {
- return maxdepth;
- }
- private double d50;
- /**
- * D50 in m
- */
- public double getD50() {
- return d50;
- }
- /**
- * Parameter constructor
- */
- public D50Measurement(double km, Date mindate, Date maxdate, int cnt, double mindepth, double maxdepth, double d50mm) {
- this.km = km;
- this.mindate = mindate;
- this.maxdate = maxdate;
- this.cnt = cnt;
- this.mindepth = mindepth;
- this.maxdepth = maxdepth;
- this.d50 = d50mm / 1000;
- }
-
- /**
- * Query result row constructor
- */
- public D50Measurement(Object[] tuple, String[] aliases) {
- km = 0;
- mindate = null;
- maxdate = null;
- cnt = 0;
- mindepth = Double.NaN;
- maxdepth = Double.NaN;
- d50 = Double.NaN;
- for (int i = 0; i < tuple.length; ++i) {
- if (tuple[i] == null)
- continue;
- switch (aliases[i]) {
- case "km":
- km = ((Number) tuple[i]).doubleValue();
- break;
- case "mindate":
- mindate = (Date) tuple[i];
- break;
- case "maxdate":
- maxdate = (Date) tuple[i];
- break;
- case "cnt":
- cnt = ((Number) tuple[i]).intValue();
- break;
- case "mindepth":
- mindepth = ((Number) tuple[i]).doubleValue();
- break;
- case "maxdepth":
- maxdepth = ((Number) tuple[i]).doubleValue();
- break;
- case "d50":
- d50 = ((Number) tuple[i]).doubleValue() / 1000; // mm to m
- break;
- default:
- break;
- }
- }
- }
- }
-
- /***** FIELDS *****/
-
- /**
- * Private log to use here.
- */
- private static Logger log = Logger.getLogger(BedQualityD50KmValueFinder.class);
-
- /**
- * Query that aggregates by km for a km range and a time period all sub layer bed measurements with their d50<br />
- * <br />
- * A km may have bed measurements for multiple dates, multiple distances from the river bank, and multiple depth layers.
- * The query filters by km range, time period and layer (sub layer: below bed to max. 50 cm depth).
- * Those measurements are then grouped by km, and the D50 aggregated as average value.
- */
- private static final String SQL_BED_D50_SUBLAYER_MEASUREMENT =
- "SELECT t.km, MIN(t.datum) AS mindate, MAX(t.datum) AS maxdate, COUNT(*) AS cnt,"
- + " MIN(p.tiefevon) AS mindepth, MAX(p.tiefebis) AS maxdepth, AVG(a.d50) AS d50"
- + " FROM sohltest t INNER JOIN station s ON t.stationid = s.stationid"
- + " INNER JOIN gewaesser g ON s.gewaesserid = g.gewaesserid"
- + " INNER JOIN sohlprobe p ON t.sohltestid = p.sohltestid"
- + " INNER JOIN siebanalyse a ON p.sohlprobeid = a.sohlprobeid"
- + " WHERE (g.name = :name) AND (s.km BETWEEN :fromkm - 0.0001 AND :tokm + 0.0001)"
- + " AND (p.tiefevon > 0.0) AND (p.tiefebis <= 0.5)"
- + " AND (t.datum BETWEEN :fromdate AND :todate)"
- + " GROUP BY t.km"
- + " ORDER BY t.km";
- private static final String[] SQL_BED_D50_SELECT_ALIAS = {"km", "mindate", "maxdate", "cnt", "mindepth", "maxdepth", "d50"};
-
- /**
- * Real linear interpolator for kms and d50 values
- */
- private PolynomialSplineFunction interpolator;
-
-
- /***** METHODS *****/
-
- /**
- * Returns the d50 value interpolated according to a km
- * @return d50 (mm) of the km, or NaN
- */
- public double findD50(double km) throws ArgumentOutsideDomainException {
- return interpolator.value(km);
- /* ohne interpolation:
- if ((kms == null) || (kms.size() == 0))
- return Double.NaN;
- int i = kms.binarySearch(km);
- if (i >= 0)
- return values.get(i);
- i = -i - 1;
- if ((i - 1 >= 0) && Utils.epsilonEquals(km, kms.get(i - 1), 0.0001))
- return values.get(i - 1);
- else if ((i >= 0) && (i <= kms.size() - 1) && Utils.epsilonEquals(km, kms.get(i), 0.0001))
- return values.get(i);
- else
- return Double.NaN; */
- }
-
- /**
- * Loads the range of the river's kms with their associated values.
- * @return Whether the load has been successful
- */
- public boolean loadValues(final River river, final DoubleRange kmRange, final DateRange dateRange) {
- log.debug(String.format("loadValues km %.3f - %.3f %tF - %tF", kmRange.getMinimumDouble(), kmRange.getMaximumDouble(), dateRange.getFrom(), dateRange.getTo()));
- Session session = SedDBSessionHolder.HOLDER.get();
- SQLQuery sqlQuery = session.createSQLQuery(SQL_BED_D50_SUBLAYER_MEASUREMENT)
- .addScalar("km", StandardBasicTypes.DOUBLE)
- .addScalar("mindate", StandardBasicTypes.DATE)
- .addScalar("maxdate", StandardBasicTypes.DATE)
- .addScalar("cnt", StandardBasicTypes.INTEGER)
- .addScalar("mindepth", StandardBasicTypes.DOUBLE)
- .addScalar("maxdepth", StandardBasicTypes.DOUBLE)
- .addScalar("d50", StandardBasicTypes.DOUBLE);
- String seddbRiver = river.nameForSeddb();
- sqlQuery.setString("name", seddbRiver);
- sqlQuery.setDouble("fromkm", kmRange.getMinimumDouble());
- sqlQuery.setDouble("tokm", kmRange.getMaximumDouble());
- sqlQuery.setDate("fromdate", dateRange.getFrom());
- sqlQuery.setDate("todate", dateRange.getTo());
- @SuppressWarnings("unchecked")
- final List<Object[]> rows = sqlQuery.list();
- final double[] kms = new double[rows.size()];
- final double[] values = new double[rows.size()];
- D50Measurement measurement;
- int i = -1;
- for (Object[] row : rows) {
- measurement = new D50Measurement(row, SQL_BED_D50_SELECT_ALIAS);
- i++;
- kms[i] = measurement.getKm();
- values[i] = measurement.getD50();
- log.debug(String.format("loadValues km %.3f d50(mm) %.1f count %d", kms[i], values[i], measurement.getCnt()));
- }
- try {
- interpolator = new LinearInterpolator().interpolate(kms, values);
- return true;
- } catch (Exception e) {
- interpolator = null;
- return false;
- }
- }
-
-}
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthAccess.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthAccess.java Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthAccess.java Wed Feb 28 17:27:15 2018 +0100
@@ -1,6 +1,6 @@
/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- * Björnsen Beratende Ingenieure GmbH
+ * 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)
@@ -14,6 +14,7 @@
import java.util.Collection;
import java.util.Collections;
+import org.apache.commons.lang.math.DoubleRange;
import org.dive4elements.river.artifacts.access.RangeAccess;
import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
import org.dive4elements.river.artifacts.sinfo.SinfoCalcMode;
@@ -21,68 +22,71 @@
/**
* Access to the flow depth calculation type specific SInfo artifact data.
- * REMARK: this class is NOT intended to be hold in the results (or anywhere else), in order to avoid a permanent reference to the artifact instance.
+ * REMARK: this class is NOT intended to be hold in the results (or anywhere else), in order to avoid a permanent
+ * reference to the artifact instance.
* Hence we do NOT cache any data.
- *
+ *
* @author Gernot Belger
*/
-public class FlowDepthAccess
-extends RangeAccess
-{
- public static class DifferencesPair
- {
- private final String wstId;
- private final String soundingId;
+final class FlowDepthAccess extends RangeAccess {
+ public static class DifferencesPair {
+ private final String wstId;
+ private final String soundingId;
- public DifferencesPair( final String wstId, final String soundingId ) {
- this.wstId = wstId;
- this.soundingId = soundingId;
- }
-
- public String getWstId() {
- return this.wstId;
- }
+ public DifferencesPair(final String wstId, final String soundingId) {
+ this.wstId = wstId;
+ this.soundingId = soundingId;
+ }
- public String getSoundingId() {
- return this.soundingId;
- }
- }
+ public String getWstId() {
+ return this.wstId;
+ }
- private static final String FIELD_USE_TKH = "use_transport_bodies"; //$NON-NLS-1$
+ public String getSoundingId() {
+ return this.soundingId;
+ }
+ }
- public FlowDepthAccess(final SINFOArtifact artifact) {
- super(artifact);
+ private static final String FIELD_USE_TKH = "use_transport_bodies"; //$NON-NLS-1$
- /* assert calculation mode */
- final SinfoCalcMode calculationMode = artifact.getCalculationMode();
- assert(calculationMode == SinfoCalcMode.sinfo_calc_flow_depth);
- }
+ public FlowDepthAccess(final SINFOArtifact artifact) {
+ super(artifact);
- public boolean isUseTransportBodies() {
- final Boolean useTkh = artifact.getDataAsBoolean( FIELD_USE_TKH );
- return useTkh == null ? false : useTkh;
- }
+ /* assert calculation mode */
+ final SinfoCalcMode calculationMode = artifact.getCalculationMode();
+ assert (calculationMode == SinfoCalcMode.sinfo_calc_flow_depth);
+ }
- public Collection<DifferencesPair> getDifferencePairs() {
+ public DoubleRange getRange() {
+ final double from = getFrom();
+ final double to = getTo();
+ return new DoubleRange(from, to);
+ }
- final Collection<DifferencesPair> diffPairs = new ArrayList<>();
+ public boolean isUseTransportBodies() {
+ final Boolean useTkh = this.artifact.getDataAsBoolean(FIELD_USE_TKH);
+ return useTkh == null ? false : useTkh;
+ }
- final String diffids = super.getString("diffids");
- if( diffids == null )
- {
- // Should never happen as this is handled by the ui
- return Collections.emptyList();
- }
+ public Collection<DifferencesPair> getDifferencePairs() {
- // FIXME: this way of parsing the datacage-ids is repeated all over flys!
- final String datas[] = diffids.split("#");
- for(int i = 0; i < datas.length; i+=2) {
- final String leftId = StringUtil.unbracket( datas[i] );
- final String rightId = StringUtil.unbracket( datas[i+1] );
+ final Collection<DifferencesPair> diffPairs = new ArrayList<>();
- diffPairs.add(new DifferencesPair(leftId, rightId));
- }
+ final String diffids = super.getString("diffids");
+ if (diffids == null) {
+ // Should never happen as this is handled by the ui
+ return Collections.emptyList();
+ }
- return Collections.unmodifiableCollection(diffPairs);
- }
+ // FIXME: this way of parsing the datacage-ids is repeated all over flys!
+ final String datas[] = diffids.split("#");
+ for (int i = 0; i < datas.length; i += 2) {
+ final String leftId = StringUtil.unbracket(datas[i]);
+ final String rightId = StringUtil.unbracket(datas[i + 1]);
+
+ diffPairs.add(new DifferencesPair(leftId, rightId));
+ }
+
+ return Collections.unmodifiableCollection(diffPairs);
+ }
}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 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 Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Wed Feb 28 17:27:15 2018 +0100
@@ -9,49 +9,33 @@
*/
package org.dive4elements.river.artifacts.sinfo.flowdepth;
-import java.util.ArrayList;
-import java.util.Calendar;
import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
import org.apache.commons.lang.math.DoubleRange;
-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;
import org.dive4elements.river.artifacts.model.Calculation;
import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.DateRange;
-import org.dive4elements.river.artifacts.model.LocationProvider;
-import org.dive4elements.river.artifacts.model.QKms;
import org.dive4elements.river.artifacts.model.WKms;
import org.dive4elements.river.artifacts.resources.Resources;
import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair;
-import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator;
+import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
+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.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;
class FlowDepthCalculation {
// private static Logger log = Logger.getLogger(FlowDepthCalculation.class);
- private static final int VALID_BED_MEASUREMENT_YEARS = 20;
-
- private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range";
-
private final CallContext context;
public FlowDepthCalculation(final CallContext context) {
@@ -60,12 +44,7 @@
public CalculationResult calculate(final SINFOArtifact sinfo) {
- /*
- * find the user of this artifact, sadly this is not part of the calling context, so instead we determine the
- * owner oft the artifact
- */
- final ArtifactDatabase database = this.context.getDatabase();
- final String user = database.findArtifactUser(sinfo.identifier());
+ final String user = CalculationUtils.findArtifactUser(this.context, sinfo);
/* access input data */
final FlowDepthAccess access = new FlowDepthAccess(sinfo);
@@ -74,24 +53,21 @@
final Collection<DifferencesPair> diffPairs = access.getDifferencePairs();
- final double from = access.getFrom();
- final double to = access.getTo();
- final DoubleRange calcRange = new DoubleRange(from, to);
+ final DoubleRange calcRange = access.getRange();
final boolean useTkh = access.isUseTransportBodies();
/* calculate results for each diff pair */
final Calculation problems = new Calculation();
- final List<Gauge> gauges = river.determineGauges(from, to);
- final GaugeIndex gaugeIndex = new GaugeIndex(gauges);
+ final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange);
final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh);
for (final DifferencesPair diffPair : diffPairs) {
- final FlowDepthCalculationResult result = calculateResult(river, calcRange, diffPair, problems, gaugeIndex, useTkh);
+ final FlowDepthCalculationResult result = calculateResult(calcRange, diffPair, problems, infoProvider, useTkh);
if (result != null)
results.addResult(result);
}
@@ -101,15 +77,17 @@
/**
* Calculates one W-MSH differences pair.
+ *
+ * @param infoProvider
*/
- private FlowDepthCalculationResult calculateResult(final River river, final DoubleRange calcRange, final DifferencesPair diffPair,
- final Calculation problems, final GaugeIndex gaugeIndex, final boolean useTkh) {
+ private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final DifferencesPair diffPair,
+ final Calculation problems, final RiverInfoProvider infoProvider, final boolean useTkh) {
/* access real input data from database */
final String soundingId = diffPair.getSoundingId();
final String wstId = diffPair.getWstId();
- final BedHeight bedHeight = loadBedHeight(soundingId);
+ final BedHeightsFinder bedHeight = loadBedHeight(soundingId, calcRange);
if (bedHeight == null) {
final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId);
problems.addProblem(message);
@@ -126,223 +104,29 @@
final WKms wstKms = waterlevel.getWkms();
final String wspLabel = wstKms.getName();
- final String soundingLabel = bedHeight.getDescription();
+ final String soundingLabel = bedHeight.getInfo().getDescription();
final String label = String.format("%s - %s", wspLabel, soundingLabel);
- checkYearDifference(label, waterlevel, bedHeight, problems);
+ checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems);
checkWaterlevelDiscretisation(wstKms, calcRange, problems);
// TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden
/* 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);
+ final RiverInfoProvider riverInfoProvider = infoProvider.forWaterlevel(waterlevel);
- final Gauge refGauge = waterlevel.findReferenceGauge(river);
- final String refGaugeName = refGauge == null ? notinrange : refGauge.getName();
+ final int wspYear = waterlevel.getYear();
+ final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge());
- final BedHeightInfo sounding = BedHeightInfo.from(bedHeight);
- final int wspYear = waterlevel.getYear();
- final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, refGaugeName);
+ final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms);
- final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding);
+ final River river = riverInfoProvider.getRiver();
+ final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, dischargeProvider,
+ bedHeight);
- boolean doCalcTkh = useTkh;
- if (doCalcTkh && !(wstKms instanceof QKms)) {
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
- problems.addProblem(message);
- doCalcTkh = false;
- }
-
- BedQualityD50KmValueFinder bedMeasurementsFinder = null;
- if (doCalcTkh) {
- bedMeasurementsFinder = loadBedMeasurements(river, calcRange, sounding.getYear().intValue());
- if (bedMeasurementsFinder == null) {
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
- problems.addProblem(message);
- doCalcTkh = false;
- }
- }
-
- final String bedHeightLabel = bedHeight.getDescription();
- final String wstLabel = wstKms.getName();
-
- final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs());
- UnivariateRealFunction qInterpolator = null;
- DoubleRange qRange = null;
- if (doCalcTkh) {
- qInterpolator = DoubleUtil.getLinearInterpolator(((QKms) wstKms).allKms(), ((QKms) wstKms).allQs());
- if (qInterpolator != null)
- qRange = new DoubleRange(((QKms) wstKms).allQs().min(), ((QKms) wstKms).allQs().max());
- else {
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
- problems.addProblem(message);
- doCalcTkh = false;
- }
- }
-
- // FIXME: sort by station first, but in what direction?
- // FIXME: using river.getKmUp()?
- final List<BedHeightValue> values = bedHeight.getValues();
-
- final List<BedHeightValue> sortedValues = new ArrayList<>(values);
- Collections.sort(sortedValues, new BedHeightStationComparator());
-
- // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden?
- /* SoilKind lastKind = SoilKind.mobil; */
- SoilKindKmValueFinder soilKindFinder = null;
- if (doCalcTkh) {
- soilKindFinder = new SoilKindKmValueFinder();
- if (!soilKindFinder.loadValues(river, calcRange)) {
- doCalcTkh = false;
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
- problems.addProblem(message);
- }
- }
-
- FlowVelocityModelKmValueFinder flowVelocitiesFinder = null;
- if (doCalcTkh) {
- flowVelocitiesFinder = new FlowVelocityModelKmValueFinder();
- if (!flowVelocitiesFinder.loadValues(river, calcRange, qRange)) {
- doCalcTkh = false;
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingVelocity", null, label);
- problems.addProblem(message);
- }
- }
-
- for (final BedHeightValue bedHeightValue : sortedValues) {
-
- final Double station = bedHeightValue.getStation();
- if (station == null || station.isNaN())
- continue;
-
- final Double meanBedHeightDbl = bedHeightValue.getHeight();
- if (meanBedHeightDbl == null || meanBedHeightDbl.isNaN())
- continue;
-
- final double km = station;
- final double meanBedHeight = meanBedHeightDbl;
-
- if (!calcRange.containsDouble(km))
- continue;
-
- try {
- // FIXME: check out of range
- final double wst = wstInterpolator.value(km);
-
- final double flowDepth = wst - meanBedHeight;
-
- // FIXME: piecewise constant interpolation?
- // final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN;
- double discharge;
- if (qInterpolator != null)
- discharge = qInterpolator.value(km);
- else
- discharge = Double.NaN;
-
- // Calculate tkh
- double tkh = 0;
- if (doCalcTkh) {
- double d50 = Double.NaN;
- try {
- d50 = bedMeasurementsFinder.findD50(km);
- }
- catch (final Exception e) {
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingD50", null, label);
- problems.addProblem(km, message);
- // FIXME: cumulate problems to one message?
- }
- if (!Double.isNaN(d50)) {
- if (flowVelocitiesFinder.findKmQValues(km, discharge)) {
- tkh = calculateTkh(wst - meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), d50, flowVelocitiesFinder.getFindTauFound());
- if (!Double.isNaN(tkh) && (tkh < 0))
- tkh = 0;
- /*
- * log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f",
- * km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(),
- * d50*1000, tkh));
- */
- } else {
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
- problems.addProblem(km, message);
- // FIXME: cumulate problems to one message?
- }
- } else
- tkh = Double.NaN;
- }
-
- // Soil kind
- SoilKind kind = SoilKind.mobil;
- if (doCalcTkh) {
- try {
- kind = soilKindFinder.findSoilKind(km);
- }
- catch (final Exception e) {
- final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
- problems.addProblem(km, message);
- // FIXME: cumulate problems to one message?
- }
- }
-
- final double flowDepthTkh;
- final double tkhUp;
- final double tkhDown;
- switch (kind) {
- case starr:
- flowDepthTkh = wst - (meanBedHeight + tkh / 100);
- tkhUp = tkh;
- tkhDown = 0;
- break;
-
- case mobil:
- default:
- flowDepthTkh = wst - (meanBedHeight + tkh / 200);
- tkhUp = tkh / 2;
- tkhDown = -tkh / 2;
- break;
- }
-
- // 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, kind, tkh, tkhUp, tkhDown, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel,
- location);
- }
- catch (final FunctionEvaluationException e) {
- /* should only happen if out of range */
- e.printStackTrace();
- /* simply ignore */
- }
- }
-
- return resultData;
+ final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wstKms, dischargeProvider, bedHeight, tkhCalculator);
+ return calculator.execute(label, wstInfo, calcRange);
}
- /**
- * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
- * Abhängig von Peiljahr
- */
- private BedQualityD50KmValueFinder loadBedMeasurements(final River river, final DoubleRange kmRange, final int soundingYear) {
-
- /* construct valid measurement time range */
- final Calendar cal = Calendar.getInstance();
- cal.clear();
-
- cal.set(soundingYear - VALID_BED_MEASUREMENT_YEARS, 0, 1);
- final Date startTime = cal.getTime();
-
- cal.set(soundingYear + VALID_BED_MEASUREMENT_YEARS, 11, 31);
- final Date endTime = cal.getTime();
-
- final BedQualityD50KmValueFinder finder = new BedQualityD50KmValueFinder();
- if (finder.loadValues(river, kmRange, new DateRange(startTime, endTime)))
- return finder;
- else
- return null;
- }
/**
* Checks the year difference between waterlevels and sounding, and issues a warning if too big.
@@ -353,9 +137,7 @@
* 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();
+ private void checkYearDifference(final String label, final WaterlevelData waterlevel, final Integer soundingYear, final Calculation problems) {
if (soundingYear == null)
return;
@@ -388,21 +170,6 @@
return 3;
}
- private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex, final double km) {
-
- // REMARK: using same logic as in WaterlevelExporter here
-
- final boolean showAllGauges = waterlevel.isShowAllGauges();
-
- if (showAllGauges)
- return gaugeIndex.findGauge(km);
-
- if (refGauge.getRange().contains(km))
- return refGauge;
-
- return null;
- }
-
/* Checks if the discretisation of the waterlevel exceeds 1000m */
private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) {
@@ -424,7 +191,7 @@
}
}
- private BedHeight loadBedHeight(final String soundingId) {
+ private BedHeightsFinder loadBedHeight(final String soundingId, final DoubleRange calcRange) {
// REMARK: absolutely unbelievable....
// The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type
@@ -438,6 +205,11 @@
final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context);
final Integer bedheightId = artifact.getDataAsInteger("height_id");
+ if (bedheightId == null) {
+ // FIXME: error message!
+ return null;
+ }
+
// 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.
@@ -449,35 +221,6 @@
// 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);
- }
-
- /**
- * Calculates a transport body height
- *
- * @param h
- * flow depth in m
- * @param vm
- * flow velocity in m
- * @param d50
- * grain diameter D50 in m (!)
- * @param tau
- * shear stress in N/m^2
- * @return transport body height in cm (!)
- */
- private double calculateTkh(final double h, final double vm, final double d50, final double tau) {
- final double PHYS_G = 9.81;
- final double PHYS_SPECGRAV_S = 2.6;
- final double PHYS_VELOCCOEFF_N = 6;
- final double PHYS_FORMCOEFF_ALPHA = 0.7;
- final double PHYS_VISCOSITY_NUE = 1.3e-6;
- final double PHYS_GRAIN_DENSITY_RHOS = 2603;
- final double PHYS_WATER_DENSITY_RHO = 999.97;
-
- final double froude = vm / Math.sqrt(PHYS_G * h);
- final double partReynolds = Math.sqrt((PHYS_SPECGRAV_S - 1) * PHYS_G * d50) / PHYS_VISCOSITY_NUE * d50;
- final double critShields = 0.22 * Math.pow(partReynolds, -0.6) + 0.06 * Math.pow(10, 7.7 * Math.pow(partReynolds, -0.6));
- final double critTau = critShields * (PHYS_GRAIN_DENSITY_RHOS - PHYS_WATER_DENSITY_RHO) * PHYS_G * d50;
- return 100 * h * (1 - Math.pow(froude, 2)) / (2 * PHYS_VELOCCOEFF_N * PHYS_FORMCOEFF_ALPHA) * (1 - critTau / tau);
+ return BedHeightsFinder.forId(bedheightId, calcRange);
}
}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java Wed Feb 28 17:27:15 2018 +0100
@@ -9,12 +9,9 @@
*/
package org.dive4elements.river.artifacts.sinfo.flowdepth;
-import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
+import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoCalculationResult;
import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
@@ -25,53 +22,31 @@
*
* @author Gernot Belger
*/
-class FlowDepthCalculationResult implements Serializable {
+final class FlowDepthCalculationResult extends AbstractSInfoCalculationResult<FlowDepthRow> {
private static final long serialVersionUID = 1L;
- private final Collection<FlowDepthRow> rows = new ArrayList<>();
-
- private final String label;
-
private final BedHeightInfo sounding;
- private final WstInfo wst;
+ public FlowDepthCalculationResult(final String label, final WstInfo wst, final BedHeightInfo sounding, final boolean hasTkh,
+ final Collection<FlowDepthRow> rows) {
+ super(label, wst, hasTkh, rows);
- public FlowDepthCalculationResult(final String label, final WstInfo wst, final BedHeightInfo sounding) {
- this.label = label;
- this.wst = wst;
this.sounding = sounding;
}
- public void addRow(final double station, final double flowDepth, final double flowDepthWithTkh, final SoilKind tkhKind, final double tkh,
- final double tkhUp, final double tkhDown, final double waterlevel, final double discharge, final String waterlevelLabel, final String gauge,
- final double meanBedHeight, final String sondageLabel, final String location) {
- this.rows.add(new FlowDepthRow(station, flowDepth, flowDepthWithTkh, tkhKind, tkh, tkhUp, tkhDown, waterlevel, discharge, waterlevelLabel, gauge,
- meanBedHeight, sondageLabel, location));
- }
-
- public String getLabel() {
- return this.label;
- }
-
- public WstInfo getWst() {
- return this.wst;
- }
-
public BedHeightInfo getSounding() {
return this.sounding;
}
- public Collection<FlowDepthRow> getRows() {
- return Collections.unmodifiableCollection(this.rows);
- }
-
public double[][] getFlowDepthPoints() {
- final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
- final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+ final Collection<FlowDepthRow> rows = getRows();
- for (final FlowDepthRow row : this.rows) {
+ final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size());
+ final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size());
+
+ for (final FlowDepthRow row : rows) {
xPoints.add(row.getStation());
yPoints.add(row.getFlowDepth());
}
@@ -81,85 +56,16 @@
public double[][] getFlowDepthTkhPoints() {
- final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
- final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+ final Collection<FlowDepthRow> rows = getRows();
- for (final FlowDepthRow row : this.rows) {
+ final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size());
+ final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size());
+
+ for (final FlowDepthRow row : rows) {
xPoints.add(row.getStation());
yPoints.add(row.getFlowDepthWithTkh());
}
return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
}
-
- public double[][] getTkhUpPoints() {
- final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
- final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
- final List<SoilKind> kinds = new ArrayList<>(this.rows.size());
-
- for (final FlowDepthRow row : this.rows) {
- xPoints.add(row.getStation());
- yPoints.add(row.getTkhUp());
- kinds.add(row.getTkhKind());
- }
-
- return adjustTkhVisualization(xPoints, yPoints, kinds);
- }
-
- public double[][] getTkhDownPoints() {
- final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
- final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
- final List<SoilKind> kinds = new ArrayList<>(this.rows.size());
-
- for (final FlowDepthRow row : this.rows) {
- xPoints.add(row.getStation());
- yPoints.add(row.getTkhDown());
- kinds.add(row.getTkhKind());
- }
-
- return adjustTkhVisualization(xPoints, yPoints, kinds);
- }
-
- /**
- * the up and down points must be further adjusted for visualization, see Mail Hr. Reiß
- * basically we need to introduce extra points when the kind changes, so we get vertical lines in that case
- */
- private double[][] adjustTkhVisualization(final TDoubleArrayList xPoints, final TDoubleArrayList yPoints, final List<SoilKind> kinds) {
-
- final TDoubleArrayList adjustedX = new TDoubleArrayList(xPoints.size());
- final TDoubleArrayList adjustedY = new TDoubleArrayList(yPoints.size());
-
- adjustedX.add(xPoints.get(0));
- adjustedY.add(yPoints.get(0));
-
- for (int i = 1; i < xPoints.size(); i++) {
-
- final SoilKind kind1 = kinds.get(i - 1);
- final SoilKind kind2 = kinds.get(i);
-
- if (kind1 != kind2) {
- /* introduce two extra points in order to create a vertical line in the middle of the two adjacent points */
- final double x1 = xPoints.get(i - 1);
- final double y1 = yPoints.get(i - 1);
- final double x2 = xPoints.get(i);
- final double y2 = yPoints.get(i);
-
- final double middleX = (x1 + x2) / 2;
-
- // REMARK: we can't produce a 100% vertical line, as the area-renderer will not work correctly
- adjustedX.add(middleX - 0.0001);
- adjustedY.add(y1);
-
- adjustedX.add(middleX + 0.0001);
- adjustedY.add(y2);
- }
-
- /* always add the real point now */
- adjustedX.add(xPoints.get(i));
- adjustedY.add(yPoints.get(i));
- }
-
-
- return new double[][] { adjustedX.toNativeArray(), adjustedY.toNativeArray() };
- }
}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java Wed Feb 28 17:27:15 2018 +0100
@@ -20,7 +20,7 @@
/**
* @author Gernot Belger
*/
-public final class FlowDepthCalculationResults implements Serializable {
+final class FlowDepthCalculationResults implements Serializable {
private static final long serialVersionUID = 1L;
private final List<FlowDepthCalculationResult> results = new ArrayList<>();
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,129 @@
+/** 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.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.dive4elements.river.artifacts.model.WKms;
+import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.SoilKind;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator;
+import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+import org.dive4elements.river.utils.DoubleUtil;
+
+/**
+ * @author Gernot Belger
+ */
+final class FlowDepthCalculator {
+
+ private final Collection<FlowDepthRow> rows = new ArrayList<>();
+
+ private final DischargeValuesFinder dischargeProvider;
+
+ private final BedHeightsFinder bedHeight;
+
+ private final TkhCalculator tkhCalculator;
+
+ private final PolynomialSplineFunction wstInterpolator;
+
+ private final RiverInfoProvider riverInfoProvider;
+
+ private final String bedHeightLabel;
+
+ private final String wstLabel;
+
+ public FlowDepthCalculator(final RiverInfoProvider riverInfoProvider, final WKms wstKms,
+ final DischargeValuesFinder dischargeProvider, final BedHeightsFinder bedHeight, final TkhCalculator tkhCalculator) {
+
+ this.riverInfoProvider = riverInfoProvider;
+
+ this.dischargeProvider = dischargeProvider;
+ this.bedHeight = bedHeight;
+ this.tkhCalculator = tkhCalculator;
+
+ this.wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs());
+
+ this.bedHeightLabel = bedHeight.getInfo().getDescription();
+ this.wstLabel = wstKms.getName();
+ }
+
+ public FlowDepthCalculationResult execute(final String label, final WstInfo wstInfo, final DoubleRange calcRange) {
+
+ final Collection<Double> stations = this.bedHeight.getStations();
+ for (final Double station : stations) {
+ if (calcRange.containsDouble(station))
+ calculateResultRow(station);
+ }
+
+ return new FlowDepthCalculationResult(label, wstInfo, this.bedHeight.getInfo(), this.tkhCalculator != null, this.rows);
+ }
+
+ private void calculateResultRow(final double station) {
+
+ try {
+ // FIXME: check out of range of waterlevel?
+ final double wst = this.wstInterpolator.value(station);
+
+ final Tkh tkh = calculateTkh(station, wst);
+
+ final double meanBedHeight = tkh.getMeanBedHeight();
+
+ final double flowDepth = wst - meanBedHeight;
+ final double flowDepthTkh = calculateFlowDepthTkh(tkh, wst, meanBedHeight);
+
+ // REMARK: access the location once only during calculation
+ final String location = this.riverInfoProvider.getLocation(station);
+
+ // REMARK: access the gauge once only during calculation
+ final String gaugeLabel = this.riverInfoProvider.findGauge(station);
+
+ this.rows.add(new FlowDepthRow(flowDepth, flowDepthTkh, tkh, this.wstLabel, gaugeLabel, this.bedHeightLabel, location));
+ }
+ catch (final FunctionEvaluationException e) {
+ /* should only happen if out of range */
+ e.printStackTrace();
+ /* simply ignore */
+ }
+ }
+
+ private Tkh calculateTkh(final double station, final double wst) throws FunctionEvaluationException {
+ if (this.tkhCalculator == null) {
+ final double discharge = this.dischargeProvider.getDischarge(station);
+ final double meanBedHeight = this.bedHeight.getMeanBedHeight(station);
+ return new Tkh(station, wst, meanBedHeight, discharge);
+ }
+
+ return this.tkhCalculator.getTkh(station, wst);
+ }
+
+ private double calculateFlowDepthTkh(final Tkh tkh, final double wst, final double meanBedHeight) {
+ final double tkhValue = tkh.getTkh();
+ final SoilKind tkhKind = tkh.getKind();
+
+ if (Double.isNaN(tkhValue) || tkhKind == null)
+ return Double.NaN;
+
+ switch (tkhKind) {
+ case starr:
+ return wst - (meanBedHeight + tkhValue / 100);
+
+ case mobil:
+ default:
+ return wst - (meanBedHeight + tkhValue / 200);
+ }
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java Wed Feb 28 17:27:15 2018 +0100
@@ -9,66 +9,31 @@
*/
package org.dive4elements.river.artifacts.sinfo.flowdepth;
-import java.io.Serializable;
+import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoResultRow;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
/**
* Part of {@link FlowDepthCalculationResult} which represents one calculated row of flow depth data.
*
* @author Gernot Belger
*/
-final class FlowDepthRow implements Serializable {
+final class FlowDepthRow extends AbstractSInfoResultRow {
private static final long serialVersionUID = 1L;
- private final double station;
-
private final double flowDepth;
private final double flowDepthWithTkh;
- private final SoilKind tkhKind;
+ private final String soundingLabel;
- private final double tkh;
+ public FlowDepthRow(final double flowDepth, final double flowDepthWithTkh, final Tkh tkh, final String waterlevelLabel,
+ final String gauge, final String soundingLabel, final String location) {
- private final double tkhUp;
+ super(tkh, waterlevelLabel, gauge, location);
- private final double tkhDown;
-
- private final double waterlevel;
-
- private final double discharge;
-
- private final String waterlevelLabel;
-
- private final String gauge;
-
- private final double meanBedHeight;
-
- private final String soundageLabel;
-
- private final String location;
-
- public FlowDepthRow(final double station, final double flowDepth, final double flowDepthWithTkh, final SoilKind tkhKind, final double tkh,
- final double tkhUp, final double tkhDown,
- final double waterlevel, final double discharge, final String waterlevelLabel, final String gauge, final double meanBedHeight,
- final String soundageLabel, final String location) {
- this.station = station;
this.flowDepth = flowDepth;
this.flowDepthWithTkh = flowDepthWithTkh;
- this.tkhKind = tkhKind;
- this.tkh = tkh;
- this.tkhUp = tkhUp;
- this.tkhDown = tkhDown;
- this.waterlevel = waterlevel;
- this.discharge = discharge;
- this.waterlevelLabel = waterlevelLabel;
- this.gauge = gauge;
- this.meanBedHeight = meanBedHeight;
- this.soundageLabel = soundageLabel;
- this.location = location;
- }
-
- public double getStation() {
- return this.station;
+ this.soundingLabel = soundingLabel;
}
public double getFlowDepth() {
@@ -79,47 +44,7 @@
return this.flowDepthWithTkh;
}
- public SoilKind getTkhKind() {
- return this.tkhKind;
- }
-
- public double getTkh() {
- return this.tkh;
- }
-
- public double getTkhUp() {
- return this.tkhUp;
- }
-
- public double getTkhDown() {
- return this.tkhDown;
- }
-
- public double getWaterlevel() {
- return this.waterlevel;
- }
-
- public double getDischarge() {
- return this.discharge;
- }
-
- public String getWaterlevelLabel() {
- return this.waterlevelLabel;
- }
-
- public String getGauge() {
- return this.gauge;
- }
-
- public double getMeanBedHeight() {
- return this.meanBedHeight;
- }
-
public String getSoundageLabel() {
- return this.soundageLabel;
- }
-
- public String getLocation() {
- return this.location;
+ return this.soundingLabel;
}
}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowVelocityModelKmValueFinder.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowVelocityModelKmValueFinder.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +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.sinfo.flowdepth;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang.math.DoubleRange;
-import org.apache.log4j.Logger;
-import org.hibernate.SQLQuery;
-import org.hibernate.Session;
-import org.hibernate.type.StandardBasicTypes;
-
-import gnu.trove.TDoubleArrayList;
-
-import org.dive4elements.river.artifacts.math.Linear;
-import org.dive4elements.river.artifacts.math.Utils;
-import org.dive4elements.river.backend.SessionHolder;
-import org.dive4elements.river.model.River;
-
-/**
- * Searchable sorted km array with parallel FlowVelocityKmModelValues array and linear interpolation for km and the model values between the array elements.<br />
- * {@link loadValues} loads all the model values for a given km range of a river.<br />
- * {@link findKmQValues} then searches a km in the values table or the nearest including km interval, resp.
- * The v and tau values for a given discharge are either found directly or also interpolated linearly.<br />
- *
- * (Created based on a copy of FlowVelocityMeasurementFactory.)
- *
- * @author Matthias Schäfer
- *
- */
-public class FlowVelocityModelKmValueFinder
-{
- /***** FIELDS *****/
-
- /**
- * Private log to use here.
- */
- private static Logger log = Logger.getLogger(FlowVelocityModelKmValueFinder.class);
-
- /**
- * Query for a range of stations of a river with all their q, main-v and tau values.<br />
- * (Might be several 10000 rows if many stations and large q range)
- */
- private static final String SQL_SELECT_ALL =
- "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
- + " FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
- + " INNER JOIN flow_velocity_model_values fvmv ON fvm.id = fvmv.flow_velocity_model_id"
- + " WHERE (dz.river_id = :river_id) AND (fvmv.station BETWEEN :kmfrom - 0.0001 AND :kmto + 0.0001)"
- /* + " WHERE (dz.river_id = :river_id) AND (fvmv.q BETWEEN :qmin AND :qmax)" */
- + " ORDER BY fvmv.station ASC, fvmv.q ASC";
-
- /**
- * Query for a river's max km below a limit with all its q, main-v and tau values.
- */
- private static final String SQL_SELECT_KMLOWER =
- "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
- + " FROM flow_velocity_model_values fvmv"
- + " INNER JOIN (SELECT MAX(fvmvi.station) AS kmmax"
- + " FROM(discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
- + " INNER JOIN flow_velocity_model_values fvmvi ON fvm.id = fvmvi.flow_velocity_model_id"
- + " WHERE (dz.river_id = :river_id) AND (fvmvi.station < :kmfrom - 0.0001)) finf ON fvmv.station = finf.kmmax"
- + " ORDER BY fvmv.q ASC";
-
- /**
- * Query for a river's min km above a limit with all its q, main-v and tau values.
- */
- private static final String SQL_SELECT_KMUPPER =
- "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
- + " FROM flow_velocity_model_values fvmv"
- + " INNER JOIN (SELECT MIN(fvmvi.station) AS kmmin"
- + " FROM(discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
- + " INNER JOIN flow_velocity_model_values fvmvi ON fvm.id = fvmvi.flow_velocity_model_id"
- + " WHERE (dz.river_id = :river_id) AND (fvmvi.station > :kmto + 0.0001)) fsup ON fvmv.station = fsup.kmmin"
- + " ORDER BY fvmv.q ASC";
-
- /**
- * Query to select all km-q-v-tau of a river that are the q maxima below a q limit
- */
- private static final String SQL_SELECT_QLOWER =
- "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
- + " FROM flow_velocity_model_values fvmv"
- + " INNER JOIN (SELECT fv2.station, MAX(fv2.q) AS q"
- + " FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
- + " INNER JOIN flow_velocity_model_values fv2 ON fvm.id = fv2.flow_velocity_model_id"
- + " WHERE (dz.river_id = :river_id) AND (fv2.q < :qlim) GROUP BY fv2.station) qx"
- + " ON (fvmv.station=qx.station) AND (fvmv.q=qx.q)"
- + " ORDER BY fvmv.station ASC";
-
- /**
- * Query to select all km-q-v-tau of a river that are the q minima above a q limit
- */
- private static final String SQL_SELECT_QUPPER =
- "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
- + " FROM flow_velocity_model_values fvmv"
- + " INNER JOIN (SELECT fv2.station, MIN(fv2.q) AS q"
- + " FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
- + " INNER JOIN flow_velocity_model_values fv2 ON fvm.id = fv2.flow_velocity_model_id"
- + " WHERE (dz.river_id = :river_id) AND (fv2.q > :qlim) GROUP BY fv2.station) qx"
- + " ON (fvmv.station=qx.station) AND (fvmv.q=qx.q)"
- + " ORDER BY fvmv.station ASC";
-
- /**
- * Kms of the loaded river range
- */
- private TDoubleArrayList kms;
-
- /**
- * For each km in kms a list of q-v-tau-tupels
- */
- private List<FlowVelocityKmModelValues> values;
-
- /**
- * Searched km of the last findKmValue
- */
- private double findKm;
-
- /**
- * kms and values index of the interval start found by the last findKmValue
- */
- private int leftIndexFound = -1;
-
- /**
- * kms and values index of the interval end found by the last findKmValue
- */
- private int rightIndexFound = -1;
-
- /**
- * Q of the last findKmQValues
- */
- private double findQ;
-
- /***** METHODS *****/
-
- /**
- * Discharge of the last {@link findKmQValue}
- */
- public double getFindQ() {
- return findQ;
- }
-
- /**
- * Velocity of the last {@link findKmQValues}
- */
- public double getFindVmainFound() {
- if (leftIndexFound < 0)
- return Double.NaN;
- else if (leftIndexFound == rightIndexFound)
- return getLeftValues().getVmainFound();
- else
- return Linear.linear(findKm, getLeftValues().getKm(), getRightValues().getKm(), getLeftValues().getVmainFound(), getRightValues().getVmainFound());
- }
-
- /**
- * Shear stress tau of the last {@link findKmQValues}
- */
- public double getFindTauFound() {
- if (leftIndexFound < 0)
- return Double.NaN;
- else if (leftIndexFound == rightIndexFound)
- return getLeftValues().getTauFound();
- else
- return Linear.linear(findKm, getLeftValues().getKm(), getRightValues().getKm(), getLeftValues().getTauFound(), getRightValues().getTauFound());
- }
-
- /**
- * Whether the discharge has been interpolated in the last {@link findKmQValues}
- */
- public boolean getFindIsQInterpolated() {
- return (getLeftValues() != null) && (getLeftValues().getIsInterpolated() || getRightValues().getIsInterpolated());
- }
-
- /**
- * Queries a range of a river's kms with all their q-v-tau values.
- * @return Whether the load has been successful
- */
- @SuppressWarnings("unchecked")
- public boolean loadValues(River river, DoubleRange kmRange, DoubleRange qRange) {
- // DB session
- log.debug(String.format("loadValues km %.3f - %.3f / q %.1f - %.1f", kmRange.getMinimumDouble(), kmRange.getMaximumDouble(), qRange.getMinimumDouble(), qRange.getMaximumDouble()));
- kms = new TDoubleArrayList();
- values = new ArrayList<FlowVelocityKmModelValues>();
- boolean isDemoValuesCorrection = river.getName().equalsIgnoreCase("beispielfluss");
- final Session session = SessionHolder.HOLDER.get();
-
- // Select km infimum
- SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_KMLOWER)
- .addScalar("station", StandardBasicTypes.DOUBLE)
- .addScalar("q", StandardBasicTypes.DOUBLE)
- .addScalar("vmain", StandardBasicTypes.DOUBLE)
- .addScalar("tau", StandardBasicTypes.DOUBLE);
- sqlQuery.setParameter("river_id", river.getId());
- sqlQuery.setParameter("kmfrom", kmRange.getMinimumDouble());
- addKms(sqlQuery.list(), isDemoValuesCorrection);
-
- // Select km range
- sqlQuery = session.createSQLQuery(SQL_SELECT_ALL)
- .addScalar("station", StandardBasicTypes.DOUBLE)
- .addScalar("q", StandardBasicTypes.DOUBLE)
- .addScalar("vmain", StandardBasicTypes.DOUBLE)
- .addScalar("tau", StandardBasicTypes.DOUBLE);
- sqlQuery.setParameter("river_id", river.getId());
- sqlQuery.setParameter("kmfrom", kmRange.getMinimumDouble());
- sqlQuery.setParameter("kmto", kmRange.getMaximumDouble());
- //sqlQuery.setParameter("qmin", qRange.getMinimumDouble());
- //sqlQuery.setParameter("qmax", qRange.getMaximumDouble());
- int kmcount = kms.size();
- int rowcount = addKms(sqlQuery.list(), isDemoValuesCorrection);
- kmcount = kms.size() - kmcount;
-
- // Select km supremum
- sqlQuery = session.createSQLQuery(SQL_SELECT_KMUPPER)
- .addScalar("station", StandardBasicTypes.DOUBLE)
- .addScalar("q", StandardBasicTypes.DOUBLE)
- .addScalar("vmain", StandardBasicTypes.DOUBLE)
- .addScalar("tau", StandardBasicTypes.DOUBLE);
- sqlQuery.setParameter("river_id", river.getId());
- sqlQuery.setParameter("kmto", kmRange.getMaximumDouble());
- int supcnt = addKms(sqlQuery.list(), isDemoValuesCorrection);
-
- // Add copy of last km for search of max km value
- if ((supcnt == 0) && (values.size() >= 1)) {
- kms.add(kms.getQuick(kms.size()) + 0.0001);
- values.add(new FlowVelocityKmModelValues(kms.getQuick(kms.size()-1), values.get(values.size()-1)));
- }
-
- // log.debug
- if (values.size() - 1 >= 0) {
- log.debug(String.format("loadValues %d: km %.3f - %d values", 0, values.get(0).getKm(), values.get(0).size()));
- if (values.size() - 1 >= 1) {
- log.debug(String.format("loadValues %d: km %.3f - %d values", 1, values.get(1).getKm(), values.get(1).size()));
- if (values.size() - 1 >= 2)
- log.debug("loadValues ...");
- if (values.size() - 2 >= 3)
- log.debug(String.format("loadValues %d: km %.3f - %d values", values.size()-2, values.get(values.size()-2).getKm(), values.get(values.size()-2).size()));
- if (values.size() - 1 >= 3)
- log.debug(String.format("loadValues %d: km %.3f - %d values", values.size()-1, values.get(values.size()-1).getKm(), values.get(values.size()-1).size()));
- }
- }
- log.debug(String.format("loadValues %d kms, %d values loaded", kmcount, rowcount));
- return (kms.size() >= 1);
- }
-
- /**
- * Adds the km-q-v-tau values of a query result row to the last km of the list, or a new one resp.
- * @return Number of rows
- */
- private int addKms(List<Object[]> rows, boolean isDemoValuesCorrection) {
- for (Object[] row : rows) {
- if ((kms.size() == 0) || !Utils.epsilonEquals(kms.get(kms.size()-1), (double) row[0], 0.0001)) {
- kms.add((double) row[0]);
- values.add(new FlowVelocityKmModelValues(kms.get(kms.size()-1)));
- }
- if (isDemoValuesCorrection)
- // "Verfremdung" der v-Werte etwas korrigieren (Originalwerte wurden mit Zufallswert zwischen 10 und 20 multipliziert)
- values.get(values.size()-1).addValues((double) row[1], ((double) row[2]) / 10, (double) row[3]);
- else
- values.get(values.size()-1).addValues((double) row[1], (double) row[2], (double) row[3]);
- }
- return rows.size();
- }
-
- /**
- * Searches a km and finds or interpolates the velocity and shear stress values for a discharge<br />
- * The values may be got via {@link getVmainFound} etc.
- * @return Whether values have been found
- */
- public boolean findKmQValues(double km, double q) {
- findQ = q;
- if (!searchKm(km))
- return false;
- if (leftIndexFound == rightIndexFound) {
- // Exact km match
- final double qfound = getLeftValues().findQ(q);
- log.debug(String.format("findKmQValues km %.3f q %.0f = %.0f (%d)", km, q, qfound, leftIndexFound));
- return !Double.isNaN(qfound);
- }
- else {
- final double[] qfound = {getLeftValues().findQ(q), getRightValues().findQ(q)};
- log.debug(String.format("findKmQValues km %.3f q %.0f = %.0f (%d, %.3f) - %.0f (%d, %.3f)", km, q, qfound[0], leftIndexFound,
- getLeftValues().getKm(), qfound[1], rightIndexFound, getRightValues().getKm()));
- return !Double.isNaN(qfound[0]) && !Double.isNaN(qfound[1]);
- }
- }
-
- /**
- * Searches a km
- * @return Whether the km was within the supported range
- */
- private boolean searchKm(double km) {
- findKm = km;
- leftIndexFound = -1;
- rightIndexFound = -1;
- if ((kms == null) || (kms.size() == 0))
- return false;
- int i = kms.binarySearch(km);
- if (i >= 0) {
- // Exact km match
- leftIndexFound = i;
- rightIndexFound = i;
- return true;
- }
- else {
- // Out of range or within km interval
- if (i < 0)
- i = -i - 1;
- if ((i <= 0) || (i >= kms.size()))
- return false;
- leftIndexFound = i - 1;
- rightIndexFound = i;
- return true;
- }
- }
-
- private FlowVelocityKmModelValues getLeftValues() {
- return values.get(leftIndexFound);
- }
- private FlowVelocityKmModelValues getRightValues() {
- return values.get(rightIndexFound);
- }
-
-}
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/SoilKind.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/SoilKind.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +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.sinfo.flowdepth;
-
-public enum SoilKind {
- mobil, starr
-}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/SoilKindKmValueFinder.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/SoilKindKmValueFinder.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +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.sinfo.flowdepth;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang.math.DoubleRange;
-import org.apache.commons.math.ArgumentOutsideDomainException;
-import org.apache.log4j.Logger;
-import org.dive4elements.river.model.River;
-
-import gnu.trove.TDoubleArrayList;
-
-/**
- * @author matthias
- *
- */
-public class SoilKindKmValueFinder
-{
- /**
- * Private log to use here.
- */
- private static Logger log = Logger.getLogger(SoilKindKmValueFinder.class);
-
- private TDoubleArrayList kms;
-
- private List<SoilKind> values;
-
- /***** METHODS *****/
-
- /**
- * Searches a km with its soil kind
- */
- public SoilKind findSoilKind(double km) throws ArgumentOutsideDomainException {
- if ((kms == null) || (kms.size() == 0))
- throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN);
- int i = kms.binarySearch(km);
- if (i >= 0) {
- // Exact km match
- return values.get(i);
- }
- else {
- // Out of range or within km interval
- if (i < 0)
- i = -i - 1;
- if ((i <= 0) || (i >= kms.size()))
- throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN);
- if (km <= ((kms.get(i-1) + kms.get(i)) / 2))
- return values.get(i-1);
- else
- return values.get(i);
- }
- }
-
- /**
- * Loads the range of the river's kms with their soil kind.
- * @return Whether the load has been successful
- */
- public boolean loadValues(River river, DoubleRange kmRange) {
- kms = new TDoubleArrayList();
- values = new ArrayList<SoilKind>();
- //FIXME Echte Daten aus der Datenbank abfragen
- addKmKind(0, SoilKind.starr);
- addKmKind(15.7, SoilKind.mobil);
- addKmKind(15.8, SoilKind.mobil);
- addKmKind(15.9, SoilKind.starr);
- addKmKind(108.7, SoilKind.mobil);
- addKmKind(108.8, SoilKind.mobil);
- addKmKind(108.9, SoilKind.starr);
- addKmKind(119.1, SoilKind.mobil);
- addKmKind(119.4, SoilKind.mobil);
- addKmKind(119.5, SoilKind.starr);
- addKmKind(128.3, SoilKind.mobil);
- addKmKind(128.9, SoilKind.mobil);
- addKmKind(129, SoilKind.starr);
- addKmKind(133.1, SoilKind.mobil);
- addKmKind(135.9, SoilKind.mobil);
- addKmKind(136, SoilKind.starr);
- addKmKind(136.5, SoilKind.mobil);
- addKmKind(139.9, SoilKind.mobil);
- addKmKind(140, SoilKind.starr);
- addKmKind(140.5, SoilKind.mobil);
- addKmKind(165, SoilKind.mobil);
- addKmKind(165.1, SoilKind.starr);
- addKmKind(165.9, SoilKind.mobil);
- addKmKind(180.8, SoilKind.mobil);
- addKmKind(180.9, SoilKind.starr);
- addKmKind(182, SoilKind.mobil);
- addKmKind(221.3, SoilKind.mobil);
- return true;
- }
-
- private void addKmKind(double km, SoilKind kind) {
- kms.add(km);
- values.add(kind);
- }
-}
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkh/TkhState.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkh/TkhState.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * 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.tkh;
-
-import java.util.List;
-
-import org.dive4elements.artifactdatabase.state.Facet;
-import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.ChartArtifact;
-import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.WINFOArtifact;
-import org.dive4elements.river.artifacts.model.Calculation;
-import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.EmptyFacet;
-import org.dive4elements.river.artifacts.model.WQKms;
-import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
-import org.dive4elements.river.artifacts.states.DefaultState;
-
-/** State in which a waterlevel has been calculated. */
-public class TkhState extends DefaultState {
-
- /// ** The log that is used in this state. */
- // private static Logger log = Logger.getLogger(FlowDepthState.class);
-
- private static final long serialVersionUID = 1L;
-
- private static final String I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.filtered.description";
-
- private static final String I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.tkh.filtered.description";
-
- private static final String I18N_FACET_TKH_DESCRIPTION = "sinfo.facet.tkh.description";
-
- private static final String SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL = "sinfo.chart.flow_depth.yaxis.label";
-
- private static final String SINFO_CHART_TKX_YAXIS_LABEL = "sinfo.chart.tkh.yaxis.label";
-
- /**
- * From this state can only be continued trivially.
- */
- @Override
- protected String getUIProvider() {
- return "continue";
- }
-
- @Override
- public Object computeFeed(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
- // FIXME: why is this necessary?
- if (artifact instanceof ChartArtifact) {
- facets.add(new EmptyFacet());
- return null;
- }
-
- return compute((SINFOArtifact) artifact, context, hash, facets, old);
- }
-
- @Override
- public Object computeAdvance(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
- if (artifact instanceof ChartArtifact) {
- facets.add(new EmptyFacet());
- return null;
- }
- return compute((SINFOArtifact) artifact, context, hash, facets, old);
- }
-
- /**
- * Compute result or returned object from cache, create facets.
- *
- * @param old
- * Object that was cached.
- */
- private Object compute(final SINFOArtifact sinfo, final CallContext context, final String hash, final List<Facet> facets, final Object old) {
-
- final CalculationResult res = doCompute(sinfo, context, old);
-
- if (facets == null)
- return res;
-
- // final FlowDepthCalculationResults results = (FlowDepthCalculationResults) res.getData();
- //
- // /* add themes for chart, for each result */
- // final List<FlowDepthCalculationResult> resultList = results.getResults();
- // for (int index = 0; index < resultList.size(); index++) {
- //
- // final FlowDepthCalculationResult result = resultList.get(index);
- //
- // /* filtered (zoom dependent mean) flow depth */
- // final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(),
- // I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION,
- // I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, result.getLabel());
- // facets.add(new FlowDepthFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED, facetFlowDepthFilteredDescription,
- // SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
- //
- // if (results.isUseTkh()) {
- // /* filtered (zoom dependent mean) flow depth including tkh */
- // final String facetFlowDepthTkhFilteredDescription = Resources.getMsg(context.getMeta(),
- // I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION,
- // I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION, result.getLabel());
- // facets.add(new FlowDepthFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_TKH_FILTERED,
- // facetFlowDepthTkhFilteredDescription,
- // SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
- //
- // // FIXME: add other themes
- // // - Streckenfavoriten
- //
- // // FIXME:
- // // - Gemittelte Linie der Fließtiefe mitsamt TKH
- // // - Transportkörperhöhen (oben/unten/schraffur)
- // final String facetTkhDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_DESCRIPTION,
- // I18N_FACET_TKH_DESCRIPTION,
- // result.getLabel());
- // facets.add(new FlowDepthFacet(index, TkhProcessor.FACET_TKH, facetTkhDescription, SINFO_CHART_TKX_YAXIS_LABEL,
- // ComputeType.ADVANCE, this.id,
- // hash));
- // }
- //
- // // FIXME: Datenkorbkonfiguration
- // }
- //
- // if (!resultList.isEmpty()) {
- // final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
- // final Facet pdf = new DataFacet(FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id);
- //
- // facets.add(csv);
- // facets.add(pdf);
- // }
- //
- // final Calculation report = res.getReport();
- //
- // if (report.hasProblems()) {
- // facets.add(new ReportFacet(ComputeType.ADVANCE, hash, this.id));
- // }
- //
- // return res;
- return null;
- }
-
- private CalculationResult doCompute(final SINFOArtifact sinfo, final CallContext context, final Object old) {
- if (old instanceof CalculationResult)
- return (CalculationResult) old;
-
- // res = new FlowDepthCalculation(context).calculate(sinfo);
-
- final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo);
-
- final CalculationResult waterlevelData = winfo.getWaterlevelData(context);
- final Calculation winfoProblems = waterlevelData.getReport();
-
- final WQKms[] kms = (WQKms[]) waterlevelData.getData();
-
- final Object result = new Object();
- final Calculation problems = new Calculation();
-
- return new CalculationResult(result, problems);
- }
-}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkh/WinfoArtifactWrapper.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkh/WinfoArtifactWrapper.java Tue Feb 27 18:06:52 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +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.sinfo.tkh;
-
-import java.util.Collection;
-
-import org.dive4elements.artifactdatabase.data.DefaultStateData;
-import org.dive4elements.artifactdatabase.data.StateData;
-import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.WINFOArtifact;
-
-/**
- * Ugly wrapper around WINfoArtifact in order to a) not to break serialization of WInfoArtifact b) be able to copy data
- * into it
- *
- * @author Gernot Belger
- *
- */
-class WinfoArtifactWrapper extends WINFOArtifact {
-
- private static final long serialVersionUID = 1L;
-
- public WinfoArtifactWrapper(final D4EArtifact dataSource) {
- final Collection<StateData> allData = dataSource.getAllData();
- for (final StateData stateData : allData) {
-
- final DefaultStateData clonedData = new DefaultStateData();
- clonedData.set(stateData);
-
- addData(clonedData.getName(), clonedData);
- }
-
- addStringData("calculation_mode", "calc.surface.curve");
- }
-}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/BedQualityD50KmValueFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/BedQualityD50KmValueFinder.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,260 @@
+/* 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.tkhcalculation;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.ArgumentOutsideDomainException;
+import org.apache.commons.math.analysis.interpolation.LinearInterpolator;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.log4j.Logger;
+import org.dive4elements.river.backend.SedDBSessionHolder;
+import org.dive4elements.river.model.River;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+/**
+ * Searchable sorted km array with parallel bed measurements value array and linear interpolation for km and d50 between
+ * the array elements.<br />
+ * <br />
+ * See comment of SQL command on how the values are filtered and aggregated.
+ *
+ * @author Matthias Schäfer
+ *
+ */
+final class BedQualityD50KmValueFinder {
+
+ /***** INNER CLASSES *****/
+
+ /**
+ * A bed measurements aggregate with its d50 characteristic grain diameter
+ */
+ private static class D50Measurement {
+ private double km;
+
+ public double getKm() {
+ return this.km;
+ }
+
+ // private Date mindate;
+
+ // public Date getMinDate() {
+ // return this.mindate;
+ // }
+
+ // private Date maxdate;
+
+ // public Date getMaxDate() {
+ // return this.maxdate;
+ // }
+
+ private int cnt;
+
+ public int getCnt() {
+ return this.cnt;
+ }
+
+ // private double mindepth;
+
+ // public double getMinDepth() {
+ // return this.mindepth;
+ // }
+
+ // private double maxdepth;
+
+ // public double getMaxDepth() {
+ // return this.maxdepth;
+ // }
+
+ private double d50;
+
+ /**
+ * D50 in m
+ */
+ public double getD50() {
+ return this.d50;
+ }
+
+ // /**
+ // * Parameter constructor
+ // */
+ // public D50Measurement(final double km, final Date mindate, final Date maxdate, final int cnt, final double mindepth,
+ // final double maxdepth,
+ // final double d50mm) {
+ // this.km = km;
+ // this.mindate = mindate;
+ // this.maxdate = maxdate;
+ // this.cnt = cnt;
+ // this.mindepth = mindepth;
+ // this.maxdepth = maxdepth;
+ // this.d50 = d50mm / 1000;
+ // }
+
+ /**
+ * Query result row constructor
+ */
+ public D50Measurement(final Object[] tuple, final String[] aliases) {
+ this.km = 0;
+ // this.mindate = null;
+ // this.maxdate = null;
+ this.cnt = 0;
+ // this.mindepth = Double.NaN;
+ // this.maxdepth = Double.NaN;
+ this.d50 = Double.NaN;
+ for (int i = 0; i < tuple.length; ++i) {
+ if (tuple[i] == null)
+ continue;
+ switch (aliases[i]) {
+ case "km":
+ this.km = ((Number) tuple[i]).doubleValue();
+ break;
+ // case "mindate":
+ // this.mindate = (Date) tuple[i];
+ // break;
+ // case "maxdate":
+ // this.maxdate = (Date) tuple[i];
+ // break;
+ case "cnt":
+ this.cnt = ((Number) tuple[i]).intValue();
+ break;
+ // case "mindepth":
+ // this.mindepth = ((Number) tuple[i]).doubleValue();
+ // break;
+ // case "maxdepth":
+ // this.maxdepth = ((Number) tuple[i]).doubleValue();
+ // break;
+ case "d50":
+ this.d50 = ((Number) tuple[i]).doubleValue() / 1000; // mm to m
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /***** FIELDS *****/
+
+ /**
+ * Private log to use here.
+ */
+ private static Logger log = Logger.getLogger(BedQualityD50KmValueFinder.class);
+
+ /**
+ * Query that aggregates by km for a km range and a time period all sub layer bed measurements with their d50<br />
+ * <br />
+ * A km may have bed measurements for multiple dates, multiple distances from the river bank, and multiple depth layers.
+ * The query filters by km range, time period and layer (sub layer: below bed to max. 50 cm depth).
+ * Those measurements are then grouped by km, and the D50 aggregated as average value.
+ */
+ private static final String SQL_BED_D50_SUBLAYER_MEASUREMENT =
+ "SELECT t.km, MIN(t.datum) AS mindate, MAX(t.datum) AS maxdate, COUNT(*) AS cnt," //
+ + " MIN(p.tiefevon) AS mindepth, MAX(p.tiefebis) AS maxdepth, AVG(a.d50) AS d50" //
+ + " FROM sohltest t INNER JOIN station s ON t.stationid = s.stationid" //
+ + " INNER JOIN gewaesser g ON s.gewaesserid = g.gewaesserid" //
+ + " INNER JOIN sohlprobe p ON t.sohltestid = p.sohltestid" //
+ + " INNER JOIN siebanalyse a ON p.sohlprobeid = a.sohlprobeid" //
+ + " WHERE (g.name = :name) AND (s.km BETWEEN :fromkm - 0.0001 AND :tokm + 0.0001)" //
+ + " AND (p.tiefevon > 0.0) AND (p.tiefebis <= 0.5)" //
+ + " AND (t.datum BETWEEN :fromdate AND :todate)" //
+ + " GROUP BY t.km" //
+ + " ORDER BY t.km"; //
+
+ private static final String[] SQL_BED_D50_SELECT_ALIAS = { "km", "mindate", "maxdate", "cnt", "mindepth", "maxdepth", "d50" };
+
+ /**
+ * Real linear interpolator for kms and d50 values
+ */
+ private final PolynomialSplineFunction interpolator;
+
+ /***** METHODS *****/
+
+ private BedQualityD50KmValueFinder(final double[] kms, final double[] values) {
+ this.interpolator = new LinearInterpolator().interpolate(kms, values);
+ }
+
+ /**
+ * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
+ * Abhängig von Peiljahr
+ */
+ public static BedQualityD50KmValueFinder loadBedMeasurements(final River river, final DoubleRange kmRange, final int soundingYear, final int validYears) {
+
+ /* construct valid measurement time range */
+ final Calendar cal = Calendar.getInstance();
+ cal.clear();
+
+ cal.set(soundingYear - validYears, 0, 1);
+ final Date startTime = cal.getTime();
+
+ cal.set(soundingYear + validYears, 11, 31);
+ final Date endTime = cal.getTime();
+
+ log.debug(String.format("loadValues km %.3f - %.3f %tF - %tF", kmRange.getMinimumDouble(), kmRange.getMaximumDouble(), startTime, endTime));
+ final Session session = SedDBSessionHolder.HOLDER.get();
+ final SQLQuery sqlQuery = session.createSQLQuery(SQL_BED_D50_SUBLAYER_MEASUREMENT).addScalar("km", StandardBasicTypes.DOUBLE)
+ .addScalar("mindate", StandardBasicTypes.DATE).addScalar("maxdate", StandardBasicTypes.DATE).addScalar("cnt", StandardBasicTypes.INTEGER)
+ .addScalar("mindepth", StandardBasicTypes.DOUBLE).addScalar("maxdepth", StandardBasicTypes.DOUBLE).addScalar("d50", StandardBasicTypes.DOUBLE);
+ final String seddbRiver = river.nameForSeddb();
+ sqlQuery.setString("name", seddbRiver);
+ sqlQuery.setDouble("fromkm", kmRange.getMinimumDouble());
+ sqlQuery.setDouble("tokm", kmRange.getMaximumDouble());
+ sqlQuery.setDate("fromdate", startTime);
+ sqlQuery.setDate("todate", endTime);
+
+ final List<Object[]> rows = sqlQuery.list();
+ final double[] kms = new double[rows.size()];
+ final double[] values = new double[rows.size()];
+ D50Measurement measurement;
+ int i = -1;
+ for (final Object[] row : rows) {
+ measurement = new D50Measurement(row, SQL_BED_D50_SELECT_ALIAS);
+ i++;
+ kms[i] = measurement.getKm();
+ values[i] = measurement.getD50();
+ log.debug(String.format("loadValues km %.3f d50(mm) %.1f count %d", kms[i], values[i], measurement.getCnt()));
+ }
+ try {
+ return new BedQualityD50KmValueFinder(kms, values);
+ }
+ catch (final Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Returns the d50 value interpolated according to a km
+ *
+ * @return d50 (mm) of the km, or NaN
+ */
+ public double findD50(final double km) throws ArgumentOutsideDomainException {
+ return this.interpolator.value(km);
+ /*
+ * ohne interpolation:
+ * if ((kms == null) || (kms.size() == 0))
+ * return Double.NaN;
+ * int i = kms.binarySearch(km);
+ * if (i >= 0)
+ * return values.get(i);
+ * i = -i - 1;
+ * if ((i - 1 >= 0) && Utils.epsilonEquals(km, kms.get(i - 1), 0.0001))
+ * return values.get(i - 1);
+ * else if ((i >= 0) && (i <= kms.size() - 1) && Utils.epsilonEquals(km, kms.get(i), 0.0001))
+ * return values.get(i);
+ * else
+ * return Double.NaN;
+ */
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,61 @@
+/** 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.tkhcalculation;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.dive4elements.river.artifacts.model.QKms;
+import org.dive4elements.river.artifacts.model.WKms;
+import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.utils.DoubleUtil;
+
+/**
+ * @author Gernot Belger
+ */
+public final class DischargeValuesFinder {
+
+ private final UnivariateRealFunction qInterpolator;
+ private final QKms qKms;
+
+ /**
+ * Create an instance from a {@link WKms} object. If the given {@link WKms} is not a {@link WQKms}, a finder that always
+ * returns {@link Double#NaN} is returned.
+ */
+ public static DischargeValuesFinder fromKms(final WKms wstKms) {
+ if (!(wstKms instanceof QKms)) {
+ return new DischargeValuesFinder(null);
+ }
+
+ final QKms qKms = (QKms) wstKms;
+
+ return new DischargeValuesFinder(qKms);
+ }
+
+ public DischargeValuesFinder(final QKms qKms) {
+ this.qKms = qKms;
+ this.qInterpolator = qKms == null ? null : DoubleUtil.getLinearInterpolator(qKms.allKms(), qKms.allQs());
+ }
+
+ /**
+ * If this provider may return valid data at all.
+ */
+ public boolean isValid() {
+ return this.qInterpolator != null;
+ }
+
+ public DoubleRange getRange() {
+ return new DoubleRange(this.qKms.allQs().min(), this.qKms.allQs().max());
+ }
+
+ public double getDischarge(final double station) throws FunctionEvaluationException {
+ return this.qInterpolator.value(station);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/FlowVelocityModelKmValueFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/FlowVelocityModelKmValueFinder.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,337 @@
+/* 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.tkhcalculation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.log4j.Logger;
+import org.dive4elements.river.artifacts.math.Linear;
+import org.dive4elements.river.artifacts.math.Utils;
+import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowVelocityKmModelValues;
+import org.dive4elements.river.backend.SessionHolder;
+import org.dive4elements.river.model.River;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+import gnu.trove.TDoubleArrayList;
+
+/**
+ * Searchable sorted km array with parallel FlowVelocityKmModelValues array and linear interpolation for km and the
+ * model values between the array elements.<br />
+ * {@link loadValues} loads all the model values for a given km range of a river.<br />
+ * {@link findKmQValues} then searches a km in the values table or the nearest including km interval, resp.
+ * The v and tau values for a given discharge are either found directly or also interpolated linearly.<br />
+ *
+ * (Created based on a copy of FlowVelocityMeasurementFactory.)
+ *
+ * @author Matthias Schäfer
+ */
+final class FlowVelocityModelKmValueFinder {
+ /***** FIELDS *****/
+
+ /**
+ * Private log to use here.
+ */
+ private static Logger log = Logger.getLogger(FlowVelocityModelKmValueFinder.class);
+
+ /**
+ * Query for a range of stations of a river with all their q, main-v and tau values.<br />
+ * (Might be several 10000 rows if many stations and large q range)
+ */
+ private static final String SQL_SELECT_ALL = //
+ "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
+ + " FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
+ + " INNER JOIN flow_velocity_model_values fvmv ON fvm.id = fvmv.flow_velocity_model_id"
+ + " WHERE (dz.river_id = :river_id) AND (fvmv.station BETWEEN :kmfrom - 0.0001 AND :kmto + 0.0001)"
+ /* + " WHERE (dz.river_id = :river_id) AND (fvmv.q BETWEEN :qmin AND :qmax)" */
+ + " ORDER BY fvmv.station ASC, fvmv.q ASC";
+
+ /**
+ * Query for a river's max km below a limit with all its q, main-v and tau values.
+ */
+ private static final String SQL_SELECT_KMLOWER = //
+ "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau" + " FROM flow_velocity_model_values fvmv"
+ + " INNER JOIN (SELECT MAX(fvmvi.station) AS kmmax"
+ + " FROM(discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
+ + " INNER JOIN flow_velocity_model_values fvmvi ON fvm.id = fvmvi.flow_velocity_model_id"
+ + " WHERE (dz.river_id = :river_id) AND (fvmvi.station < :kmfrom - 0.0001)) finf ON fvmv.station = finf.kmmax"
+ + " ORDER BY fvmv.q ASC";
+
+ /**
+ * Query for a river's min km above a limit with all its q, main-v and tau values.
+ */
+ private static final String SQL_SELECT_KMUPPER = //
+ "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau" + " FROM flow_velocity_model_values fvmv"
+ + " INNER JOIN (SELECT MIN(fvmvi.station) AS kmmin"
+ + " FROM(discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
+ + " INNER JOIN flow_velocity_model_values fvmvi ON fvm.id = fvmvi.flow_velocity_model_id"
+ + " WHERE (dz.river_id = :river_id) AND (fvmvi.station > :kmto + 0.0001)) fsup ON fvmv.station = fsup.kmmin"
+ + " ORDER BY fvmv.q ASC";
+
+ // /**
+ // * Query to select all km-q-v-tau of a river that are the q maxima below a q limit
+ // */
+ // private static final String SQL_SELECT_QLOWER =
+ // "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
+ // + " FROM flow_velocity_model_values fvmv"
+ // + " INNER JOIN (SELECT fv2.station, MAX(fv2.q) AS q"
+ // + " FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
+ // + " INNER JOIN flow_velocity_model_values fv2 ON fvm.id = fv2.flow_velocity_model_id"
+ // + " WHERE (dz.river_id = :river_id) AND (fv2.q < :qlim) GROUP BY fv2.station) qx"
+ // + " ON (fvmv.station=qx.station) AND (fvmv.q=qx.q)"
+ // + " ORDER BY fvmv.station ASC";
+ //
+ // /**
+ // * Query to select all km-q-v-tau of a river that are the q minima above a q limit
+ // */
+ // private static final String SQL_SELECT_QUPPER =
+ // "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
+ // + " FROM flow_velocity_model_values fvmv"
+ // + " INNER JOIN (SELECT fv2.station, MIN(fv2.q) AS q"
+ // + " FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
+ // + " INNER JOIN flow_velocity_model_values fv2 ON fvm.id = fv2.flow_velocity_model_id"
+ // + " WHERE (dz.river_id = :river_id) AND (fv2.q > :qlim) GROUP BY fv2.station) qx"
+ // + " ON (fvmv.station=qx.station) AND (fvmv.q=qx.q)"
+ // + " ORDER BY fvmv.station ASC";
+
+ /**
+ * Kms of the loaded river range
+ */
+ private final TDoubleArrayList kms = new TDoubleArrayList();
+
+ /**
+ * For each km in kms a list of q-v-tau-tupels
+ */
+ private final List<FlowVelocityKmModelValues> values = new ArrayList<>();
+
+ /**
+ * Searched km of the last findKmValue
+ */
+ private double findKm;
+
+ /**
+ * kms and values index of the interval start found by the last findKmValue
+ */
+ private int leftIndexFound = -1;
+
+ /**
+ * kms and values index of the interval end found by the last findKmValue
+ */
+ private int rightIndexFound = -1;
+
+ /**
+ * Q of the last findKmQValues
+ */
+ private double findQ;
+
+ /***** METHODS *****/
+
+ /**
+ * Discharge of the last {@link findKmQValue}
+ */
+ public double getFindQ() {
+ return this.findQ;
+ }
+
+ /**
+ * Velocity of the last {@link findKmQValues}
+ */
+ public double getFindVmainFound() {
+ if (this.leftIndexFound < 0)
+ return Double.NaN;
+ else if (this.leftIndexFound == this.rightIndexFound)
+ return getLeftValues().getVmainFound();
+ else
+ return Linear.linear(this.findKm, getLeftValues().getKm(), getRightValues().getKm(), getLeftValues().getVmainFound(),
+ getRightValues().getVmainFound());
+ }
+
+ /**
+ * Shear stress tau of the last {@link findKmQValues}
+ */
+ public double getFindTauFound() {
+ if (this.leftIndexFound < 0)
+ return Double.NaN;
+ else if (this.leftIndexFound == this.rightIndexFound)
+ return getLeftValues().getTauFound();
+ else
+ return Linear.linear(this.findKm, getLeftValues().getKm(), getRightValues().getKm(), getLeftValues().getTauFound(), getRightValues().getTauFound());
+ }
+
+ /**
+ * Whether the discharge has been interpolated in the last {@link findKmQValues}
+ */
+ public boolean getFindIsQInterpolated() {
+ return (getLeftValues() != null) && (getLeftValues().getIsInterpolated() || getRightValues().getIsInterpolated());
+ }
+
+ /**
+ * Static constructor: queries a range of a river's kms with all their q-v-tau values.
+ *
+ * @return Whether the load has been successful the new instance, <code>null</code> otherwise.
+ */
+ public static FlowVelocityModelKmValueFinder loadValues(final River river, final DoubleRange kmRange, final DoubleRange qRange) {
+ // DB session
+ log.debug(String.format("loadValues km %.3f - %.3f / q %.1f - %.1f", kmRange.getMinimumDouble(), kmRange.getMaximumDouble(), qRange.getMinimumDouble(),
+ qRange.getMaximumDouble()));
+
+ final FlowVelocityModelKmValueFinder instance = new FlowVelocityModelKmValueFinder();
+
+ final TDoubleArrayList kms = instance.kms;
+ final List<FlowVelocityKmModelValues> values = instance.values;
+
+ final boolean isDemoValuesCorrection = river.getName().equalsIgnoreCase("beispielfluss");
+ final Session session = SessionHolder.HOLDER.get();
+
+ // Select km infimum
+ SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_KMLOWER).addScalar("station", StandardBasicTypes.DOUBLE).addScalar("q", StandardBasicTypes.DOUBLE)
+ .addScalar("vmain", StandardBasicTypes.DOUBLE).addScalar("tau", StandardBasicTypes.DOUBLE);
+ sqlQuery.setParameter("river_id", river.getId());
+ sqlQuery.setParameter("kmfrom", kmRange.getMinimumDouble());
+ instance.addKms(sqlQuery.list(), isDemoValuesCorrection);
+
+ // Select km range
+ sqlQuery = session.createSQLQuery(SQL_SELECT_ALL).addScalar("station", StandardBasicTypes.DOUBLE).addScalar("q", StandardBasicTypes.DOUBLE)
+ .addScalar("vmain", StandardBasicTypes.DOUBLE).addScalar("tau", StandardBasicTypes.DOUBLE);
+ sqlQuery.setParameter("river_id", river.getId());
+ sqlQuery.setParameter("kmfrom", kmRange.getMinimumDouble());
+ sqlQuery.setParameter("kmto", kmRange.getMaximumDouble());
+ // sqlQuery.setParameter("qmin", qRange.getMinimumDouble());
+ // sqlQuery.setParameter("qmax", qRange.getMaximumDouble());
+
+ int kmcount = kms.size();
+ final int rowcount = instance.addKms(sqlQuery.list(), isDemoValuesCorrection);
+ kmcount = kms.size() - kmcount;
+
+ // Select km supremum
+ sqlQuery = session.createSQLQuery(SQL_SELECT_KMUPPER).addScalar("station", StandardBasicTypes.DOUBLE).addScalar("q", StandardBasicTypes.DOUBLE)
+ .addScalar("vmain", StandardBasicTypes.DOUBLE).addScalar("tau", StandardBasicTypes.DOUBLE);
+ sqlQuery.setParameter("river_id", river.getId());
+ sqlQuery.setParameter("kmto", kmRange.getMaximumDouble());
+ final int supcnt = instance.addKms(sqlQuery.list(), isDemoValuesCorrection);
+
+ // Add copy of last km for search of max km value
+ if ((supcnt == 0) && (values.size() >= 1)) {
+ kms.add(kms.getQuick(kms.size()) + 0.0001);
+ values.add(new FlowVelocityKmModelValues(kms.getQuick(kms.size() - 1), values.get(values.size() - 1)));
+ }
+
+ // log.debug
+ if (values.size() - 1 >= 0) {
+ log.debug(String.format("loadValues %d: km %.3f - %d values", 0, values.get(0).getKm(), values.get(0).size()));
+
+ if (values.size() - 1 >= 1) {
+ log.debug(String.format("loadValues %d: km %.3f - %d values", 1, values.get(1).getKm(), values.get(1).size()));
+
+ if (values.size() - 1 >= 2)
+ log.debug("loadValues ...");
+
+ if (values.size() - 2 >= 3)
+ log.debug(String.format("loadValues %d: km %.3f - %d values", values.size() - 2, values.get(values.size() - 2).getKm(),
+ values.get(values.size() - 2).size()));
+
+ if (values.size() - 1 >= 3)
+ log.debug(String.format("loadValues %d: km %.3f - %d values", values.size() - 1, values.get(values.size() - 1).getKm(),
+ values.get(values.size() - 1).size()));
+ }
+ }
+
+ log.debug(String.format("loadValues %d kms, %d values loaded", kmcount, rowcount));
+
+ if (kms.size() == 0)
+ return null;
+
+ return instance;
+ }
+
+ /**
+ * Adds the km-q-v-tau values of a query result row to the last km of the list, or a new one resp.
+ *
+ * @return Number of rows
+ */
+ private int addKms(final List<Object[]> rows, final boolean isDemoValuesCorrection) {
+ for (final Object[] row : rows) {
+ if ((this.kms.size() == 0) || !Utils.epsilonEquals(this.kms.get(this.kms.size() - 1), (double) row[0], 0.0001)) {
+ this.kms.add((double) row[0]);
+ this.values.add(new FlowVelocityKmModelValues(this.kms.get(this.kms.size() - 1)));
+ }
+ if (isDemoValuesCorrection)
+ // "Verfremdung" der v-Werte etwas korrigieren (Originalwerte wurden mit Zufallswert zwischen 10 und 20 multipliziert)
+ this.values.get(this.values.size() - 1).addValues((double) row[1], ((double) row[2]) / 10, (double) row[3]);
+ else
+ this.values.get(this.values.size() - 1).addValues((double) row[1], (double) row[2], (double) row[3]);
+ }
+ return rows.size();
+ }
+
+ /**
+ * Searches a km and finds or interpolates the velocity and shear stress values for a discharge<br />
+ * The values may be got via {@link getVmainFound} etc.
+ *
+ * @return Whether values have been found
+ */
+ public boolean findKmQValues(final double km, final double q) {
+ this.findQ = q;
+ if (!searchKm(km))
+ return false;
+ if (this.leftIndexFound == this.rightIndexFound) {
+ // Exact km match
+ final double qfound = getLeftValues().findQ(q);
+ log.debug(String.format("findKmQValues km %.3f q %.0f = %.0f (%d)", km, q, qfound, this.leftIndexFound));
+ return !Double.isNaN(qfound);
+ } else {
+ final double[] qfound = { getLeftValues().findQ(q), getRightValues().findQ(q) };
+ log.debug(String.format("findKmQValues km %.3f q %.0f = %.0f (%d, %.3f) - %.0f (%d, %.3f)", km, q, qfound[0], this.leftIndexFound,
+ getLeftValues().getKm(), qfound[1], this.rightIndexFound, getRightValues().getKm()));
+ return !Double.isNaN(qfound[0]) && !Double.isNaN(qfound[1]);
+ }
+ }
+
+ /**
+ * Searches a km
+ *
+ * @return Whether the km was within the supported range
+ */
+ private boolean searchKm(final double km) {
+ this.findKm = km;
+ this.leftIndexFound = -1;
+ this.rightIndexFound = -1;
+ if ((this.kms == null) || (this.kms.size() == 0))
+ return false;
+ int i = this.kms.binarySearch(km);
+ if (i >= 0) {
+ // Exact km match
+ this.leftIndexFound = i;
+ this.rightIndexFound = i;
+ return true;
+ } else {
+ // Out of range or within km interval
+ if (i < 0)
+ i = -i - 1;
+ if ((i <= 0) || (i >= this.kms.size()))
+ return false;
+ this.leftIndexFound = i - 1;
+ this.rightIndexFound = i;
+ return true;
+ }
+ }
+
+ private FlowVelocityKmModelValues getLeftValues() {
+ return this.values.get(this.leftIndexFound);
+ }
+
+ private FlowVelocityKmModelValues getRightValues() {
+ return this.values.get(this.rightIndexFound);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/SoilKind.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/SoilKind.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,14 @@
+/** 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.tkhcalculation;
+
+public enum SoilKind {
+ mobil, starr
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/SoilKindKmValueFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/SoilKindKmValueFinder.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,118 @@
+/* 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.tkhcalculation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.ArgumentOutsideDomainException;
+import org.dive4elements.river.model.River;
+
+import gnu.trove.TDoubleArrayList;
+
+/**
+ * @author Matthias Schäfer
+ */
+final class SoilKindKmValueFinder {
+ // /**
+ // * Private log to use here.
+ // */
+ // private static Logger log = Logger.getLogger(SoilKindKmValueFinder.class);
+
+ private final TDoubleArrayList kms = new TDoubleArrayList();
+
+ private final List<SoilKind> values = new ArrayList<>();
+
+ /**
+ * Loads the range of the river's kms with their soil kind.
+ *
+ * @return Whether the load has been successful
+ */
+ public static SoilKindKmValueFinder loadValues(final River river, final DoubleRange kmRange) {
+
+ final SoilKindKmValueFinder instance = new SoilKindKmValueFinder();
+
+ // FIXME Echte Daten aus der Datenbank abfragen
+ instance.addKmKind(0, SoilKind.starr);
+ instance.addKmKind(15.7, SoilKind.mobil);
+ instance.addKmKind(15.8, SoilKind.mobil);
+ instance.addKmKind(15.9, SoilKind.starr);
+ instance.addKmKind(108.7, SoilKind.mobil);
+ instance.addKmKind(108.8, SoilKind.mobil);
+ instance.addKmKind(108.9, SoilKind.starr);
+ instance.addKmKind(119.1, SoilKind.mobil);
+ instance.addKmKind(119.4, SoilKind.mobil);
+ instance.addKmKind(119.5, SoilKind.starr);
+ instance.addKmKind(128.3, SoilKind.mobil);
+ instance.addKmKind(128.9, SoilKind.mobil);
+ instance.addKmKind(129, SoilKind.starr);
+ instance.addKmKind(133.1, SoilKind.mobil);
+ instance.addKmKind(135.9, SoilKind.mobil);
+ instance.addKmKind(136, SoilKind.starr);
+ instance.addKmKind(136.5, SoilKind.mobil);
+ instance.addKmKind(139.9, SoilKind.mobil);
+ instance.addKmKind(140, SoilKind.starr);
+ instance.addKmKind(140.5, SoilKind.mobil);
+ instance.addKmKind(165, SoilKind.mobil);
+ instance.addKmKind(165.1, SoilKind.starr);
+ instance.addKmKind(165.9, SoilKind.mobil);
+ instance.addKmKind(180.8, SoilKind.mobil);
+ instance.addKmKind(180.9, SoilKind.starr);
+ instance.addKmKind(182, SoilKind.mobil);
+ instance.addKmKind(221.3, SoilKind.mobil);
+
+ return instance;
+ }
+
+ private SoilKindKmValueFinder() {
+ /* only instantiate me via static constructor */
+ }
+
+ /***** METHODS *****/
+
+ /**
+ * Searches a km with its soil kind
+ */
+ public SoilKind findSoilKind(final double km) throws ArgumentOutsideDomainException {
+ if ((this.kms == null) || (this.kms.size() == 0))
+ throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN);
+
+ // TODO: Voraussetzung für die binäre suche ist, dass nach km sortiert ist.
+ // In diesem Fall könnte man ggf. auch gleich eine bessere Datenklasse benutzen, z.B. eine TreeMap<Double, SoilKind>
+ // (also station -> art), und deren funktionen zum finden verwenden:
+ // final double station = 0.0;
+ // final NavigableMap<Double, SoilKind> data = new TreeMap<>();
+ // data.ceilingEntry(station);
+ // data.floorEntry(station);
+
+ int i = this.kms.binarySearch(km);
+ if (i >= 0) {
+ // Exact km match
+ return this.values.get(i);
+ } else {
+ // Out of range or within km interval
+ if (i < 0)
+ i = -i - 1;
+ if ((i <= 0) || (i >= this.kms.size()))
+ throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN);
+ if (km <= ((this.kms.get(i - 1) + this.kms.get(i)) / 2))
+ return this.values.get(i - 1);
+ else
+ return this.values.get(i);
+ }
+ }
+
+ private void addKmKind(final double km, final SoilKind kind) {
+ this.kms.add(km);
+ this.values.add(kind);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/Tkh.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/Tkh.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,86 @@
+/** 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.tkhcalculation;
+
+import java.io.Serializable;
+
+/**
+ * Result of a transport bodies height calculation.
+ *
+ * @author Gernot Belger
+ */
+public final class Tkh implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final double km;
+
+ private final double wst;
+
+ private final double meanBedHeight;
+
+ private final double discharge;
+
+ private final SoilKind kind;
+
+ private final double tkh;
+
+ private final double tkhUp;
+
+ private final double tkhDown;
+
+ public Tkh(final double km, final double wst, final double meanBedHeight, final double discharge) {
+ this(km, wst, meanBedHeight, discharge, null, Double.NaN, Double.NaN, Double.NaN);
+ }
+
+ public Tkh(final double km, final double wst, final double meanBedHeight, final double discharge, final SoilKind kind, final double tkh, final double tkhUp,
+ final double tkhDown) {
+ this.km = km;
+ this.wst = wst;
+ this.meanBedHeight = meanBedHeight;
+ this.discharge = discharge;
+ this.kind = kind;
+ this.tkh = tkh;
+ this.tkhUp = tkhUp;
+ this.tkhDown = tkhDown;
+ }
+
+ public double getStation() {
+ return this.km;
+ }
+
+ public double getTkh() {
+ return this.tkh;
+ }
+
+ public SoilKind getKind() {
+ return this.kind;
+ }
+
+ public double getUp() {
+ return this.tkhUp;
+ }
+
+ public double getDown() {
+ return this.tkhDown;
+ }
+
+ public double getWaterlevel() {
+ return this.wst;
+ }
+
+ public double getDischarge() {
+ return this.discharge;
+ }
+
+ public double getMeanBedHeight() {
+ return this.meanBedHeight;
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,232 @@
+/** 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.tkhcalculation;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.ArgumentOutsideDomainException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.model.Calculation;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
+import org.dive4elements.river.model.River;
+
+/**
+ * @author Gernot Belger
+ */
+public final class TkhCalculator {
+
+ private static final int VALID_BED_MEASUREMENT_YEARS = 20;
+
+ private final Calculation problems;
+
+ private final String problemLabel;
+
+ private final CallContext context;
+
+ private final BedQualityD50KmValueFinder bedMeasurementsFinder;
+
+ private final SoilKindKmValueFinder soilKindFinder;
+
+ private final BedHeightsFinder bedHeightsProvider;
+
+ private final DischargeValuesFinder dischargeProvider;
+
+ private final FlowVelocityModelKmValueFinder flowVelocitiesFinder;
+
+ public static TkhCalculator buildTkhCalculator(final boolean useTkh, final CallContext context, final Calculation problems, final String label,
+ final River river, final DoubleRange calcRange, final DischargeValuesFinder dischargeProvider, final BedHeightsFinder bedHeightsProvider) {
+
+ if (!useTkh)
+ return null;
+
+ if (!dischargeProvider.isValid()) {
+ final String message = Resources.getMsg(context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
+ problems.addProblem(message);
+ return null;
+ }
+
+ final Integer soundingYear = bedHeightsProvider.getInfo().getYear();
+ final BedQualityD50KmValueFinder bedMeasurementsFinder = BedQualityD50KmValueFinder.loadBedMeasurements(river, calcRange, soundingYear,
+ VALID_BED_MEASUREMENT_YEARS);
+
+ if (bedMeasurementsFinder == null) {
+ final String message = Resources.getMsg(context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
+ problems.addProblem(message);
+ return null;
+ }
+
+ // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden?
+ final SoilKindKmValueFinder soilKindFinder = SoilKindKmValueFinder.loadValues(river, calcRange);
+ if (soilKindFinder == null) {
+ final String message = Resources.getMsg(context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
+ problems.addProblem(message);
+ return null;
+ }
+
+ final DoubleRange qRange = dischargeProvider.getRange();
+ final FlowVelocityModelKmValueFinder flowVelocitiesFinder = FlowVelocityModelKmValueFinder.loadValues(river, calcRange, qRange);
+ if (flowVelocitiesFinder == null) {
+ final String message = Resources.getMsg(context.getMeta(), "sinfo_calc_flow_depth.warning.missingVelocity", null, label);
+ problems.addProblem(message);
+ return null;
+ }
+
+ return new TkhCalculator(problems, label, context, bedMeasurementsFinder, dischargeProvider, bedHeightsProvider, soilKindFinder, flowVelocitiesFinder);
+ }
+
+ private TkhCalculator(final Calculation problems, final String problemLabel, final CallContext context,
+ final BedQualityD50KmValueFinder bedMeasurementsFinder, final DischargeValuesFinder dischargeProvider, final BedHeightsFinder bedHeightsProvider,
+ final SoilKindKmValueFinder soilKindFinder,
+ final FlowVelocityModelKmValueFinder flowVelocitiesFinder) {
+ this.problems = problems;
+ this.problemLabel = problemLabel;
+ this.context = context;
+ this.bedMeasurementsFinder = bedMeasurementsFinder;
+ this.dischargeProvider = dischargeProvider;
+ this.bedHeightsProvider = bedHeightsProvider;
+ this.soilKindFinder = soilKindFinder;
+ this.flowVelocitiesFinder = flowVelocitiesFinder;
+ }
+
+ private double getDischarge(final double km) {
+
+ try {
+ return this.dischargeProvider.getDischarge(km);
+ }
+ catch (final FunctionEvaluationException e) {
+ // TODO: exceptions nicht komplett schlucken? evtl. mit log.debug(e) ausgeben
+ return Double.NaN;
+ }
+ }
+
+ private SoilKind getSoilKind(final double km) {
+
+ try {
+ return this.soilKindFinder.findSoilKind(km);
+ }
+ catch (final ArgumentOutsideDomainException e) {
+ // FIXME: cumulate problems to one message?
+ final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, this.problemLabel);
+ this.problems.addProblem(km, message);
+ return null;
+ }
+ }
+
+ private double getBedMeasurement(final double km) {
+
+ try {
+ return this.bedMeasurementsFinder.findD50(km);
+ }
+ catch (final Exception e) {
+ // FIXME: cumulate problems to one message?
+ final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingD50", null, this.problemLabel);
+ this.problems.addProblem(km, message);
+
+ return Double.NaN;
+ }
+ }
+
+ public Tkh getTkh(final double km, final double wst) {
+
+ final SoilKind kind = getSoilKind(km);
+
+ final double meanBedHeight = this.bedHeightsProvider.getMeanBedHeight(km);
+
+ final double discharge = getDischarge(km);
+ if (Double.isNaN(discharge)) {
+
+ // final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null,
+ // this.problemLabel);
+ // this.problems.addProblem(km, message);
+
+ // TODO: nochmal gemeinsam überlegen welche probleme wir loggen, an dieser stelle müsste man ggf. die station
+ // mitausgeben
+
+ return new Tkh(km, wst, meanBedHeight, Double.NaN, kind, Double.NaN, Double.NaN, Double.NaN);
+ }
+
+ final double d50 = getBedMeasurement(km);
+ if (Double.isNaN(d50))
+ return new Tkh(km, wst, meanBedHeight, discharge, kind, Double.NaN, Double.NaN, Double.NaN);
+
+ if (!this.flowVelocitiesFinder.findKmQValues(km, discharge)) {
+ // TODO: ggf. station in Fehlermeldung?
+ final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, this.problemLabel);
+ this.problems.addProblem(km, message);
+ // FIXME: cumulate problems to one message?
+ }
+
+ final double tkh = calculateTkh(wst - meanBedHeight, this.flowVelocitiesFinder.getFindVmainFound(), d50, this.flowVelocitiesFinder.getFindTauFound());
+ // FIXME: noch mal prüfen, im alten code wurde hier immer auf 0 gesetzt
+ if (Double.isNaN(tkh) || (tkh < 0)) {
+ // TODO: ggf. station in Fehlermeldung?
+
+ // FIXME: Fehlermeldung nicht korrekt, passiert mit Wasserspiegel 'MHQ' und 'QP-1993': alle Daten (auch Abfluss)
+ // vorhanden, aber tkh negativ...
+ final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, this.problemLabel);
+ this.problems.addProblem(km, message);
+
+ return new Tkh(km, wst, meanBedHeight, discharge, kind, Double.NaN, Double.NaN, Double.NaN);
+ }
+
+ /*
+ * log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f",
+ * km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(),
+ * d50*1000, tkh));
+ */
+
+ double tkhUp;
+ double tkhDown;
+ switch (kind) {
+ case starr:
+ tkhUp = tkh;
+ tkhDown = 0;
+ break;
+
+ case mobil:
+ default:
+ tkhUp = tkh / 2;
+ tkhDown = -tkh / 2;
+ break;
+ }
+
+ return new Tkh(km, wst, meanBedHeight, discharge, kind, tkh, tkhUp, tkhDown);
+ }
+
+ /**
+ * Calculates a transport body height
+ *
+ * @param h
+ * flow depth in m
+ * @param vm
+ * flow velocity in m
+ * @param d50
+ * grain diameter D50 in m (!)
+ * @param tau
+ * shear stress in N/m^2
+ * @return transport body height in cm (!)
+ */
+ private double calculateTkh(final double h, final double vm, final double d50, final double tau) {
+ final double PHYS_G = 9.81;
+ final double PHYS_SPECGRAV_S = 2.6;
+ final double PHYS_VELOCCOEFF_N = 6;
+ final double PHYS_FORMCOEFF_ALPHA = 0.7;
+ final double PHYS_VISCOSITY_NUE = 1.3e-6;
+ final double PHYS_GRAIN_DENSITY_RHOS = 2603;
+ final double PHYS_WATER_DENSITY_RHO = 999.97;
+
+ final double froude = vm / Math.sqrt(PHYS_G * h);
+ final double partReynolds = Math.sqrt((PHYS_SPECGRAV_S - 1) * PHYS_G * d50) / PHYS_VISCOSITY_NUE * d50;
+ final double critShields = 0.22 * Math.pow(partReynolds, -0.6) + 0.06 * Math.pow(10, 7.7 * Math.pow(partReynolds, -0.6));
+ final double critTau = critShields * (PHYS_GRAIN_DENSITY_RHOS - PHYS_WATER_DENSITY_RHO) * PHYS_G * d50;
+ return 100 * h * (1 - Math.pow(froude, 2)) / (2 * PHYS_VELOCCOEFF_N * PHYS_FORMCOEFF_ALPHA) * (1 - critTau / tau);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/BedHeightsFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/BedHeightsFinder.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,134 @@
+/** 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.tkhstate;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.river.artifacts.math.Linear;
+import org.dive4elements.river.artifacts.model.Calculation;
+import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
+import org.dive4elements.river.model.BedHeight;
+import org.dive4elements.river.model.BedHeightValue;
+import org.dive4elements.river.model.River;
+
+/**
+ * Provides bed heigts for vcarious calculations.
+ *
+ * @author Gernot Belger
+ */
+public final class BedHeightsFinder {
+
+ private final BedHeightInfo info;
+
+ private final NavigableMap<Double, BedHeightValue> values;
+
+ /**
+ * Create specific bed heights used in tkh-calculation
+ *
+ * @param problems
+ */
+ public static Collection<BedHeightsFinder> createTkhBedHeights(final River river, final Calculation problems, final DoubleRange range) {
+ // FIXME: determine relevant bed-heights by river: read from some configuration file
+ // '3' is already the right one for demo-model == '"DGM-2004_Epoche-2-SOBEK"'
+ final int bedheightId = 3;
+
+ final Collection<BedHeight> bedHeights = Collections.singletonList(BedHeight.getBedHeightById(bedheightId));
+
+ // TODO: check for overlapping ranges... and provide a warning message, else we get problems later
+
+ final List<BedHeightsFinder> result = new ArrayList<>(bedHeights.size());
+
+ for (final BedHeight bedHeight : bedHeights) {
+ result.add(createBedHeights(bedHeight, range));
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates a {@link BedHeightsFinder} for a dataset from the database, specified by its id.
+ *
+ * @return <code>null</code> if no bed height with the given id exists.
+ */
+ public static BedHeightsFinder forId(final int id, final DoubleRange range) {
+
+ final BedHeight bedHeight = BedHeight.getBedHeightById(id);
+ if (bedHeight == null)
+ return null;
+
+ return BedHeightsFinder.createBedHeights(bedHeight, range);
+ }
+
+ /**
+ * Create a finder for a given bed height.
+ *
+ * @param range
+ */
+ private static BedHeightsFinder createBedHeights(final BedHeight bedHeight, final DoubleRange range) {
+
+ // FIXME: sort by station, but in what direction?
+ // FIXME: using river.getKmUp()?
+ final NavigableMap<Double, BedHeightValue> values = new TreeMap<>();
+
+ for (final BedHeightValue bedHeightValue : bedHeight.getValues()) {
+ final Double station = bedHeightValue.getStation();
+ if (station != null && range.containsDouble(station)) {
+
+ if (bedHeightValue.getHeight() != null)
+ values.put(station, bedHeightValue);
+ }
+ }
+
+ final BedHeightInfo info = BedHeightInfo.from(bedHeight);
+
+ return new BedHeightsFinder(info, values);
+ }
+
+ private BedHeightsFinder(final BedHeightInfo info, final NavigableMap<Double, BedHeightValue> values) {
+ this.info = info;
+ this.values = values;
+ }
+
+ public BedHeightInfo getInfo() {
+ return this.info;
+ }
+
+ public Collection<Double> getStations() {
+ return this.values.keySet();
+ }
+
+ public double getMeanBedHeight(final double km) {
+
+ if (this.values.containsKey(km))
+ return this.values.get(km).getHeight();
+
+ final Entry<Double, BedHeightValue> floorEntry = this.values.floorEntry(km);
+ final Entry<Double, BedHeightValue> ceilingEntry = this.values.ceilingEntry(km);
+
+ if (floorEntry == null || ceilingEntry == null)
+ return Double.NaN;
+
+ final double floorKm = floorEntry.getKey();
+ final double floorHeight = floorEntry.getValue().getHeight();
+ final double ceilKm = ceilingEntry.getKey();
+ final double ceilHeight = ceilingEntry.getValue().getHeight();
+
+ // FIXME: check if we always want that...
+
+ return Linear.linear(km, floorKm, ceilKm, floorHeight, ceilHeight);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhAccess.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhAccess.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,40 @@
+/* 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.tkhstate;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.river.artifacts.access.RangeAccess;
+import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.sinfo.SinfoCalcMode;
+
+/**
+ * Access to the flow depth calculation type specific SInfo artifact data.
+ * REMARK: this class is NOT intended to be hold in the results (or anywhere else), in order to avoid a permanent
+ * reference to the artifact instance.
+ * Hence we do NOT cache any data.
+ *
+ * @author Gernot Belger
+ */
+final class TkhAccess extends RangeAccess {
+ public TkhAccess(final SINFOArtifact artifact) {
+ super(artifact);
+
+ /* assert calculation mode */
+ final SinfoCalcMode calculationMode = artifact.getCalculationMode();
+ assert (calculationMode == SinfoCalcMode.sinfo_calc_transport_bodies_heights);
+ }
+
+ public DoubleRange getRange() {
+ final double from = getFrom();
+ final double to = getTo();
+ return new DoubleRange(from, to);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,152 @@
+/** 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.tkhstate;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.WINFOArtifact;
+import org.dive4elements.river.artifacts.model.Calculation;
+import org.dive4elements.river.artifacts.model.Calculation.Problem;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
+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.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.model.River;
+
+/**
+ * @author Gernot Belger
+ */
+final class TkhCalculation {
+
+ private final CallContext context;
+
+ public TkhCalculation(final CallContext context) {
+ this.context = context;
+ }
+
+ public CalculationResult calculate(final SINFOArtifact sinfo) {
+
+ /* access input data */
+ final TkhAccess access = new TkhAccess(sinfo);
+ final River river = access.getRiver();
+ final RiverInfo riverInfo = new RiverInfo(river);
+ final DoubleRange calcRange = access.getRange();
+
+ final Calculation problems = new Calculation();
+
+ /* find relevant bed-heights */
+ final Collection<BedHeightsFinder> bedHeights = BedHeightsFinder.createTkhBedHeights(river, problems, calcRange);
+
+ /* calculate waterlevels */
+ final WQKms[] kms = calculateWaterlevels(sinfo, problems);
+
+ final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange);
+
+ final String user = CalculationUtils.findArtifactUser(this.context, sinfo);
+
+ final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
+
+ /* for each waterlevel, do a tkh calculation */
+ final TkhCalculationResults results = new TkhCalculationResults(calcModeLabel, user, riverInfo, calcRange);
+
+ for (final WQKms wqKms : kms) {
+
+ final TkhCalculationResult result = calculateResult(calcRange, infoProvider, wqKms, bedHeights, problems);
+ if (result != null)
+ // FIXME: must be sorted by station!
+ results.addResult(result);
+ }
+
+ return new CalculationResult(results, problems);
+ }
+
+ private WQKms[] calculateWaterlevels(final SINFOArtifact sinfo, final Calculation problems) {
+
+ /* misuse winfo-artifact to calculate waterlevels in the same way */
+ final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo);
+
+ final CalculationResult waterlevelData = winfo.getWaterlevelData(this.context);
+
+ /* copy all problems */
+ final Calculation winfoProblems = waterlevelData.getReport();
+ for (final Problem problem : winfoProblems.getProblems()) {
+ problems.addProblem(problem);
+ }
+
+ return (WQKms[]) waterlevelData.getData();
+ }
+
+ private TkhCalculationResult calculateResult(final DoubleRange calcRange, final RiverInfoProvider riverInfo, final WQKms wkms,
+ final Collection<BedHeightsFinder> bedHeights, final Calculation problems) {
+
+ // FIXME: wo kommt das her? via winfo kein jahr vorhanden, oder doch? aber soll in metadaten ausgegeben werden...
+ final int wspYear = -1;
+ // FIXME: richtig? vgl. WInfo?
+ final boolean showAllGauges = false;
+ final WaterlevelData waterlevel = new WaterlevelData(wkms, wspYear, showAllGauges);
+
+ final RiverInfoProvider riverInfoProvider = riverInfo.forWaterlevel(waterlevel);
+
+ final String label = waterlevel.getName();
+
+ final WstInfo wstInfo = new WstInfo(label, wspYear, riverInfoProvider.getReferenceGauge());
+
+ 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
+ */
+ for (final BedHeightsFinder bedHeightsProvider : bedHeights) {
+
+ final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wkms);
+
+ /* initialize tkh calculator */
+ final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(true, this.context, problems, label, 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?
+
+ 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 gaugeLabel = riverInfoProvider.findGauge(station);
+ final String location = riverInfoProvider.getLocation(station);
+
+ rows.add(new TkhResultRow(tkh, label, gaugeLabel, location));
+ }
+ }
+
+ return new TkhCalculationResult(label, wstInfo, true, rows);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,29 @@
+/* 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.tkhstate;
+
+import java.util.Collection;
+
+import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoCalculationResult;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+
+/**
+ * Contains the results of a {@link FlowDepthCalculation}.
+ *
+ * @author Gernot Belger
+ */
+final class TkhCalculationResult extends AbstractSInfoCalculationResult<TkhResultRow> {
+
+ private static final long serialVersionUID = 1L;
+
+ public TkhCalculationResult(final String label, final WstInfo wst, final boolean hasTkh, final Collection<TkhResultRow> rows) {
+ super(label, wst, hasTkh, rows);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResults.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResults.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,66 @@
+/** 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.tkhstate;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+
+/**
+ * @author Gernot Belger
+ */
+final class TkhCalculationResults implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final List<TkhCalculationResult> results = new ArrayList<>();
+
+ private final String calcModeLabel;
+
+ private final String user;
+
+ private final RiverInfo river;
+
+ private final DoubleRange calcRange;
+
+ public TkhCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) {
+ this.calcModeLabel = calcModeLabel;
+ this.user = user;
+ this.river = river;
+ this.calcRange = calcRange;
+ }
+
+ public String getCalcModeLabel() {
+ return this.calcModeLabel;
+ }
+
+ public String getUser() {
+ return this.user;
+ }
+
+ public RiverInfo getRiver() {
+ return this.river;
+ }
+
+ public DoubleRange getCalcRange() {
+ return this.calcRange;
+ }
+
+ void addResult(final TkhCalculationResult result) {
+ this.results.add(result);
+ }
+
+ public List<TkhCalculationResult> getResults() {
+ return Collections.unmodifiableList(this.results);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhResultRow.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhResultRow.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,25 @@
+/** 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.tkhstate;
+
+import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoResultRow;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
+
+/**
+ * @author Gernot Belger
+ */
+final class TkhResultRow extends AbstractSInfoResultRow {
+
+ private static final long serialVersionUID = 1L;
+
+ public TkhResultRow(final Tkh tkh, final String waterlevelLabel, final String gauge, final String location) {
+ super(tkh, waterlevelLabel, gauge, location);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,146 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * 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.tkhstate;
+
+import java.util.List;
+
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.ChartArtifact;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.EmptyFacet;
+import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.states.DefaultState;
+
+/** State in which a waterlevel has been calculated. */
+public class TkhState extends DefaultState {
+
+ /// ** The log that is used in this state. */
+ // private static Logger log = Logger.getLogger(FlowDepthState.class);
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.filtered.description";
+
+ private static final String I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.tkh.filtered.description";
+
+ private static final String I18N_FACET_TKH_DESCRIPTION = "sinfo.facet.tkh.description";
+
+ private static final String SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL = "sinfo.chart.flow_depth.yaxis.label";
+
+ private static final String SINFO_CHART_TKX_YAXIS_LABEL = "sinfo.chart.tkh.yaxis.label";
+
+ /**
+ * From this state can only be continued trivially.
+ */
+ @Override
+ protected String getUIProvider() {
+ return "continue";
+ }
+
+ @Override
+ public Object computeFeed(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
+ // FIXME: why is this necessary?
+ if (artifact instanceof ChartArtifact) {
+ facets.add(new EmptyFacet());
+ return null;
+ }
+
+ return compute((SINFOArtifact) artifact, context, hash, facets, old);
+ }
+
+ @Override
+ public Object computeAdvance(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
+ if (artifact instanceof ChartArtifact) {
+ facets.add(new EmptyFacet());
+ return null;
+ }
+ return compute((SINFOArtifact) artifact, context, hash, facets, old);
+ }
+
+ /**
+ * Compute result or returned object from cache, create facets.
+ *
+ * @param old
+ * Object that was cached.
+ */
+ private Object compute(final SINFOArtifact sinfo, final CallContext context, final String hash, final List<Facet> facets, final Object old) {
+
+ final CalculationResult res = doCompute(sinfo, context, old);
+
+ if (facets == null)
+ return res;
+
+ // final FlowDepthCalculationResults results = (FlowDepthCalculationResults) res.getData();
+ //
+ // /* add themes for chart, for each result */
+ // final List<FlowDepthCalculationResult> resultList = results.getResults();
+ // for (int index = 0; index < resultList.size(); index++) {
+ //
+ // final FlowDepthCalculationResult result = resultList.get(index);
+ //
+ // /* filtered (zoom dependent mean) flow depth */
+ // final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(),
+ // I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION,
+ // I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, result.getLabel());
+ // facets.add(new FlowDepthFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED, facetFlowDepthFilteredDescription,
+ // SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
+ //
+ // if (results.isUseTkh()) {
+ // /* filtered (zoom dependent mean) flow depth including tkh */
+ // final String facetFlowDepthTkhFilteredDescription = Resources.getMsg(context.getMeta(),
+ // I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION,
+ // I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION, result.getLabel());
+ // facets.add(new FlowDepthFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_TKH_FILTERED,
+ // facetFlowDepthTkhFilteredDescription,
+ // SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
+ //
+ // // FIXME: add other themes
+ // // - Streckenfavoriten
+ //
+ // // FIXME:
+ // // - Gemittelte Linie der Fließtiefe mitsamt TKH
+ // // - Transportkörperhöhen (oben/unten/schraffur)
+ // final String facetTkhDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_DESCRIPTION,
+ // I18N_FACET_TKH_DESCRIPTION,
+ // result.getLabel());
+ // facets.add(new FlowDepthFacet(index, TkhProcessor.FACET_TKH, facetTkhDescription, SINFO_CHART_TKX_YAXIS_LABEL,
+ // ComputeType.ADVANCE, this.id,
+ // hash));
+ // }
+ //
+ // // FIXME: Datenkorbkonfiguration
+ // }
+ //
+ // if (!resultList.isEmpty()) {
+ // final Facet csv = new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id);
+ // final Facet pdf = new DataFacet(FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id);
+ //
+ // facets.add(csv);
+ // facets.add(pdf);
+ // }
+ //
+ // final Calculation report = res.getReport();
+ //
+ // if (report.hasProblems()) {
+ // facets.add(new ReportFacet(ComputeType.ADVANCE, hash, this.id));
+ // }
+ //
+ // return res;
+ return null;
+ }
+
+ private CalculationResult doCompute(final SINFOArtifact sinfo, final CallContext context, final Object old) {
+ if (old instanceof CalculationResult)
+ return (CalculationResult) old;
+
+ return new TkhCalculation(context).calculate(sinfo);
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/WinfoArtifactWrapper.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/WinfoArtifactWrapper.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,42 @@
+/** 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.tkhstate;
+
+import java.util.Collection;
+
+import org.dive4elements.artifactdatabase.data.DefaultStateData;
+import org.dive4elements.artifactdatabase.data.StateData;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.WINFOArtifact;
+
+/**
+ * Ugly wrapper around WINfoArtifact in order to a) not to break serialization of WInfoArtifact b) be able to copy data
+ * into it
+ *
+ * @author Gernot Belger
+ *
+ */
+class WinfoArtifactWrapper extends WINFOArtifact {
+
+ private static final long serialVersionUID = 1L;
+
+ public WinfoArtifactWrapper(final D4EArtifact dataSource) {
+ final Collection<StateData> allData = dataSource.getAllData();
+ for (final StateData stateData : allData) {
+
+ final DefaultStateData clonedData = new DefaultStateData();
+ clonedData.set(stateData);
+
+ addData(clonedData.getName(), clonedData);
+ }
+
+ addStringData("calculation_mode", "calc.surface.curve");
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/CalculationUtils.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/CalculationUtils.java Wed Feb 28 17:27:15 2018 +0100
@@ -0,0 +1,37 @@
+/** 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.util;
+
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.ArtifactDatabase;
+import org.dive4elements.artifacts.CallContext;
+
+/**
+ * @author Gernot Belger
+ */
+public final class CalculationUtils {
+
+
+ private CalculationUtils() {
+ throw new UnsupportedOperationException("Helper class");
+ }
+
+ /**
+ * Find the the user of the given artifact, sadly this is not part of the calling context, so instead we determine the
+ * owner oft the artifact
+ *
+ * @param artifact
+ * @param context
+ */
+ public static String findArtifactUser(final CallContext context, final Artifact artifact) {
+ final ArtifactDatabase database = context.getDatabase();
+ return database.findArtifactUser(artifact.identifier());
+ }
+}
\ No newline at end of file
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/WstInfo.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/WstInfo.java Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/WstInfo.java Wed Feb 28 17:27:15 2018 +0100
@@ -24,10 +24,10 @@
private final String gauge;
- public WstInfo(final String label, final int year, final String gauge) {
+ public WstInfo(final String label, final int year, final String refGauge) {
this.label = label;
this.year = year;
- this.gauge = gauge;
+ this.gauge = refGauge;
}
public String getLabel() {
diff -r e3519c3e7a0a -r d9dbf0b74bc2 artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelData.java
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelData.java Tue Feb 27 18:06:52 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelData.java Wed Feb 28 17:27:15 2018 +0100
@@ -10,8 +10,6 @@
package org.dive4elements.river.artifacts.states;
import org.dive4elements.river.artifacts.model.WKms;
-import org.dive4elements.river.model.Gauge;
-import org.dive4elements.river.model.River;
/**
* Represents a waterlevel fetched with the {@link WaterlevelFetcher}.
@@ -68,23 +66,6 @@
return this.showAllGauges;
}
- public Gauge findReferenceGauge(final River river) {
- final double[] wstFromTo = findWstFromTo();
- return river.determineRefGauge(wstFromTo, true);
- }
-
- private double[] findWstFromTo() {
-
- final double from = this.wkms.getKm(0);
- final double to = this.wkms.getKm(this.wkms.size() - 1);
-
- final boolean waterIncreasing = this.wkms.guessWaterIncreasing();
- if (waterIncreasing)
- return new double[] { to, from };
-
- return new double[] { from, to };
- }
-
public int getYear() {
return this.year;
}
More information about the Dive4Elements-commits
mailing list