Mercurial > dive4elements > river
changeset 9202:b4402594213b
More work on calculations and output for S-Info flood duration workflow (chart types 1 and 2)
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/sinfo.xml Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/doc/conf/artifacts/sinfo.xml Mon Jul 02 07:33:53 2018 +0200 @@ -365,7 +365,7 @@ </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="sinfo_facet_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"/>
--- a/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml Mon Jul 02 07:33:53 2018 +0200 @@ -59,6 +59,7 @@ <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.FloodHeightProcessor" axis="W"/> <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 Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/doc/conf/generators/longitudinal-diagrams.xml Mon Jul 02 07:33:53 2018 +0200 @@ -178,5 +178,18 @@ <arg expr="artifact.river"/> </subtitle> </output-generator> + + <output-generator + names="sinfo_flood_height,sinfo_flood_height_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="sinfo.chart.flood_duration.height.section.title" default="Überflutung Infrastruktur BWaStr (DEFAULT)"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="W"/> + <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/themes.xml Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/doc/conf/themes.xml Mon Jul 02 07:33:53 2018 +0200 @@ -441,8 +441,15 @@ <mapping from="sinfo_facet_waterlevel_difference.filtered" to="SInfoWaterlevelDifference" /> <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_collision_calc_count" to="SInfoCollisionCount" /> + <mapping from="sinfo_facet_flood_duration" to="SInfoFloodDuration" /> + <mapping from="mainvalue.1.duration" to="SInfoMainValues1" /> + <mapping from="mainvalue.2.duration" to="SInfoMainValues2" /> + <mapping from="mainvalue.3.duration" to="SInfoMainValues3" /> + <mapping from="sinfo_facet_flood_height" to="SInfoInfrastructureHeight" /> + <mapping from="mainvalue.1.w" to="SInfoMainValues1" /> + <mapping from="mainvalue.2.w" to="SInfoMainValues2" /> + <mapping from="mainvalue.3.w" to="SInfoMainValues3" /> <mapping from="sinfo_facet_predefined_channel_width" to="SInfoPredefinedChannelWidth" /> <mapping from="sinfo_facet_predefined_channel_depth" to="SInfoPredefinedChannelDepth" />
--- a/artifacts/doc/conf/themes/default.xml Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/doc/conf/themes/default.xml Mon Jul 02 07:33:53 2018 +0200 @@ -3082,4 +3082,28 @@ <field name="pointcolor" type="Color" display="Punktfarbe" default="68, 216, 40" /> </fields> </theme> + <theme name="SInfoMainValues1"> + <inherits> + <inherit from="MainValuesW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" default="0, 96, 192" /> + </fields> + </theme> + <theme name="SInfoMainValues2"> + <inherits> + <inherit from="MainValuesW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" default="192, 0, 0" /> + </fields> + </theme> + <theme name="SInfoMainValues3"> + <inherits> + <inherit from="MainValuesW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" default="96, 128, 0" /> + </fields> + </theme> </themegroup> \ No newline at end of file
--- a/artifacts/doc/conf/themes/second.xml Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/doc/conf/themes/second.xml Mon Jul 02 07:33:53 2018 +0200 @@ -3070,4 +3070,28 @@ <field name="pointcolor" type="Color" display="Punktfarbe" default="68, 216, 40" /> </fields> </theme> + <theme name="MainValues1"> + <inherits> + <inherit from="MainValuesW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" default="0, 96, 192" /> + </fields> + </theme> + <theme name="MainValues2"> + <inherits> + <inherit from="MainValuesW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" default="192, 0, 0" /> + </fields> + </theme> + <theme name="MainValues3"> + <inherits> + <inherit from="MainValuesW" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" default="96, 128, 0" /> + </fields> + </theme> </themegroup> \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationResult.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationResult.java Mon Jul 02 07:33:53 2018 +0200 @@ -45,7 +45,7 @@ // this.rows.add(resultRow); // } - public final Collection<ResultRow> getRows() { + public Collection<ResultRow> getRows() { return Collections.unmodifiableCollection(this.rows); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/common/ResultRow.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/ResultRow.java Mon Jul 02 07:33:53 2018 +0200 @@ -9,12 +9,11 @@ */ package org.dive4elements.river.artifacts.common; -import java.io.Serializable; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.dive4elements.artifacts.CallContext; -import org.dive4elements.river.artifacts.common.IResultType; /** * Generic container for results that come in rows. @@ -22,14 +21,20 @@ * @author Gernot Belger */ public class ResultRow implements Serializable { - protected static final long serialVersionUID = 1L; //TODO: Make private (wenn SInfoResultRow gelöscht ist + private static final long serialVersionUID = 1L; - private final Map<IResultType, Object> values = new HashMap<IResultType, Object>(); + private final Map<IResultType, Object> values = new HashMap<>(); public static ResultRow create() { return new ResultRow(); } + public static ResultRow create(final ResultRow src) { + final ResultRow dst = create(); + dst.values.putAll(src.values); + return dst; + } + protected ResultRow() { }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java Mon Jul 02 07:33:53 2018 +0200 @@ -110,16 +110,44 @@ * Facet-names (ManualPoints for example). */ public enum ChartType { - FD("fix_derivate_curve"), LS("longitudinal_section"), CS("cross_section"), DLS("discharge_longitudinal_section"), CDC("computed_discharge_curve"), DUC( - "duration_curve"), DIC("discharge_curve"), RC("reference_curve"), RCN("reference_curve_normalized"), WD("wdifferences"), BHDY( - "bedheight_difference_height_year"), BDY("bed_difference_year"), FWQC("fix_wq_curve"), FDWC("fix_deltawt_curve"), FLSC( - "fix_longitudinal_section_curve"), FDC("fix_derivate_curve"), EWQ("extreme_wq_curve"), BHM("bedheight_middle"), BLS( - "bed_longitudinal_section"), SLS("sedimentload_ls"), FV( - "flow_velocity"), SQA("sq_relation_a"), SQB("sq_relation_b"), W_D("w_differences"), SQC("sq_relation_c"), SQD( - "sq_relation_d"), SQE("sq_relation_e"), SQF("sq_relation_f"), HD("historical_discharge"), HDWQ( - "historical_discharge_wq"), SFD("sinfo_flow_depth"), SFDMM("sinfo_flow_depth_minmax"), SFDD( - "sinfo_flow_depth_development"), SFDDPY("sinfo_flow_depth_development_peryear"), SC( - "sinfo_collision"), SFDUR("sinfo_flood_duration"), STKH("sinfo_tkk"); + FD("fix_derivate_curve"), // + LS("longitudinal_section"), // + CS("cross_section"), // + DLS("discharge_longitudinal_section"), // + CDC("computed_discharge_curve"), // + DUC("duration_curve"), // + DIC("discharge_curve"), // + RC("reference_curve"), // + RCN("reference_curve_normalized"), // + WD("wdifferences"), // + BHDY("bedheight_difference_height_year"), // + BDY("bed_difference_year"), // + FWQC("fix_wq_curve"), // + FDWC("fix_deltawt_curve"), // + FLSC("fix_longitudinal_section_curve"), // + FDC("fix_derivate_curve"), // + EWQ("extreme_wq_curve"), // + BHM("bedheight_middle"), // + BLS("bed_longitudinal_section"), // + SLS("sedimentload_ls"), // + FV("flow_velocity"), // + SQA("sq_relation_a"), // + SQB("sq_relation_b"), // + W_D("w_differences"), // + SQC("sq_relation_c"), // + SQD("sq_relation_d"), // + SQE("sq_relation_e"), // + SQF("sq_relation_f"), // + HD("historical_discharge"), // + HDWQ("historical_discharge_wq"), // + SFD("sinfo_flow_depth"), // + SFDMM("sinfo_flow_depth_minmax"), // + SFDD("sinfo_flow_depth_development"), // + SFDDPY("sinfo_flow_depth_development_peryear"), // + SC("sinfo_collision"), // + SFDUR("sinfo_flood_duration"), // + STKH("sinfo_tkk"), // + SFW("sinfo_flood_height"); private final String chartTypeString;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionArtifact.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionArtifact.java Mon Jul 02 07:33:53 2018 +0200 @@ -103,7 +103,7 @@ log.error("Invalid datacage ID '" + code + "'"); return; } - final ArrayList<Facet> facets = new ArrayList<>(2); + final ArrayList<Facet> facets = new ArrayList<>(1); facets.add(CollisionCountProcessor.createFacet(callMeta, year)); // facets.add(CollisionGaugeWProcessor.createFacet(callMeta, seriesName)); //REMARK gauge_w is the cm above gauge datum, // therefore only useful with transformation to NHN
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionCalculation.java Mon Jul 02 07:33:53 2018 +0200 @@ -24,7 +24,7 @@ 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.GaugeMainValueFinder; import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; @@ -80,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, GaugeMainValueNameFinder> zoneFinders = new HashMap<>(); + final Map<Gauge, GaugeMainValueFinder> zoneFinders = new HashMap<>(); for (final Gauge gauge : river.determineGauges(calcRange.getMinimumDouble(), calcRange.getMaximumDouble())) { qFinders.put(gauge, GaugeDischargeValuesFinder.loadValues(gauge, problems)); - zoneFinders.put(gauge, GaugeMainValueNameFinder.loadValues(MainValueTypeKey.Q, gauge, problems)); + zoneFinders.put(gauge, GaugeMainValueFinder.loadValues(MainValueTypeKey.Q, gauge, problems)); } final Collection<ResultRow> detailsRows = new ArrayList<>(); @@ -121,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, GaugeMainValueNameFinder> zoneFinders) { + final Map<Gauge, GaugeMainValueFinder> 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); @@ -132,7 +132,7 @@ .putValue(SInfoResultType.collisionGaugeW, collision.getGaugeW()) .putValue(SInfoResultType.gaugeLabel, collision.getGaugeName()) .putValue(SInfoResultType.discharge, qOut) - .putValue(SInfoResultType.dischargeZone, zoneFinders.get(gauge).getZoneName(q))); + .putValue(SInfoResultType.dischargeZone, zoneFinders.get(gauge).findZoneName(q))); } } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/GaugeDischargeValuesFinder.java Sun Jul 01 15:29:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde - * Software engineering by - * Björnsen Beratende Ingenieure GmbH - * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt - * - * This file is Free Software under the GNU AGPL (>=v3) - * and comes with ABSOLUTELY NO WARRANTY! Check out the - * documentation coming with Dive4Elements River for details. - */ -package org.dive4elements.river.artifacts.sinfo.collision; - -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 - * - * @author Matthias Schäfer - * - */ -public final class GaugeDischargeValuesFinder { - - /***** FIELDS *****/ - - // private static Logger log = Logger.getLogger(GaugeDischargeValuesFinder.class); - - private final Gauge gauge; - - private final 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.isEmpty()) - this.wRange = new DoubleRange(ws.get(0), ws.get(ws.size() - 1)); - else - this.wRange = null; - this.wInterpolator = new LinearInterpolator().interpolate(ws.toNativeArray(), qs.toNativeArray()); - } - - - /***** 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)) - 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 - * - * @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
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FloodDurationProcessor.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FloodDurationProcessor.java Mon Jul 02 07:33:53 2018 +0200 @@ -16,6 +16,9 @@ import org.dive4elements.artifactdatabase.state.Facet; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.common.AbstractCalculationResult; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCalculationResult; +import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; /** * Processor to generate the facet and data series of infrastructure flood durations @@ -31,6 +34,10 @@ public static final String FACET_MAIN_VALUE_1_DURATION = "mainvalue.1.duration"; + public static final String FACET_MAIN_VALUE_2_DURATION = "mainvalue.2.duration"; + + public static final String FACET_MAIN_VALUE_3_DURATION = "mainvalue.3.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"; @@ -40,6 +47,8 @@ static { HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION); HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_1_DURATION); + HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_2_DURATION); + HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_3_DURATION); } public FloodDurationProcessor() { @@ -49,11 +58,18 @@ @Override protected double[][] doGetPoints(final AbstractCalculationResult data, final String facetName) { + if (FACET_FLOOD_DURATION.contentEquals(facetName)) - return data.getStationPoints(SInfoResultType.floodDuration); + return ((FloodDurationCalculationResult) data).fetchInfrastructurePoints(SInfoResultType.floodDuration); if (FACET_MAIN_VALUE_1_DURATION.contentEquals(facetName)) - return data.getStationPoints(SInfoResultType.mainValue1Duration); + return ((FloodDurationCalculationResult) data).fetchMainValuePoints(SInfoResultType.mainValue1Duration); + + if (FACET_MAIN_VALUE_2_DURATION.contentEquals(facetName)) + return ((FloodDurationCalculationResult) data).fetchMainValuePoints(SInfoResultType.mainValue2Duration); + + if (FACET_MAIN_VALUE_3_DURATION.contentEquals(facetName)) + return ((FloodDurationCalculationResult) data).fetchMainValuePoints(SInfoResultType.mainValue3Duration); final String error = String.format("Unknown facet name: %s", facetName); throw new UnsupportedOperationException(error); @@ -61,13 +77,18 @@ 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); + FACET_FLOOD_DURATION, FACET_FLOOD_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); + final FloodDurationCalculationResult result, final int index) { + + final String description = Resources.getMsg(context.getMeta(), FACET_MAIN_VALUE_DURATION_DESCRIPTION, FACET_MAIN_VALUE_DURATION_DESCRIPTION, + result.getMainValueLabel(index)); + assert ((index >= 0) && (index <= 2)); + final String facetName = new String[] { FACET_MAIN_VALUE_1_DURATION, FACET_MAIN_VALUE_2_DURATION, FACET_MAIN_VALUE_3_DURATION }[index]; + return new SInfoResultFacet(0, facetName, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash); } } \ 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/FloodHeightProcessor.java Mon Jul 02 07:33:53 2018 +0200 @@ -0,0 +1,92 @@ +/** 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; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCalculationResult; +import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; +import org.dive4elements.river.exports.LongitudinalSectionGenerator; + +/** + * Processor to generate the facet and data series of infrastructure flood heights + * + * @author Matthias Schäfer + * + */ +public final class FloodHeightProcessor extends AbstractSInfoLineProcessor<AbstractCalculationResult> { + + public static final String FACET_FLOOD_HEIGHT = "sinfo_facet_flood_height"; + + public static final String FACET_FLOOD_HEIGHT_DESCRIPTION = "sinfo_facet_flood_height.description"; + + public static final String FACET_MAIN_VALUE_1_HEIGHT = "mainvalue.1.w"; + + public static final String FACET_MAIN_VALUE_2_HEIGHT = "mainvalue.2.w"; + + public static final String FACET_MAIN_VALUE_3_HEIGHT = "mainvalue.3.w"; + + public static final String FACET_MAIN_VALUE_HEIGHT_DESCRIPTION = "mainvalue.w.description"; + + private static final String I18N_AXIS_LABEL = LongitudinalSectionGenerator.I18N_YAXIS_LABEL; + + private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>(); + + static { + HANDLED_FACET_TYPES.add(FACET_FLOOD_HEIGHT); + HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_1_HEIGHT); + HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_2_HEIGHT); + HANDLED_FACET_TYPES.add(FACET_MAIN_VALUE_3_HEIGHT); + } + + public FloodHeightProcessor() { + super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES); + } + + + @Override + protected double[][] doGetPoints(final AbstractCalculationResult data, final String facetName) { + if (FACET_FLOOD_HEIGHT.contentEquals(facetName)) + return ((FloodDurationCalculationResult) data).fetchInfrastructurePoints(SInfoResultType.infrastructureHeight); + + if (FACET_MAIN_VALUE_1_HEIGHT.contentEquals(facetName)) + return ((FloodDurationCalculationResult) data).fetchMainValuePoints(SInfoResultType.waterlevel1); + + if (FACET_MAIN_VALUE_2_HEIGHT.contentEquals(facetName)) + return ((FloodDurationCalculationResult) data).fetchMainValuePoints(SInfoResultType.waterlevel2); + + if (FACET_MAIN_VALUE_3_HEIGHT.contentEquals(facetName)) + return ((FloodDurationCalculationResult) data).fetchMainValuePoints(SInfoResultType.waterlevel3); + + final String error = String.format("Unknown facet name: %s", facetName); + throw new UnsupportedOperationException(error); + } + + public static Facet createFloodHeightFacet(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_HEIGHT, FACET_FLOOD_HEIGHT_DESCRIPTION); + } + + public static Facet createMainValueHeightFacet(final CallContext context, final String hash, final String id, + final FloodDurationCalculationResult result, final int index) { + final String description = Resources.getMsg(context.getMeta(), FACET_MAIN_VALUE_HEIGHT_DESCRIPTION, FACET_MAIN_VALUE_HEIGHT_DESCRIPTION, + result.getMainValueLabel(index)); + assert ((index >= 0) && (index <= 2)); + final String facetName = new String[] { FACET_MAIN_VALUE_1_HEIGHT, FACET_MAIN_VALUE_2_HEIGHT, FACET_MAIN_VALUE_3_HEIGHT }[index]; + return new SInfoResultFacet(0, facetName, description, I18N_AXIS_LABEL, ComputeType.ADVANCE, id, hash); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDischargeValuesFinder.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDischargeValuesFinder.java Mon Jul 02 07:33:53 2018 +0200 @@ -44,14 +44,16 @@ /***** CONSTRUCTORS *****/ private GaugeDischargeValuesFinder(final Gauge gauge, final Calculation problems, final DischargeTable dischargeTable) { + // Load W-Q-values from database this.gauge = gauge; this.problems = problems; final TDoubleArrayList ws = new TDoubleArrayList(); final TDoubleArrayList qs = new TDoubleArrayList(); - for (final DischargeTableValue v : DischargeTable.getValuesSortedByW(dischargeTable)) { + for (final DischargeTableValue v : DischargeTable.fetchValuesSortedByW(dischargeTable)) { ws.add(v.getW().doubleValue()); qs.add(v.getQ().doubleValue()); } + // Build interpolator 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)); @@ -71,12 +73,12 @@ /***** METHODS *****/ /** - * Loads the the main discharge table of a gauge (GAUGE.at) + * 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); + final DischargeTable table = gauge.fetchMasterDischargeTable(); if ((table == null) || (table.getDischargeTableValues().size() == 0)) { problems.addProblem("gauge_discharge_table.missing", gauge.getName()); return null;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDurationValuesFinder.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeDurationValuesFinder.java Mon Jul 02 07:33:53 2018 +0200 @@ -21,7 +21,7 @@ import gnu.trove.TDoubleArrayList; /** - * Loading and search/interpolate the duration main values of a gauge + * Search/interpolation of the duration main values of a gauge * * @author Matthias Schäfer * @@ -49,6 +49,7 @@ /***** CONSTRUCTORS *****/ private GaugeDurationValuesFinder(final Gauge gauge, final Calculation problems) { + // Load the duration main values from the database (each duration has a Q) this.gauge = gauge; this.problems = problems; final TDoubleArrayList qs = new TDoubleArrayList(); @@ -57,6 +58,7 @@ qs.add(v.getValue().doubleValue()); durs.add(Integer.valueOf(v.getMainValue().getName()).doubleValue()); } + // Build the duration-by-Q interpolator try { this.qInterpolator = new LinearInterpolator().interpolate(qs.toNativeArray(), durs.toNativeArray()); this.qRange = new DoubleRange(qs.get(0), qs.get(qs.size() - 1)); @@ -65,12 +67,14 @@ this.qInterpolator = null; this.qRange = null; } + // Load the Q values by duration from the database qs.clear(); durs.clear(); for (final MainValue v : MainValue.getDurationDischargesOfGauge(gauge)) { durs.add(Integer.valueOf(v.getMainValue().getName()).doubleValue()); qs.add(v.getValue().doubleValue()); } + // Build the Q-by-duration interpolator try { this.durInterpolator = new LinearInterpolator().interpolate(durs.toNativeArray(), qs.toNativeArray()); this.durRange = new DoubleRange(durs.get(0), durs.get(durs.size() - 1)); @@ -79,6 +83,7 @@ this.durInterpolator = null; this.durRange = null; } + // Report problems if (((this.qInterpolator == null) || (this.durInterpolator == null)) && (this.problems != null)) { this.problems.addProblem("gauge_duration.missing", gauge.getName()); // Report only once @@ -89,7 +94,7 @@ /***** METHODS *****/ /** - * Loads the the discharge-duration table of a gauge (GAUGE.glt) + * Loads the the discharge-duration table of a gauge ({gauge}.sta) * * @return The main values finder of a a gauge, or null */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeMainValueFinder.java Mon Jul 02 07:33:53 2018 +0200 @@ -0,0 +1,239 @@ +/** 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 the main values of a gauge to find relative positions of a value and build a corresponding zone name + * + * @author Matthias Schäfer + * + */ +public final class GaugeMainValueFinder { + + /***** FIELDS *****/ + + // private static Logger log = Logger.getLogger(GaugeMainValueNameFinder.class); + + private final Gauge gauge; + + private Calculation problems; + + private final NavigableMap<Double, MainValue> mainValues; + + private final MainValueTypeKey keyType; + + private final String approxPrefix = "ca."; // "\u2248" geht wohl nicht + + private Entry<Double, MainValue> foundCeiling; + + private Entry<Double, MainValue> foundFloor; + + private double foundRelativeDistance; + + + /***** CONSTRUCTORS *****/ + + private GaugeMainValueFinder(final MainValueTypeKey keyType, final Gauge gauge, final Calculation problems) { + this.gauge = gauge; + this.problems = problems; + this.keyType = keyType; + this.mainValues = new TreeMap<>(); + for (final MainValue mainValue : MainValue.getValuesOfGaugeAndType(gauge, keyType)) + 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.sta) + * + * @return The main values finder of a type and a gauge, or null + */ + public static GaugeMainValueFinder loadValues(final MainValueTypeKey type, final Gauge gauge, final Calculation problems) { + return new GaugeMainValueFinder(type, gauge, problems); + } + + /** + * If this provider may return valid data at all. + */ + public boolean isValid() { + return (this.mainValues != null); + } + + /** + * Searches the main value zone for a value, and returns a textual description of the zone + * (name for an exact match, circa expression for +/- 10% match, less-than/between/greater-than expression otherwise) + */ + public String findZoneName(final double value) { + if (!this.findValue(value)) + return ""; + + // Clearly below or just (max. 10%) below lowest named value + if (this.foundFloor == null) { + if (Double.isInfinite(this.foundRelativeDistance)) + return "<" + this.foundCeiling.getValue().getMainValue().getName(); + else + return this.approxPrefix + this.foundCeiling.getValue().getMainValue().getName(); + } + + // Clearly above or just (max. 10%) above highest named value + if (this.foundCeiling == null) { + if (Double.isInfinite(this.foundRelativeDistance)) + return ">" + this.foundFloor.getValue().getMainValue().getName(); + else + return this.approxPrefix + this.foundFloor.getValue().getMainValue().getName(); + } + + // Exact match + if (this.mainValues.containsKey(Double.valueOf(value))) + return this.mainValues.get(Double.valueOf(value)).getMainValue().getName(); + + // Near (10%) one of the borders of a zone interval, or clearly within a zone + if (this.foundRelativeDistance <= 0.001) + return this.foundFloor.getValue().getMainValue().getName(); + else if (this.foundRelativeDistance <= 0.1) + return this.approxPrefix + this.foundFloor.getValue().getMainValue().getName(); + else if (this.foundRelativeDistance >= 0.9) + return this.approxPrefix + this.foundCeiling.getValue().getMainValue().getName(); + else + return this.foundFloor.getValue().getMainValue().getName() + "-" + this.foundCeiling.getValue().getMainValue().getName(); + } + + /** + * Searches the main value zone for a value, and returns the zone name for an exact match, the nomatchReturn otherwise + */ + public String findExactZoneName(final double value, final String noMatchReturn) { + this.findValue(value); + if ((this.foundFloor != null) && (this.foundFloor.getKey() == this.foundCeiling.getKey())) + return this.foundFloor.getValue().getMainValue().getName(); + else + return noMatchReturn; + } + + /** + * Searches the interval of a main value and its relative distance from the lower value + */ + public boolean findValue(final double value) { + this.foundFloor = null; + this.foundCeiling = null; + this.foundRelativeDistance = Double.NaN; + if (!this.isValid()) + return false; + if (Double.isNaN(value)) + return false; + + // Clearly below or just (max. 10%) below lowest named value + this.foundFloor = this.mainValues.floorEntry(Double.valueOf(value)); + if (this.foundFloor == null) { + this.foundCeiling = this.mainValues.firstEntry(); + if (value >= this.mainValues.firstKey().doubleValue() * 0.9) { + this.foundRelativeDistance = 0.9; + return true; + } + else { + this.foundRelativeDistance = Double.NEGATIVE_INFINITY; + return false; + } + } + + // Clearly above or just (max. 10%) above highest named value + this.foundCeiling = this.mainValues.ceilingEntry(Double.valueOf(value)); + if (this.foundCeiling == null) { + if (value <= this.mainValues.lastKey().doubleValue() * 1.1) { + this.foundRelativeDistance = 0.1; + return true; + } + else { + this.foundRelativeDistance = Double.POSITIVE_INFINITY; + return false; + } + } + + // Exact match or within an interval + if (this.foundCeiling.getKey() == this.foundFloor.getKey()) + this.foundRelativeDistance = 0.0; + else + this.foundRelativeDistance = (value - this.foundFloor.getKey().doubleValue()) + / (this.foundCeiling.getKey().doubleValue() - this.foundFloor.getKey().doubleValue()); + return true; + } + + /** + * Floor value of the last findValue + */ + public MainValue getFoundFloorValue() { + if (this.foundFloor != null) + return this.foundFloor.getValue(); + else + return null; + } + + /** + * Ceiling value of the last findValue + */ + public MainValue getFoundCeilingValue() { + if (this.foundCeiling != null) + return this.foundCeiling.getValue(); + else + return null; + } + + /** + * Relative distance of the last findValue + */ + public double getFoundRelativeDistance() { + return this.getFoundRelativeDistance(); + } + + /** + * Searches a pair of zone names and return the a value within the interval by a relative distance, or NaN + */ + public double findValue(final String floorZone, final String ceilingZone, final double relativeDistance) { + this.foundFloor = null; + this.foundCeiling = null; + this.foundRelativeDistance = relativeDistance; + for (final Entry<Double, MainValue> mainValue : this.mainValues.entrySet()) { + if (mainValue.getValue().getMainValue().getName().equalsIgnoreCase(floorZone)) { + this.foundFloor = mainValue; + break; + } + } + if (this.foundFloor == null) + return Double.NaN; + if (floorZone.equalsIgnoreCase(ceilingZone)) + return this.foundFloor.getKey().doubleValue(); + for (final Entry<Double, MainValue> mainValue : this.mainValues.entrySet()) { + if (mainValue.getValue().getMainValue().getName().equalsIgnoreCase(ceilingZone)) { + this.foundCeiling = mainValue; + break; + } + } + if (this.foundCeiling == null) + return Double.NaN; + else + return (this.foundCeiling.getKey().doubleValue() - this.foundFloor.getKey().doubleValue()) * this.foundRelativeDistance + + this.foundFloor.getKey().doubleValue(); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/GaugeMainValueNameFinder.java Sun Jul 01 15:29:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde - * Software engineering by - * Björnsen Beratende Ingenieure GmbH - * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt - * - * This file is Free Software under the GNU AGPL (>=v3) - * and comes with ABSOLUTELY NO WARRANTY! Check out the - * documentation coming with Dive4Elements River for details. - */ -package org.dive4elements.river.artifacts.sinfo.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 = "\u2248";// "ca."; - - /***** 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/SInfoI18NStrings.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoI18NStrings.java Mon Jul 02 07:33:53 2018 +0200 @@ -75,7 +75,9 @@ String PREFIX_TKH_KIND = "sinfo.export.tkh.soilkind."; - String CSV_INFRASTRUCTURE_HEIGHT_HEADER = "sinfo.export.csv.header.infrastructure.height"; + String CSV_INFRASTRUCTURE_HEIGHT_HEADER = "sinfo.export.flood_duration.csv.header.infrastructure.height"; + + String PDF_INFRASTRUCTURE_HEIGHT_HEADER = "sinfo.export.flood_duration.pdf.header.infrastructure.height"; String CSV_COLLISION_COUNT_HEADER = "sinfo.export.csv.header.collision.count";
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultFacet.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultFacet.java Mon Jul 02 07:33:53 2018 +0200 @@ -20,7 +20,7 @@ import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; /** - * Facet of a FlowDepth curve. + * Facet of one of the S-Info curves. */ public final class SInfoResultFacet extends DataFacet {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java Mon Jul 02 07:33:53 2018 +0200 @@ -87,8 +87,40 @@ } }; - 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") { + public static final SInfoResultType mainValue1Duration = new SInfoResultType(null, "sinfo.flood_duration.header.mainvalue.1.duration", + "sinfo.flood_duration.header.pdf.mainvalue.1.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 + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getIntegerFormatter(context); + } + }; + + public static final SInfoResultType mainValue2Duration = new SInfoResultType(null, "sinfo.flood_duration.header.mainvalue.2.duration", + "sinfo.flood_duration.header.pdf.mainvalue.2.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 + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getIntegerFormatter(context); + } + }; + + public static final SInfoResultType mainValue3Duration = new SInfoResultType(null, "sinfo.flood_duration.header.mainvalue.3.duration", + "sinfo.flood_duration.header.pdf.mainvalue.3.duration") { private static final long serialVersionUID = 1L; @Override @@ -121,6 +153,54 @@ } }; + public static final SInfoResultType waterlevel1 = new SInfoResultType(null, "sinfo.flood_duration.header.mainvalue.1.w", + "sinfo.flood_duration.header.pdf.mainvalue.1.w") { + 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 + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getFlowDepth(context); + } + }; + + public static final SInfoResultType waterlevel2 = new SInfoResultType(null, "sinfo.flood_duration.header.mainvalue.2.w", + "sinfo.flood_duration.header.pdf.mainvalue.2.w") { + 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 + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getFlowDepth(context); + } + }; + + public static final SInfoResultType waterlevel3 = new SInfoResultType(null, "sinfo.flood_duration.header.mainvalue.3.w", + "sinfo.flood_duration.header.pdf.mainvalue.3.w") { + 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 + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getFlowDepth(context); + } + }; + public static final SInfoResultType waterlevelLabel = new SInfoResultType(I18NStrings.UNIT_NONE, SInfoI18NStrings.CSV_LABEL_HEADER) { private static final long serialVersionUID = 1L; @@ -166,6 +246,57 @@ } }; + public static final SInfoResultType discharge1 = new SInfoResultType(I18NStrings.UNIT_CUBIC_M, "sinfo.flood_duration.header.mainvalue.1.q", + "sinfo.flood_duration.header.pdf.mainvalue.1.q") { + private static final long serialVersionUID = 1L; + + @Override + public String exportValue(final CallContext context, final Object value) { + final double doubleValue = asDouble(value); + final double roundedDischarge = RiverUtils.roundQ(doubleValue); + return exportDoubleValue(context, roundedDischarge); + } + + @Override + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getWaterlevelQ(context); + } + }; + + public static final SInfoResultType discharge2 = new SInfoResultType(I18NStrings.UNIT_CUBIC_M, "sinfo.flood_duration.header.mainvalue.2.q", + "sinfo.flood_duration.header.pdf.mainvalue.2.q") { + private static final long serialVersionUID = 1L; + + @Override + public String exportValue(final CallContext context, final Object value) { + final double doubleValue = asDouble(value); + final double roundedDischarge = RiverUtils.roundQ(doubleValue); + return exportDoubleValue(context, roundedDischarge); + } + + @Override + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getWaterlevelQ(context); + } + }; + + public static final SInfoResultType discharge3 = new SInfoResultType(I18NStrings.UNIT_CUBIC_M, "sinfo.flood_duration.header.mainvalue.3.q", + "sinfo.flood_duration.header.pdf.mainvalue.3.q") { + private static final long serialVersionUID = 1L; + + @Override + public String exportValue(final CallContext context, final Object value) { + final double doubleValue = asDouble(value); + final double roundedDischarge = RiverUtils.roundQ(doubleValue); + return exportDoubleValue(context, roundedDischarge); + } + + @Override + protected NumberFormat createFormatter(final CallContext context) { + return Formatter.getWaterlevelQ(context); + } + }; + public static final SInfoResultType meanBedHeight = new SInfoResultType(null, SInfoI18NStrings.CSV_MEAN_BED_HEIGHT_HEADER, SInfoI18NStrings.CSV_MEAN_BED_HEIGHT_HEADER_SHORT) { private static final long serialVersionUID = 1L; @@ -545,23 +676,8 @@ } }; - public static final SInfoResultType infrastructureHeightFloodDur = new SInfoResultType(I18NStrings.UNIT_M, - "sinfo.export.flood_duration.csv.header.infrastructure.height", "sinfo.export.flood_duration.pdf.header.infrastructure.height") { - 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 - protected NumberFormat createFormatter(final CallContext context) { - return Formatter.getInfrastructureHeight(context); - } - }; - - public static final SInfoResultType infrastructureHeight = new SInfoResultType(I18NStrings.UNIT_M, SInfoI18NStrings.CSV_INFRASTRUCTURE_HEIGHT_HEADER) { + public static final SInfoResultType infrastructureHeight = new SInfoResultType(I18NStrings.UNIT_M, SInfoI18NStrings.CSV_INFRASTRUCTURE_HEIGHT_HEADER, + SInfoI18NStrings.PDF_INFRASTRUCTURE_HEIGHT_HEADER) { private static final long serialVersionUID = 1L; @Override
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java Mon Jul 02 07:33:53 2018 +0200 @@ -11,13 +11,16 @@ 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.RiverInfo; import org.dive4elements.river.model.River; import org.dive4elements.river.model.sinfo.Infrastructure; @@ -41,6 +44,7 @@ /* 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(); final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange); @@ -51,8 +55,20 @@ final Calculation problems = new Calculation(); - final FloodDurationCalculationResults results = calculateResult(calcModeLabel, infrasType, riverside, calcRange, infoProvider, - RiversideChoiceKey.fromKey(access.getRiverside()), user, problems); + // Calculate the selected main values, if any + /* misuse winfo-artifact to calculate waterlevels in the same way */ + final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo); + int mainValueCount = 0; + if (winfo.isW()) + mainValueCount = winfo.getWs().length; + else if (winfo.isQ()) + mainValueCount = winfo.getQs().length; + + final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange, mainValueCount); + + final FloodDurationCalculationResult result = calculateResult(infrasType, riverside, calcRange, infoProvider, + RiversideChoiceKey.fromKey(access.getRiverside()), problems, winfo); + results.addResult(result, problems); return new CalculationResult(results, problems); } @@ -60,12 +76,11 @@ /** * Calculates the flood durations of the infrastructures of a km range of a river */ - private FloodDurationCalculationResults 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) { + private FloodDurationCalculationResult calculateResult(final String infrastructureType, final String riverside, final DoubleRange calcRange, + final RiverInfoProvider riverInfoProvider, final RiversideChoiceKey riversideKey, final Calculation problems, final WINFOArtifact winfo) { final FloodDurationCalculator calculator = new FloodDurationCalculator(this.context, riverInfoProvider); final String label = infrastructureType + ", " + riverside; - return calculator.execute(problems, label, calcModeLabel, calcRange, riversideKey, user); + return calculator.execute(problems, label, calcRange, riversideKey, winfo); } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java Mon Jul 02 07:33:53 2018 +0200 @@ -11,38 +11,108 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.List; import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult; import org.dive4elements.river.artifacts.common.ExportContextCSV; import org.dive4elements.river.artifacts.common.ExportContextPDF; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.common.IExportContext; +import org.dive4elements.river.artifacts.common.IResultType; import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; import org.dive4elements.river.artifacts.common.ResultRow; +import org.dive4elements.river.artifacts.sinfo.common.SInfoI18NStrings; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; +import gnu.trove.TDoubleArrayList; + /** * Contains the result of a {@link FloodDurationCalculation}. * * @author Gernot Belger */ -final class FloodDurationCalculationResult extends AbstractCalculationExportableResult { +public final class FloodDurationCalculationResult extends AbstractCalculationExportableResult { private static final long serialVersionUID = 1L; private static final String JASPER_FILE = "/jasper/templates/sinfo.floodduration.jrxml"; - public FloodDurationCalculationResult(final String label, final Collection<ResultRow> rows) { + private final String[] mainvalueLabels; + + public FloodDurationCalculationResult(final String label, final String[] mainvalueLabels, final Collection<ResultRow> rows) { super(label, rows); + this.mainvalueLabels = mainvalueLabels; + } + + /** + * The label of one of the optional main values, or null + */ + public String getMainValueLabel(final int index) { + if (index <= this.mainvalueLabels.length - 1) + return this.mainvalueLabels[index]; + else + return null; + } + + /** + * Collection of the result rows containing only the rows describing an infrastructure + */ + @Override + public Collection<ResultRow> getRows() { + final List<ResultRow> infrasOnlyRows = new ArrayList<>(); + for (final ResultRow row : this.rows) + if (row.getValue(SInfoResultType.infrastructuretype) != null) + infrasOnlyRows.add(row); + return Collections.unmodifiableCollection(infrasOnlyRows); + } + + /** + * Fetches the km-longitudinal section of the infrastructures and one of their result fields + */ + public final double[][] fetchInfrastructurePoints(final IResultType type) { + final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); + for (final ResultRow row : this.rows) { + if (row.getValue(SInfoResultType.infrastructuretype) != null) { + xPoints.add(row.getDoubleValue(GeneralResultType.station)); + yPoints.add(row.getDoubleValue(type)); + } + } + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } + + /** + * Fetches the km-longitudinal section of a main value + */ + public final double[][] fetchMainValuePoints(final IResultType type) { + final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size()); + final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size()); + // final IResultType check = new IResultType[] { SInfoResultType.mainValue1Duration, SInfoResultType.mainValue2Duration, + // SInfoResultType.mainValue3Duration }[index]; + for (final ResultRow row : this.rows) { + // if (!Double.isNaN(row.getDoubleValue(check))) { + xPoints.add(row.getDoubleValue(GeneralResultType.station)); + yPoints.add(row.getDoubleValue(type)); + // } + } + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; } @Override protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) { - // TODO Metadaten der Wasserspiegellage(n) falls gewählt - // exportContextCSV.writeCSVWaterlevelMetadata(this.wstInfo); - // exportContextCSV.writeBlankLine(); - // writer.writeNext(new String[] { "" }); // break line + if (this.mainvalueLabels.length >= 1) { + // "##METADATEN WASSERSPIEGELLAGE" + exportContextCSV.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL); + for (int i = 1; i <= this.mainvalueLabels.length; i++) { + // "# Bezeichnung der Wasserspiegellage: " + final String label = this.getMainValueLabel(i - 1); + exportContextCSV.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_NAME, String.format("%d: %s", i, label)); + } + // "# Bezugspegel: " + exportContextCSV.writeCSVMetaEntry(SInfoI18NStrings.CSV_META_HEADER_WATERLEVEL_GAUGE, "TODO: gauge"); + } } @Override @@ -62,7 +132,21 @@ lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructureHeight)); lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructuretype)); - // TODO Wasserspiegellage(n) und Dauerzahlen falls gewählt + if (this.getMainValueLabel(0) != null) { + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.waterlevel1)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.mainValue1Duration)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.discharge1)); + if (this.getMainValueLabel(1) != null) { + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.waterlevel2)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.mainValue2Duration)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.discharge2)); + if (this.getMainValueLabel(2) != null) { + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.waterlevel3)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.mainValue3Duration)); + lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.discharge3)); + } + } + } lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.gaugeLabel)); lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.location)); @@ -82,7 +166,21 @@ header.add(exportContextCSV.msgUnitCSV(SInfoResultType.infrastructureHeight, SInfoResultType.infrastructureHeight.getUnit())); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructuretype)); - // TODO Je vier Spalten der bis zu drei Wasserspiegellagen + if (this.getMainValueLabel(0) != null) { + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.waterlevel1, SInfoResultType.waterlevel.getUnit())); + header.add(exportContextCSV.formatCsvHeader(SInfoResultType.mainValue1Duration)); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.discharge1, SInfoResultType.discharge.getUnit())); + if (this.getMainValueLabel(1) != null) { + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.waterlevel2, SInfoResultType.waterlevel2.getUnit())); + header.add(exportContextCSV.formatCsvHeader(SInfoResultType.mainValue2Duration)); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.discharge2, SInfoResultType.discharge2.getUnit())); + if (this.getMainValueLabel(2) != null) { + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.waterlevel3, SInfoResultType.waterlevel3.getUnit())); + header.add(exportContextCSV.formatCsvHeader(SInfoResultType.mainValue3Duration)); + header.add(exportContextCSV.msgUnitCSV(SInfoResultType.discharge3, SInfoResultType.discharge3.getUnit())); + } + } + } header.add(exportContextCSV.formatCsvHeader(SInfoResultType.gaugeLabel)); header.add(exportContextCSV.formatCsvHeader(SInfoResultType.location)); @@ -111,10 +209,25 @@ 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_height_header", SInfoResultType.infrastructureHeight); exportContextPDF.addJRMetadata(source, "infrastructure_type_header", SInfoResultType.infrastructuretype); - // TODO Je vier Spalten der bis zu drei Wasserspiegellagen + // TODO Feldnamen ergaenzen und aktivieren wenn Report fertig + // if (this.getMainValueLabel(0) != null) { + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.waterlevel); + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.mainValue1Duration); + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.discharge); + // if (this.getMainValueLabel(1) != null) { + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.waterlevel2); + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.mainValue2Duration); + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.discharge2); + // if (this.getMainValueLabel(2) != null) { + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.waterlevel3); + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.mainValue3Duration); + // exportContextPDF.addJRMetadata(source, "?", SInfoResultType.discharge3); + // } + // } + // } exportContextPDF.addJRMetadata(source, "gauge_header", SInfoResultType.gaugeLabel); exportContextPDF.addJRMetadata(source, "location_header", SInfoResultType.location);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java Mon Jul 02 07:33:53 2018 +0200 @@ -20,7 +20,15 @@ private static final long serialVersionUID = 1L; - public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) { + private final int mainValueCount; + + public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange, + final int mainValueCount) { super(calcModeLabel, user, river, calcRange); + this.mainValueCount = mainValueCount; + } + + public int getMainValueCount() { + return this.mainValueCount; } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java Mon Jul 02 07:33:53 2018 +0200 @@ -12,23 +12,33 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.WINFOArtifact; +import org.dive4elements.river.artifacts.access.ComputationRangeAccess; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.common.ResultRow; import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.artifacts.model.Calculation.Problem; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.WQKms; import org.dive4elements.river.artifacts.sinfo.common.GaugeDurationValuesFinder; +import org.dive4elements.river.artifacts.sinfo.common.GaugeMainValueFinder; 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.model.Attribute.AttributeKey; import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.MainValueType.MainValueTypeKey; import org.dive4elements.river.model.sinfo.InfrastructureValue; +import gnu.trove.TDoubleArrayList; + /** * Calculation of the result rows of the flood duration of the infrastructures in a river km range * and selected main value durations @@ -50,60 +60,207 @@ } /** - * Calculate the result rows - * - * @return a result collection with one result + * Calculate the infrastructures flood duration result rows */ - public FloodDurationCalculationResults execute(final Calculation problems, final String label, final String calcModeLabel, - final DoubleRange calcRange, final RiversideChoiceKey riverside, final String user) { + public FloodDurationCalculationResult execute(final Calculation problems, final String label, final DoubleRange calcRange, + final RiversideChoiceKey riverside, final WINFOArtifact winfo) { - final WQBaseTableFinder wqFinder = WQBaseTableFinder.loadValues(this.riverInfoProvider.getRiver(), calcRange.getMinimumDouble(), - calcRange.getMaximumDouble(), problems); + // Find all gauges of the calc range, and create the duration finders final Map<Gauge, GaugeDurationValuesFinder> durFinders = new HashMap<>(); + Gauge firstGauge = null; 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); + if (firstGauge == null) + firstGauge = gauge; } - final FloodDurationCalculationResult result = new FloodDurationCalculationResult(label, this.rows); + // Find all infrastructures within the calc range + final AttributeKey bankKey = riverside.getAttributeKey(); + final List<InfrastructureValue> infras = InfrastructureValue.getValues(this.riverInfoProvider.getRiver(), calcRange.getMinimumDouble(), + calcRange.getMaximumDouble(), bankKey); - final RiverInfo riverInfo = new RiverInfo(this.riverInfoProvider.getRiver()); + // Merge all stations (range/step, borders of gauge ranges, infrastructures) + final Map<Double, InfrastructureValue> allStations = new HashMap<>(); + final Map<Double, InfrastructureValue> secondBank = new HashMap<>(); // any second infrastructure in case of both-banks-option + addRangeStations(allStations, winfo); + addGaugeLimits(allStations, durFinders.keySet(), calcRange.getMinimumDouble(), calcRange.getMaximumDouble()); + addInfrastructures(allStations, secondBank, infras); + final double[] stationsSorted = sortStations(allStations.keySet()); - final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange); - results.addResult(result, problems); - return results; + // Calculate W and Q for all stations and the selected discharge states + final WQKms[] wqkmsArray = calculateWaterlevels(winfo, stationsSorted, problems); + + // Determine discharge state labels of the main values + final String[] mainValueLabels = findMainValueLabels(wqkmsArray, winfo.getQs(), firstGauge, problems); + + // Create a finder for Q in the {river}.wst km-w-q table + final WQBaseTableFinder wqFinder = WQBaseTableFinder.loadValues(this.riverInfoProvider.getRiver(), calcRange.getMinimumDouble(), + calcRange.getMaximumDouble(), problems); + + // Calculate the durations and create the result rows + for (int i = 0; i <= stationsSorted.length - 1; i++) { + final Gauge gauge = this.riverInfoProvider.getGauge(stationsSorted[i], true); + final ResultRow row = createRow(stationsSorted[i], gauge, wqkmsArray, durFinders.get(gauge), i); + if (allStations.containsKey(stationsSorted[i]) && (allStations.get(stationsSorted[i]) != null)) + calculateInfrastructure(row, gauge, allStations.get(stationsSorted[i]), wqFinder, durFinders); + this.rows.add(row); + if (secondBank.containsKey(stationsSorted[i])) { + final ResultRow row2 = ResultRow.create(row); + calculateInfrastructure(row2, gauge, secondBank.get(stationsSorted[i]), wqFinder, durFinders); + this.rows.add(row2); + } + } + + return new FloodDurationCalculationResult(label, mainValueLabels, this.rows); } /** - * Calculate the result row for one infrastructure + * Adds to a stations map all stations corresponding to the active range and step */ - private void calculateResultRow(final InfrastructureValue infrastructure, final WQBaseTableFinder wqFinder, - final Map<Gauge, GaugeDurationValuesFinder> durFinders) { + private void addRangeStations(final Map<Double, InfrastructureValue> allStations, final WINFOArtifact winfo) { + for (final double station : new ComputationRangeAccess(winfo).getKms()) + allStations.put(Double.valueOf(station), null); + } + + /** + * Adds to a stations map all range limits of the gauges within the calc range + */ + private void addGaugeLimits(final Map<Double, InfrastructureValue> allStations, final Set<Gauge> gauges, final double fromKm, final double toKm) { + for (final Gauge gauge : gauges) { + final Double kmA = Double.valueOf(gauge.getRange().getA().doubleValue()); + final Double kmB = Double.valueOf(gauge.getRange().getB().doubleValue()); + if (kmA > fromKm - 0.0001) + allStations.put(kmA, null); + if (kmB < toKm + 0.0001) + allStations.put(kmB, null); + } + } + + /** + * Adds to a stations map all (first) infrastructures of a station, and the second, if any, to another map + */ + private void addInfrastructures(final Map<Double, InfrastructureValue> allStations, final Map<Double, InfrastructureValue> secondBank, + final List<InfrastructureValue> infrastructures) { + for (final InfrastructureValue infrastructure : infrastructures) { + final Double station = infrastructure.getStation(); + if (!allStations.containsKey(station) || !(allStations.get(station) instanceof InfrastructureValue)) + allStations.put(station, infrastructure); + else + secondBank.put(station, infrastructure); + } + } + + /** + * Returns a double array with a sorted stations set + */ + private double[] sortStations(final Set<Double> stations) { + final TDoubleArrayList sorted = new TDoubleArrayList(); + for (final Double station : stations) + sorted.add(station.doubleValue()); + sorted.sort(); + return sorted.toNativeArray(); + } + + /** + * Calculates an array of w-q-longitudinal sections for all artifact W/Q options + */ + private WQKms[] calculateWaterlevels(final WINFOArtifact winfo, final double[] stations, final Calculation problems) { + // REMARK aus TkhCalculation - move to WinfoArtifactWrapper? + // TODO das ist ziemlich langsam - durch den WQBaseTableFinder ersetzen? (vorher W-Optionen in Q umrechnen) + // (So funktioniert computeWaterlevelData wohl: + // Es sucht die Spalte(n) zum Bezugspegel-Q in der W-Q-Tabelle ({river}.wst in Wst etc.) + // und interpoliert für diese horizontale Tabellenposition jeweils die vertikale Tabellenposition der station; + // das ergibt das W einer station für einen Abflusszustand; + // bei Vorgabe eines Pegel-W wird vorher anhand der W-Q-Tabelle des Pegels ({gauge}.at in DischargeTable) das Q + // interpoliert; + // bei Vorgabe eines W auf freier Strecke wird wohl vorher noch die .wst-Interpolation eingesetzt. + final CalculationResult waterlevelData = winfo.computeWaterlevelData(stations); + + /* copy all problems */ + final Calculation winfoProblems = waterlevelData.getReport(); + final List<Problem> problems2 = winfoProblems.getProblems(); + if (problems2 != null) { + for (final Problem problem : problems2) { + problems.addProblem(problem); + } + } + return (WQKms[]) waterlevelData.getData(); + } + + /** + * Determines the discharge state labels for the selected Q or W values + */ + private String[] findMainValueLabels(final WQKms[] wqkmsArray, final double[] qs, final Gauge gauge, final Calculation problems) { + final String[] mainValueLabels = new String[wqkmsArray.length]; + if (wqkmsArray.length >= 1) { + // Labels like Q=123 or W=123 + for (int i = 0; i <= wqkmsArray.length - 1; i++) + mainValueLabels[i] = wqkmsArray[i].getName(); + // Replace labels for named main Q values + final GaugeMainValueFinder zoneFinder = GaugeMainValueFinder.loadValues(MainValueTypeKey.Q, gauge, problems); + if ((zoneFinder != null) && (qs != null)) { + for (int i = 0; i <= qs.length - 1; i++) + mainValueLabels[i] = zoneFinder.findExactZoneName(qs[i], mainValueLabels[i]); + } + } + return mainValueLabels; + } + + /** + * Create a result row for a station and its gauge, and add w-q-values as selected + */ + private ResultRow createRow(final Double station, final Gauge gauge, final WQKms[] wqkmsArray, + final GaugeDurationValuesFinder durationFinder, final int kmIndex) { final ResultRow row = ResultRow.create(); + row.putValue(GeneralResultType.station, station); + row.putValue(SInfoResultType.infrastructuretype, null); // is replaced later for an infrastructure + row.putValue(SInfoResultType.floodDuration, Double.NaN); // is replaced later for an infrastructure + row.putValue(SInfoResultType.gaugeLabel, gauge.getName()); + final String location = this.riverInfoProvider.getLocation(station); + row.putValue(SInfoResultType.location, location); - final Gauge gauge = this.riverInfoProvider.getGauge(infrastructure.getStation(), true); + if (wqkmsArray.length >= 1) { + assert (wqkmsArray[0].getKm(kmIndex) == station.doubleValue()); + row.putValue(SInfoResultType.waterlevel1, wqkmsArray[0].getW(kmIndex)); + row.putValue(SInfoResultType.discharge1, wqkmsArray[0].getQ(kmIndex)); + row.putValue(SInfoResultType.mainValue1Duration, underflowDaysToOverflowDays(durationFinder.getDuration(wqkmsArray[0].getQ(kmIndex)))); + if (wqkmsArray.length >= 2) { + assert (wqkmsArray[1].getKm(kmIndex) == station.doubleValue()); + row.putValue(SInfoResultType.waterlevel2, wqkmsArray[1].getW(kmIndex)); + row.putValue(SInfoResultType.discharge2, wqkmsArray[1].getQ(kmIndex)); + row.putValue(SInfoResultType.mainValue2Duration, underflowDaysToOverflowDays(durationFinder.getDuration(wqkmsArray[1].getQ(kmIndex)))); + if (wqkmsArray.length >= 3) { + assert (wqkmsArray[2].getKm(kmIndex) == station.doubleValue()); + row.putValue(SInfoResultType.waterlevel3, wqkmsArray[2].getW(kmIndex)); + row.putValue(SInfoResultType.discharge3, wqkmsArray[2].getQ(kmIndex)); + row.putValue(SInfoResultType.mainValue3Duration, underflowDaysToOverflowDays(durationFinder.getDuration(wqkmsArray[2].getQ(kmIndex)))); + } + } + } + return row; + } + + /** + * Calculate the result row fields for one infrastructure + */ + private void calculateInfrastructure(final ResultRow row, final Gauge gauge, final InfrastructureValue infrastructure, + final WQBaseTableFinder wqFinder, final Map<Gauge, GaugeDurationValuesFinder> durFinders) { + 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(infrastructure.getStation()); - row.putValue(GeneralResultType.station, infrastructure.getStation()); + final double dur = underflowDaysToOverflowDays(durFinders.get(gauge).getDuration(q)); row.putValue(SInfoResultType.riverside, infrastructure.getAttributeKey().getName()); // TODO i18n - row.putValue(SInfoResultType.floodDuration, 365 - durFinders.get(gauge).getDuration(q)); + row.putValue(SInfoResultType.floodDuration, dur); row.putValue(SInfoResultType.floodDischarge, qOut); row.putValue(SInfoResultType.infrastructureHeight, infrastructure.getHeight()); row.putValue(SInfoResultType.infrastructuretype, infrastructure.getInfrastructure().getType().getName()); - - // TODO Berechne W, Überflutungsdauer, Q und Bezeichnung von bis zu drei WSPL - // row.putValue(SInfoResultType.customMultiRowColWaterlevel, rowWsps); + } - row.putValue(SInfoResultType.gaugeLabel, gauge.getName()); - row.putValue(SInfoResultType.location, location); - - this.rows.add(row); + /** + * Translates underflow duration into overflow duration + */ + private double underflowDaysToOverflowDays(final double underflowDays) { + return 365 - underflowDays; } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationExporter.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationExporter.java Mon Jul 02 07:33:53 2018 +0200 @@ -15,7 +15,7 @@ import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; /** - * Generates different output formats (csv, pdf) of data that resulted from a flow depths min/max computation. + * Generates different output formats (csv, pdf) of data that resulted from a flood duration computation. * * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> * @author Gernot Belger
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java Mon Jul 02 07:33:53 2018 +0200 @@ -22,6 +22,7 @@ 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.sinfo.common.FloodHeightProcessor; import org.dive4elements.river.artifacts.states.DefaultState; /** @@ -79,7 +80,15 @@ for (final FloodDurationCalculationResult result : resultList) { facets.add(FloodDurationProcessor.createFloodDurationFacet(context, hash, this.id, result, index)); - facets.add(FloodDurationProcessor.createMainValueDurationFacet(context, hash, this.id, result, index)); + for (int j = 0; j <= 2; j++) { + if (result.getMainValueLabel(j) != null) + facets.add(FloodDurationProcessor.createMainValueDurationFacet(context, hash, this.id, result, j)); + } + facets.add(FloodHeightProcessor.createFloodHeightFacet(context, hash, this.id, result, index)); + for (int j = 0; j <= 2; j++) { + if (result.getMainValueLabel(j) != null) + facets.add(FloodHeightProcessor.createMainValueHeightFacet(context, hash, this.id, result, j)); + } 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));
--- a/artifacts/src/main/resources/messages.properties Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/resources/messages.properties Mon Jul 02 07:33:53 2018 +0200 @@ -920,6 +920,7 @@ sinfo.export.flow_depth.csv.header.mean_bed_height.short = Mittlere Sohl- sinfo.export.flow_depth.csv.header.sounding = Peilung/Epoche 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.duration = \u00dcberflutungsdauer [d/a] @@ -1004,10 +1005,10 @@ sinfo.flood_duration.header.pdf.bezeichnung_index = Bezeich-nung{0} sinfo.flood_duration.header.fd_per_year_index = \u00dcberflutungsdauer WSPL{0} [d/a] sinfo.flood_duration.header.pdf.fd_per_year_index = \u00dcberflu-tungs-dauer WSPL{0} [d/a] -sinfo.flood_duration.header.pdf.fd_per_year_index = \u00dcberflu-tungs-dauer WSPL{0} [d/a] sinfo.flood_duration.header.w_index = Wasser-stand/Wasser-spiegel-lage{0} sinfo.flood_duration.header.pdf.w_index = Wasser-stand/ Wasser-spiegel-lage{0} -sinfo.flood_duration.header.q_index = Q{0} [m\u00b3/sec] +sinfo.flood_duration.header.q_index = Q{0} +sinfo.flood_duration.header.pdf.q_index = Q{0} [m\u00b3/s] sinfo.export.flow_depth_minmax.csv.header.min = Minimale Flie\u00dftiefe sinfo.export.flow_depth_minmax.csv.header.max = Maximale Flie\u00dftiefe @@ -1135,8 +1136,35 @@ 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.1.duration = \u00dcberflutungsdauer-1 mainvalue.duration.description = \u00dcberflutungsdauer ({0}) +mainvalue.2.duration = \u00dcberflutungsdauer-2 +mainvalue.3.duration = \u00dcberflutungsdauer-3 +mainvalue.1.w = W-1 +mainvalue.w.description = W ({0}) +mainvalue.2.w = W-2 +mainvalue.3.w = W-3 +sinfo.flood_duration.header.mainvalue.1.duration = \u00dcberflutungsdauer WSPL-1 [d/a] +sinfo.flood_duration.header.pdf.mainvalue.1.duration = \u00dcberflu-tungs-dauer WSPL-1 [d/a] +sinfo.flood_duration.header.mainvalue.1.w = Wasserstand/Wasserspiegel-lage-1 +sinfo.flood_duration.header.pdf.mainvalue.1.w = Wasser-stand/Wasser-spiegel-lage-1 +sinfo.flood_duration.header.mainvalue.1.q = Q-1 +sinfo.flood_duration.header.pdf.mainvalue.1.q = Q-1 [m\u00b3/s] +sinfo.flood_duration.header.mainvalue.2.duration = \u00dcberflutungsdauer WSPL-2 [d/a] +sinfo.flood_duration.header.pdf.mainvalue.2.duration = \u00dcberflu-tungs-dauer WSPL-2 [d/a] +sinfo.flood_duration.header.mainvalue.2.w = Wasserstand/Wasserspiegel-lage-2 +sinfo.flood_duration.header.pdf.mainvalue.2.w = Wasser-stand/Wasser-spiegel-lage-2 +sinfo.flood_duration.header.mainvalue.2.q = Q-2 +sinfo.flood_duration.header.pdf.mainvalue.2.q = Q-2 [m\u00b3/s] +sinfo.flood_duration.header.mainvalue.3.duration = \u00dcberflutungsdauer WSPL-3 [d/a] +sinfo.flood_duration.header.pdf.mainvalue.3.duration = \u00dcberflu-tungs-dauer WSPL-3 [d/a] +sinfo.flood_duration.header.mainvalue.3.w = Wasserstand/Wasserspiegel-lage-3 +sinfo.flood_duration.header.pdf.mainvalue.3.w = Wasser-stand/Wasser-spiegel-lage-3 +sinfo.flood_duration.header.mainvalue.3.q = Q-3 +sinfo.flood_duration.header.pdf.mainvalue.3.q = Q-3 [m\u00b3/s] +sinfo.chart.flood_duration.height.section.title = H\u00f6he Infrastrukturen BWaStr +sinfo_facet_flood_height = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr +sinfo_facet_flood_height.description = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr ({0}) bundu_bezugswst = Bezugswasserst\u00e4nde bundu_analysis = Fixinganalysis
--- a/artifacts/src/main/resources/messages_de.properties Sun Jul 01 15:29:40 2018 +0200 +++ b/artifacts/src/main/resources/messages_de.properties Mon Jul 02 07:33:53 2018 +0200 @@ -920,6 +920,7 @@ sinfo.export.flow_depth.csv.header.mean_bed_height.short = Mittlere Sohl- sinfo.export.flow_depth.csv.header.sounding = Peilung/Epoche 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.duration = \u00dcberflutungsdauer [d/a] @@ -1002,12 +1003,13 @@ sinfo.flood_duration.header.bezeichnung_index = Bezeichnung{0} sinfo.flood_duration.header.pdf.bezeichnung_index = Bezeich-nung{0} +sinfo.flood_duration.header.duration_index = \u00dcberflutungsdauer WSPL{0} [d/a] sinfo.flood_duration.header.fd_per_year_index = \u00dcberflutungsdauer WSPL{0} [d/a] sinfo.flood_duration.header.pdf.fd_per_year_index = \u00dcberflu-tungs-dauer WSPL{0} [d/a] -sinfo.flood_duration.header.pdf.fd_per_year_index = \u00dcberflu-tungs-dauer WSPL{0} [d/a] sinfo.flood_duration.header.w_index = Wasser-stand/Wasser-spiegel-lage{0} sinfo.flood_duration.header.pdf.w_index = Wasser-stand/ Wasser-spiegel-lage{0} -sinfo.flood_duration.header.q_index = Q{0} [m\u00b3/sec] +sinfo.flood_duration.header.q_index = Q{0} +sinfo.flood_duration.header.pdf.q_index = Q{0} [m\u00b3/s] sinfo.export.flow_depth_minmax.csv.header.min = Minimale Flie\u00dftiefe sinfo.export.flow_depth_minmax.csv.header.max = Maximale Flie\u00dftiefe @@ -1135,8 +1137,35 @@ 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.1.duration = \u00dcberflutungsdauer-1 mainvalue.duration.description = \u00dcberflutungsdauer ({0}) +mainvalue.2.duration = \u00dcberflutungsdauer-2 +mainvalue.3.duration = \u00dcberflutungsdauer-3 +mainvalue.1.w = W-1 +mainvalue.w.description = W ({0}) +mainvalue.2.w = W-2 +mainvalue.3.w = W-3 +sinfo.flood_duration.header.mainvalue.1.duration = \u00dcberflutungsdauer WSPL-1 [d/a] +sinfo.flood_duration.header.pdf.mainvalue.1.duration = \u00dcberflu-tungs-dauer WSPL-1 [d/a] +sinfo.flood_duration.header.mainvalue.1.w = Wasserstand/Wasserspiegel-lage-1 +sinfo.flood_duration.header.pdf.mainvalue.1.w = Wasser-stand/Wasser-spiegel-lage-1 +sinfo.flood_duration.header.mainvalue.1.q = Q-1 +sinfo.flood_duration.header.pdf.mainvalue.1.q = Q-1 [m\u00b3/s] +sinfo.flood_duration.header.mainvalue.2.duration = \u00dcberflutungsdauer WSPL-2 [d/a] +sinfo.flood_duration.header.pdf.mainvalue.2.duration = \u00dcberflu-tungs-dauer WSPL-2 [d/a] +sinfo.flood_duration.header.mainvalue.2.w = Wasserstand/Wasserspiegel-lage-2 +sinfo.flood_duration.header.pdf.mainvalue.2.w = Wasser-stand/Wasser-spiegel-lage-2 +sinfo.flood_duration.header.mainvalue.2.q = Q-2 +sinfo.flood_duration.header.pdf.mainvalue.2.q = Q-2 [m\u00b3/s] +sinfo.flood_duration.header.mainvalue.3.duration = \u00dcberflutungsdauer WSPL-3 [d/a] +sinfo.flood_duration.header.pdf.mainvalue.3.duration = \u00dcberflu-tungs-dauer WSPL-3 [d/a] +sinfo.flood_duration.header.mainvalue.3.w = Wasserstand/Wasserspiegel-lage-3 +sinfo.flood_duration.header.pdf.mainvalue.3.w = Wasser-stand/Wasser-spiegel-lage-3 +sinfo.flood_duration.header.mainvalue.3.q = Q-3 +sinfo.flood_duration.header.pdf.mainvalue.3.q = Q-3 [m\u00b3/s] +sinfo.chart.flood_duration.height.section.title = H\u00f6he Infrastrukturen BWaStr +sinfo_facet_flood_height = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr +sinfo_facet_flood_height.description = Geod\u00e4tische H\u00f6he Infrastrukturen BWaStr ({0}) bundu_bezugswst = Bezugswasserst\u00e4nde bundu_analysis = Fixierungsanalyse
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Sun Jul 01 15:29:40 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Mon Jul 02 07:33:53 2018 +0200 @@ -1542,4 +1542,6 @@ String sinfo_flood_duration(); String sinfo_collision_export(); + + String sinfo_flood_height(); } \ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Sun Jul 01 15:29:40 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Mon Jul 02 07:33:53 2018 +0200 @@ -812,6 +812,7 @@ sinfo_collision = Grundber\u00fchrungen sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr +sinfo_flood_height = H\u00f6he Infrastruktur BWaStr uinfo = U-INFO uinfo_inundation_duration_export = \u00dcberflutungsdauern Export
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Sun Jul 01 15:29:40 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Mon Jul 02 07:33:53 2018 +0200 @@ -812,6 +812,7 @@ sinfo_collision = Grundber\u00fchrungen sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr +sinfo_flood_height = H\u00f6he Infrastruktur BWaStr uinfo = U-INFO uinfo_inundation_duration_export = \u00dcberflutungsdauern Export