# HG changeset patch # User gernotbelger # Date 1520963373 -3600 # Node ID 5d5d482da3e93adf17b535e3a3397c5babaec4af # Parent 4a6b6a3c279cdd5e02ef29908c3092fb2cce6a33 Implementing SINFO - FlowDepthMinMax calculation diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/doc/conf/artifacts/sinfo.xml --- a/artifacts/doc/conf/artifacts/sinfo.xml Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/doc/conf/artifacts/sinfo.xml Tue Mar 13 18:49:33 2018 +0100 @@ -83,6 +83,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/doc/conf/generators/generators.xml --- a/artifacts/doc/conf/generators/generators.xml Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/doc/conf/generators/generators.xml Tue Mar 13 18:49:33 2018 +0100 @@ -62,6 +62,8 @@ + + diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SINFOArtifact.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SINFOArtifact.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SINFOArtifact.java Tue Mar 13 18:49:33 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) @@ -17,26 +17,26 @@ * * @author Gernot Belger */ -public class SINFOArtifact -extends D4EArtifact -{ +public class SINFOArtifact extends D4EArtifact { + + private static final long serialVersionUID = 1L; + /** Error message that is thrown if no mode has been chosen. */ - private static final String ERROR_NO_CALCULATION_MODE = - "error_feed_no_calculation_mode"; + private static final String ERROR_NO_CALCULATION_MODE = "error_feed_no_calculation_mode"; - /** Error message that is thrown if an invalid calculation mode has been - * chosen. */ - private static final String ERROR_INVALID_CALCULATION_MODE = - "error_feed_invalid_calculation_mode"; + /** + * Error message that is thrown if an invalid calculation mode has been + * chosen. + */ + private static final String ERROR_INVALID_CALCULATION_MODE = "error_feed_invalid_calculation_mode"; - /** The name of the artifact. */ private static final String ARTIFACT_NAME = "sinfo"; private static final String FIELD_RIVER = "river"; private static final String FIELD_MODE = "calculation_mode"; - + /** * Default constructor, because it's serializable. */ @@ -52,22 +52,23 @@ public String getName() { return ARTIFACT_NAME; } - + public SinfoCalcMode getCalculationMode() { - final String calc = getDataAsString(FIELD_MODE); + final String calc = getDataAsString(FIELD_MODE); if (calc == null) { - throw new IllegalArgumentException(ERROR_NO_CALCULATION_MODE); + throw new IllegalArgumentException(ERROR_NO_CALCULATION_MODE); } try { - return SinfoCalcMode.valueOf(StringUtils.trimToEmpty(calc).toLowerCase()); - } catch (Exception e) { - throw new IllegalArgumentException(ERROR_INVALID_CALCULATION_MODE, e); - } - } - + return SinfoCalcMode.valueOf(StringUtils.trimToEmpty(calc).toLowerCase()); + } + catch (final Exception e) { + throw new IllegalArgumentException(ERROR_INVALID_CALCULATION_MODE, e); + } + } + public String getRiver() { - return getDataAsString(FIELD_RIVER); - } + return getDataAsString(FIELD_RIVER); + } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SInfoI18NStrings.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SInfoI18NStrings.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SInfoI18NStrings.java Tue Mar 13 18:49:33 2018 +0100 @@ -16,57 +16,61 @@ */ public interface SInfoI18NStrings { - public static final String CSV_META_HEADER_RESULT = "sinfo.export.flow_depth.csv.meta.header.result"; - - public static final String CSV_META_HEADER_RESULT_LABEL = "sinfo.export.flow_depth.csv.meta.header.result.label"; - - public static final String CSV_META_VERSION = "sinfo.export.flow_depth.csv.meta.version"; - - public static final String CSV_META_VERSION_LABEL = "sinfo.export.flow_depth.csv.meta.version.label"; - - public static final String CSV_META_USER = "sinfo.export.flow_depth.csv.meta.user"; - - public static final String CSV_META_USER_LABEL = "sinfo.export.flow_depth.csv.meta.user.label"; - - public static final String CSV_META_CREATION = "sinfo.export.flow_depth.csv.meta.creation"; - - public static final String CSV_META_CREATION_LABEL = "sinfo.export.flow_depth.csv.meta.creation.label"; - - public static final String CSV_META_RIVER = "sinfo.export.flow_depth.csv.meta.river"; - - public static final String CSV_META_RIVER_LABEL = "sinfo.export.flow_depth.csv.meta.river.label"; - - public static final String CSV_KM_HEADER = "sinfo.export.flow_depth.csv.header.km"; - - public static final String CSV_MEAN_BED_HEIGHT_HEADER = "sinfo.export.flow_depth.csv.header.mean_bed_height"; - - public static final String CSV_WATERLEVEL_HEADER = "sinfo.export.flow_depth.csv.header.waterlevel"; + String CSV_META_HEADER_RESULT = "sinfo.export.flow_depth.csv.meta.header.result"; - public static final String CSV_DISCHARGE_HEADER = "sinfo.export.flow_depth.csv.header.discharge"; - - public static final String CSV_LABEL_HEADER = "sinfo.export.flow_depth.csv.header.label"; - - public static final String CSV_GAUGE_HEADER = "sinfo.export.flow_depth.csv.header.gauge"; - - public static final String CSV_LOCATION_HEADER = "sinfo.export.flow_depth.csv.header.location"; - - public static final String CSV_META_HEADER_WATERLEVEL = "sinfo.export.flow_depth.csv.meta.header.waterlevel"; - - public static final String CSV_META_HEADER_WATERLEVEL_NAME = "sinfo.export.flow_depth.csv.meta.header.waterlevel.name"; - - public static final String CSV_META_HEADER_WATERLEVEL_GAUGE = "sinfo.export.flow_depth.csv.meta.header.waterlevel.gauge"; + String CSV_META_HEADER_RESULT_LABEL = "sinfo.export.flow_depth.csv.meta.header.result.label"; - public static final String CSV_META_HEADER_WATERLEVEL_YEAR = "sinfo.export.flow_depth.csv.meta.header.waterlevel.year"; - - public static final String CSV_META_RANGE = "sinfo.export.flow_depth.csv.meta.range"; - - public static final String CSV_META_RANGE_LABEL = "sinfo.export.flow_depth.csv.meta.range.label"; + String CSV_META_VERSION = "sinfo.export.flow_depth.csv.meta.version"; - public static final String CSV_META_HEIGHT_UNIT_RIVER = "sinfo.export.flow_depth.csv.meta.height_unit.river"; - - public static final String UNIT_M = "m"; + String CSV_META_VERSION_LABEL = "sinfo.export.flow_depth.csv.meta.version.label"; - public static final String UNIT_CM = "cm"; + String CSV_META_USER = "sinfo.export.flow_depth.csv.meta.user"; - public static final String UNIT_CUBIC_M = "m³/s"; + String CSV_META_USER_LABEL = "sinfo.export.flow_depth.csv.meta.user.label"; + + String CSV_META_CREATION = "sinfo.export.flow_depth.csv.meta.creation"; + + String CSV_META_CREATION_LABEL = "sinfo.export.flow_depth.csv.meta.creation.label"; + + String CSV_META_RIVER = "sinfo.export.flow_depth.csv.meta.river"; + + String CSV_META_RIVER_LABEL = "sinfo.export.flow_depth.csv.meta.river.label"; + + String CSV_KM_HEADER = "sinfo.export.flow_depth.csv.header.km"; + + String CSV_MEAN_BED_HEIGHT_HEADER = "sinfo.export.flow_depth.csv.header.mean_bed_height"; + + String CSV_WATERLEVEL_HEADER = "sinfo.export.flow_depth.csv.header.waterlevel"; + + String CSV_DISCHARGE_HEADER = "sinfo.export.flow_depth.csv.header.discharge"; + + String CSV_LABEL_HEADER = "sinfo.export.flow_depth.csv.header.label"; + + String CSV_GAUGE_HEADER = "sinfo.export.flow_depth.csv.header.gauge"; + + String CSV_LOCATION_HEADER = "sinfo.export.flow_depth.csv.header.location"; + + String CSV_SOUNDING_HEADER = "sinfo.export.flow_depth.csv.header.sounding"; + + String CSV_META_HEADER_WATERLEVEL = "sinfo.export.flow_depth.csv.meta.header.waterlevel"; + + String CSV_META_HEADER_WATERLEVEL_NAME = "sinfo.export.flow_depth.csv.meta.header.waterlevel.name"; + + String CSV_META_HEADER_WATERLEVEL_GAUGE = "sinfo.export.flow_depth.csv.meta.header.waterlevel.gauge"; + + String CSV_META_HEADER_WATERLEVEL_YEAR = "sinfo.export.flow_depth.csv.meta.header.waterlevel.year"; + + String CSV_META_RANGE = "sinfo.export.flow_depth.csv.meta.range"; + + String CSV_META_RANGE_LABEL = "sinfo.export.flow_depth.csv.meta.range.label"; + + String CSV_META_HEIGHT_UNIT_RIVER = "sinfo.export.flow_depth.csv.meta.height_unit.river"; + + String CSV_MEAN_BED_HEIGHT_HEADER_SHORT = "sinfo.export.flow_depth.csv.header.mean_bed_height.short"; + + String UNIT_M = "m"; + + String UNIT_CM = "cm"; + + String UNIT_CUBIC_M = "m³/s"; } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java Tue Mar 13 18:49:33 2018 +0100 @@ -13,13 +13,9 @@ 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 */ @@ -31,14 +27,11 @@ 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 rows) { + public AbstractSInfoCalculationResult(final String label, final WstInfo wst, final Collection rows) { this.label = label; this.wst = wst; - this.hasTkh = hasTkh; this.rows = new ArrayList<>(rows); } @@ -46,10 +39,6 @@ return this.label; } - public final boolean hasTkh() { - return this.hasTkh; - } - public final WstInfo getWst() { return this.wst; } @@ -61,139 +50,4 @@ public final Collection 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()); - - for (final ROW row : this.rows) { - xPoints.add(row.getStation()); - yPoints.add(row.getFlowDepth()); - } - - return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; - } - - public double[][] getFlowDepthTkhPoints() { - - final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); - final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); - - for (final ROW row : this.rows) { - xPoints.add(row.getStation()); - yPoints.add(row.getFlowDepthWithTkh()); - } - - return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; - } - - public final double[][] getTkhUpPoints() { - final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); - final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); - final List 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 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); - } - - public double[][] getVelocityPoints() { - - final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); - final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); - - for (final ROW row : this.rows) { - xPoints.add(row.getStation()); - yPoints.add(row.getVelocity()); - } - - return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; - } - - public double[][] getD50Points() { - - final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); - final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); - - for (final ROW row : this.rows) { - xPoints.add(row.getStation()); - yPoints.add(row.getD50()); - } - - return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; - } - - public double[][] getTauPoints() { - - final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); - final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); - - for (final ROW row : this.rows) { - xPoints.add(row.getStation()); - yPoints.add(row.getTau()); - } - - return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; - } - - /** - * 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 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 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoExporter.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoExporter.java Tue Mar 13 18:49:33 2018 +0100 @@ -10,17 +10,26 @@ package org.dive4elements.river.artifacts.sinfo.common; import java.io.OutputStream; +import java.text.DateFormat; +import java.text.NumberFormat; import java.util.Collection; +import java.util.Date; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import org.apache.commons.lang.math.DoubleRange; import org.apache.log4j.Logger; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.common.utils.Config; +import org.dive4elements.river.FLYS; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.SInfoI18NStrings; +import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; import org.dive4elements.river.artifacts.sinfo.util.MetaAndTableJRDataSource; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; +import org.dive4elements.river.artifacts.sinfo.util.WstInfo; import org.dive4elements.river.exports.AbstractExporter; import au.com.bytecode.opencsv.CSVWriter; @@ -35,6 +44,20 @@ */ public abstract class AbstractSInfoExporter, RESULTS extends AbstractSInfoCalculationResults> extends AbstractExporter { + private static final String CSV_META_HEADER_SOUNDING = "sinfo.export.flow_depth.csv.meta.header.sounding"; + + private static final String CSV_META_HEADER_SOUNDING_YEAR = "sinfo.export.flow_depth.csv.meta.header.sounding.year"; + + private static final String CSV_META_HEADER_SOUNDING_TYPE = "sinfo.export.flow_depth.csv.meta.header.sounding.type"; + + private static final String CSV_META_HEADER_SOUNDING_EVALUATOR = "sinfo.export.flow_depth.csv.meta.header.sounding.evaluator"; + + private static final String CSV_META_HEADER_SOUNDING_PRJ = "sinfo.export.flow_depth.csv.meta.header.sounding.prj"; + + private static final String CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL = "sinfo.export.flow_depth.csv.meta.header.sounding.elevationmodel"; + + private static final String CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL = "sinfo.export.flow_depth.csv.meta.header.sounding.elevationmodel.original"; + /** The storage that contains the current calculation result. */ private RESULTS data = null; @@ -173,4 +196,98 @@ } protected abstract String[] formatPDFRow(RESULTS results, final ROW row); + + protected final void writeCSVGlobalMetadataDefaults(final CSVWriter writer, final AbstractSInfoCalculationResults results) { + + final String calcModeLabel = results.getCalcModeLabel(); + final RiverInfo river = results.getRiver(); + final DoubleRange calcRange = results.getCalcRange(); + + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_RESULT, msg(SInfoI18NStrings.CSV_META_HEADER_RESULT_LABEL), river.getName(), calcModeLabel); + + // "# FLYS-Version: " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_VERSION, msg(SInfoI18NStrings.CSV_META_VERSION_LABEL), FLYS.VERSION); + + // "# Bearbeiter: " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_USER, msg(SInfoI18NStrings.CSV_META_USER_LABEL), results.getUser()); + + // "# Datum der Erstellung: " + final Locale locale = Resources.getLocale(this.context.getMeta()); + final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_CREATION, msg(SInfoI18NStrings.CSV_META_CREATION_LABEL), df.format(new Date())); + + // "# Gewässer: " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_RIVER, msg(SInfoI18NStrings.CSV_META_RIVER_LABEL), river.getName()); + + // "# Höhensystem des Flusses: " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEIGHT_UNIT_RIVER, river.getWstUnit()); + + // "# Ort/Bereich (km): " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_RANGE, msg(SInfoI18NStrings.CSV_META_RANGE_LABEL), + getKmFormatter().format(calcRange.getMinimumDouble()), getKmFormatter().format(calcRange.getMaximumDouble())); + } + + protected final void writeCSVSoundingMetadata(final CSVWriter writer, final BedHeightInfo sounding) { + // "##METADATEN PEILUNG" + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING); + + // "# Jahr der Peilung: " + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_YEAR, Integer.toString(sounding.getYear())); + // "# Aufnahmeart: " + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_TYPE, sounding.getType()); + // "# Auswerter: " + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_EVALUATOR, sounding.getEvaluationBy()); + // "# Lagesystem: " + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_PRJ, sounding.getLocationSystem()); + // "# Höhensystem: " + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL, sounding.getCurElevationModelUnit()); + // "# ursprüngliches Höhensystem: " + writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL, sounding.getOldElevationModelUnit()); + } + + protected final void writeCSVWaterlevelMetadata(final CSVWriter writer, final WstInfo wst) { + // "##METADATEN WASSERSPIEGELLAGE" + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL); + + // "# Bezeichnung der Wasserspiegellage: " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_NAME, wst.getLabel()); + + // "# Bezugspegel: " + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_GAUGE, wst.getGauge()); + + // "# Jahr/Zeitraum der Wasserspiegellage: " + final int year = wst.getYear(); + if (year > 0) + writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_YEAR, Integer.toString(year)); + } + + protected final void addJRMetaDataDefaults(final MetaAndTableJRDataSource source, final AbstractSInfoCalculationResults results) { + + final RiverInfo river = results.getRiver(); + final String wstUnitName = river.getWstUnit(); + + source.addMetaData("header", msg(SInfoI18NStrings.CSV_META_HEADER_RESULT_LABEL)); + source.addMetaData("calcMode", results.getCalcModeLabel()); + + source.addMetaData("version_label", msg(SInfoI18NStrings.CSV_META_VERSION_LABEL)); + source.addMetaData("version", FLYS.VERSION); + + source.addMetaData("user_label", msg(SInfoI18NStrings.CSV_META_USER_LABEL)); + source.addMetaData("user", results.getUser()); + + final Locale locale = Resources.getLocale(this.context.getMeta()); + final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + source.addMetaData("date_label", msg(SInfoI18NStrings.CSV_META_CREATION_LABEL)); + source.addMetaData("date", df.format(new Date())); + + source.addMetaData("river_label", msg(SInfoI18NStrings.CSV_META_RIVER_LABEL)); + source.addMetaData("river", river.getName()); + source.addMetaData("river_unit", wstUnitName); + + final DoubleRange calcRange = results.getCalcRange(); + final NumberFormat kmFormatter = getKmFormatter(); + final String rangeValue = String.format("%s - %s", kmFormatter.format(calcRange.getMinimumDouble()), kmFormatter.format(calcRange.getMaximumDouble())); + source.addMetaData("range_label", msg(SInfoI18NStrings.CSV_META_RANGE_LABEL)); + source.addMetaData("range", rangeValue); + } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java Tue Mar 13 18:49:33 2018 +0100 @@ -26,7 +26,7 @@ import org.dive4elements.river.jfree.StyledXYSeries; import org.dive4elements.river.themes.ThemeDocument; -abstract class AbstractSInfoLineProcessor extends AbstractSInfoProcessor { +abstract class AbstractSInfoLineProcessor> extends AbstractSInfoProcessor { public AbstractSInfoLineProcessor(final String i18nAxisLabel, final Set handledFacetType) { super(i18nAxisLabel, handledFacetType); @@ -44,7 +44,8 @@ series.putMetaData(metaData, artifact, context); final String facetName = bundle.getFacetName(); - final AbstractSInfoCalculationResult data = (AbstractSInfoCalculationResult) bundle.getData(context); + @SuppressWarnings("unchecked") + final RESULT data = (RESULT) bundle.getData(context); if (data == null) { // Check has been here before so we keep it for security reasons // this should never happen though. @@ -74,7 +75,7 @@ return scales.getRadius(river, start, end); } - private double[][] generatePoints(final CallContext context, final Artifact artifact, final AbstractSInfoCalculationResult data, + private double[][] generatePoints(final CallContext context, final Artifact artifact, final RESULT data, final String facetName) { final double[][] points = doGetPoints(data, facetName); @@ -87,7 +88,7 @@ return points; } - protected abstract double[][] doGetPoints(AbstractSInfoCalculationResult data, String facetName); + protected abstract double[][] doGetPoints(RESULT data, String facetName); private double[][] movingAverage(final Double radius, final double[][] points) { diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java Tue Mar 13 18:49:33 2018 +0100 @@ -11,9 +11,6 @@ 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. * @@ -22,49 +19,18 @@ 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; + public AbstractSInfoResultRow(final String waterlevelLabel, final String gauge, final String location) { 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; } @@ -73,30 +39,6 @@ return this.gauge; } - public final double getMeanBedHeight() { - return this.tkh.getMeanBedHeight(); - } - - public final double getFlowDepth() { - return this.tkh.getFlowDepth(); - } - - public double getFlowDepthWithTkh() { - return this.tkh.getFlowDepthTkh(); - } - - public double getVelocity() { - return this.tkh.getVelocity(); - } - - public double getD50() { - return this.tkh.getD50(); - } - - public double getTau() { - return this.tkh.getTau(); - } - public final String getLocation() { return this.location; } diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractTkhCalculationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractTkhCalculationResult.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,189 @@ +/** 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.ArrayList; +import java.util.Collection; +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 AbstractTkhCalculationResult extends AbstractSInfoCalculationResult { + + private static final long serialVersionUID = 1L; + + private final boolean hasTkh; + + public AbstractTkhCalculationResult(final String label, final WstInfo wst, final boolean hasTkh, final Collection rows) { + super(label, wst, rows); + this.hasTkh = hasTkh; + } + + public final boolean hasTkh() { + return this.hasTkh; + } + + public double[][] getFlowDepthPoints() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getFlowDepth()); + } + + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } + + public double[][] getFlowDepthTkhPoints() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getFlowDepthWithTkh()); + } + + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } + + public final double[][] getTkhUpPoints() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + final List kinds = new ArrayList<>(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getTkhUp()); + kinds.add(row.getTkhKind()); + } + + return adjustTkhVisualization(xPoints, yPoints, kinds); + } + + public final double[][] getTkhDownPoints() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + final List kinds = new ArrayList<>(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getTkhDown()); + kinds.add(row.getTkhKind()); + } + + return adjustTkhVisualization(xPoints, yPoints, kinds); + } + + public double[][] getVelocityPoints() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getVelocity()); + } + + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } + + public double[][] getD50Points() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getD50()); + } + + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } + + public double[][] getTauPoints() { + + final Collection rows = getRows(); + + final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + + for (final ROW row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getTau()); + } + + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } + + /** + * 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 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 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractTkhResultRow.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractTkhResultRow.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,81 @@ +/** 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 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 AbstractTkhResultRow extends AbstractSInfoResultRow { + private static final long serialVersionUID = 1L; + + private final Tkh tkh; + + public AbstractTkhResultRow(final Tkh tkh, final String waterlevelLabel, final String gauge, final String location) { + super(waterlevelLabel, gauge, location); + this.tkh = tkh; + } + + 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 double getMeanBedHeight() { + return this.tkh.getMeanBedHeight(); + } + + public final double getFlowDepth() { + return this.tkh.getFlowDepth(); + } + + public double getFlowDepthWithTkh() { + return this.tkh.getFlowDepthTkh(); + } + + public double getVelocity() { + return this.tkh.getVelocity(); + } + + public double getD50() { + return this.tkh.getD50(); + } + + public double getTau() { + return this.tkh.getTau(); + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java Tue Mar 13 18:49:33 2018 +0100 @@ -18,7 +18,7 @@ import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; -public final class D50Processor extends AbstractSInfoLineProcessor { +public final class D50Processor extends AbstractSInfoLineProcessor> { // FIXME: check: filtered or not? public static final String FACET_TKH_D50_FILTERED = "sinfo_facet_d50.filtered"; @@ -40,7 +40,7 @@ } @Override - protected double[][] doGetPoints(final AbstractSInfoCalculationResult data, final String facetName) { + protected double[][] doGetPoints(final AbstractTkhCalculationResult data, final String facetName) { if (FACET_TKH_D50_FILTERED.contentEquals(facetName)) return data.getD50Points(); diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java Tue Mar 13 18:49:33 2018 +0100 @@ -18,7 +18,7 @@ import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; -public final class FlowDepthProcessor extends AbstractSInfoLineProcessor { +public final class FlowDepthProcessor extends AbstractSInfoLineProcessor> { private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label"; @@ -47,7 +47,7 @@ } @Override - protected double[][] doGetPoints(final AbstractSInfoCalculationResult data, final String facetName) { + protected double[][] doGetPoints(final AbstractTkhCalculationResult data, final String facetName) { if (FACET_FLOW_DEPTH_FILTERED.contentEquals(facetName)) return data.getFlowDepthPoints(); diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java Tue Mar 13 18:49:33 2018 +0100 @@ -18,7 +18,7 @@ import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; -public final class TauProcessor extends AbstractSInfoLineProcessor { +public final class TauProcessor extends AbstractSInfoLineProcessor> { // FIXME: check: filtered or not? public static final String FACET_TKH_TAU_FILTERED = "sinfo_facet_tau.filtered"; @@ -40,7 +40,7 @@ } @Override - protected double[][] doGetPoints(final AbstractSInfoCalculationResult data, final String facetName) { + protected double[][] doGetPoints(final AbstractTkhCalculationResult data, final String facetName) { if (FACET_TKH_TAU_FILTERED.contentEquals(facetName)) return data.getTauPoints(); diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java Tue Mar 13 18:49:33 2018 +0100 @@ -49,7 +49,7 @@ final CallContext context = generator.getCallContext(); final String facetName = bundle.getFacetName(); - final AbstractSInfoCalculationResult data = (AbstractSInfoCalculationResult) bundle.getData(context); + final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) bundle.getData(context); if (data == null) { // Check has been here before so we keep it for security reasons // this should never happen though. diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java Tue Mar 13 18:49:33 2018 +0100 @@ -18,7 +18,7 @@ import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; -public final class VelocityProcessor extends AbstractSInfoLineProcessor { +public final class VelocityProcessor extends AbstractSInfoLineProcessor> { // FIXME: check: filtered or not? public static final String FACET_TKH_VELOCITY_FILTERED = "sinfo_facet_velocity.filtered"; @@ -40,7 +40,7 @@ } @Override - protected double[][] doGetPoints(final AbstractSInfoCalculationResult data, final String facetName) { + protected double[][] doGetPoints(final AbstractTkhCalculationResult data, final String facetName) { if (FACET_TKH_VELOCITY_FILTERED.contentEquals(facetName)) return data.getVelocityPoints(); diff -r 4a6b6a3c279c -r 5d5d482da3e9 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 Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthAccess.java Tue Mar 13 18:49:33 2018 +0100 @@ -10,7 +10,6 @@ package org.dive4elements.river.artifacts.sinfo.flowdepth; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -18,7 +17,6 @@ import org.dive4elements.river.artifacts.access.RangeAccess; import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; import org.dive4elements.river.artifacts.sinfo.SinfoCalcMode; -import org.dive4elements.river.backend.utils.StringUtil; /** * Access to the flow depth calculation type specific SInfo artifact data. @@ -29,23 +27,8 @@ * @author Gernot Belger */ 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 String getSoundingId() { - return this.soundingId; - } - } + private static final String FIELD_DIFFIDS = "diffids"; private static final String FIELD_USE_TKH = "use_transport_bodies"; //$NON-NLS-1$ @@ -68,25 +51,15 @@ return useTkh == null ? false : useTkh; } - public Collection getDifferencePairs() { + public Collection getDifferencePairs() { - final Collection diffPairs = new ArrayList<>(); - - final String diffids = super.getString("diffids"); + final String diffids = getString(FIELD_DIFFIDS); if (diffids == null) { // Should never happen as this is handled by the ui return Collections.emptyList(); } - // 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); + final Collection pairs = WstSoundingIdPair.parsePairs(diffids); + return pairs; } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 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 Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Tue Mar 13 18:49:33 2018 +0100 @@ -13,16 +13,15 @@ import org.apache.commons.lang.math.DoubleRange; 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.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.tkhcalculation.DischargeValuesFinder; import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator; +import org.dive4elements.river.artifacts.sinfo.tkhcalculation.WaterlevelValuesFinder; import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; @@ -30,7 +29,6 @@ import org.dive4elements.river.artifacts.states.WaterlevelData; import org.dive4elements.river.artifacts.states.WaterlevelFetcher; import org.dive4elements.river.model.River; -import org.dive4elements.river.utils.RiverUtils; class FlowDepthCalculation { @@ -51,7 +49,7 @@ final River river = access.getRiver(); final RiverInfo riverInfo = new RiverInfo(river); - final Collection diffPairs = access.getDifferencePairs(); + final Collection diffPairs = access.getDifferencePairs(); final DoubleRange calcRange = access.getRange(); @@ -66,7 +64,7 @@ final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); - for (final DifferencesPair diffPair : diffPairs) { + for (final WstSoundingIdPair diffPair : diffPairs) { final FlowDepthCalculationResult result = calculateResult(calcRange, diffPair, problems, infoProvider, useTkh); if (result != null) results.addResult(result); @@ -80,34 +78,29 @@ * * @param infoProvider */ - private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final DifferencesPair diffPair, - final Calculation problems, final RiverInfoProvider infoProvider, final boolean useTkh) { + private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final WstSoundingIdPair 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 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); + final BedHeightsFinder bedHeight = BedHeightsFinder.forId(this.context, soundingId, calcRange, problems); + if (bedHeight == null) return null; - } /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */ - final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN); - if (waterlevel == null) { - final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'", wstId); - problems.addProblem(message); + final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN, problems); + if (waterlevel == null) return null; - } + final WKms wstKms = waterlevel.getWkms(); final String wspLabel = wstKms.getName(); final String soundingLabel = bedHeight.getInfo().getDescription(); final String label = String.format("%s - %s", wspLabel, soundingLabel); - checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems); + FlowDepthUtils.checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems); checkWaterlevelDiscretisation(wstKms, calcRange, problems); // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden @@ -117,61 +110,19 @@ final int wspYear = waterlevel.getYear(); final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge()); + final WaterlevelValuesFinder waterlevelProvider = WaterlevelValuesFinder.fromKms(wstKms); final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms); final River river = riverInfoProvider.getRiver(); - final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, dischargeProvider, + final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, waterlevelProvider, + dischargeProvider, bedHeight); - final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wstKms, dischargeProvider, bedHeight, tkhCalculator); + final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wspLabel, bedHeight, tkhCalculator); return calculator.execute(label, wstInfo, calcRange); } - - /** - * Checks the year difference between waterlevels and sounding, and issues a warning if too big. - * - * Zeitraum Zeitliche Differenz [a] - * X ≥ 1998 ± 3 - * 1958 ≤ X < 1998 ± 6 - * 1918 ≤ X < 1958 ± 12 - * X < 1918 ± 25 - */ - private void checkYearDifference(final String label, final WaterlevelData waterlevel, final Integer soundingYear, final Calculation problems) { - if (soundingYear == null) - return; - - final int wstYear = waterlevel.getYear(); - if (wstYear < 0) - return; - - final int maxDifference = getMaxDifferenceYears(soundingYear); - - final int difference = Math.abs(soundingYear - wstYear); - if (difference > maxDifference) { - final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.year_difference", null, label, wstYear, - soundingYear); - problems.addProblem(message); - } - } - - private int getMaxDifferenceYears(final int year) { - - if (year < 1918) - return 25; - - if (1918 <= year && year < 1958) - return 12; - - if (1958 <= year && year < 1998) - return 6; - - /* >= 1998 */ - return 3; - } - /* Checks if the discretisation of the waterlevel exceeds 1000m */ - private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { final int size = wstKms.size(); @@ -190,37 +141,4 @@ } } } - - 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 - // throughout flys. - // The knowledge on how to parse the datacage-ids is spread through the complete code-base... - - // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but - // this is plain random - final String[] parts = soundingId.split(";"); - - 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. - // final String bedheightType = artifact.getDataAsString("type"); - - // REMARK: BedDifferences uses this, but we also need the metadata of the BedHeight - // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via - // hibernate stuff - // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. - // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); - - return BedHeightsFinder.forId(bedheightId, calcRange); - } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 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 Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java Tue Mar 13 18:49:33 2018 +0100 @@ -11,7 +11,7 @@ import java.util.Collection; -import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoCalculationResult; +import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult; import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; import org.dive4elements.river.artifacts.sinfo.util.WstInfo; @@ -20,7 +20,7 @@ * * @author Gernot Belger */ -final class FlowDepthCalculationResult extends AbstractSInfoCalculationResult { +final class FlowDepthCalculationResult extends AbstractTkhCalculationResult { private static final long serialVersionUID = 1L; diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java Tue Mar 13 18:49:33 2018 +0100 @@ -13,16 +13,11 @@ 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.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 @@ -31,33 +26,26 @@ private final Collection 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) { + public FlowDepthCalculator(final RiverInfoProvider riverInfoProvider, final String wstLabel, final BedHeightsFinder bedHeight, + final TkhCalculator tkhCalculator) { this.riverInfoProvider = riverInfoProvider; + this.wstLabel = wstLabel; - 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) { @@ -68,40 +56,21 @@ calculateResultRow(station); } - return new FlowDepthCalculationResult(label, wstInfo, this.bedHeight.getInfo(), this.tkhCalculator != null, this.rows); + final boolean hasTkh = this.tkhCalculator.hasTkh(); + + return new FlowDepthCalculationResult(label, wstInfo, this.bedHeight.getInfo(), hasTkh, 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); - - // 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); + final Tkh tkh = this.tkhCalculator.getTkh(station); - this.rows.add(new FlowDepthRow(tkh, this.wstLabel, gaugeLabel, this.bedHeightLabel, location)); - } - catch (final FunctionEvaluationException e) { - /* should only happen if out of range */ - e.printStackTrace(); - /* simply ignore */ - } - } + // REMARK: access the location once only during calculation + final String location = this.riverInfoProvider.getLocation(station); - 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); - final double flowDepth = wst - meanBedHeight; - return new Tkh(station, wst, meanBedHeight, flowDepth, discharge); - } + // REMARK: access the gauge once only during calculation + final String gaugeLabel = this.riverInfoProvider.findGauge(station); - return this.tkhCalculator.getTkh(station, wst); + this.rows.add(new FlowDepthRow(tkh, this.wstLabel, gaugeLabel, this.bedHeightLabel, location)); } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java Tue Mar 13 18:49:33 2018 +0100 @@ -8,18 +8,11 @@ package org.dive4elements.river.artifacts.sinfo.flowdepth; -import java.text.DateFormat; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; -import java.util.Locale; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.math.DoubleRange; import org.apache.log4j.Logger; -import org.dive4elements.river.FLYS; -import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.sinfo.SInfoI18NStrings; import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoExporter; import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; @@ -31,7 +24,7 @@ import au.com.bytecode.opencsv.CSVWriter; /** - * Generates different output formats (csv, pdf) of data that resulted from a flow depths computation. + * Generates different output formats (csv, pdf) of data that resulted from a flow depths min/max computation. * * @author Ingo Weinzierl * @author Gernot Belger @@ -42,28 +35,13 @@ /** The log used in this exporter. */ private static Logger log = Logger.getLogger(FlowDepthExporter.class); - private static final String CSV_FLOWDEPTH_HEADER = "sinfo.export.flow_depth.csv.header.flowdepth"; - private static final String CSV_FLOWDEPTHTKH_HEADER = "sinfo.export.flow_depth.csv.header.flowdepthTkh"; + private static final String CSV_FLOWDEPTHMINMAX_HEADER = "sinfo.export.flow_depth_minmax.csv.header.flowdepthminmax"; + + private static final String CSV_FLOWDEPTHTKHMINMAX_HEADER = "sinfo.export.flow_depth_minmax.csv.header.flowdepthTkh"; + private static final String CSV_TKH_HEADER = "sinfo.export.flow_depth.csv.header.tkh"; - private static final String CSV_MEAN_BED_HEIGHT_HEADER_SHORT = "sinfo.export.flow_depth.csv.header.mean_bed_height.short"; - private static final String CSV_SOUNDING_HEADER = "sinfo.export.flow_depth.csv.header.sounding"; - - private static final String CSV_META_HEADER_SOUNDING = "sinfo.export.flow_depth.csv.meta.header.sounding"; - - private static final String CSV_META_HEADER_SOUNDING_YEAR = "sinfo.export.flow_depth.csv.meta.header.sounding.year"; - - private static final String CSV_META_HEADER_SOUNDING_TYPE = "sinfo.export.flow_depth.csv.meta.header.sounding.type"; - - private static final String CSV_META_HEADER_SOUNDING_EVALUATOR = "sinfo.export.flow_depth.csv.meta.header.sounding.evaluator"; - - private static final String CSV_META_HEADER_SOUNDING_PRJ = "sinfo.export.flow_depth.csv.meta.header.sounding.prj"; - - private static final String CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL = "sinfo.export.flow_depth.csv.meta.header.sounding.elevationmodel"; - - private static final String CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL = "sinfo.export.flow_depth.csv.meta.header.sounding.elevationmodel.original"; - - private static final String JASPER_FILE = "/jasper/sinfo.flowdepth.jasper"; + private static final String JASPER_FILE = "/jasper/sinfo.flowdepthminmax.jasper"; @Override protected Logger getLog() { @@ -71,70 +49,22 @@ } @Override - protected void writeCSVResultMetadata(final CSVWriter writer, final FlowDepthCalculationResults results, final FlowDepthCalculationResult result) { - - /* first some specific metadata */ - final BedHeightInfo sounding = result.getSounding(); - final WstInfo wst = result.getWst(); - - // "##METADATEN PEILUNG" - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING); + protected void writeCSVGlobalMetadata(final CSVWriter writer, final FlowDepthCalculationResults results) { + log.info("FlowDepthExporter.writeCSVMeta"); - // "# Jahr der Peilung: " - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_YEAR, Integer.toString(sounding.getYear())); - // "# Aufnahmeart: " - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_TYPE, sounding.getType()); - // "# Auswerter: " - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_EVALUATOR, sounding.getEvaluationBy()); - // "# Lagesystem: " - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_PRJ, sounding.getLocationSystem()); - // "# Höhensystem: " - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL, sounding.getCurElevationModelUnit()); - // "# ursprüngliches Höhensystem: " - writeCSVMetaEntry(writer, CSV_META_HEADER_SOUNDING_ELEVATIOIN_MODEL_ORIGINAL, sounding.getOldElevationModelUnit()); + super.writeCSVGlobalMetadataDefaults(writer, results); - // "##METADATEN WASSERSPIEGELLAGE" - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL); - // "# Bezeichnung der Wasserspiegellage: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_NAME, wst.getLabel()); - // "# Bezugspegel: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_GAUGE, wst.getGauge()); - // "# Jahr/Zeitraum der Wasserspiegellage: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_YEAR, Integer.toString(wst.getYear())); + writer.writeNext(new String[] { "" }); } @Override - protected void writeCSVGlobalMetadata(final CSVWriter writer, final FlowDepthCalculationResults results) { - log.info("FlowDepthExporter.writeCSVMeta"); - - final String calcModeLabel = results.getCalcModeLabel(); - final RiverInfo river = results.getRiver(); - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_RESULT, msg(SInfoI18NStrings.CSV_META_HEADER_RESULT_LABEL), river.getName(), calcModeLabel); - - // "# FLYS-Version: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_VERSION, msg(SInfoI18NStrings.CSV_META_VERSION_LABEL), FLYS.VERSION); - - // "# Bearbeiter: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_USER, msg(SInfoI18NStrings.CSV_META_USER_LABEL), results.getUser()); + protected void writeCSVResultMetadata(final CSVWriter writer, final FlowDepthCalculationResults results, final FlowDepthCalculationResult result) { - // "# Datum der Erstellung: " - final Locale locale = Resources.getLocale(this.context.getMeta()); - final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_CREATION, msg(SInfoI18NStrings.CSV_META_CREATION_LABEL), df.format(new Date())); - - // "# Gewässer: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_RIVER, msg(SInfoI18NStrings.CSV_META_RIVER_LABEL), river.getName()); + final BedHeightInfo sounding = result.getSounding(); + super.writeCSVSoundingMetadata(writer, sounding); - // "# Höhensystem des Flusses: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEIGHT_UNIT_RIVER, river.getWstUnit()); - - // "# Ort/Bereich (km): " - final DoubleRange calcRange = results.getCalcRange(); - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_RANGE, msg(SInfoI18NStrings.CSV_META_RANGE_LABEL), - getKmFormatter().format(calcRange.getMinimumDouble()), - getKmFormatter().format(calcRange.getMaximumDouble())); - - writer.writeNext(new String[] { "" }); + final WstInfo wst = result.getWst(); + super.writeCSVWaterlevelMetadata(writer, wst); } /** @@ -152,9 +82,9 @@ final Collection header = new ArrayList<>(11); header.add(msg(SInfoI18NStrings.CSV_KM_HEADER)); - header.add(msgUnit(CSV_FLOWDEPTH_HEADER, SInfoI18NStrings.UNIT_M)); + header.add(msgUnit(CSV_FLOWDEPTHMINMAX_HEADER, SInfoI18NStrings.UNIT_M)); if (getData().isUseTkh()) { - header.add(msgUnit(CSV_FLOWDEPTHTKH_HEADER, SInfoI18NStrings.UNIT_M)); + header.add(msgUnit(CSV_FLOWDEPTHTKHMINMAX_HEADER, SInfoI18NStrings.UNIT_M)); header.add(msgUnit(CSV_TKH_HEADER, SInfoI18NStrings.UNIT_CM)); } @@ -163,7 +93,7 @@ header.add(msg(SInfoI18NStrings.CSV_LABEL_HEADER)); header.add(msg(SInfoI18NStrings.CSV_GAUGE_HEADER)); header.add(msgUnit(SInfoI18NStrings.CSV_MEAN_BED_HEIGHT_HEADER, river.getWstUnit())); - header.add(msg(CSV_SOUNDING_HEADER)); + header.add(msg(SInfoI18NStrings.CSV_SOUNDING_HEADER)); header.add(msg(SInfoI18NStrings.CSV_LOCATION_HEADER)); writer.writeNext(header.toArray(new String[header.size()])); @@ -235,45 +165,20 @@ @Override protected final void addJRMetaData(final MetaAndTableJRDataSource source, final FlowDepthCalculationResults results) { - final RiverInfo river = results.getRiver(); - final String wstUnitName = river.getWstUnit(); - /* general metadata */ - source.addMetaData("header", msg(SInfoI18NStrings.CSV_META_HEADER_RESULT_LABEL)); - source.addMetaData("calcMode", results.getCalcModeLabel()); - - source.addMetaData("version_label", msg(SInfoI18NStrings.CSV_META_VERSION_LABEL)); - source.addMetaData("version", FLYS.VERSION); - - source.addMetaData("user_label", msg(SInfoI18NStrings.CSV_META_USER_LABEL)); - source.addMetaData("user", results.getUser()); - - final Locale locale = Resources.getLocale(this.context.getMeta()); - final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - source.addMetaData("date_label", msg(SInfoI18NStrings.CSV_META_CREATION_LABEL)); - source.addMetaData("date", df.format(new Date())); - - source.addMetaData("river_label", msg(SInfoI18NStrings.CSV_META_RIVER_LABEL)); - source.addMetaData("river", river.getName()); - - final DoubleRange calcRange = results.getCalcRange(); - final NumberFormat kmFormatter = getKmFormatter(); - final String rangeValue = String.format("%s - %s", kmFormatter.format(calcRange.getMinimumDouble()), kmFormatter.format(calcRange.getMaximumDouble())); - source.addMetaData("range_label", msg(SInfoI18NStrings.CSV_META_RANGE_LABEL)); - source.addMetaData("range", rangeValue); + super.addJRMetaDataDefaults(source, results); /* column headings */ source.addMetaData("station_header", msg(SInfoI18NStrings.CSV_KM_HEADER)); - source.addMetaData("flowdepth_header", msg(CSV_FLOWDEPTH_HEADER)); - source.addMetaData("flowdepth_tkh_header", msg(CSV_FLOWDEPTHTKH_HEADER)); + source.addMetaData("flowdepth_header", msg(CSV_FLOWDEPTHMINMAX_HEADER)); + source.addMetaData("flowdepth_tkh_header", msg(CSV_FLOWDEPTHTKHMINMAX_HEADER)); source.addMetaData("tkh_header", msg(CSV_TKH_HEADER)); source.addMetaData("waterlevel_header", msg(SInfoI18NStrings.CSV_WATERLEVEL_HEADER)); - source.addMetaData("river_unit", wstUnitName); source.addMetaData("discharge_header", msg(SInfoI18NStrings.CSV_DISCHARGE_HEADER)); source.addMetaData("waterlevel_name_header", msg(SInfoI18NStrings.CSV_LABEL_HEADER)); source.addMetaData("gauge_header", msg(SInfoI18NStrings.CSV_GAUGE_HEADER)); - source.addMetaData("bedheight_header", msg(CSV_MEAN_BED_HEIGHT_HEADER_SHORT)); - source.addMetaData("sounding_name_header", msg(CSV_SOUNDING_HEADER)); + source.addMetaData("bedheight_header", msg(SInfoI18NStrings.CSV_MEAN_BED_HEIGHT_HEADER_SHORT)); + source.addMetaData("sounding_name_header", msg(SInfoI18NStrings.CSV_SOUNDING_HEADER)); source.addMetaData("location_header", msg(SInfoI18NStrings.CSV_LOCATION_HEADER)); } diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java Tue Mar 13 18:49:33 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) @@ -15,13 +15,15 @@ * @author Gernot Belger * */ -public class FlowDepthPairSelectState -// FIXME: very ugly; but probably we will break the serialization of WaterlevelPairSelectState if we introduce an abstraction -extends WaterlevelPairSelectState { +// FIXME: very ugly; but probably we will break the serialization of WaterlevelPairSelectState if we introduce an +// abstraction +public final class FlowDepthPairSelectState extends WaterlevelPairSelectState { + + private static final long serialVersionUID = 1L; /** Specify to display a datacage_twin_panel. */ @Override protected String getUIProvider() { return "sinfo_flowdepth_twin_panel"; } -} +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 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 Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java Tue Mar 13 18:49:33 2018 +0100 @@ -9,7 +9,7 @@ */ package org.dive4elements.river.artifacts.sinfo.flowdepth; -import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoResultRow; +import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhResultRow; import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh; /** @@ -17,7 +17,7 @@ * * @author Gernot Belger */ -final class FlowDepthRow extends AbstractSInfoResultRow { +final class FlowDepthRow extends AbstractTkhResultRow { private static final long serialVersionUID = 1L; private final String soundingLabel; diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthUtils.java Tue Mar 13 18:49:33 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.flowdepth; + +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.artifacts.states.WaterlevelData; + +/** + * @author Gernot Belger + */ +public final class FlowDepthUtils { + + private FlowDepthUtils() { + throw new UnsupportedOperationException(); + } + + /** + * Checks the year difference between waterlevels and sounding, and issues a warning if too big. + * + * Zeitraum Zeitliche Differenz [a] + * X ≥ 1998 ± 3 + * 1958 ≤ X < 1998 ± 6 + * 1918 ≤ X < 1958 ± 12 + * X < 1918 ± 25 + */ + public static void checkYearDifference(final String label, final WaterlevelData waterlevel, final int soundingYear, final Calculation problems) { + + final int wstYear = waterlevel.getYear(); + if (wstYear < 0) + return; + + final int maxDifference = getMaxDifferenceYears(soundingYear); + + final int difference = Math.abs(soundingYear - wstYear); + if (difference > maxDifference) { + problems.addProblem("sinfo_calc_flow_depth.warning.year_difference", label, wstYear, soundingYear); + } + } + + public static int getMaxDifferenceYears(final int year) { + + if (year < 1918) + return 25; + + if (1918 <= year && year < 1958) + return 12; + + if (1958 <= year && year < 1998) + return 6; + + /* >= 1998 */ + return 3; + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/UseTransportBodiesChoice.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/UseTransportBodiesChoice.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/UseTransportBodiesChoice.java Tue Mar 13 18:49:33 2018 +0100 @@ -15,7 +15,9 @@ */ public class UseTransportBodiesChoice extends BooleanChoiceState { + private static final long serialVersionUID = 1L; + public UseTransportBodiesChoice() { - super( "useTransportBodies.option", "useTransportBodies.active", "useTransportBodies.inactive" ); - } + super( "useTransportBodies.option", "useTransportBodies.active", "useTransportBodies.inactive" ); + } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/WstSoundingIdPair.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/WstSoundingIdPair.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,56 @@ +/** 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.Collections; +import java.util.List; + +import org.dive4elements.river.backend.utils.StringUtil; + +/** + * @author Gernot Belger + */ +public final class WstSoundingIdPair { + + private final String wstId; + + private final String soundingId; + + public WstSoundingIdPair(final String wstId, final String soundingId) { + this.wstId = wstId; + this.soundingId = soundingId; + } + + public String getWstId() { + return this.wstId; + } + + public String getSoundingId() { + return this.soundingId; + } + + public static List parsePairs(final String diffids) { + + // FIXME: this way of parsing the datacage-ids is repeated all over flys! + final String datas[] = diffids.split("#"); + + final List diffPairs = new ArrayList<>(datas.length); + + 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 WstSoundingIdPair(leftId, rightId)); + } + + return Collections.unmodifiableList(diffPairs); + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxAccess.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,105 @@ +/* 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.flowdepthminmax; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +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; +import org.dive4elements.river.artifacts.sinfo.flowdepth.WstSoundingIdPair; + +/** + * 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 FlowDepthMinMaxAccess extends RangeAccess { + + public static class MinMaxIdPair { + + private final String wstId; + + private final String minSoundingId; + + private final String maxSoundingId; + + public MinMaxIdPair(final String wstId, final String minSoundingId, final String maxSoundingId) { + this.wstId = wstId; + this.minSoundingId = minSoundingId; + this.maxSoundingId = maxSoundingId; + } + + public String getWstId() { + return this.wstId; + } + + public String getMinSoundingId() { + return this.minSoundingId; + } + + public String getMaxSoundingId() { + return this.maxSoundingId; + } + } + + private static final String FIELD_DIFFIDS = "diffids"; + + public FlowDepthMinMaxAccess(final SINFOArtifact artifact) { + super(artifact); + + /* assert calculation mode */ + final SinfoCalcMode calculationMode = artifact.getCalculationMode(); + assert (calculationMode == SinfoCalcMode.sinfo_calc_flow_depth_minmax); + } + + public DoubleRange getRange() { + final double from = getFrom(); + final double to = getTo(); + return new DoubleRange(from, to); + } + + public Collection getMinMaxPairs() { + + final String diffids = getString(FIELD_DIFFIDS); + + /* fetch the raw configured pairs */ + final List diffPairs = WstSoundingIdPair.parsePairs(diffids); + + /* now sort eleemnts into pairs of TL/KL */ + // FIXME: use sounding-ids to determine how pairs fit together + // or, let the ui already enforce it somehow + + final List minMaxPairs = new ArrayList<>(diffPairs.size()); + // FIXME: at the moment, we simply pair by order + for (int i = 0; i < diffPairs.size(); i++) { + + final WstSoundingIdPair minPair = diffPairs.get(i); + + if (i < diffPairs.size() - 1) { + final WstSoundingIdPair maxPair = diffPairs.get(i + 1); + minMaxPairs.add(new MinMaxIdPair(minPair.getWstId(), minPair.getSoundingId(), maxPair.getSoundingId())); + i++; + } else { + minMaxPairs.add(new MinMaxIdPair(minPair.getWstId(), minPair.getSoundingId(), null)); + } + } + + return Collections.unmodifiableCollection(minMaxPairs); + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculation.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,201 @@ +/** 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.flowdepthminmax; + +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.model.Calculation; +import org.dive4elements.river.artifacts.model.CalculationResult; +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.FlowDepthUtils; +import org.dive4elements.river.artifacts.sinfo.flowdepthminmax.FlowDepthMinMaxAccess.MinMaxIdPair; +import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder; +import org.dive4elements.river.artifacts.sinfo.tkhcalculation.WaterlevelValuesFinder; +import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; +import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; +import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; +import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; +import org.dive4elements.river.artifacts.sinfo.util.WstInfo; +import org.dive4elements.river.artifacts.states.WaterlevelData; +import org.dive4elements.river.artifacts.states.WaterlevelFetcher; +import org.dive4elements.river.model.River; + +/** + * @author Gernot Belger + */ +final class FlowDepthMinMaxCalculation { + + private final CallContext context; + + public FlowDepthMinMaxCalculation(final CallContext context) { + this.context = context; + } + + public CalculationResult calculate(final SINFOArtifact sinfo) { + + final String user = CalculationUtils.findArtifactUser(this.context, sinfo); + + /* access input data */ + final FlowDepthMinMaxAccess access = new FlowDepthMinMaxAccess(sinfo); + final River river = access.getRiver(); + final RiverInfo riverInfo = new RiverInfo(river); + + final Collection minMaxPairs = access.getMinMaxPairs(); + + final DoubleRange calcRange = access.getRange(); + + /* calculate results for each diff pair */ + final Calculation problems = new Calculation(); + + final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange); + + final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); + + final FlowDepthMinMaxCalculationResults results = new FlowDepthMinMaxCalculationResults(calcModeLabel, user, riverInfo, calcRange); + + for (final MinMaxIdPair minMaxPair : minMaxPairs) { + final FlowDepthMinMaxCalculationResult result = calculateResult(calcRange, minMaxPair, problems, infoProvider); + if (result != null) + results.addResult(result); + } + + return new CalculationResult(results, problems); + } + + /** + * Calculates one W-MSH differences pair. + * + * @param infoProvider + */ + private FlowDepthMinMaxCalculationResult calculateResult(final DoubleRange calcRange, final MinMaxIdPair minMaxPair, final Calculation problems, + final RiverInfoProvider infoProvider) { + + /* access real input data from database */ + final String wstId = minMaxPair.getWstId(); + final String minSoundingId = minMaxPair.getMinSoundingId(); + final String maxSoundingId = minMaxPair.getMinSoundingId(); + + final BedHeightsFinder minBedHeight = minSoundingId == null ? null : BedHeightsFinder.forId(this.context, minSoundingId, calcRange, problems); + final BedHeightsFinder maxBedHeight = maxSoundingId == null ? null : BedHeightsFinder.forId(this.context, maxSoundingId, calcRange, problems); + if (minBedHeight == null && maxBedHeight == null) + return null; + + /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */ + final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN, problems); + if (waterlevel == null) + return null; + + final String label = createLabel(waterlevel, minBedHeight, maxBedHeight); + + final WKms wstKms = waterlevel.getWkms(); + + final int soundingYear = checkSoundingYear(minBedHeight, maxBedHeight, problems); + FlowDepthUtils.checkYearDifference(label, waterlevel, soundingYear, problems); + // FIXME + // 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 RiverInfoProvider riverInfoProvider = infoProvider.forWaterlevel(waterlevel); + + final int wspYear = waterlevel.getYear(); + final WstInfo wstInfo = new WstInfo(waterlevel.getName(), wspYear, riverInfoProvider.getReferenceGauge()); + + final WaterlevelValuesFinder waterlevelProvider = WaterlevelValuesFinder.fromKms(wstKms); + final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms); + + final String waterlevelLabel = waterlevel.getName(); + final String soundingLabel = buildSoundingLabel(minBedHeight, maxBedHeight); + + /* real calculation loop */ + final Collection rows = new ArrayList<>(); + + // FIXME: determine what is the spatial discretisation that we will use... + final double[] allKms = wstKms.allKms().toNativeArray(); + for (final double station : allKms) { + if (calcRange.containsDouble(station)) { + + final double wst = waterlevelProvider.getWaterlevel(station); + final double discharge = dischargeProvider.getDischarge(station); + + final double minBedHeightValue = minBedHeight == null ? Double.NaN : minBedHeight.getMeanBedHeight(station); + final double maxBedHeightValue = maxBedHeight == null ? Double.NaN : maxBedHeight.getMeanBedHeight(station); + + final double minFlowDepth = wst - minBedHeightValue; + final double maxFlowDepth = wst - maxBedHeightValue; + + // FIXME: unclear what is meant here... + final double meanBedHeight = Double.NaN; + + // REMARK: access the location once only during calculation + final String location = riverInfoProvider.getLocation(station); + + // REMARK: access the gauge once only during calculation + final String gaugeLabel = riverInfoProvider.findGauge(station); + + rows.add(new FlowDepthMinMaxRow(station, minFlowDepth, maxFlowDepth, wst, discharge, waterlevelLabel, gaugeLabel, meanBedHeight, soundingLabel, + location)); + } + } + + final BedHeightInfo minBedHeightInfo = minBedHeight == null ? null : minBedHeight.getInfo(); + final BedHeightInfo maxBedHeightInfo = maxBedHeight == null ? null : maxBedHeight.getInfo(); + return new FlowDepthMinMaxCalculationResult(label, wstInfo, minBedHeightInfo, maxBedHeightInfo, rows); + } + + private String buildSoundingLabel(final BedHeightsFinder minBedHeight, final BedHeightsFinder maxBedHeight) { + + if (minBedHeight == null) + return maxBedHeight.getInfo().getDescription(); + + if (maxBedHeight == null) + return minBedHeight.getInfo().getDescription(); + + return String.format("%s / %s", minBedHeight.getInfo().getDescription(), maxBedHeight.getInfo().getDescription()); + } + + private String createLabel(final WaterlevelData waterlevel, final BedHeightsFinder minBedHeight, final BedHeightsFinder maxBedHeight) { + + final StringBuilder buffer = new StringBuilder(waterlevel.getName()); + + if (minBedHeight != null) + buffer.append(" - "). // + append(minBedHeight.getInfo().getDescription()); + + if (maxBedHeight != null) + buffer.append(" - "). // + append(maxBedHeight.getInfo().getDescription()); + + return buffer.toString(); + } + + private int checkSoundingYear(final BedHeightsFinder minBedHeight, final BedHeightsFinder maxBedHeight, final Calculation problems) { + + if (maxBedHeight == null) + return minBedHeight.getInfo().getYear(); + + if (minBedHeight == null) + return maxBedHeight.getInfo().getYear(); + + final int minYear = minBedHeight.getInfo().getYear(); + final int maxYear = minBedHeight.getInfo().getYear(); + + if (minYear != maxYear) + problems.addProblem("sinfo.flowdepthminmaxcalculation.soundingyear.different"); + + return minYear; + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResult.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,53 @@ +/* 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.flowdepthminmax; + +import java.util.Collection; + +import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoCalculationResult; +import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; +import org.dive4elements.river.artifacts.sinfo.util.WstInfo; + +/** + * Contains the results of a {@link FlowDepthCalculation}. + * + * @author Gernot Belger + */ +final class FlowDepthMinMaxCalculationResult extends AbstractSInfoCalculationResult { + + private static final long serialVersionUID = 1L; + + private final BedHeightInfo minSounding; + + private final BedHeightInfo maxSounding; + + public FlowDepthMinMaxCalculationResult(final String label, final WstInfo wst, final BedHeightInfo minSounding, final BedHeightInfo maxSounding, + final Collection rows) { + super(label, wst, rows); + + this.minSounding = minSounding; + this.maxSounding = maxSounding; + } + + public BedHeightInfo getMinSounding() { + return this.minSounding; + } + + public BedHeightInfo getMaxSounding() { + return this.maxSounding; + } + + public BedHeightInfo getAnySounding() { + if (this.minSounding != null) + return this.minSounding; + + return this.maxSounding; + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxCalculationResults.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,26 @@ +/** 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.flowdepthminmax; + +import org.apache.commons.lang.math.DoubleRange; +import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoCalculationResults; +import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; + +/** + * @author Gernot Belger + */ +final class FlowDepthMinMaxCalculationResults extends AbstractSInfoCalculationResults { + + private static final long serialVersionUID = 1L; + + public FlowDepthMinMaxCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) { + super(calcModeLabel, user, river, calcRange); + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxExporter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxExporter.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,179 @@ +/* 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.flowdepthminmax; + +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dive4elements.river.artifacts.sinfo.SInfoI18NStrings; +import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoExporter; +import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; +import org.dive4elements.river.artifacts.sinfo.util.MetaAndTableJRDataSource; +import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; +import org.dive4elements.river.artifacts.sinfo.util.WstInfo; +import org.dive4elements.river.utils.RiverUtils; + +import au.com.bytecode.opencsv.CSVWriter; + +/** + * Generates different output formats (csv, pdf) of data that resulted from a flow depths computation. + * + * @author Ingo Weinzierl + * @author Gernot Belger + */ +// REMARK: must be public because its registered in generators.xml +public class FlowDepthMinMaxExporter extends AbstractSInfoExporter { + + /** The log used in this exporter. */ + private static Logger log = Logger.getLogger(FlowDepthMinMaxExporter.class); + + private static final String CSV_FLOWDEPTH_MIN_HEADER = "sinfo.export.flow_depth_minmax.csv.header.min"; + + private static final String CSV_FLOWDEPTH_MAX_HEADER = "sinfo.export.flow_depth_minmax.csv.header.max"; + + private static final String JASPER_FILE = "/jasper/sinfo.flowdepth.jasper"; + + @Override + protected Logger getLog() { + return log; + } + + @Override + protected void writeCSVResultMetadata(final CSVWriter writer, final FlowDepthMinMaxCalculationResults results, + final FlowDepthMinMaxCalculationResult result) { + + final BedHeightInfo sounding = result.getAnySounding(); + super.writeCSVSoundingMetadata(writer, sounding); + + final WstInfo wst = result.getWst(); + writeCSVWaterlevelMetadata(writer, wst); + } + + @Override + protected void writeCSVGlobalMetadata(final CSVWriter writer, final FlowDepthMinMaxCalculationResults results) { + + super.writeCSVGlobalMetadataDefaults(writer, results); + + writer.writeNext(new String[] { "" }); + } + + /** + * Write the header, with different headings depending on whether at a + * gauge or at a location. + * + * @param river + * @param useTkh + */ + @Override + protected void writeCSVHeader(final CSVWriter writer, final FlowDepthMinMaxCalculationResults results, final RiverInfo river) { + log.info("FlowDepthExporter.writeCSVHeader"); + + final Collection header = new ArrayList<>(11); + + header.add(msg(SInfoI18NStrings.CSV_KM_HEADER)); + + header.add(msgUnit(CSV_FLOWDEPTH_MIN_HEADER, SInfoI18NStrings.UNIT_M)); + header.add(msgUnit(CSV_FLOWDEPTH_MAX_HEADER, SInfoI18NStrings.UNIT_M)); + + header.add(msgUnit(SInfoI18NStrings.CSV_WATERLEVEL_HEADER, river.getWstUnit())); + header.add(msgUnit(SInfoI18NStrings.CSV_DISCHARGE_HEADER, SInfoI18NStrings.UNIT_CUBIC_M)); + header.add(msg(SInfoI18NStrings.CSV_LABEL_HEADER)); + header.add(msg(SInfoI18NStrings.CSV_GAUGE_HEADER)); + header.add(msgUnit(SInfoI18NStrings.CSV_MEAN_BED_HEIGHT_HEADER, river.getWstUnit())); + header.add(msg(SInfoI18NStrings.CSV_SOUNDING_HEADER)); + header.add(msg(SInfoI18NStrings.CSV_LOCATION_HEADER)); + + writer.writeNext(header.toArray(new String[header.size()])); + } + + @Override + protected String[] formatCSVRow(final FlowDepthMinMaxCalculationResults results, final FlowDepthMinMaxRow row) { + return formatFlowDepthRow(row); + } + + /** + * Format a row of a flow depth result into an array of string, both used by csv and pdf + * + * @param useTkh + */ + private String[] formatFlowDepthRow(final FlowDepthMinMaxRow row) { + + final Collection lines = new ArrayList<>(11); + + // Fluss-km + lines.add(getKmFormatter().format(row.getStation())); + + // FIXME: spalten weglassen, wenn min oder max fehlt + + // Minimale Fließtiefe [m] + lines.add(getFlowDepthFormatter().format(row.getMinFlowDepth())); + // Maximale Fließtiefe [m] + lines.add(getFlowDepthFormatter().format(row.getMaxFlowDepth())); + + // Wasserstand [NN + m] + lines.add(getW2Formatter().format(row.getWaterlevel())); + + // Q [m³/s] + final double discharge = row.getDischarge(); + if (Double.isNaN(discharge)) + lines.add(StringUtils.EMPTY); + else { + final double roundedDischarge = RiverUtils.roundQ(discharge); + lines.add(getQFormatter().format(roundedDischarge)); + } + + // Bezeichnung + lines.add(row.getWaterlevelLabel()); + + // Bezugspegel + lines.add(row.getGauge()); + + // Mittlere Sohlhöhe [NN + m] + lines.add(getMeanBedHeighFormatter().format(row.getMeanBedHeight())); + + // Peilung/Epoche + lines.add(row.getSoundageLabel()); + + // Lage + lines.add(row.getLocation()); + + return lines.toArray(new String[lines.size()]); + } + + @Override + protected final String getJasperFile() { + return JASPER_FILE; + } + + @Override + protected final void addJRMetaData(final MetaAndTableJRDataSource source, final FlowDepthMinMaxCalculationResults results) { + + /* general metadata */ + super.addJRMetaDataDefaults(source, results); + + /* column headings */ + source.addMetaData("station_header", msg(SInfoI18NStrings.CSV_KM_HEADER)); + source.addMetaData("flowdepthmin_header", msg(CSV_FLOWDEPTH_MIN_HEADER)); + source.addMetaData("flowdepthmax_header", msg(CSV_FLOWDEPTH_MAX_HEADER)); + source.addMetaData("waterlevel_header", msg(SInfoI18NStrings.CSV_WATERLEVEL_HEADER)); + source.addMetaData("discharge_header", msg(SInfoI18NStrings.CSV_DISCHARGE_HEADER)); + source.addMetaData("waterlevel_name_header", msg(SInfoI18NStrings.CSV_LABEL_HEADER)); + source.addMetaData("gauge_header", msg(SInfoI18NStrings.CSV_GAUGE_HEADER)); + source.addMetaData("bedheight_header", msg(SInfoI18NStrings.CSV_MEAN_BED_HEIGHT_HEADER_SHORT)); + source.addMetaData("sounding_name_header", msg(SInfoI18NStrings.CSV_SOUNDING_HEADER)); + source.addMetaData("location_header", msg(SInfoI18NStrings.CSV_LOCATION_HEADER)); + } + + @Override + protected String[] formatPDFRow(final FlowDepthMinMaxCalculationResults results, final FlowDepthMinMaxRow row) { + return formatFlowDepthRow(row); + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxRow.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxRow.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,81 @@ +/* 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.flowdepthminmax; + +import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoResultRow; + +/** + * Part of {@link FlowDepthMinMaxCalculationResult} which represents one calculated row of flow depth data. + * + * @author Gernot Belger + */ +final class FlowDepthMinMaxRow extends AbstractSInfoResultRow { + private static final long serialVersionUID = 1L; + + private final double station; + + private final double minFlowDepth; + + private final double maxFlowDepth; + + private final double waterlevel; + + private final double discharge; + + private final double meanBedHeight; + + private final String soundingLabel; + + public FlowDepthMinMaxRow(final double station, final double minFlowDepth, final double maxFlowDepth, final double waterlevel, final double discharge, + final String waterlevelLabel, final String gauge, final double meanBedHeight, final String soundingLabel, final String location) { + + super(waterlevelLabel, gauge, location); + + this.station = station; + this.minFlowDepth = minFlowDepth; + this.maxFlowDepth = maxFlowDepth; + this.waterlevel = waterlevel; + this.discharge = discharge; + this.meanBedHeight = meanBedHeight; + this.soundingLabel = soundingLabel; + } + + public String getSoundageLabel() { + return this.soundingLabel; + } + + public double getStation() { + return this.station; + } + + public double getMinFlowDepth() { + return this.minFlowDepth; + } + + public double getMaxFlowDepth() { + return this.maxFlowDepth; + } + + public double getWaterlevel() { + return this.waterlevel; + } + + public double getDischarge() { + return this.discharge; + } + + public double getMeanBedHeight() { + return this.meanBedHeight; + } + + public String getSoundingLabel() { + return this.soundingLabel; + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxState.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,109 @@ +/* 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.flowdepthminmax; + +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.Calculation; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.DataFacet; +import org.dive4elements.river.artifacts.model.EmptyFacet; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.artifacts.model.ReportFacet; +import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; +import org.dive4elements.river.artifacts.states.DefaultState; + +/** State in which a waterlevel has been calculated. */ +public class FlowDepthMinMaxState extends DefaultState { + + /// ** The log that is used in this state. */ + // private static Logger log = Logger.getLogger(FlowDepthState.class); + + private static final long serialVersionUID = 1L; + + /** + * 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 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 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 facets, final Object old) { + + final CalculationResult res = doCompute(sinfo, context, old); + + if (facets == null) + return res; + + final FlowDepthMinMaxCalculationResults results = (FlowDepthMinMaxCalculationResults) res.getData(); + + /* add themes for chart, for each result */ + final List resultList = results.getResults(); + for (int index = 0; index < resultList.size(); index++) { + + final FlowDepthMinMaxCalculationResult result = resultList.get(index); + + /* filtered (zoom dependent mean) flow depth */ + // facets.add(FlowDepthProcessor.createFlowDepthFacet(context, hash, this.id, result, index)); + + } + + 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; + } + + private CalculationResult doCompute(final SINFOArtifact sinfo, final CallContext context, final Object old) { + if (old instanceof CalculationResult) + return (CalculationResult) old; + + return new FlowDepthMinMaxCalculation(context).calculate(sinfo); + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java Tue Mar 13 18:49:33 2018 +0100 @@ -46,14 +46,20 @@ public DischargeValuesFinder(final QKms qKms) { this.qKms = qKms; - this.qInterpolator = qKms == null ? null : DoubleUtil.getLinearInterpolator(qKms.allKms(), qKms.allQs()); - - this.exactValues = new TDoubleDoubleHashMap(qKms.size()); - for (int i = 0; i < qKms.size(); i++) { - final double station = qKms.getKm(i); - final double discharge = qKms.getQ(i); - this.exactValues.put(station, discharge); + if (qKms == null) { + this.qInterpolator = null; + this.exactValues = null; + } else { + this.qInterpolator = DoubleUtil.getLinearInterpolator(qKms.allKms(), qKms.allQs()); + + this.exactValues = new TDoubleDoubleHashMap(qKms.size()); + + for (int i = 0; i < qKms.size(); i++) { + final double station = qKms.getKm(i); + final double discharge = qKms.getQ(i); + this.exactValues.put(station, discharge); + } } } @@ -68,14 +74,23 @@ return new DoubleRange(this.qKms.allQs().min(), this.qKms.allQs().max()); } - public double getDischarge(final double station) throws FunctionEvaluationException { + public double getDischarge(final double station) { - // IMPORTANT: we first try to retreive the exact value if it is present, to avoid rounding changes due to interpolation. - // This is important because in the WaterlevelExporter code, these values are double-compared (with '==' ...) in order - // to find the corresponding main-value. - if (this.exactValues.contains(station)) - return this.exactValues.get(station); + try { + // IMPORTANT: we first try to retrieve the exact value if it is present, to avoid rounding changes due to interpolation. + // This is important because in the WaterlevelExporter code, these values are double-compared (with '==' ...) in order + // to find the corresponding main-value. + if (this.exactValues != null && this.exactValues.contains(station)) + return this.exactValues.get(station); - return this.qInterpolator.value(station); + if (this.qInterpolator == null) + return Double.NaN; + + return this.qInterpolator.value(station); + } + catch (final FunctionEvaluationException e) { + e.printStackTrace(); + return Double.NaN; + } } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java Tue Mar 13 18:49:33 2018 +0100 @@ -11,7 +11,6 @@ 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; @@ -37,30 +36,33 @@ private final BedHeightsFinder bedHeightsProvider; + private final WaterlevelValuesFinder waterlevelProvider; + 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) { + final River river, final DoubleRange calcRange, final WaterlevelValuesFinder waterlevelProvider, final DischargeValuesFinder dischargeProvider, + final BedHeightsFinder bedHeightsProvider) { if (!useTkh) - return null; + return new TkhCalculator(problems, label, context, null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); if (!dischargeProvider.isValid()) { final String message = Resources.getMsg(context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); problems.addProblem(message); - return null; + return new TkhCalculator(problems, label, context, null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); } - final Integer soundingYear = bedHeightsProvider.getInfo().getYear(); + final int 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.missingD50", null, label); problems.addProblem(message); - return null; + return new TkhCalculator(problems, label, context, null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); } // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden? @@ -68,7 +70,7 @@ if (soilKindFinder == null) { final String message = Resources.getMsg(context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label); problems.addProblem(message); - return null; + return new TkhCalculator(problems, label, context, null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); } final DoubleRange qRange = dischargeProvider.getRange(); @@ -76,35 +78,43 @@ 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, null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); } - return new TkhCalculator(problems, label, context, bedMeasurementsFinder, dischargeProvider, bedHeightsProvider, soilKindFinder, flowVelocitiesFinder); + return new TkhCalculator(problems, label, context, bedMeasurementsFinder, waterlevelProvider, 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 BedQualityD50KmValueFinder bedMeasurementsFinder, final WaterlevelValuesFinder waterlevelProvider, + 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.waterlevelProvider = waterlevelProvider; this.dischargeProvider = dischargeProvider; this.bedHeightsProvider = bedHeightsProvider; this.soilKindFinder = soilKindFinder; this.flowVelocitiesFinder = flowVelocitiesFinder; } - private double getDischarge(final double km) { + public boolean hasTkh() { - try { - return this.dischargeProvider.getDischarge(km); - } - catch (final FunctionEvaluationException e) { - // TODO: exceptions nicht komplett schlucken? evtl. mit log.debug(e) ausgeben - return Double.NaN; - } + if (this.dischargeProvider == null || !this.dischargeProvider.isValid()) + return false; + + if (this.bedMeasurementsFinder == null) + return false; + + if (this.soilKindFinder == null) + return false; + + if (this.flowVelocitiesFinder == null) + return false; + + return true; } private SoilKind getSoilKind(final double km) { @@ -134,26 +144,22 @@ } } - public Tkh getTkh(final double km, final double wst) { + public Tkh getTkh(final double km) { final SoilKind kind = getSoilKind(km); + final double wst = this.waterlevelProvider.getWaterlevel(km); + final double meanBedHeight = this.bedHeightsProvider.getMeanBedHeight(km); final double flowDepth = wst - meanBedHeight; - final double discharge = getDischarge(km); - if (Double.isNaN(discharge)) { + final double discharge = this.dischargeProvider.getDischarge(km); + if (Double.isNaN(discharge)) + return new Tkh(km, wst, meanBedHeight, flowDepth, Double.NaN, kind); - // 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 - + if (!this.hasTkh()) return new Tkh(km, wst, meanBedHeight, flowDepth, Double.NaN, kind); - } final double d50 = getBedMeasurement(km); if (Double.isNaN(d50)) diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/WaterlevelValuesFinder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/WaterlevelValuesFinder.java Tue Mar 13 18:49:33 2018 +0100 @@ -0,0 +1,43 @@ +/** 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.math.ArgumentOutsideDomainException; +import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; +import org.dive4elements.river.artifacts.model.WKms; +import org.dive4elements.river.utils.DoubleUtil; + +/** + * Abstraction for access to waterlevels by station. + * + * @author Gernot Belger + */ +public class WaterlevelValuesFinder { + + public static WaterlevelValuesFinder fromKms(final WKms wkms) { + return new WaterlevelValuesFinder(wkms); + } + + private final PolynomialSplineFunction wstInterpolator; + + private WaterlevelValuesFinder(final WKms wkms) { + this.wstInterpolator = DoubleUtil.getLinearInterpolator(wkms.allKms(), wkms.allWs()); + } + + public double getWaterlevel(final double km) { + try { + return this.wstInterpolator.value(km); + } + catch (final ArgumentOutsideDomainException e) { + e.printStackTrace(); + return Double.NaN; + } + } +} \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/BedHeightsFinder.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/BedHeightsFinder.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/BedHeightsFinder.java Tue Mar 13 18:49:33 2018 +0100 @@ -17,10 +17,14 @@ import java.util.TreeMap; import org.apache.commons.lang.math.DoubleRange; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.BedHeightsArtifact; 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.utils.RiverUtils; /** * Provides bed heigts for vcarious calculations. @@ -47,12 +51,47 @@ return result; } + public static BedHeightsFinder forId(final CallContext context, final String soundingId, final DoubleRange calcRange, final Calculation problems) { + + // REMARK: absolutely unbelievable.... + // The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type + // throughout flys. + // The knowledge on how to parse the datacage-ids is spread through the complete code-base... + + // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but + // this is plain random + final String[] parts = soundingId.split(";"); + + final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], context); + + final Integer bedheightId = artifact.getDataAsInteger("height_id"); + + // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the + // other type means) + // Luckily, the requirement is to only access 'single' data here. + // final String bedheightType = artifact.getDataAsString("type"); + + // REMARK: BedDifferences uses this, but we also need the metadata of the BedHeight + // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via + // hibernate stuff + // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. + // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); + + final BedHeightsFinder bedHeight = bedheightId == null ? null : BedHeightsFinder.forId(bedheightId, calcRange); + if (bedHeight != null) + return bedHeight; + + // FIXME: 10n + problems.addProblem("Failed to access sounding with id '{0}'", soundingId); + return null; + } + /** * Creates a {@link BedHeightsFinder} for a dataset from the database, specified by its id. * * @return null if no bed height with the given id exists. */ - public static BedHeightsFinder forId(final int id, final DoubleRange range) { + private static BedHeightsFinder forId(final int id, final DoubleRange range) { final BedHeight bedHeight = BedHeight.getBedHeightById(id); if (bedHeight == null) diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java Tue Mar 13 18:49:33 2018 +0100 @@ -31,6 +31,7 @@ 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.tkhcalculation.WaterlevelValuesFinder; import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; @@ -143,14 +144,13 @@ for (int i = 0; i < size; i++) { final double station = wkms.getKm(i); - final double wst = wkms.getW(i); /* find the right calculator (i.e. bedheigh) depending on station, there should only be one maximal */ final TkhCalculator tkhCalculator = findCalculator(calculatorsByRanges, station); if (tkhCalculator == null) continue; - final Tkh tkh = tkhCalculator.getTkh(station, wst); + final Tkh tkh = tkhCalculator.getTkh(station); final String description = descBuilder.getDesc(wkms); final String gaugeLabel = riverInfoProvider.findGauge(station); @@ -185,11 +185,12 @@ final NumberRange range = new NumberRange(info.getFrom(), info.getTo()); + final WaterlevelValuesFinder waterlevelProvider = WaterlevelValuesFinder.fromKms(wkms); final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wkms); /* initialize tkh calculator */ final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(true, this.context, problems, wstLabel, riverInfoProvider.getRiver(), - calcRange, dischargeProvider, bedHeightsProvider); + calcRange, waterlevelProvider, dischargeProvider, bedHeightsProvider); if (tkhCalculator != null) { /* just ignore null ones, problems have already been updated by buildTkhCalculator() */ diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculationResult.java Tue Mar 13 18:49:33 2018 +0100 @@ -11,7 +11,7 @@ import java.util.Collection; -import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoCalculationResult; +import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult; import org.dive4elements.river.artifacts.sinfo.util.WstInfo; /** @@ -19,7 +19,7 @@ * * @author Gernot Belger */ -final class TkhCalculationResult extends AbstractSInfoCalculationResult { +final class TkhCalculationResult extends AbstractTkhCalculationResult { private static final long serialVersionUID = 1L; diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhExporter.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhExporter.java Tue Mar 13 18:49:33 2018 +0100 @@ -8,17 +8,10 @@ package org.dive4elements.river.artifacts.sinfo.tkhstate; -import java.text.DateFormat; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; -import java.util.Locale; -import org.apache.commons.lang.math.DoubleRange; import org.apache.log4j.Logger; -import org.dive4elements.river.FLYS; -import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.sinfo.SInfoI18NStrings; import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoExporter; import org.dive4elements.river.artifacts.sinfo.util.MetaAndTableJRDataSource; @@ -64,31 +57,7 @@ protected void writeCSVGlobalMetadata(final CSVWriter writer, final TkhCalculationResults results) { log.info("TkhExporter.writeCSVMeta"); - final String calcModeLabel = results.getCalcModeLabel(); - final RiverInfo river = results.getRiver(); - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_RESULT, msg(SInfoI18NStrings.CSV_META_HEADER_RESULT_LABEL), river.getName(), calcModeLabel); - - // "# FLYS-Version: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_VERSION, msg(SInfoI18NStrings.CSV_META_VERSION_LABEL), FLYS.VERSION); - - // "# Bearbeiter: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_USER, msg(SInfoI18NStrings.CSV_META_USER_LABEL), results.getUser()); - - // "# Datum der Erstellung: " - final Locale locale = Resources.getLocale(this.context.getMeta()); - final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_CREATION, msg(SInfoI18NStrings.CSV_META_CREATION_LABEL), df.format(new Date())); - - // "# Gewässer: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_RIVER, msg(SInfoI18NStrings.CSV_META_RIVER_LABEL), river.getName()); - - // "# Höhensystem des Flusses: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEIGHT_UNIT_RIVER, river.getWstUnit()); - - // "# Ort/Bereich (km): " - final DoubleRange calcRange = results.getCalcRange(); - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_RANGE, msg(SInfoI18NStrings.CSV_META_RANGE_LABEL), - getKmFormatter().format(calcRange.getMinimumDouble()), getKmFormatter().format(calcRange.getMaximumDouble())); + super.writeCSVGlobalMetadataDefaults(writer, results); // "# Berechnungsgrundlage: Gleichung nach GILL (1971)" writeCSVMetaEntry(writer, CSV_META_CALCULATION_FORMULA); @@ -128,17 +97,12 @@ // FIXME: rename protected void writeCSVResultMetadata(final CSVWriter writer, final TkhCalculationResults results, final TkhCalculationResult result) { - /* first some specific metadata */ final WstInfo wst = result.getWst(); + super.writeCSVWaterlevelMetadata(writer, wst); - // "##METADATEN WASSERSPIEGELLAGE" - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL); - // "# Bezeichnung der Wasserspiegellage: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_NAME, wst.getLabel()); - // "# Bezugspegel: " - writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_GAUGE, wst.getGauge()); - // // "# Jahr/Zeitraum der Wasserspiegellage: " - // writeCSVMetaEntry(writer, SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_YEAR, Integer.toString(wst.getYear())); + // TODO: + // "# W/Pegel [cm]: " (nur bei Eingabe des Wasserstands am Pegel) + // "# Q (m³/s): " (nur bei Eingabe des Durchflusses) } @Override @@ -199,33 +163,8 @@ @Override protected final void addJRMetaData(final MetaAndTableJRDataSource source, final TkhCalculationResults results) { - final RiverInfo river = results.getRiver(); - final String wstUnitName = river.getWstUnit(); - /* general metadata */ - source.addMetaData("header", msg(SInfoI18NStrings.CSV_META_HEADER_RESULT_LABEL)); - source.addMetaData("calcMode", results.getCalcModeLabel()); - - source.addMetaData("version_label", msg(SInfoI18NStrings.CSV_META_VERSION_LABEL)); - source.addMetaData("version", FLYS.VERSION); - - source.addMetaData("user_label", msg(SInfoI18NStrings.CSV_META_USER_LABEL)); - source.addMetaData("user", results.getUser()); - - final Locale locale = Resources.getLocale(this.context.getMeta()); - final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - source.addMetaData("date_label", msg(SInfoI18NStrings.CSV_META_CREATION_LABEL)); - source.addMetaData("date", df.format(new Date())); - - source.addMetaData("river_label", msg(SInfoI18NStrings.CSV_META_RIVER_LABEL)); - source.addMetaData("river", river.getName()); - source.addMetaData("river_unit", wstUnitName); - - final DoubleRange calcRange = results.getCalcRange(); - final NumberFormat kmFormatter = getKmFormatter(); - final String rangeValue = String.format("%s - %s", kmFormatter.format(calcRange.getMinimumDouble()), kmFormatter.format(calcRange.getMaximumDouble())); - source.addMetaData("range_label", msg(SInfoI18NStrings.CSV_META_RANGE_LABEL)); - source.addMetaData("range", rangeValue); + super.addJRMetaDataDefaults(source, results); /* column headings */ source.addMetaData("station_header", msg(SInfoI18NStrings.CSV_KM_HEADER)); diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhResultRow.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhResultRow.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhResultRow.java Tue Mar 13 18:49:33 2018 +0100 @@ -9,13 +9,13 @@ */ package org.dive4elements.river.artifacts.sinfo.tkhstate; -import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoResultRow; +import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhResultRow; import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh; /** * @author Gernot Belger */ -final class TkhResultRow extends AbstractSInfoResultRow { +final class TkhResultRow extends AbstractTkhResultRow { private static final long serialVersionUID = 1L; diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/BedHeightInfo.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/BedHeightInfo.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/BedHeightInfo.java Tue Mar 13 18:49:33 2018 +0100 @@ -23,7 +23,7 @@ private static final long serialVersionUID = 1L; - private final Integer year; + private final int year; private final String description; @@ -58,7 +58,7 @@ this.to = bedHeight.getRange().getB(); } - public Integer getYear() { + public int getYear() { return this.year; } diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/MetaAndTableJRDataSource.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/MetaAndTableJRDataSource.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/MetaAndTableJRDataSource.java Tue Mar 13 18:49:33 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) @@ -21,16 +21,16 @@ /** * @author Raimund Renkert */ -public final class MetaAndTableJRDataSource implements JRDataSource -{ - private List data = new ArrayList<>(); +public final class MetaAndTableJRDataSource implements JRDataSource { - private Map metaData = new HashMap<>(); + private final List data = new ArrayList<>(); + + private final Map metaData = new HashMap<>(); private int index = -1; - public void addData(final String[] data) { - this.data.add(data); + public void addData(final String[] row) { + this.data.add(row); } public void addMetaData(final String key, final String value) { @@ -38,27 +38,24 @@ } @Override - public boolean next() throws JRException - { - index++; + public boolean next() throws JRException { + this.index++; - return index < data.size(); + return this.index < this.data.size(); } @Override - public Object getFieldValue(final JRField field) throws JRException - { + public Object getFieldValue(final JRField field) throws JRException { final String fieldName = field.getName(); - - if( fieldName.startsWith("meta:")) - return metaData.get(fieldName.substring("meta:".length())); - if( fieldName.startsWith("data:")) - { - int column = Integer.valueOf(fieldName.substring("data:".length())); - return data.get(index)[column]; + if (fieldName.startsWith("meta:")) + return this.metaData.get(fieldName.substring("meta:".length())); + + if (fieldName.startsWith("data:")) { + final int column = Integer.valueOf(fieldName.substring("data:".length())); + return this.data.get(this.index)[column]; } - + return null; } } \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelFetcher.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelFetcher.java Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelFetcher.java Tue Mar 13 18:49:33 2018 +0100 @@ -19,6 +19,7 @@ import org.dive4elements.river.artifacts.StaticWQKmsArtifact; import org.dive4elements.river.artifacts.WINFOArtifact; import org.dive4elements.river.artifacts.access.FixRealizingAccess; +import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.Segment; import org.dive4elements.river.artifacts.model.WKms; @@ -39,7 +40,7 @@ private static Logger log = Logger.getLogger(WaterlevelFetcher.class); public WaterlevelData findWaterlevel(final CallContext context, final String mingle, final double from, - final double to) { + final double to, final Calculation problems) { final String[] def = mingle.split(";"); final String uuid = def[0]; @@ -48,7 +49,11 @@ final D4EArtifact d4eArtifact = RiverUtils.getArtifact(uuid, context); final WaterlevelData data = fetchWaterlevelFromArtifact(context, d4eArtifact, idx, from, to); - return data.withName(name); + if (data != null) + return data.withName(name); + + problems.addProblem("waterlevelfetcher.missing'", mingle); + return null; } private WaterlevelData fetchWaterlevelFromArtifact(final CallContext context, final D4EArtifact d4eArtifact, diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/resources/messages.properties --- a/artifacts/src/main/resources/messages.properties Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/resources/messages.properties Tue Mar 13 18:49:33 2018 +0100 @@ -886,4 +886,11 @@ sinfo.chart.tkh_d50.section.yaxis.label = Sohlbeschaffenheit D50 [mm] sinfo.chart.tkh_d50.yaxis.label = Sohlbeschaffenheit D50 [mm] -sinfo.facet.tkh_d50.filtered.description = Sohlbeschaffenheit D50 ({0}) \ No newline at end of file +sinfo.facet.tkh_d50.filtered.description = Sohlbeschaffenheit D50 ({0}) + +sinfo.flowdepthminmaxcalculation.soundingyear.different = Die Peiljahre von Talweg und Kammlage untersheiden sich + +sinfo.export.flow_depth_minmax.csv.header.min = Minimale Flie\u00dftiefe +sinfo.export.flow_depth_minmax.csv.header.max = Maximale Flie\u00dftiefe + +waterlevelfetcher.missing = Failed to access waterlevel with id '{0}' \ No newline at end of file diff -r 4a6b6a3c279c -r 5d5d482da3e9 artifacts/src/main/resources/messages_de.properties --- a/artifacts/src/main/resources/messages_de.properties Tue Mar 13 09:55:53 2018 +0100 +++ b/artifacts/src/main/resources/messages_de.properties Tue Mar 13 18:49:33 2018 +0100 @@ -886,4 +886,11 @@ sinfo.chart.tkh_d50.section.yaxis.label = Sohlbeschaffenheit D50 [mm] sinfo.chart.tkh_d50.yaxis.label = Sohlbeschaffenheit D50 [mm] -sinfo.facet.tkh_d50.filtered.description = Sohlbeschaffenheit D50 ({0}) \ No newline at end of file +sinfo.facet.tkh_d50.filtered.description = Sohlbeschaffenheit D50 ({0}) + +sinfo.flowdepthminmaxcalculation.soundingyear.different = Die Peiljahre von Talweg und Kammlage untersheiden sich + +sinfo.export.flow_depth_minmax.csv.header.min = Minimale Flie\u00dftiefe +sinfo.export.flow_depth_minmax.csv.header.max = Maximale Flie\u00dftiefe + +waterlevelfetcher.missing = Fehler beim Zugriff auf Wasserspiegel mit id '{0}' \ No newline at end of file