Mercurial > dive4elements > river
changeset 9176:1614cb14308f
Work on calculations for S-Info flood duration workflow
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/manualpoints.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/artifacts/manualpoints.xml Mon Jun 25 19:21:11 2018 +0200 @@ -42,6 +42,7 @@ <facet name="sinfo_flow_depth_development_peryear.manualpoints" /> <facet name="sinfo_tkk" /> <facet name="sinfo_collision.manualpoints" /> + <facet name="sinfo_flood_duration.manualpoints" /> </facets> </outputmode> </outputmodes>
--- a/artifacts/doc/conf/artifacts/sinfo.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/artifacts/sinfo.xml Mon Jun 25 19:21:11 2018 +0200 @@ -335,8 +335,6 @@ <condition data="calculation_mode" value="sinfo_calc_flood_duration" operator="equal" /> </transition> - - <transition transition="org.dive4elements.river.artifacts.transitions.ValueCompareTransition"> <from state="state.sinfo.wspl" /> <to state="state.sinfo.wq" /> @@ -359,7 +357,29 @@ <outputmodes> <outputmode name="sinfo_flood_duration" description="output.sinfo_flood_duration" mime-type="image/png" type="chart"> <facets> - + <facet name="sinfo_facet_flood_duration" description="flood duration of the heights of the infrastructures (points)"/> + <facet name="mainvalue.1.duration" description="flood duration of first W main value"/> + <facet name="mainvalue.2.duration" description="flood duration of second W main value"/> + <facet name="mainvalue.3.duration" description="flood duration of third W main value"/> + </facets> + </outputmode> + <outputmode name="sinfo_flood_height" description="output.sinfo_flood_height" mime-type="image/png" type="chart"> + <facets> + <facet name="infrastructure.flood.height" description="flood heights of the infrastructures (points)"/> + <facet name="mainvalue.1.w" description="W of first main value"/> + <facet name="mainvalue.2.w" description="W of second main value"/> + <facet name="mainvalue.3.w" description="W of third main value"/> + </facets> + </outputmode> + <outputmode name="sinfo_flood_duration_curve" description="output.sinfo_duration_curve" mime-type="image/png" type="chart"> + <facets> + <facet name="duration_curve.w" description="facet.duration_curve.w"/> + <facet name="duration_curve.q" description="facet.duration_curve.q"/> + <facet name="infrastructure.w" description="geodetic height of the infrastructure"/> + <facet name="mainvalues.w" description="W Main Values"/> + <facet name="mainvalues.q" description="Q Main Values at optional second axis"/> + <facet name="infrastructure.q" description="discharge of the infrastructure height"/> + <facet name="duration_curve.manualpoints" description="Manuelle Punkte"/> </facets> </outputmode>
--- a/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml Mon Jun 25 19:21:11 2018 +0200 @@ -19,6 +19,7 @@ <axis name="flowdepthDevelopmentAxis"/> <axis name="flowdepthDevelopmentPerYearAxis"/> <axis name="countAxis" include-zero="true"/> + <axis name="durationAxis" include-zero="true"/> <domain-axis key="chart.longitudinal.section.xaxis.label" default="Fluss-Km" inverted="org.dive4elements.river.exports.IsKmUpEvaluator()"> <arg expr="artifact.river"/> @@ -57,6 +58,7 @@ <processor class="org.dive4elements.river.artifacts.sinfo.common.FlowDepthDevelopmentProcessor" axis="flowdepthDevelopmentAxis"/> <processor class="org.dive4elements.river.artifacts.sinfo.common.FlowDepthDevelopmentPerYearProcessor" axis="flowdepthDevelopmentPerYearAxis"/> <processor class="org.dive4elements.river.artifacts.sinfo.common.CollisionCalcProcessor" axis="countAxis"/> + <processor class="org.dive4elements.river.artifacts.sinfo.common.FloodDurationProcessor" axis="durationAxis"/> <processor class="org.dive4elements.river.artifacts.sinfo.common.PredefinedChannelWidthProcessor" axis="Width"/> <processor class="org.dive4elements.river.artifacts.sinfo.common.PredefinedChannelDepthProcessor" axis="flowdepthAxis"/>
--- a/artifacts/doc/conf/generators/longitudinal-diagrams.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/generators/longitudinal-diagrams.xml Mon Jun 25 19:21:11 2018 +0200 @@ -165,5 +165,18 @@ <arg expr="artifact.river"/> </subtitle> </output-generator> + + <output-generator + names="sinfo_flood_duration,sinfo_flood_duration_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="sinfo.chart.flood_duration.section.title" default="Überflutungsdauer Infrastruktur BWaStr (DEFAULT)"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="durationAxis"/> + <subtitle key="chart.w_differences.subtitle" default="-"> + <arg expr="artifact.river"/> + </subtitle> + </output-generator> </longitudinal-diagrams> \ No newline at end of file
--- a/artifacts/doc/conf/meta-data.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/meta-data.xml Mon Jun 25 19:21:11 2018 +0200 @@ -136,6 +136,15 @@ <dc:when test="$out = 'sinfo_collision'"> <dc:call-macro name="annotations" /> </dc:when> + <dc:when test="$out = 'sinfo_flood_duration'"> + <dc:call-macro name="annotations" /> + </dc:when> + <dc:when test="$out = 'sinfo_flood_height'"> + <dc:call-macro name="annotations" /> + </dc:when> + <dc:when test="$out = 'sinfo_flood_duration_curve'"> + <dc:call-macro name="annotations" /> + </dc:when> </dc:choose> </dc:iterate> </dc:when> @@ -303,6 +312,15 @@ <dc:when test="$out = 'sinfo_collision'"> <dc:call-macro name="longitudinal-section-prototype" /> </dc:when> + <dc:when test="$out = 'sinfo_flood_duration'"> + <dc:call-macro name="longitudinal-section-prototype" /> + </dc:when> + <dc:when test="$out = 'sinfo_flood_height'"> + <dc:call-macro name="longitudinal-section-prototype" /> + </dc:when> + <dc:when test="$out = 'sinfo_flood_duration_curve'"> + <dc:call-macro name="longitudinal-section-prototype" /> + </dc:when> </dc:choose> </dc:iterate> </dc:otherwise> @@ -1653,6 +1671,7 @@ <dc:call-macro name="sinfo_flow_depth_development" /> <dc:call-macro name="sinfo_tkh" /> <dc:call-macro name="sinfo_collision" /> + <dc:call-macro name="sinfo_flood_duration" /> <dc:comment> WINFO/DIFF/FIX </dc:comment> <dc:call-macro name="longitudinal" /> @@ -3414,6 +3433,24 @@ </dc:filter> </dc:macro> + <dc:macro name="sinfo_flood_duration"> + <dc:filter expr="$a_state = 'state.sinfo.flood_duration'"> + <dc:if test="dc:has-result()"> + <sinfo_flood_duration> + <dc:for-each> + <dc:element name="${facet_name}"> + <dc:attribute name="factory" value="sinfo" /> + <dc:attribute name="target_out" value="${out}" /> + <dc:attribute name="description" value="${facet_description}" /> + <dc:attribute name="ids" value="${facet_num}" /> + <dc:attribute name="artifact-id" value="${a_gid}" /> + <dc:attribute name="out" value="${out_name}" /> + </dc:element> + </dc:for-each> + </sinfo_flood_duration> + </dc:if> + </dc:filter> + </dc:macro> <!-- channel size imported from CSV-files for S-INFO --> <dc:macro name="sinfo_predefined_channel"> <dc:context>
--- a/artifacts/doc/conf/themes.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/themes.xml Mon Jun 25 19:21:11 2018 +0200 @@ -442,6 +442,7 @@ <mapping from="sinfo_facet_bedheight_difference.filtered" to="SInfoBedHeightDifference" /> <mapping from ="sinfo_facet_collision_calc_count" to="SInfoCollisionCount" /> + <mapping from ="sinfo_facet_flood_duration" to="SInfoFloodDuration" /> <mapping from="sinfo_facet_predefined_channel_width" to="SInfoPredefinedChannelWidth" /> <mapping from="sinfo_facet_predefined_channel_depth" to="SInfoPredefinedChannelDepth" /> @@ -458,5 +459,6 @@ <mapping from="sinfo_flow_depth_development_peryear.manualpoints" to="ManualPoints" /> <mapping from="sinfo_tkk" to="ManualPoints" /> <mapping from="sinfo_collision.manualpoints" to="ManualPoints" /> + <mapping from="sinfo_flood_duration.manualpoints" to="ManualPoints" /> </mappings> </themes> \ No newline at end of file
--- a/artifacts/doc/conf/themes/default.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/themes/default.xml Mon Jun 25 19:21:11 2018 +0200 @@ -3063,4 +3063,13 @@ <field name="pointcolor" type="Color" display="Punktfarbe" default="48, 96, 255" /> </fields> </theme> + <theme name="SInfoFloodDuration"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="pointsize" type="int" display="Punktdicke" default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" default="68, 216, 40" /> + </fields> + </theme> </themegroup> \ No newline at end of file
--- a/artifacts/doc/conf/themes/second.xml Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/doc/conf/themes/second.xml Mon Jun 25 19:21:11 2018 +0200 @@ -3050,4 +3050,13 @@ <field name="pointcolor" type="Color" display="Punktfarbe" default="48, 96, 192" /> </fields> </theme> + <theme name="SInfoFloodDuration"> + <inherits> + <inherit from="LongitudinalSectionPoints" /> + </inherits> + <fields> + <field name="pointsize" type="int" display="Punktdicke" default="3" /> + <field name="pointcolor" type="Color" display="Punktfarbe" default="68, 192, 40" /> + </fields> + </theme> </themegroup> \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractResultType.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractResultType.java Mon Jun 25 19:21:11 2018 +0200 @@ -86,14 +86,14 @@ return this.formatters.get(locale); } + protected abstract NumberFormat createFormatter(CallContext context); + protected final String exportDateValue(final CallContext context, final Date value) { final Locale locale = Resources.getLocale(context.getMeta()); final DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); return df.format(value); } - protected abstract NumberFormat createFormatter(CallContext context); - @Override public final String getCsvHeader() { return this.csvHeader;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcDetailResult.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalcDetailResult.java Mon Jun 25 19:21:11 2018 +0200 @@ -45,16 +45,16 @@ final int colSize = 6; exportContextCSV.writeTitleForTabs("sinfo.export.csv.title.collision.detail", 6); // Voraussetzung für Tabs ist, dass der Titel vor den Headern - // geschrieben wird. + // geschrieben wird. // Das ist etwas doof. final Collection<String> header = new ArrayList<>(colSize); header.add(exportContextCSV.formatCsvHeader(GeneralResultType.station)); header.add(exportContextCSV.formatCsvHeader(GeneralResultType.date)); - header.add(exportContextCSV.formatCsvHeader(SInfoResultType.collisionGaugeW)); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.collisionGaugeW, SInfoResultType.collisionGaugeW.getUnit())); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.gaugeLabel)); - header.add(exportContextCSV.msgUnitCSV(SInfoResultType.discharge)); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.discharge, SInfoResultType.discharge.getUnit())); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.dischargeZone)); exportContextCSV.writeCSVLine(header.toArray(new String[colSize]));
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java Mon Jun 25 19:21:11 2018 +0200 @@ -23,12 +23,15 @@ import org.dive4elements.river.artifacts.model.DateRange; import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; +import org.dive4elements.river.artifacts.sinfo.common.GaugeDischargeValuesFinder; +import org.dive4elements.river.artifacts.sinfo.common.GaugeMainValueNameFinder; import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; import org.dive4elements.river.backend.utils.DateUtil; import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.MainValueType.MainValueTypeKey; import org.dive4elements.river.model.River; import org.dive4elements.river.model.sinfo.CollisionAggregateValue; import org.dive4elements.river.model.sinfo.CollisionValue; @@ -77,10 +80,10 @@ // create q-for-w-finders for all gauges of the calculation km range final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange); final Map<Gauge, GaugeDischargeValuesFinder> qFinders = new HashMap<>(); - final Map<Gauge, GaugeDischargeZoneFinder> zoneFinders = new HashMap<>(); + final Map<Gauge, GaugeMainValueNameFinder> zoneFinders = new HashMap<>(); for (final Gauge gauge : river.determineGauges(calcRange.getMinimumDouble(), calcRange.getMaximumDouble())) { qFinders.put(gauge, GaugeDischargeValuesFinder.loadValues(gauge, problems)); - zoneFinders.put(gauge, GaugeDischargeZoneFinder.loadValues(gauge, problems)); + zoneFinders.put(gauge, GaugeMainValueNameFinder.loadValues(MainValueTypeKey.Q, gauge, problems)); } final Collection<ResultRow> detailsRows = new ArrayList<>(); @@ -118,7 +121,7 @@ */ private void calculateDetails(final Collection<ResultRow> rows, final RiverInfoProvider riverInfo, final double fromKm, final double toKm, final int fromYear, final int toYear, final Map<Gauge, GaugeDischargeValuesFinder> qFinders, - final Map<Gauge, GaugeDischargeZoneFinder> zoneFinders) { + final Map<Gauge, GaugeMainValueNameFinder> zoneFinders) { for (final CollisionValue collision : CollisionValue.getValues(riverInfo.getRiver(), fromKm, toKm, DateUtil.getStartDateFromYear(fromYear), DateUtil.getEndDateFromYear(toYear))) { final Gauge gauge = riverInfo.getGauge(collision.getStation(), true); @@ -129,7 +132,7 @@ .putValue(SInfoResultType.collisionGaugeW, collision.getGaugeW()) .putValue(SInfoResultType.gaugeLabel, collision.getGaugeName()) .putValue(SInfoResultType.discharge, qOut) - .putValue(SInfoResultType.dischargeZone, zoneFinders.get(gauge).getDischargeZone(q))); + .putValue(SInfoResultType.dischargeZone, zoneFinders.get(gauge).getZoneName(q))); } } } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FloodDurationProcessor.java Mon Jun 25 19:21:11 2018 +0200 @@ -0,0 +1,73 @@ +/** 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.HashSet; +import java.util.Set; + +import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.common.AbstractCalculationResult; + +/** + * Processor to generate the facet and data series of infrastructure flood durations + * + * @author Matthias Schäfer + * + */ +public final class FloodDurationProcessor extends AbstractSInfoLineProcessor<AbstractCalculationResult> { + + public static final String FACET_FLOOD_DURATION = "sinfo_facet_flood_duration"; + + public static final String FACET_FLOOD_DURATION_DESCRIPTION = "sinfo_facet_flood_duration.description"; + + public static final String FACET_MAIN_VALUE_1_DURATION = "mainvalue.1.duration"; + + public static final String FACET_MAIN_VALUE_DURATION_DESCRIPTION = "mainvalue.duration.description"; + + private static final String I18N_AXIS_LABEL = "sinfo.chart.flood_duration.section.yaxis.label"; + + private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>(); + + static { + HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION); + HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_1_DURATION); + } + + public FloodDurationProcessor() { + super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES); + } + + + @Override + protected double[][] doGetPoints(final AbstractCalculationResult data, final String facetName) { + if (FACET_FLOOD_DURATION.contentEquals(facetName)) + return data.getStationPoints(SInfoResultType.floodDuration); + + if (FACET_MAIN_VALUE_1_DURATION.contentEquals(facetName)) + return data.getStationPoints(SInfoResultType.mainValue1Duration); + + final String error = String.format("Unknown facet name: %s", facetName); + throw new UnsupportedOperationException(error); + } + + public static Facet createFloodDurationFacet(final CallContext context, final String hash, final String id, + final AbstractCalculationResult result, final int index) { + return AbstractSInfoLineProcessor.createFacet(context, hash, id, result, index, I18N_AXIS_LABEL, + FACET_MAIN_VALUE_1_DURATION, FACET_MAIN_VALUE_DURATION_DESCRIPTION); + } + + public static Facet createMainValueDurationFacet(final CallContext context, final String hash, final String id, + final AbstractCalculationResult result, final int index) { + return AbstractSInfoLineProcessor.createFacet(context, hash, id, result, index, I18N_AXIS_LABEL, + FACET_FLOOD_DURATION, FACET_FLOOD_DURATION_DESCRIPTION); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDischargeValuesFinder.java Mon Jun 25 19:21:11 2018 +0200 @@ -0,0 +1,118 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.common; + +import org.apache.commons.lang.math.DoubleRange; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.UnivariateRealFunction; +import org.apache.commons.math.analysis.interpolation.LinearInterpolator; +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.model.DischargeTable; +import org.dive4elements.river.model.DischargeTableValue; +import org.dive4elements.river.model.Gauge; + +import gnu.trove.TDoubleArrayList; + +/** + * Loading and search/interpolation of a gauge's discharge table (.at) + * + * @author Matthias Schäfer + * + */ +public final class GaugeDischargeValuesFinder { + + /***** FIELDS *****/ + + // private static Logger log = Logger.getLogger(GaugeDischargeValuesFinder.class); + + private final Gauge gauge; + + private Calculation problems; + + private final UnivariateRealFunction wInterpolator; + + private final DoubleRange wRange; + + + /***** CONSTRUCTORS *****/ + + private GaugeDischargeValuesFinder(final Gauge gauge, final Calculation problems, final DischargeTable dischargeTable) { + this.gauge = gauge; + this.problems = problems; + final TDoubleArrayList ws = new TDoubleArrayList(); + final TDoubleArrayList qs = new TDoubleArrayList(); + for (final DischargeTableValue v : DischargeTable.getValuesSortedByW(dischargeTable)) { + ws.add(v.getW().doubleValue()); + qs.add(v.getQ().doubleValue()); + } + if (ws.size() >= 2) { + this.wInterpolator = new LinearInterpolator().interpolate(ws.toNativeArray(), qs.toNativeArray()); + this.wRange = new DoubleRange(ws.get(0), ws.get(ws.size() - 1)); + } + else { + this.wInterpolator = null; + this.wRange = null; + } + if ((this.wInterpolator == null) && (this.problems != null)) { + this.problems.addProblem("gauge_discharge_table.missing", gauge.getName()); + // Report only once + this.problems = null; + } + } + + + /***** METHODS *****/ + + /** + * Loads the the main discharge table of a gauge (GAUGE.at) + * + * @return The discharge table values finder of the gauge, or null + */ + public static GaugeDischargeValuesFinder loadValues(final Gauge gauge, final Calculation problems) { + final DischargeTable table = DischargeTable.getGaugeMainDischargeTable(gauge); + if ((table == null) || (table.getDischargeTableValues().size() == 0)) { + problems.addProblem("gauge_discharge_table.missing", gauge.getName()); + return null; + } + else + return new GaugeDischargeValuesFinder(gauge, problems, table); + } + + /** + * If this provider may return valid data at all. + */ + public boolean isValid() { + return (this.wInterpolator != null); + } + + /** + * Discharge for a W + * + * @param w + * W in cm above gauge datum + * @return Q, or NegInf for w less than all, or PosInf for w greater then all, or NaN in case of exception + */ + public double getDischarge(final double w) { + try { + if (this.wInterpolator == null) + return Double.NaN; + else if (w < this.wRange.getMinimumDouble()) + return Double.NEGATIVE_INFINITY; + else if (w > this.wRange.getMaximumDouble()) + return Double.POSITIVE_INFINITY; + else + return this.wInterpolator.value(w); + } + catch (@SuppressWarnings("unused") final FunctionEvaluationException e) { + // ignore exception because this can/will happen regularly + return Double.NaN; + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDurationValuesFinder.java Mon Jun 25 19:21:11 2018 +0200 @@ -0,0 +1,152 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.common; + +import org.apache.commons.lang.math.DoubleRange; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.UnivariateRealFunction; +import org.apache.commons.math.analysis.interpolation.LinearInterpolator; +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.MainValue; +import org.dive4elements.river.model.MainValueType.MainValueTypeKey; + +import gnu.trove.TDoubleArrayList; + +/** + * Loading and search/interpolate the duration main values of a gauge + * + * @author Matthias Schäfer + * + */ +public final class GaugeDurationValuesFinder { + + /***** FIELDS *****/ + + // private static Logger log = Logger.getLogger(GaugeDurationValuesFinder.class); + + private final Gauge gauge; + + private Calculation problems; + + private UnivariateRealFunction qInterpolator; + + private DoubleRange qRange; + + private UnivariateRealFunction durInterpolator; + + private DoubleRange durRange; + + private final String approxPrefix = "ca."; // "\u2248" geht wohl nicht + + + /***** CONSTRUCTORS *****/ + + private GaugeDurationValuesFinder(final Gauge gauge, final Calculation problems) { + this.gauge = gauge; + this.problems = problems; + final TDoubleArrayList qs = new TDoubleArrayList(); + final TDoubleArrayList durs = new TDoubleArrayList(); + for (final MainValue v : MainValue.getValuesOfGaugeAndType(gauge, MainValueTypeKey.DURATION)) { + qs.add(v.getValue().doubleValue()); + durs.add(Integer.valueOf(v.getMainValue().getName()).doubleValue()); + } + try { + this.qInterpolator = new LinearInterpolator().interpolate(qs.toNativeArray(), durs.toNativeArray()); + this.qRange = new DoubleRange(qs.get(0), qs.get(qs.size() - 1)); + } + catch (final Exception e) { + this.qInterpolator = null; + this.qRange = null; + } + qs.clear(); + durs.clear(); + for (final MainValue v : MainValue.getDurationDischargesOfGauge(gauge)) { + durs.add(Integer.valueOf(v.getMainValue().getName()).doubleValue()); + qs.add(v.getValue().doubleValue()); + } + try { + this.durInterpolator = new LinearInterpolator().interpolate(durs.toNativeArray(), qs.toNativeArray()); + this.durRange = new DoubleRange(durs.get(0), durs.get(durs.size() - 1)); + } + catch (final Exception e) { + this.durInterpolator = null; + this.durRange = null; + } + if (((this.qInterpolator == null) || (this.durInterpolator == null)) && (this.problems != null)) { + this.problems.addProblem("gauge_duration.missing", gauge.getName()); + // Report only once + this.problems = null; + } + } + + + /***** METHODS *****/ + + /** + * Loads the the discharge-duration table of a gauge (GAUGE.glt) + * + * @return The main values finder of a a gauge, or null + */ + public static GaugeDurationValuesFinder loadValues(final Gauge gauge, final Calculation problems) { + return new GaugeDurationValuesFinder(gauge, problems); + } + + /** + * If this provider may return valid data at all. + */ + public boolean isValid() { + return (this.qInterpolator != null); + } + + /** + * Discharge for a duration + * + * @return Q, or NegInf for duration less than all, or PosInf for duration greater then all, or NaN in case of exception + */ + public double getDischarge(final int duration) { + try { + if (this.durInterpolator == null) + return Double.NaN; + else if (duration < this.durRange.getMinimumDouble()) + return Double.NEGATIVE_INFINITY; + else if (duration > this.durRange.getMaximumDouble()) + return Double.POSITIVE_INFINITY; + else + return this.durInterpolator.value(duration); + } + catch (@SuppressWarnings("unused") final FunctionEvaluationException e) { + // ignore exception because this can/will happen regularly + return Double.NaN; + } + } + + /** + * Duration for a discharge + * + * @return duration, or 0 for Q less than all, or 365 for duration greater then all, or -1 in case of exception + */ + public double getDuration(final double q) { + try { + if (this.qInterpolator == null) + return -1; + else if (q < this.qRange.getMinimumDouble()) + return 0; + else if (q > this.qRange.getMaximumDouble()) + return 365; + else + return this.qInterpolator.value(q); + } + catch (@SuppressWarnings("unused") final FunctionEvaluationException e) { + // ignore exception because this can/will happen regularly + return -1; + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeMainValueNameFinder.java Mon Jun 25 19:21:11 2018 +0200 @@ -0,0 +1,115 @@ +/** 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.Map.Entry; +import java.util.NavigableMap; +import java.util.TreeMap; + +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.MainValue; +import org.dive4elements.river.model.MainValueType.MainValueTypeKey; + +/** + * Loading and search the main values of a gauge to find and build a name + * + * @author Matthias Schäfer + * + */ +public final class GaugeMainValueNameFinder { + + /***** FIELDS *****/ + + // private static Logger log = Logger.getLogger(GaugeMainValueNameFinder.class); + + private final Gauge gauge; + + private Calculation problems; + + private final NavigableMap<Double, MainValue> mainValues; + + private final String approxPrefix = "ca."; // "\u2248" geht wohl nicht + + + /***** CONSTRUCTORS *****/ + + private GaugeMainValueNameFinder(final MainValueTypeKey type, final Gauge gauge, final Calculation problems) { + this.gauge = gauge; + this.problems = problems; + this.mainValues = new TreeMap<>(); + for (final MainValue mainValue : MainValue.getValuesOfGaugeAndType(gauge, type)) + this.mainValues.put(Double.valueOf(mainValue.getValue().doubleValue()), mainValue); + if (this.mainValues.isEmpty() && (this.problems != null)) { + this.problems.addProblem("gauge_main_values.missing", gauge.getName()); + // Report only once + this.problems = null; + } + } + + + /***** METHODS *****/ + + /** + * Loads the the main values table of a type and a gauge (GAUGE.glt) + * + * @return The main values finder of a type and a gauge, or null + */ + public static GaugeMainValueNameFinder loadValues(final MainValueTypeKey type, final Gauge gauge, final Calculation problems) { + return new GaugeMainValueNameFinder(type, gauge, problems); + } + + /** + * If this provider may return valid data at all. + */ + public boolean isValid() { + return (this.mainValues != null); + } + + /** + * Main value zone for a value. + */ + public String getZoneName(final double value) { + if (!this.isValid()) + return ""; + if (Double.isNaN(value)) + return ""; + + // Exact match + if (this.mainValues.containsKey(Double.valueOf(value))) + return this.mainValues.get(Double.valueOf(value)).getMainValue().getName(); + + // Clearly below or just (max. 10%) below lowest named value + final Entry<Double, MainValue> lowerZone = this.mainValues.floorEntry(Double.valueOf(value)); + if (lowerZone == null) { + if (value >= this.mainValues.firstKey().doubleValue() * 0.9) + return this.approxPrefix + this.mainValues.firstEntry().getValue().getMainValue().getName(); + else + return "<" + this.mainValues.firstEntry().getValue().getMainValue().getName(); + } + + // Clearly above or just (max. 10%) above highest named value + final Entry<Double, MainValue> higherZone = this.mainValues.ceilingEntry(Double.valueOf(value)); + if (higherZone == null) { + if (value <= this.mainValues.lastKey().doubleValue() * 1.1) + return this.approxPrefix + this.mainValues.lastEntry().getValue().getMainValue().getName(); + else + return ">" + this.mainValues.lastEntry().getValue().getMainValue().getName(); + } + + // Near (10%) one of the borders of a zone interval, or clearly within a zone + if (value <= lowerZone.getKey().doubleValue() * 1.1) + return this.approxPrefix + lowerZone.getValue().getMainValue().getName(); + else if (value >= higherZone.getKey().doubleValue() * 0.9) + return this.approxPrefix + higherZone.getValue().getMainValue().getName(); + else + return lowerZone.getValue().getMainValue().getName() + "-" + higherZone.getValue().getMainValue().getName(); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java Mon Jun 25 19:21:11 2018 +0200 @@ -55,20 +55,14 @@ }; - public static final SInfoResultType inundationdurationq = new SInfoResultType(null, "sinfo.export.flood_duration.csv.header.inundation_duration_q", - "sinfo.export.flood_duration.pdf.header.inundation_duration_q") { + public static final SInfoResultType floodDischarge = new SInfoResultType(I18NStrings.UNIT_CUBIC_M, "sinfo.export.flood_duration.csv.header.discharge", + "sinfo.export.flood_duration.pdf.header.discharge") { private static final long serialVersionUID = 1L; @Override public String exportValue(final CallContext context, final Object value) { final double doubleValue = asDouble(value); - return exportDoubleValue(context, doubleValue); // integer - // als - // double? - // finde - // gerade - // kein - // int-beispiel + return exportDoubleValue(context, doubleValue); } @Override @@ -77,20 +71,30 @@ } }; - public static final SInfoResultType inundationduration = new SInfoResultType(null, "sinfo.export.flood_duration.csv.header.inundation_duration", - "sinfo.export.flood_duration.pdf.header.inundation_duration") { + public static final SInfoResultType floodDuration = new SInfoResultType(null, "sinfo.export.flood_duration.csv.header.duration", + "sinfo.export.flood_duration.pdf.header.duration") { private static final long serialVersionUID = 1L; @Override public String exportValue(final CallContext context, final Object value) { final double doubleValue = asDouble(value); - return exportDoubleValue(context, doubleValue); // integer - // als - // double? - // finde - // gerade - // kein - // int-beispiel + return exportDoubleValue(context, doubleValue); + } + + @Override + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getIntegerFormatter(context); + } + }; + + public static final SInfoResultType mainValue1Duration = new SInfoResultType(null, "sinfo.export.main_value_1_duration.csv.header.duration", + "sinfo.export.main_value_1_duration.pdf.header.duration") { + private static final long serialVersionUID = 1L; + + @Override + public String exportValue(final CallContext context, final Object value) { + final double doubleValue = asDouble(value); + return exportDoubleValue(context, doubleValue); } @Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/WQBaseTableFinder.java Mon Jun 25 19:21:11 2018 +0200 @@ -0,0 +1,185 @@ +/** 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.List; +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.TreeMap; + +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.interpolation.LinearInterpolator; +import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; +import org.dive4elements.river.artifacts.math.Linear; +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.backend.SessionHolder; +import org.dive4elements.river.model.River; +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; + +import gnu.trove.TDoubleArrayList; + +/** + * Loading and search/interpolation of a W/Q base table of a river + * + * @author Matthias Schäfer + * + */ +public final class WQBaseTableFinder { + + /***** FIELDS *****/ + + // private static Logger log = Logger.getLogger(WQTableFinder.class); + + private final River river; + + private Calculation problems; + + private final List<String> columnNames; + + private final NavigableMap<Double, PolynomialSplineFunction> kmWs; + + private final NavigableMap<Double, PolynomialSplineFunction> kmQs; + + private static final String SQLCOLUMNS = "SELECT wc.position AS colindex, wc.name AS qzone" + + " FROM wsts w" + + " INNER JOIN wst_columns wc ON w.id=wc.wst_id" + + " WHERE w.river_id = :river_id" + + " AND w.kind = 0" + + " ORDER BY wc.position ASC"; + + private static final String SQLMAIN = "SELECT wcv.position AS station, wc.position AS colindex, wcv.w, wqr.q" + + " FROM wsts w" + + " INNER JOIN wst_columns wc ON w.id=wc.wst_id" + + " INNER JOIN wst_column_values wcv ON wc.id=wcv.wst_column_id" + + " INNER JOIN wst_column_q_ranges wcqr ON wc.id=wcqr.wst_column_id" + + " INNER JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id=wqr.id" + + " INNER JOIN ranges r ON wqr.range_id=r.id AND wcv.position BETWEEN r.a AND r.b" + + " WHERE w.river_id = :river_id" + + " AND w.kind = 0" + + " AND r.river_id = :river_id" + + " AND wcv.position BETWEEN :kmfrom - 1 AND :kmto + 1" // some tolerance for start and end of list + + " ORDER BY wcv.position ASC, " + + " wc.position ASC"; + + + /***** CONSTRUCTORS *****/ + + private WQBaseTableFinder(final River river, final Calculation problems, final List<Object[]> colnames, final List<Object[]> rows) { + this.river = river; + this.problems = problems; + this.columnNames = new ArrayList<>(); + for (final Object[] colname : colnames) + this.columnNames.add(colname[1].toString()); + this.kmWs = new TreeMap<>(); + this.kmQs = new TreeMap<>(); + final TDoubleArrayList ws = new TDoubleArrayList(); + final TDoubleArrayList qs = new TDoubleArrayList(); + double km = Double.NaN; + for (int i = 0; i <= rows.size() - 1; i++) { + if (ws.isEmpty() || ((double) rows.get(i)[0] <= km + 0.0001)) { + if (ws.isEmpty()) + km = (double) rows.get(i)[0]; + ws.add((double) rows.get(i)[2]); + qs.add((double) rows.get(i)[3]); + } + if ((i == rows.size() - 1) || ((double) rows.get(i)[0] > km + 0.0001)) { + try { + this.kmWs.put(km, new LinearInterpolator().interpolate(ws.toNativeArray(), qs.toNativeArray())); + this.kmQs.put(km, new LinearInterpolator().interpolate(qs.toNativeArray(), ws.toNativeArray())); + } + catch (final Exception e) { + if (this.problems != null) { + this.problems.addProblem(km, "wq_base_data.missing"); + // Report only once + this.problems = null; + } + } + ws.clear(); + qs.clear(); + km = (double) rows.get(i)[0]; + ws.add((double) rows.get(i)[2]); + qs.add((double) rows.get(i)[3]); + } + } + } + + + /***** METHODS *****/ + + /** + * Loads the the W/Q tables of a km range of a river + * + * @return The W/Q table finder of the river, or null + */ + public static WQBaseTableFinder loadValues(final River river, final double fromKm, final double toKm, final Calculation problems) { + final Session session = SessionHolder.HOLDER.get(); + final SQLQuery colQuery = session.createSQLQuery(SQLCOLUMNS) + .addScalar("colindex", StandardBasicTypes.INTEGER) + .addScalar("qzone", StandardBasicTypes.STRING); + colQuery.setParameter("river_id", river.getId()); + final List<Object[]> colnames = colQuery.list(); + if ((colnames == null) || colnames.isEmpty()) { + problems.addProblem("wq_table.missing"); + return null; + } + final SQLQuery wqQuery = session.createSQLQuery(SQLMAIN) + .addScalar("station", StandardBasicTypes.DOUBLE) + .addScalar("colindex", StandardBasicTypes.INTEGER) + .addScalar("w", StandardBasicTypes.DOUBLE) + .addScalar("q", StandardBasicTypes.DOUBLE); + wqQuery.setParameter("river_id", river.getId()); + wqQuery.setParameter("kmfrom", fromKm); + wqQuery.setParameter("kmto", toKm); + final List<Object[]> rows = wqQuery.list(); + if ((rows != null) && !rows.isEmpty()) + return new WQBaseTableFinder(river, problems, colnames, rows); + else { + problems.addProblem("wq_table.missing"); + return null; + } + } + + /** + * If this provider may return valid data at all. + */ + public boolean isValid() { + return (this.kmWs != null); + } + + /** + * Discharge for a W + * + * @param station + * station to find or interpolate + * @param w + * W in m+NN or m+NHN + * @return Q, or NegInf for w less than all, or PosInf for w greater then all, or NaN in case of exception + */ + public double getDischarge(final double station, final double w) { + if (this.kmWs == null) + return Double.NaN; + final Entry<Double, PolynomialSplineFunction> lowerEntry = this.kmWs.floorEntry(Double.valueOf(station)); + final Entry<Double, PolynomialSplineFunction> upperEntry = this.kmWs.ceilingEntry(Double.valueOf(station)); + if ((lowerEntry == null) || (upperEntry == null)) + return Double.NaN; + try { + final double lowerQ = lowerEntry.getValue().value(w); + final double upperQ = upperEntry.getValue().value(w); + return Linear.linear(station, lowerEntry.getKey().doubleValue(), upperEntry.getKey().doubleValue(), lowerQ, upperQ); + } + catch (@SuppressWarnings("unused") final FunctionEvaluationException e) { + // ignore exception because this can/will happen regularly + return Double.NaN; + } + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationAccess.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationAccess.java Mon Jun 25 19:21:11 2018 +0200 @@ -12,12 +12,11 @@ import org.apache.log4j.Logger; import org.dive4elements.river.artifacts.access.RangeAccess; -import org.dive4elements.river.artifacts.common.EpochYearAccessHelper; import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; import org.dive4elements.river.artifacts.sinfo.SinfoCalcMode; /** - * Access to the flow depth calculation type specific SInfo artifact data. + * Access to the flood duration 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. @@ -28,14 +27,11 @@ private static Logger log = Logger.getLogger(FloodDurationAccess.class); - private final EpochYearAccessHelper helper; - public FloodDurationAccess(final SINFOArtifact artifact) { super(artifact); /* assert calculation mode */ final SinfoCalcMode calculationMode = artifact.getCalculationMode(); - this.helper = new EpochYearAccessHelper(artifact); assert (calculationMode == SinfoCalcMode.sinfo_calc_flood_duration); } @@ -47,5 +43,4 @@ public String getRiverside() { return super.getString("riverside"); } - } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java Mon Jun 25 19:21:11 2018 +0200 @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde +/** 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 @@ -11,19 +11,25 @@ import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.WINFOArtifact; import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.CalculationResult; 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.flood_duration.RiversideRadioChoice.RiversideChoiceKey; import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; -import org.dive4elements.river.artifacts.sinfo.util.WstInfo; +import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; import org.dive4elements.river.model.River; +import org.dive4elements.river.model.sinfo.Infrastructure; -class FloodDurationCalculation { - - // private static Logger log = Logger.getLogger(FloodDurationCalculation.class); +/** + * Calculation of the flood durations of the infrastructures of the km range of a river + * + * @author Matthias Schäfer + */ +final class FloodDurationCalculation { private final CallContext context; @@ -38,44 +44,39 @@ /* access input data */ final FloodDurationAccess access = new FloodDurationAccess(sinfo); final River river = access.getRiver(); - + final RiverInfo riverInfo = new RiverInfo(river); 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 String riverside = Resources.getMsg(this.context.getMeta(), access.getRiverside()); + final Infrastructure infrasSeries = Infrastructure.getSeries(river); + final String infrasType = (infrasSeries != null) ? infrasSeries.getType().getName() : "?"; - // TODO: use enum for riverside - final String riverside = access.getRiverside(); - // more - // TODO: mis- ups.. re-use WINFO Artifact as in TkhState - final WinfoArtifactWrapper winfo = new WinfoArtifactWrapper(sinfo); - // winfo.computeWaterlevelData(); - final FloodDurationCalculationResults results = calculateResult(calcModeLabel, riverside, calcRange, infoProvider, user, problems); + final Calculation problems = new Calculation(); + + final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange); + + final FloodDurationCalculationResult result = calculateResult(calcModeLabel, infrasType, riverside, calcRange, infoProvider, + RiversideChoiceKey.fromKey(access.getRiverside()), user, problems); + results.addResult(result, problems); + + // Calculate the selected main values, if any + /* misuse winfo-artifact to calculate waterlevels in the same way */ + final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo); return new CalculationResult(results, problems); } /** - * Calculates FAKE Flood Duration - * - * @param riverside - * @param calcModeLabel - * @param user - * - * @param infoProvider + * Calculates the flood durations of the infrastructures of a km range of a river */ - private FloodDurationCalculationResults calculateResult(final String calcModeLabel, final String riverside, final DoubleRange calcRange, - final RiverInfoProvider riverInfoProvider, final String user, final Calculation problems) { + private FloodDurationCalculationResult calculateResult(final String calcModeLabel, final String infrastructureType, final String riverside, + final DoubleRange calcRange, final RiverInfoProvider riverInfoProvider, final RiversideChoiceKey riversideKey, final String user, + final Calculation problems) { final FloodDurationCalculator calculator = new FloodDurationCalculator(this.context, riverInfoProvider); - final String wspLabel = "WSP-Name";// wstKms.getName(); - final int wspYear = 9999; // waterlevel.getYear(); - final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge()); - final String label = String.format("%s - %s", wspLabel, " soundingLabel"); - return calculator.execute(problems, label, wstInfo, calcModeLabel, calcRange, riverside, user); + final String label = infrastructureType + ", " + riverside; + return calculator.execute(problems, label, calcModeLabel, calcRange, riversideKey, user).getResult(); } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java Mon Jun 25 19:21:11 2018 +0200 @@ -9,191 +9,115 @@ */ package org.dive4elements.river.artifacts.sinfo.flood_duration; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult; import org.dive4elements.river.artifacts.common.ExportContextCSV; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; import org.dive4elements.river.artifacts.common.ResultRow; -import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; -import org.dive4elements.river.artifacts.sinfo.util.WstInfo; /** - * Contains the results of a {@link FloodDurationCalculation}. + * Contains the result of a {@link FloodDurationCalculation}. * * @author Gernot Belger */ -final class FloodDurationCalculationResult extends AbstractTkhCalculationResult<FloodDurationCalculationResults> { +final class FloodDurationCalculationResult extends AbstractCalculationExportableResult<FloodDurationCalculationResults> { private static final long serialVersionUID = 1L; - private final int waterlevelCount; // TODO: ggf 2 verschiedene Result-Klassen? - // private final WstInfo wstInfo; - private final int maxWaterlevelPdf = 3; - private enum ExportMode { - pdf, csv + private static final String JASPER_FILE = "/jasper/templates/sinfo.floodduration.jrxml"; + + + public FloodDurationCalculationResult(final String label, final Collection<ResultRow> rows) { + super(label, rows); } - public FloodDurationCalculationResult(final String label, final WstInfo wstInfo, final Collection<ResultRow> rows, final boolean hasTkh, - final int waterlevelCount) { - super(label, wstInfo, hasTkh, rows); - this.waterlevelCount = waterlevelCount; - // this.wstInfo = wstInfo; + + @Override + protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results) { + // TODO Metadaten der Wasserspiegellage(n) falls gewählt + // exportContextCSV.writeCSVWaterlevelMetadata(this.wstInfo); + // exportContextCSV.writeBlankLine(); + // writer.writeNext(new String[] { "" }); // break line + } + + @Override + protected String getJasperFile() { + // TODO Variante mit Wasserspiegellage(n) + return JASPER_FILE; + } + + protected String[] formatRow(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final ResultRow row) { + + final Collection<String> lines = new ArrayList<>(10); + + lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.riverside)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.floodDuration)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.floodDischarge)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructureHeight)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructuretype)); + + // TODO Wasserspiegellage(n) und Dauerzahlen falls gewählt + + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.gaugeLabel)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.location)); + + return lines.toArray(new String[lines.size()]); } @Override public void writeCSVHeader(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final RiverInfo river) { - final Collection<String> header = new ArrayList<>(99); + final Collection<String> header = new ArrayList<>(20); header.add(exportContextCSV.formatCsvHeader(GeneralResultType.station)); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.riverside)); - header.add(exportContextCSV.formatCsvHeader(SInfoResultType.inundationduration)); - header.add(exportContextCSV.formatCsvHeader(SInfoResultType.inundationdurationq)); - header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructureHeight)); + header.add(exportContextCSV.formatCsvHeader(SInfoResultType.floodDuration)); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.floodDischarge, SInfoResultType.floodDischarge.getUnit())); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.infrastructureHeight, SInfoResultType.infrastructureHeight.getUnit())); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructuretype)); - // add dynamic headers - final int waterlevelCount = // results. - getWaterlevelCount(); - for (int i = 0; i < waterlevelCount; i++) { - final int naturalIndex = i + 1; - final String appendIndex = new StringBuilder().append("_").append(naturalIndex).toString(); - final Object[] args = new Object[] { appendIndex }; - // new StringBuilder().append('\u2081').toString(); // schlechter UTF-8-Support für subscript ints - header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderW(), new Object[] { appendIndex, "results.getRiver().getWstUnit()" })); - header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderFloodDurPerYear(), args)); - header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderQ(), args)); - header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderBezeichn(), args)); - } + // TODO Je vier Spalten der bis zu drei Wasserspiegellagen header.add(exportContextCSV.formatCsvHeader(SInfoResultType.gaugeLabel)); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.location)); exportContextCSV.writeCSVLine(header.toArray(new String[header.size()])); - } - - @Override - protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results) { - - exportContextCSV.writeCSVWaterlevelMetadata(super.getWst()); // -> export in super? -> TODO - exportContextCSV.writeBlankLine(); - // writer.writeNext(new String[] { "" }); // break line } @Override protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final ResultRow row) { - // TODO Auto-generated method stub - return formatRow(exportContextCSV, results, row, ExportMode.csv); - } - - @Override - protected String[] formatPDFRow(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final ResultRow row) { - return formatRow(exportContextCSV, results, row, ExportMode.pdf); - } - - @Override - protected String getJasperFile() { - if (this.waterlevelCount <= 1) - return "/jasper/templates/sinfo.floodduration.jrxml"; // TODO 2 different result-classes? - else - return "/jasper/templates/sinfo.floodduration2.jrxml"; + return this.formatRow(exportContextCSV, results, row); } @Override - protected void addJRTableHeader(final ExportContextCSV exportContextCSV, final MetaAndTableJRDataSource source, - final FloodDurationCalculationResults results) { - /* column headings */ - exportContextCSV.addJRMetadata(source, "station_header", GeneralResultType.station); - exportContextCSV.addJRMetadata(source, "riverside_header", SInfoResultType.riverside); - exportContextCSV.addJRMetadata(source, "inundationduration_header", SInfoResultType.inundationduration); - exportContextCSV.addJRMetadata(source, "inundationduration_q_header", SInfoResultType.inundationdurationq); - exportContextCSV.addJRMetadata(source, "infrastructure_height_header", SInfoResultType.infrastructureHeightFloodDur); - exportContextCSV.addJRMetadata(source, "infrastructure_type_header", SInfoResultType.infrastructuretype); - - // add dynamic headers - - if (this.waterlevelCount == 0 || this.waterlevelCount == 2) { - source.addMetaData("dummy", "dummy"); - source.addMetaData("dummy", "dummy"); - source.addMetaData("dummy", "dummy"); - source.addMetaData("dummy", "dummy"); - } + protected String[] formatPDFRow(final ExportContextCSV exportContextPDF, final FloodDurationCalculationResults results, final ResultRow row) { - for (int i = 0; i < this.waterlevelCount; i++) { - final int naturalIndex = i + 1; - - final Object[] args = new String[] { new StringBuilder().append("_").append(naturalIndex).toString() }; - exportContextCSV.addJRMetadata(source, getPdfHeader("w", naturalIndex), exportContextCSV.msg(DurationWaterlevel.getHeaderW(), args)); - exportContextCSV.addJRMetadata(source, getPdfHeader("duration", naturalIndex), - exportContextCSV.msg(DurationWaterlevel.getHeaderFloodDurPerYear(), args)); - exportContextCSV.addJRMetadata(source, getPdfHeader("q", naturalIndex), exportContextCSV.msg(DurationWaterlevel.getHeaderQ(), args)); - exportContextCSV.addJRMetadata(source, getPdfHeader("bezeichnung", naturalIndex), - exportContextCSV.msg(DurationWaterlevel.getHeaderBezeichn(), args)); - - } - - exportContextCSV.addJRMetadata(source, "gauge_header", SInfoResultType.gaugeLabel); - exportContextCSV.addJRMetadata(source, "location_header", SInfoResultType.location); - - } - - public int getWaterlevelCount() { // der exporter muss daran, um spalten auszublenden - return this.waterlevelCount; + return this.formatRow(exportContextPDF, results, row); } - private String[] formatRow(final ExportContextCSV exportContextCSV, final FloodDurationCalculationResults results, final ResultRow row, - final ExportMode mode) { - - final Collection<String> lines = new ArrayList<>(99); - - lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station)); - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.riverside)); - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.inundationduration)); - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.inundationdurationq)); - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructureHeight)); - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructuretype)); - - final List<DurationWaterlevel> waterlevelList = (List<DurationWaterlevel>) row.getValue(SInfoResultType.customMultiRowColWaterlevel); - if (waterlevelList != null) { - final NumberFormat wFormatter = exportContextCSV.getFlowDepthFormatter(); - final NumberFormat qFormatter = exportContextCSV.getQFormatter(); - - for (int i = 0; i < waterlevelList.size(); i++) { - - if (i == this.maxWaterlevelPdf && mode == ExportMode.pdf) - break; + @Override + protected void addJRTableHeader(final ExportContextCSV exportContextPDF, final MetaAndTableJRDataSource source, + final FloodDurationCalculationResults results) { - final DurationWaterlevel item = waterlevelList.get(i); - lines.add(item.getWFormatted(wFormatter)); - lines.add(item.getFloodDurDaysPerYearFormatted()); - lines.add(item.getQFormatted(qFormatter)); - lines.add(item.getBezeichnung()); - } - } + /* column headings */ + exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station); + exportContextPDF.addJRMetadata(source, "riverside_header", SInfoResultType.riverside); + exportContextPDF.addJRMetadata(source, "inundationduration_header", SInfoResultType.floodDuration); + exportContextPDF.addJRMetadata(source, "inundationduration_q_header", SInfoResultType.floodDischarge); + exportContextPDF.addJRMetadata(source, "infrastructure_height_header", SInfoResultType.infrastructureHeightFloodDur); + exportContextPDF.addJRMetadata(source, "infrastructure_type_header", SInfoResultType.infrastructuretype); - if ((this.waterlevelCount == 0 || this.waterlevelCount == 2) && mode == ExportMode.pdf) { - lines.add("dummy"); - lines.add("dummy"); - lines.add("dummy"); - lines.add("dummy"); - } + // TODO Je vier Spalten der bis zu drei Wasserspiegellagen - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.gaugeLabel)); - lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.location)); - return lines.toArray(new String[lines.size()]); - } - - private String getPdfHeader(final String rootStr, final int index) { - final String hd = "_header"; - final StringBuilder builder = new StringBuilder(); - return builder.append(rootStr).append("_").append(index).append(hd).toString(); + exportContextPDF.addJRMetadata(source, "gauge_header", SInfoResultType.gaugeLabel); + exportContextPDF.addJRMetadata(source, "location_header", SInfoResultType.location); } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java Mon Jun 25 19:21:11 2018 +0200 @@ -9,6 +9,8 @@ */ package org.dive4elements.river.artifacts.sinfo.flood_duration; +import java.util.List; + import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult; import org.dive4elements.river.artifacts.common.AbstractCalculationResults; @@ -21,12 +23,18 @@ private static final long serialVersionUID = 1L; - private final String riverside; - - public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange, - final String riverside) { + public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) { super(calcModeLabel, user, river, calcRange); - this.riverside = riverside; // lieber in Result? } + /** + * We know that this type of results only has one result member, so we can directly access it. + */ + public FloodDurationCalculationResult getResult() { + final List<AbstractCalculationExportableResult<FloodDurationCalculationResults>> results = getResults(); + if (results.size() < 1) + return null; + + return (FloodDurationCalculationResult) results.get(0); + } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java Mon Jun 25 19:21:11 2018 +0200 @@ -11,20 +11,29 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.common.ResultRow; import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.artifacts.sinfo.common.GaugeDurationValuesFinder; import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; +import org.dive4elements.river.artifacts.sinfo.common.WQBaseTableFinder; +import org.dive4elements.river.artifacts.sinfo.flood_duration.RiversideRadioChoice.RiversideChoiceKey; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; -import org.dive4elements.river.artifacts.sinfo.util.WstInfo; +import org.dive4elements.river.model.Attribute.AttributeKey; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.sinfo.InfrastructureValue; /** - * @author Gernot Belger + * Calculation of the result rows of the flood duration of the infrastructures in a river km range + * and selected main value durations + * + * @author Matthias Schäfer */ final class FloodDurationCalculator { @@ -34,52 +43,66 @@ private final CallContext context; + public FloodDurationCalculator(final CallContext context, final RiverInfoProvider riverInfoProvider) { this.context = context; this.riverInfoProvider = riverInfoProvider; } - public FloodDurationCalculationResults execute(final Calculation problems, final String label, final WstInfo wstInfo, final String calcModeLabel, - final DoubleRange calcRange, final String riverside, final String user) { + /** + * Calculate the result rows + * + * @return a result collection with one result + */ + public FloodDurationCalculationResults execute(final Calculation problems, final String label, final String calcModeLabel, + final DoubleRange calcRange, final RiversideChoiceKey riverside, final String user) { - calculateResultRow(8888.888); - calculateResultRow(99); - calculateResultRow(77); - final boolean hasTkh = false; // TODO tkh richtig machen, oder anderen result-Type wählen als super-klasse für FloodDurationCalculationResult + final WQBaseTableFinder wqFinder = WQBaseTableFinder.loadValues(this.riverInfoProvider.getRiver(), calcRange.getMinimumDouble(), + calcRange.getMaximumDouble(), problems); + final Map<Gauge, GaugeDurationValuesFinder> durFinders = new HashMap<>(); + for (final Gauge gauge : this.riverInfoProvider.getRiver().determineGauges(calcRange.getMinimumDouble(), calcRange.getMaximumDouble())) { + durFinders.put(gauge, GaugeDurationValuesFinder.loadValues(gauge, problems)); + } + final AttributeKey bankKey = riverside.getAttributeKey(); + for (final InfrastructureValue infrastructure : InfrastructureValue.getValues(this.riverInfoProvider.getRiver(), calcRange.getMinimumDouble(), + calcRange.getMaximumDouble(), bankKey)) { + calculateResultRow(infrastructure, wqFinder, durFinders); + } - final FloodDurationCalculationResult result = new FloodDurationCalculationResult(label, wstInfo, this.rows, false, 4); + final FloodDurationCalculationResult result = new FloodDurationCalculationResult(label, this.rows); final RiverInfo riverInfo = new RiverInfo(this.riverInfoProvider.getRiver()); - final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange, riverside); + final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange); results.addResult(result, problems); return results; } - private void calculateResultRow(final double station) { + /** + * Calculate the result row for one infrastructure + */ + private void calculateResultRow(final InfrastructureValue infrastructure, final WQBaseTableFinder wqFinder, + final Map<Gauge, GaugeDurationValuesFinder> durFinders) { final ResultRow row = ResultRow.create(); + final Gauge gauge = this.riverInfoProvider.getGauge(infrastructure.getStation(), true); + final double q = wqFinder.getDischarge(infrastructure.getStation(), infrastructure.getHeight()); + final double qOut = Double.isInfinite(q) ? Double.NaN : q; // REMARK: access the location once only during calculation - final String location = this.riverInfoProvider.getLocation(station); - row.putValue(GeneralResultType.station, station); - row.putValue(SInfoResultType.riverside, "todo:getRiverside"); - row.putValue(SInfoResultType.inundationduration, 44); - row.putValue(SInfoResultType.inundationdurationq, 444); - row.putValue(SInfoResultType.infrastructureHeight, 55); - row.putValue(SInfoResultType.infrastructuretype, "todo_get_infrastructureType"); + final String location = this.riverInfoProvider.getLocation(infrastructure.getStation()); + row.putValue(GeneralResultType.station, infrastructure.getStation()); + row.putValue(SInfoResultType.riverside, infrastructure.getAttributeKey().getName()); // TODO i18n + row.putValue(SInfoResultType.floodDuration, 365 - durFinders.get(gauge).getDuration(q)); + row.putValue(SInfoResultType.floodDischarge, qOut); + row.putValue(SInfoResultType.infrastructureHeight, infrastructure.getHeight()); + row.putValue(SInfoResultType.infrastructuretype, infrastructure.getInfrastructure().getType().getName()); - // custom type; each entry produces 4 Columns - final List<DurationWaterlevel> rowWsps = new ArrayList<>(); + // TODO Berechne W, Überflutungsdauer, Q und Bezeichnung von bis zu drei WSPL + // row.putValue(SInfoResultType.customMultiRowColWaterlevel, rowWsps); - rowWsps.add(new DurationWaterlevel(222, 30, 666, "1. Test")); - rowWsps.add(new DurationWaterlevel(111, 40, 555, "2. Test")); - rowWsps.add(new DurationWaterlevel(123, 333, 33, "3. Test")); - rowWsps.add(new DurationWaterlevel(444, 452, 55, "4. Test")); - row.putValue(SInfoResultType.customMultiRowColWaterlevel, rowWsps); - - row.putValue(SInfoResultType.gaugeLabel, "todo:getReferencedGauge"); - row.putValue(SInfoResultType.location, "location"); + row.putValue(SInfoResultType.gaugeLabel, gauge.getName()); + row.putValue(SInfoResultType.location, location); this.rows.add(row); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationExporter.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationExporter.java Mon Jun 25 19:21:11 2018 +0200 @@ -31,39 +31,6 @@ public class FloodDurationExporter extends AbstractCommonExporter<FloodDurationCalculationResults> { @Override - protected void doWritePdf(final OutputStream out, final FloodDurationCalculationResults results) { - - // TODO: Move to super (hier ist aber spezieller code drin...) - try { - final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null); - - final JasperReporter reporter = new JasperReporter(); - - for (final AbstractCalculationExportableResult<FloodDurationCalculationResults> result : results.getResults()) { - final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource(); - getHelper().addJRMetaDataUSINFO(source, results); - - final JasperDesigner design = result.addReport(exportContextCSV, results, reporter, source); - if (result instanceof FloodDurationCalculationResult) { - final int wlCount = ((FloodDurationCalculationResult) result).getWaterlevelCount(); - if (wlCount == 0 || wlCount == 2) { - design.removeColumn("wOpt"); - design.removeColumn("qOpt"); - design.removeColumn("bezOpt"); - design.removeColumn("durOpt"); - } - } - } - - reporter.exportPDF(out); - } - catch (final JRException je) { - getLog().warn("Error generating PDF Report!", je); - } - - } - - @Override protected void doWriteCSVData(final CSVWriter writer, final FloodDurationCalculationResults results) { // TODO: Diesen Ablauf in super? @@ -96,4 +63,36 @@ } + @Override + protected void doWritePdf(final OutputStream out, final FloodDurationCalculationResults results) { + + // TODO: Move to super (hier ist aber spezieller code drin...) + try { + final ExportContextCSV exportContextCSV = new ExportContextCSV(this.context, null); + + final JasperReporter reporter = new JasperReporter(); + + for (final AbstractCalculationExportableResult<FloodDurationCalculationResults> result : results.getResults()) { + final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource(); + getHelper().addJRMetaDataUSINFO(source, results); + + final JasperDesigner design = result.addReport(exportContextCSV, results, reporter, source); + if (result instanceof FloodDurationCalculationResult) { + // final int wlCount = ((FloodDurationCalculationResult) result).getWaterlevelCount(); + // if (wlCount == 0 || wlCount == 2) { + design.removeColumn("wOpt"); + design.removeColumn("qOpt"); + design.removeColumn("bezOpt"); + design.removeColumn("durOpt"); + // } + } + } + + reporter.exportPDF(out); + } + catch (final JRException je) { + getLog().warn("Error generating PDF Report!", je); + } + + } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java Mon Jun 25 19:21:11 2018 +0200 @@ -14,19 +14,23 @@ import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.ChartArtifact; import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult; +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.sinfo.common.FloodDurationProcessor; import org.dive4elements.river.artifacts.states.DefaultState; -/** State in which a waterlevel has been calculated. */ +/** + * Last state of the S-Info flood duration workflow that calculates and outputs the result + */ public class FloodDurationState extends DefaultState { /// ** The log that is used in this state. */ - // private static Logger log = Logger.getLogger(FlowDepthState.class); + // private static Logger log = Logger.getLogger(FloodDurationState.class); private static final long serialVersionUID = 1L; @@ -44,7 +48,6 @@ facets.add(new EmptyFacet()); return null; } - return compute((SINFOArtifact) artifact, context, hash, facets, old); } @@ -71,32 +74,21 @@ return res; final FloodDurationCalculationResults results = (FloodDurationCalculationResults) res.getData(); - - /* add themes for chart, for each result */ - final List<AbstractCalculationExportableResult<FloodDurationCalculationResults>> resultList = results.getResults(); - for (int index = 0; index < resultList.size(); index++) { + final FloodDurationCalculationResult result = results.getResult(); + if (result != null) { + // add themes for chart + final int index = 0; - final AbstractCalculationExportableResult<FloodDurationCalculationResults> result = resultList.get(0); + facets.add(FloodDurationProcessor.createFloodDurationFacet(context, hash, this.id, result, index)); + facets.add(FloodDurationProcessor.createMainValueDurationFacet(context, hash, this.id, result, index)); - /* filtered (zoom dependent mean) flow depth TODO: */ - // facets.add(FloodDurationProcessor.createFlowDepthFilteredFacet(context, hash, this.id, result, index)); - // facets.add(FloodDurationProcessor.createFlowDepthRawFacet(context, hash, this.id, result, index)); - + facets.add(new DataFacet(FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, this.id)); + facets.add(new DataFacet(FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, this.id)); } - 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)); - // } + final Calculation report = res.getReport(); + if (report.hasProblems()) + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, this.id)); return res; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/RiversideRadioChoice.java Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/RiversideRadioChoice.java Mon Jun 25 19:21:11 2018 +0200 @@ -12,25 +12,63 @@ import java.util.List; import org.dive4elements.river.artifacts.states.RadioSelect; +import org.dive4elements.river.model.Attribute.AttributeKey; /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ public class RiversideRadioChoice extends RadioSelect { + private static final long serialVersionUID = 1L; + /***** TYPES *****/ + + public enum RiversideChoiceKey { + NONE("", AttributeKey.NONE), // + LEFT("state.sinfo.riverside.left", AttributeKey.LEFT), // + RIGHT("state.sinfo.riverside.right", AttributeKey.RIGHT), // + BOTH("state.sinfo.riverside.both", AttributeKey.UNKNOWN); + + private final String key; + private final AttributeKey attributeKey; + + RiversideChoiceKey(final String key, final AttributeKey attributeKey) { + this.key = key; + this.attributeKey = attributeKey; + } + + public static RiversideChoiceKey fromKey(final String key) { + for (final RiversideChoiceKey v : values()) { + if (key.equalsIgnoreCase(v.key)) + return v; + } + return NONE; + } + + public String getKey() { + return this.key; + } + + public AttributeKey getAttributeKey() { + return this.attributeKey; + } + } + + /***** CONSTRUCTORS *****/ + public RiversideRadioChoice() { super(); } + /***** METHODS *****/ + @Override protected List<String> makeEntries() { final List<String> entries = new ArrayList<>(); - entries.add("state.sinfo.riverside.left"); - entries.add("state.sinfo.riverside.right"); - entries.add("state.sinfo.riverside.both"); + entries.add(RiversideChoiceKey.LEFT.getKey()); + entries.add(RiversideChoiceKey.RIGHT.getKey()); + entries.add(RiversideChoiceKey.BOTH.getKey()); return entries; - } } \ No newline at end of file
--- a/artifacts/src/main/resources/messages.properties Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/resources/messages.properties Mon Jun 25 19:21:11 2018 +0200 @@ -922,11 +922,11 @@ sinfo.export.flow_depth.csv.header.location = Lage sinfo.export.flood_duration.csv.header.riverside = Uferseite sinfo.export.flood_duration.csv.header.infrastructure.height = H\u00f6he der Infrastruktur -sinfo.export.flood_duration.csv.header.inundation_duration = \u00dcberflutungsdauer [d/a] -sinfo.export.flood_duration.csv.header.inundation_duration_q = \u00dcberflutungsdauerabfluss Q[m\u00b3/s] +sinfo.export.flood_duration.csv.header.duration = \u00dcberflutungsdauer [d/a] +sinfo.export.flood_duration.csv.header.discharge = \u00dcberflutungsdauerabfluss Q sinfo.export.flood_duration.csv.header.infrastructure_type = Infrastrukturtyp -sinfo.export.flood_duration.pdf.header.inundation_duration = \u00dcberflu-tungs-dauer [d/a] -sinfo.export.flood_duration.pdf.header.inundation_duration_q = \u00dcberflu-tungs-dauer-abfluss Q[m\u00b3/s] +sinfo.export.flood_duration.pdf.header.duration = \u00dcber-flutungs-dauer [d/a] +sinfo.export.flood_duration.pdf.header.discharge = \u00dcber-flutungs-dauer-abfluss Q [m\u00b3/s] sinfo.export.flood_duration.pdf.header.infrastructure_type = Infra-struktur-typ sinfo.export.flood_duration.pdf.header.infrastructure.height = H\u00f6he der Infra-struktur @@ -1113,7 +1113,7 @@ sinfo.export.csv.header.collision.count = Anzahl der Grundber\u00fchrungen collision.count.title = Grundber\u00fchrungen {0} chart.collision_count.section.yaxis.label = H\u00e4ufigkeit -sinfo.export.csv.header.collision.gaugew = W am Pegel +sinfo.export.csv.header.collision.gaugew = Pegelstand collision.gaugew.title = W am Pegel {0} sinfo.export.csv.header.discharge.zone = Abflusszustand @@ -1123,6 +1123,17 @@ sinfo.chart.collision.section.title = Grundber\u00fchrungen +sinfo.chart.flood_duration.section.title = \u00dcberflutungsdauer Infrastrukturen BWaStr +sinfo.chart.flood_duration.section.yaxis.label = \u00dcberflutungsdauer [d/a] +sinfo_facet_flood_duration = \u00dcberflutungsdauern +sinfo_facet_flood_duration.description = \u00dcberflutungsdauern ({0}) +gauge_duration.missing = Keine Dauerzahlen vorhanden am Pegel {0} +gauge_discharge_table.missing = No discharge table available for gauge {0} +gauge_main_values.missing = No named main values available for gauge {0} +wq_base_data.missing = No base waterlevel/discharge available +mainvalue.duration = \u00dcberflutungsdauer +mainvalue.duration.description = \u00dcberflutungsdauer ({0}) + bundu_bezugswst = Bezugswasserst\u00e4nde bundu_analysis = Fixinganalysis bundu_vollmer = relocated Waterlevel Calculation
--- a/artifacts/src/main/resources/messages_de.properties Mon Jun 25 17:58:11 2018 +0200 +++ b/artifacts/src/main/resources/messages_de.properties Mon Jun 25 19:21:11 2018 +0200 @@ -922,11 +922,11 @@ sinfo.export.flow_depth.csv.header.location = Lage sinfo.export.flood_duration.csv.header.riverside = Uferseite sinfo.export.flood_duration.csv.header.infrastructure.height = H\u00f6he der Infrastruktur -sinfo.export.flood_duration.csv.header.inundation_duration = \u00dcberflutungsdauer [d/a] -sinfo.export.flood_duration.csv.header.inundation_duration_q = \u00dcberflutungsdauerabfluss Q[m\u00b3/s] +sinfo.export.flood_duration.csv.header.duration = \u00dcberflutungsdauer [d/a] +sinfo.export.flood_duration.csv.header.discharge = \u00dcberflutungsdauerabfluss Q sinfo.export.flood_duration.csv.header.infrastructure_type = Infrastrukturtyp -sinfo.export.flood_duration.pdf.header.inundation_duration = \u00dcberflu-tungs-dauer [d/a] -sinfo.export.flood_duration.pdf.header.inundation_duration_q = \u00dcberflu-tungs-dauer-abfluss Q[m\u00b3/s] +sinfo.export.flood_duration.pdf.header.duration = \u00dcber-flutungs-dauer [d/a] +sinfo.export.flood_duration.pdf.header.discharge = \u00dcber-flutungs-dauer-abfluss Q [m\u00b3/s] sinfo.export.flood_duration.pdf.header.infrastructure_type = Infra-struktur-typ sinfo.export.flood_duration.pdf.header.infrastructure.height = H\u00f6he der Infra-struktur @@ -1113,7 +1113,7 @@ sinfo.export.csv.header.collision.count = Anzahl der Grundber\u00fchrungen collision.count.title = Grundber\u00fchrungen {0} chart.collision_count.section.yaxis.label = H\u00e4ufigkeit -sinfo.export.csv.header.collision.gaugew = Pegelstand [cm] +sinfo.export.csv.header.collision.gaugew = Pegelstand collision.gaugew.title = W am Pegel {0} sinfo.export.csv.header.discharge.zone = Abflusszustand @@ -1123,6 +1123,17 @@ sinfo.chart.collision.section.title = Grundber\u00fchrungen +sinfo.chart.flood_duration.section.title = \u00dcberflutungsdauer Infrastrukturen BWaStr +sinfo.chart.flood_duration.section.yaxis.label = \u00dcberflutungsdauer [d/a] +sinfo_facet_flood_duration = \u00dcberflutungsdauern +sinfo_facet_flood_duration.description = \u00dcberflutungsdauern ({0}) +gauge_duration.missing = Dauerzahlen fehlen am Pegel {0} +gauge_discharge_table.missing = Abflusstafel fehlt am Pegel {0} +gauge_main_values.missing = Hauptwerte fehlen am Pegel {0} +wq_base_data.missing = W/Q-Daten fehlen oder sind ung\00fcltig +mainvalue.duration = \u00dcberflutungsdauer +mainvalue.duration.description = \u00dcberflutungsdauer ({0}) + bundu_bezugswst = Bezugswasserst\u00e4nde bundu_analysis = Fixierungsanalyse bundu_vollmer = ausgelagerte Wasserspiegellage
--- a/backend/src/main/java/org/dive4elements/river/model/Annotation.java Mon Jun 25 17:58:11 2018 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/Annotation.java Mon Jun 25 19:21:11 2018 +0200 @@ -10,15 +10,18 @@ import java.io.Serializable; +import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; import javax.persistence.GeneratedValue; -import javax.persistence.Column; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; import javax.persistence.SequenceGenerator; -import javax.persistence.GenerationType; -import javax.persistence.OneToOne; -import javax.persistence.JoinColumn; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.dive4elements.river.model.Attribute.AttributeKey; @Entity @Table(name = "annotations") @@ -36,12 +39,12 @@ } public Annotation( - Range range, - Attribute attribute, - Position position, - Edge edge, - AnnotationType type - ) { + final Range range, + final Attribute attribute, + final Position position, + final Edge edge, + final AnnotationType type + ) { this.range = range; this.attribute = attribute; this.position = position; @@ -51,68 +54,73 @@ @Id @SequenceGenerator( - name = "SEQUENCE_ANNOTATIONS_ID_SEQ", - sequenceName = "ANNOTATIONS_ID_SEQ", - allocationSize = 1) + name = "SEQUENCE_ANNOTATIONS_ID_SEQ", + sequenceName = "ANNOTATIONS_ID_SEQ", + allocationSize = 1) @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "SEQUENCE_ANNOTATIONS_ID_SEQ") + strategy = GenerationType.SEQUENCE, + generator = "SEQUENCE_ANNOTATIONS_ID_SEQ") @Column(name = "id") public Integer getId() { - return id; + return this.id; } - public void setId(Integer id) { + public void setId(final Integer id) { this.id = id; } @OneToOne @JoinColumn(name = "range_id") public Range getRange() { - return range; + return this.range; } - public void setRange(Range range) { + public void setRange(final Range range) { this.range = range; } @OneToOne @JoinColumn(name = "attribute_id") public Attribute getAttribute() { - return attribute; + return this.attribute; } - public void setAttribute(Attribute attribute) { + public void setAttribute(final Attribute attribute) { this.attribute = attribute; } + @Transient + public AttributeKey getAttributeKey() { + return this.getAttribute().getKey(); + } + @OneToOne @JoinColumn(name = "position_id") public Position getPosition() { - return position; + return this.position; } - public void setPosition(Position position) { + public void setPosition(final Position position) { this.position = position; } @OneToOne @JoinColumn(name = "edge_id") public Edge getEdge() { - return edge; + return this.edge; } - public void setEdge(Edge edge) { + public void setEdge(final Edge edge) { this.edge = edge; } @OneToOne @JoinColumn(name = "type_id") public AnnotationType getType() { - return type; + return this.type; } - public void setType(AnnotationType type) { + public void setType(final AnnotationType type) { this.type = type; } }
--- a/backend/src/main/java/org/dive4elements/river/model/Attribute.java Mon Jun 25 17:58:11 2018 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/Attribute.java Mon Jun 25 19:21:11 2018 +0200 @@ -9,20 +9,124 @@ package org.dive4elements.river.model; import java.io.Serializable; +import java.util.List; +import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.SequenceGenerator; import javax.persistence.Table; -import javax.persistence.GeneratedValue; -import javax.persistence.Column; -import javax.persistence.SequenceGenerator; -import javax.persistence.GenerationType; +import javax.persistence.Transient; + +import org.dive4elements.river.backend.SessionHolder; +import org.hibernate.Query; +import org.hibernate.Session; @Entity @Table(name = "attributes") public class Attribute implements Serializable { + + /***** TYPES *****/ + + /** + * River attribute (river side or range type) + * + */ + public enum AttributeKey { + NONE(""), STRECKE(">>>>>>>>>>>>>>>"), LEFT("links"), RIGHT("rechts"), UNKNOWN("?"); + + private final String name; + private int id; + private boolean ready; + + AttributeKey(final String name) { + this.name = name; + this.id = 0; + this.ready = false; + } + + /** + * Type name in the database + */ + public String getName() { + return this.name; + } + + /** + * Type id in the database + */ + public int getId() { + initFromDatabase(); + return this.id; + } + + /** + * Set the type id + */ + public void setId(final int id) { + this.id = id; + } + + protected boolean getReady() { + return this.ready; + } + + protected void setReady(final boolean ready) { + this.ready = ready; + } + + /** + * Main value type key for a database name value + */ + public static AttributeKey forDbName(final String dbname) { + initFromDatabase(); + for (final AttributeKey k : AttributeKey.values()) { + if (k.getName().equalsIgnoreCase(dbname)) + return k; + } + return UNKNOWN; + } + + /** + * Main value type key for a database id value + */ + public static AttributeKey forDbId(final int dbid) { + initFromDatabase(); + for (final AttributeKey k : AttributeKey.values()) { + if (k.getId() == dbid) + return k; + } + return UNKNOWN; + } + + /** + * Initially queries the database ids + */ + private static void initFromDatabase() { + if (STRECKE.getReady()) + return; + // Avoid recursion + for (final AttributeKey k : AttributeKey.values()) + k.setReady(true); + // Select database ids + final Session session = SessionHolder.HOLDER.get(); + final Query query = session.createQuery("FROM Attribute"); + final List<Attribute> rows = query.list(); + if (!rows.isEmpty()) { + for (int i = 0; i <= rows.size() - 1; i++) { + if (forDbName(rows.get(i).getValue()) != UNKNOWN) + forDbName(rows.get(i).getValue()).setId(rows.get(i).getId()); + } + } + } + } + + /***** FIELDS *****/ + private Integer id; private String value; @@ -30,34 +134,43 @@ public Attribute() { } - public Attribute(String value) { + /***** CONSTRUCTORS *****/ + + public Attribute(final String value) { this.value = value; } + /***** METHODS *****/ + @Id @SequenceGenerator( - name = "SEQUENCE_ATTRIBUTES_ID_SEQ", - sequenceName = "ATTRIBUTES_ID_SEQ", - allocationSize = 1) + name = "SEQUENCE_ATTRIBUTES_ID_SEQ", + sequenceName = "ATTRIBUTES_ID_SEQ", + allocationSize = 1) @GeneratedValue( - strategy = GenerationType.SEQUENCE, - generator = "SEQUENCE_ATTRIBUTES_ID_SEQ") + strategy = GenerationType.SEQUENCE, + generator = "SEQUENCE_ATTRIBUTES_ID_SEQ") @Column(name = "id") public Integer getId() { - return id; + return this.id; } - public void setId(Integer id) { + public void setId(final Integer id) { this.id = id; } @Column(name = "value") public String getValue() { - return value; + return this.value; } - public void setValue(String value) { + public void setValue(final String value) { this.value = value; } + + @Transient + public AttributeKey getKey() { + return AttributeKey.forDbId(this.getId()); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/backend/src/main/java/org/dive4elements/river/model/MainValue.java Mon Jun 25 17:58:11 2018 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/MainValue.java Mon Jun 25 19:21:11 2018 +0200 @@ -128,5 +128,19 @@ query.setParameter("typeid", typekey.getId()); return query.list(); } + + /** + * Selects from the database the discharge-duration main values of a gauge sorted by duration + */ + public static List<MainValue> getDurationDischargesOfGauge(final Gauge gauge) { + final Session session = SessionHolder.HOLDER.get(); + final Query query = session.createQuery("SELECT mv" + + " FROM MainValue AS mv JOIN mv.mainValue AS nmv" + + " WHERE mv.gauge.id=:gaugeid AND nmv.type.id=:typeid" + + " ORDER BY CAST(nmv.name AS int)"); + query.setParameter("gaugeid", gauge.getId()); + query.setParameter("typeid", MainValueTypeKey.DURATION.getId()); + return query.list(); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/backend/src/main/java/org/dive4elements/river/model/sinfo/Infrastructure.java Mon Jun 25 17:58:11 2018 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/sinfo/Infrastructure.java Mon Jun 25 19:21:11 2018 +0200 @@ -199,4 +199,18 @@ query.setParameter("id", id); return (Infrastructure) query.list().get(0); } + + /** + * Get first data series of a river + */ + public static Infrastructure getSeries(final River river) { + final Session session = SessionHolder.HOLDER.get(); + final Query query = session.createQuery("FROM Infrastructure WHERE (river=:river)"); + query.setParameter("river", river); + final List rows = query.list(); + if (!rows.isEmpty()) + return (Infrastructure) rows.get(0); + else + return null; + } } \ No newline at end of file
--- a/backend/src/main/java/org/dive4elements/river/model/sinfo/InfrastructureValue.java Mon Jun 25 17:58:11 2018 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/sinfo/InfrastructureValue.java Mon Jun 25 19:21:11 2018 +0200 @@ -22,9 +22,12 @@ import javax.persistence.OneToOne; import javax.persistence.SequenceGenerator; import javax.persistence.Table; +import javax.persistence.Transient; import org.dive4elements.river.backend.SessionHolder; import org.dive4elements.river.model.Attribute; +import org.dive4elements.river.model.Attribute.AttributeKey; +import org.dive4elements.river.model.River; import org.hibernate.Query; import org.hibernate.Session; @@ -117,6 +120,11 @@ this.attribute = attribute; } + @Transient + public AttributeKey getAttributeKey() { + return this.getAttribute().getKey(); + } + @Column(name = "height") public Double getHeight() { return this.height; @@ -127,7 +135,7 @@ } /** - * Selects the infrastructure values of a data series in a km range from the database + * Selects from the database the infrastructure values of a data series in a km range */ public static List<InfrastructureValue> getValues(final Infrastructure parent, final double kmLo, final double kmHi) { final Session session = SessionHolder.HOLDER.get(); @@ -138,4 +146,25 @@ query.setParameter("kmHi", new Double(kmHi)); return query.list(); } + + /** + * Selects from the database the infrastructure values of a km range of a river and a river side + */ + public static List<InfrastructureValue> getValues(final River river, final double kmLo, final double kmHi, final AttributeKey riverside) { + final Session session = SessionHolder.HOLDER.get(); + String riversideClause = ""; + if ((riverside == AttributeKey.LEFT) || (riverside == AttributeKey.RIGHT)) + riversideClause = " AND (v.attribute.id=:attr_id)"; + final Query query = session.createQuery("FROM InfrastructureValue v" + + " WHERE (v.infrastructure.river=:river)" + + " AND (v.station BETWEEN :kmLo - 0.0001 AND :kmHi + 0.0001)" + + riversideClause + + " ORDER BY v.station, v.attribute.id"); + query.setParameter("river", river); + query.setParameter("kmLo", new Double(kmLo)); + query.setParameter("kmHi", new Double(kmHi)); + if (!riversideClause.isEmpty()) + query.setParameter("attr_id", riverside.getId()); + return query.list(); + } }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Mon Jun 25 17:58:11 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Mon Jun 25 19:21:11 2018 +0200 @@ -1536,4 +1536,6 @@ String export_csv_title(); String waterlevel_ground_state(); + + String sinfo_flood_duration(); } \ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Mon Jun 25 17:58:11 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Mon Jun 25 19:21:11 2018 +0200 @@ -809,6 +809,8 @@ sinfo_collisions = Grundber\u00fchrungen sinfo_collision = Grundber\u00fchrungen +sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr + uinfo = U-INFO uinfo_inundation_duration_export = \u00dcberflutungsdauern Export uinfo_salix_line_export = Salix-Linie Export
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Mon Jun 25 17:58:11 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Mon Jun 25 19:21:11 2018 +0200 @@ -809,6 +809,8 @@ sinfo_collisions = Grundber\u00fchrungen sinfo_collision = Grundber\u00fchrungen +sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr + uinfo = U-INFO uinfo_inundation_duration_export = \u00dcberflutungsdauern Export uinfo_salix_line_export = Salix-Linie Export