changeset 9252:c2a0028bfa9f

Work on S-Info flood duration curve chart
author mschaefer
date Thu, 12 Jul 2018 18:09:48 +0200
parents 4082b8429353
children 68ff4087b987
files artifacts/doc/conf/artifacts/sinfo.xml artifacts/doc/conf/generators/generators.xml artifacts/doc/conf/meta-data.xml artifacts/doc/conf/themes.xml artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveFacet.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveGenerator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties
diffstat 18 files changed, 546 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/sinfo.xml	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/doc/conf/artifacts/sinfo.xml	Thu Jul 12 18:09:48 2018 +0200
@@ -366,7 +366,7 @@
        
           </facets>
         </outputmode>
-        <outputmode name="sinfo_flood_duration_curve" description="output.sinfo_duration_curve" mime-type="image/png" type="chart">
+        <outputmode name="sinfo_floodduration_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"/>
--- a/artifacts/doc/conf/generators/generators.xml	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/doc/conf/generators/generators.xml	Thu Jul 12 18:09:48 2018 +0200
@@ -70,6 +70,8 @@
   <output-generator names="sinfo_tkh_report" class="org.dive4elements.river.exports.ReportGenerator" />
   <output-generator names="sinfo_floodduration_export" class="org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationExporter" />
   <output-generator names="sinfo_floodduration_report" class="org.dive4elements.river.exports.ReportGenerator" />
+  <output-generator names="sinfo_floodduration_curve" class="org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCurveGenerator" />
+  <output-generator names="sinfo_floodduration_curve_chartinfo" class="org.dive4elements.river.artifacts.sinfo.flood_duration.FloodDurationCurveInfoGenerator" />
   <output-generator names="sinfo_collision_export" class="org.dive4elements.river.artifacts.sinfo.collision.CollisionExporter" />
   <output-generator names="sinfo_collision_report" class="org.dive4elements.river.exports.ReportGenerator" />
 
--- a/artifacts/doc/conf/meta-data.xml	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/doc/conf/meta-data.xml	Thu Jul 12 18:09:48 2018 +0200
@@ -142,9 +142,6 @@
                   <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>
--- a/artifacts/doc/conf/themes.xml	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/doc/conf/themes.xml	Thu Jul 12 18:09:48 2018 +0200
@@ -448,11 +448,9 @@
         <mapping from="sinfo_facet_flood_duration.left" to="SInfoFloodDurationLeft" />
         <mapping from="sinfo_facet_flood_duration.right" to="SInfoFloodDurationRight" />
         <mapping from="mainvalue.duration" to="SInfoMainValues" /> 
-        <mapping from="sinfo_facet_flood_height" to="SInfoInfrastructureHeight" />
         <mapping from="sinfo_facet_flood_height.left" to="SInfoInfrastructureHeightLeft" />
         <mapping from="sinfo_facet_flood_height.right" to="SInfoInfrastructureHeightRight" />
         <mapping from="mainvalue.w" to="SInfoMainValues" />
-      
         
         <mapping from="sinfo_facet_predefined_channel_width" to="SInfoPredefinedChannelWidth" />
         <mapping from="sinfo_facet_predefined_channel_depth" to="SInfoPredefinedChannelDepth" />
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java	Thu Jul 12 18:09:48 2018 +0200
@@ -147,7 +147,8 @@
         SC("sinfo_collision"), //
         SFDUR("sinfo_flood_duration"), //
         STKH("sinfo_tkk"), //
-        SFW("sinfo_flood_height");
+        SFW("sinfo_flood_height"), //
+        SFDC("sinfo_floodduration_curve");
 
         private final String chartTypeString;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Thu Jul 12 18:09:48 2018 +0200
@@ -60,8 +60,7 @@
 
         final FloodDurationCalculationResults results = new FloodDurationCalculationResults(calcModeLabel, user, riverInfo, calcRange);
 
-        final FloodDurationCalculationResult result = calculateResult(label, calcRange, infoProvider, access.getRiverside(), problems, winfo);
-        results.addResult(result, problems);
+        calculateResult(label, calcRange, infoProvider, access.getRiverside(), problems, winfo, results);
 
         return new CalculationResult(results, problems);
     }
@@ -69,10 +68,10 @@
     /**
      * Calculates the flood durations of the infrastructures of a km range of a river
      */
-    private FloodDurationCalculationResult calculateResult(final String label, final DoubleRange calcRange, final RiverInfoProvider riverInfoProvider,
-            final RiversideChoiceKey riverside, final Calculation problems, final WINFOArtifact winfo) {
+    private void calculateResult(final String label, final DoubleRange calcRange, final RiverInfoProvider riverInfoProvider,
+            final RiversideChoiceKey riverside, final Calculation problems, final WINFOArtifact winfo, final FloodDurationCalculationResults results) {
 
         final FloodDurationCalculator calculator = new FloodDurationCalculator(this.context, riverInfoProvider);
-        return calculator.execute(problems, label, calcRange, riverside, winfo);
+        calculator.execute(problems, label, calcRange, riverside, winfo, results);
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResults.java	Thu Jul 12 18:09:48 2018 +0200
@@ -11,6 +11,7 @@
 
 import org.apache.commons.lang.math.DoubleRange;
 import org.dive4elements.river.artifacts.common.AbstractCalculationResults;
+import org.dive4elements.river.artifacts.model.CalculationResult;
 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
 
 /**
@@ -23,4 +24,14 @@
     public FloodDurationCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) {
         super(calcModeLabel, user, river, calcRange);
     }
+
+    private CalculationResult durationCurve;
+
+    public CalculationResult getDurationCurve() {
+        return this.durationCurve;
+    }
+
+    public void setDurationCurve(final CalculationResult durationCurve) {
+        this.durationCurve = durationCurve;
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Thu Jul 12 18:09:48 2018 +0200
@@ -25,6 +25,7 @@
 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.WQDay;
 import org.dive4elements.river.artifacts.model.WQKms;
 import org.dive4elements.river.artifacts.sinfo.common.GaugeDurationValuesFinder;
 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
@@ -60,8 +61,8 @@
     /**
      * Calculate the infrastructures flood duration result rows
      */
-    public FloodDurationCalculationResult execute(final Calculation problems, final String label, final DoubleRange calcRange,
-            final RiversideChoiceKey riverside, final WINFOArtifact winfo) {
+    public void execute(final Calculation problems, final String label, final DoubleRange calcRange,
+            final RiversideChoiceKey riverside, final WINFOArtifact winfo, final FloodDurationCalculationResults results) {
 
         // Find all gauges of the calc range, and create the duration finders
         final Map<Gauge, GaugeDurationValuesFinder> durFinders = new HashMap<>();
@@ -113,8 +114,29 @@
                 this.rows.add(row2);
             }
         }
+        results.addResult(new FloodDurationCalculationResult(label, mainValueLabels, this.rows), problems);
+        calcWQDays(problems, stationsSorted[0], AttributeKey.LEFT, winfo, results);
+    }
 
-        return new FloodDurationCalculationResult(label, mainValueLabels, this.rows);
+    public void calcWQDays(final Calculation problems, final double station, final AttributeKey riverside, final WINFOArtifact winfo,
+            final FloodDurationCalculationResults results) {
+
+        winfo.addStringData("ld_locations", Double.toString(station));
+        final CalculationResult res = winfo.getDurationCurveData();
+        final WQDay underflow = (WQDay) res.getData();
+        // Transform underflow days into overflow days and re-sort
+        final int[] days = new int[underflow.getWs().length];
+        final double[] ws = new double[days.length];
+        final double[] qs = new double[days.length];
+        for (int i = 0, j = days.length - 1; i <= days.length - 1; i++, j--) {
+            days[j] = 365 - underflow.getDay(i);
+            ws[j] = underflow.getW(i);
+            qs[j] = underflow.getQ(i);
+        }
+        res.setData(new WQDay(days, ws, qs));
+        // TODO Infrastrukturhoehe
+        // TODO WSPL/Hauptwerte
+        results.setDurationCurve(res);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveFacet.java	Thu Jul 12 18:09:48 2018 +0200
@@ -0,0 +1,120 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.artifacts.sinfo.flood_duration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.DefaultFacet;
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.WQDay;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Data of a duration curve.
+ */
+public class FloodDurationCurveFacet extends DefaultFacet {
+
+    private static Logger log = Logger.getLogger(FloodDurationCurveFacet.class);
+
+    /** Blackboard data provider key for durationcurve (wqday) data. */
+    public static String BB_DURATIONCURVE = "durationcurve";
+
+    /** Blackboard data provider key for km of durationcurve. */
+    public static String BB_DURATIONCURVE_KM = "durationcurve.km";
+
+    public FloodDurationCurveFacet() {
+    }
+
+    public FloodDurationCurveFacet(final String name, final String description) {
+        super(0, name, description);
+    }
+
+
+    /**
+     * Expose state computation from SINFOArtifact.
+     */
+    @Override
+    public Object getData(final Artifact artifact, final CallContext context) {
+
+        log.debug("Get data for flood duration curve data");
+
+        final D4EArtifact flys = (D4EArtifact) artifact;
+
+        final CalculationResult res = (CalculationResult) flys.compute(context, ComputeType.ADVANCE, false);
+
+        final FloodDurationCalculationResults data = (FloodDurationCalculationResults) res.getData();
+
+        return data.getDurationCurve();
+        // return getTestData();
+    }
+
+    private WQDay getTestData() {
+        final int[] days = new int[366];
+        final double[] ws = new double[366];
+        final double[] qs = new double[366];
+        for (int i = 0; i <= 365; i++) {
+            days[i] = i;
+            final double x = (i - 182.5) / 182.5;
+            ws[i] = 102.0 - (Math.pow(x, 5) + x);
+            qs[i] = 1600.0 - 800 * (Math.pow(x, 9) + x);
+        }
+        return new WQDay(days, ws, qs);
+    }
+
+
+    @Override
+    public List getStaticDataProviderKeys(final Artifact art) {
+        final List list = new ArrayList();
+        list.add(BB_DURATIONCURVE);
+        list.add(BB_DURATIONCURVE_KM);
+        return list;
+    }
+
+
+    /**
+     * Can provide whatever getData returns and additionally the location.
+     * @param key      will respond on BB_DURATIONCURVE +KM
+     * @param param    ignored
+     * @param context  ignored
+     * @return whatever getData delivers or location.
+     */
+    @Override
+    public Object provideBlackboardData(final Artifact artifact,
+            final Object key,
+            final Object param,
+            final CallContext context
+            ) {
+        if (key.equals(BB_DURATIONCURVE)) {
+            return getData(artifact, context);
+        }
+        else if (key.equals(BB_DURATIONCURVE_KM)) {
+            return ((D4EArtifact)artifact).getDataAsString("ld_locations");
+        }
+        else {
+            return null;
+        }
+    }
+
+
+    /** Create a deep copy. */
+    @Override
+    public Facet deepCopy() {
+        final FloodDurationCurveFacet copy = new FloodDurationCurveFacet();
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveGenerator.java	Thu Jul 12 18:09:48 2018 +0200
@@ -0,0 +1,258 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.artifacts.sinfo.flood_duration;
+
+import java.awt.Font;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.FacetTypes;
+import org.dive4elements.river.artifacts.model.WQDay;
+import org.dive4elements.river.exports.IdentifiableNumberAxis;
+import org.dive4elements.river.exports.XYChartGenerator;
+import org.dive4elements.river.jfree.Bounds;
+import org.dive4elements.river.jfree.RiverAnnotation;
+import org.dive4elements.river.jfree.StyledXYSeries;
+import org.dive4elements.river.themes.ThemeDocument;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.Range;
+import org.jfree.data.xy.XYSeries;
+
+
+/**
+ * An OutGenerator that generates duration curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FloodDurationCurveGenerator
+extends      XYChartGenerator
+implements   FacetTypes
+{
+    public static enum YAXIS {
+        W(0),
+        Q(1);
+        public int idx;
+        private YAXIS(final int c) {
+            this.idx = c;
+        }
+    }
+
+    /** Local log. */
+    private static Logger log =
+            Logger.getLogger(FloodDurationCurveGenerator.class);
+
+    public static final String I18N_CHART_TITLE = "sinfo.chart.flood_duration.curve.section.title";
+
+    public static final String I18N_CHART_SUBTITLE = "chart.duration.curve.subtitle";
+
+    public static final String I18N_XAXIS_LABEL = "sinfo.chart.flood_duration.curve.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL_W = "chart.duration.curve.yaxis.label.w";
+
+    public static final String I18N_YAXIS_LABEL_Q = "chart.duration.curve.yaxis.label.q";
+
+    public static final String I18N_CHART_TITLE_DEFAULT = "Dauerlinie";
+
+    public static final String I18N_XAXIS_LABEL_DEFAULT = "Überflutungsdauer [d/a]";
+
+
+    public FloodDurationCurveGenerator() {
+        super();
+    }
+
+
+    /**
+     * Create Axis for given index.
+     * @return axis with according internationalized label.
+     */
+    @Override
+    protected NumberAxis createYAxis(final int index) {
+        final Font labelFont = new Font("Tahoma", Font.BOLD, 14);
+        final String label   = getYAxisLabel(index);
+
+        final NumberAxis axis = createNumberAxis(index, label);
+        if (index == YAXIS.W.idx) {
+            axis.setAutoRangeIncludesZero(false);
+        }
+        axis.setLabelFont(labelFont);
+        return axis;
+    }
+
+
+    @Override
+    protected String getDefaultChartTitle(final CallContext context) {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+
+    @Override
+    protected String getDefaultChartSubtitle(final CallContext context) {
+
+        final double[] dist  = getRange();
+        return msg(I18N_CHART_SUBTITLE, "", getRiverName(), dist[0]);
+    }
+
+
+    @Override
+    protected String getDefaultXAxisLabel(final CallContext context) {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+
+    @Override
+    protected String getDefaultYAxisLabel(final int index) {
+
+        String label = "default";
+        if (index == YAXIS.W.idx) {
+            label = msg(I18N_YAXIS_LABEL_W, I18N_YAXIS_LABEL_W, getRiverUnit());
+        }
+        else if (index == YAXIS.Q.idx) {
+            label = msg(I18N_YAXIS_LABEL_Q);
+        }
+        return label;
+    }
+
+
+    @Override
+    protected boolean zoomX(final XYPlot plot, final ValueAxis axis, final Bounds bounds, final Range x) {
+
+        final boolean zoomin = super.zoom(plot, axis, bounds, x);
+        if (!zoomin)
+            axis.setLowerBound(0d);
+        // axis.setUpperBound(364);
+        return zoomin;
+    }
+
+
+    /**
+     * This method overrides the method in the parent class to set the lower
+     * bounds of the Q axis to 0. This axis should never display negative
+     * values on its own.
+     */
+    @Override
+    protected boolean zoomY(final XYPlot plot, final ValueAxis axis, final Bounds bounds, final Range x) {
+
+        final boolean zoomin = super.zoom(plot, axis, bounds, x);
+        if (!zoomin && axis instanceof IdentifiableNumberAxis) {
+            final String id = ((IdentifiableNumberAxis) axis).getId();
+            if (YAXIS.Q.toString().equals(id))
+                axis.setLowerBound(0d);
+        }
+        return zoomin;
+    }
+
+
+    @Override
+    public void doOut(final ArtifactAndFacet artifactFacet, final ThemeDocument attr, final boolean visible) {
+
+        final String name = artifactFacet.getFacetName();
+
+        log.debug("FloodDurationCurveGenerator.doOut: " + name);
+
+        if (name == null || name.length() == 0) {
+            log.error("No facet given. Cannot create dataset.");
+            return;
+        }
+
+        final CallContext context = getContext();
+
+        if (name.equals(DURATION_W)) {
+            doWOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible);
+        }
+        else if (name.equals(DURATION_Q)) {
+            doQOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible);
+        }
+        else if (name.equals(MAINVALUES_Q) || name.equals(MAINVALUES_W)) {
+            doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible);
+        }
+        else if (name.equals(RELATIVE_POINT)) {
+            doPointOut((Point2D) artifactFacet.getData(context), artifactFacet, attr, visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactFacet.getData(context), artifactFacet, attr, visible, YAXIS.W.idx);
+        }
+        else {
+            log.warn("Unknown facet name: " + name);
+            return;
+        }
+    }
+
+    /**
+     * Creates the series for a duration curve's W facet.
+     *
+     * @param wqdays The WQDay store that contains the Ws.
+     * @param theme
+     */
+    protected void doWOut(final WQDay wqdays, final ArtifactAndFacet aaf, final ThemeDocument theme, final boolean visible) {
+
+        // log.debug("DurationCurveGenerator.doWOut");
+        final XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        final int size = wqdays.size();
+        for (int i = 0; i < size; i++) {
+            final int  day = wqdays.getDay(i);
+            final double w = wqdays.getW(i);
+            series.add(day, w);
+        }
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+    protected void doPointOut(final Point2D point, final ArtifactAndFacet aandf, final ThemeDocument theme, final boolean visible) {
+
+        // log.debug("DurationCurveGenerator.doPointOut");
+        final XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        series.add(point.getX(), point.getY());
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+
+    /**
+     * Creates the series for a duration curve's Q facet.
+     *
+     * @param wqdays The WQDay store that contains the Qs.
+     * @param theme
+     */
+    protected void doQOut(final WQDay wqdays, final ArtifactAndFacet aaf, final ThemeDocument theme, final boolean visible) {
+
+        // log.debug("DurationCurveGenerator.doQOut");
+        final XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        final int size = wqdays.size();
+        for (int i = 0; i < size; i++) {
+            final int  day = wqdays.getDay(i);
+            final double q = wqdays.getQ(i);
+            series.add(day, q);
+        }
+        addAxisSeries(series, YAXIS.Q.idx, visible);
+    }
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(final int idx) {
+                final YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+    // MainValue-Annotations should be visualized by
+    // a line that goes to the curve itself.
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveInfoGenerator.java	Thu Jul 12 18:09:48 2018 +0200
@@ -0,0 +1,26 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.artifacts.sinfo.flood_duration;
+
+import org.dive4elements.river.exports.ChartInfoGenerator;
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific duration
+ * curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FloodDurationCurveInfoGenerator
+extends      ChartInfoGenerator
+{
+    public FloodDurationCurveInfoGenerator() {
+        super(new FloodDurationCurveGenerator());
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCurveProcessor.java	Thu Jul 12 18:09:48 2018 +0200
@@ -0,0 +1,74 @@
+/** 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.flood_duration;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.common.AbstractCalculationResult;
+import org.dive4elements.river.exports.DiagramGenerator;
+import org.dive4elements.river.exports.DurationCurveGenerator;
+import org.dive4elements.river.exports.XYChartGenerator;
+import org.dive4elements.river.exports.process.DefaultProcessor;
+import org.dive4elements.river.themes.ThemeDocument;
+
+/**
+ * Processor to generate the facet and data series of a flood duration curve
+ *
+ * @author Matthias Schäfer
+ *
+ */
+public final class FloodDurationCurveProcessor extends DefaultProcessor {
+
+    private static final String FACET_FLOOD_DURATION_W = "duration_curve.w";
+
+    private static final String FACET_FLOOD_DURATION_Q = "duration_curve.q";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_W);
+        HANDLED_FACET_TYPES.add(FACET_FLOOD_DURATION_Q);
+    }
+
+    public static Facet createFloodDurationWCurveFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
+            final int facetIndex, final int resultIndex, final String description) {
+
+        return new FloodDurationCurveFacet(FACET_FLOOD_DURATION_W, description);
+    }
+
+    public static Facet createFloodDurationQCurveFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
+            final int facetIndex, final int resultIndex, final String description) {
+
+        return new FloodDurationCurveFacet(FACET_FLOOD_DURATION_Q, description);
+    }
+
+    /**
+     * Processes data to generate a chart.
+     */
+    @Override
+    public void doOut(final XYChartGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible, final int index) {
+
+    }
+
+    @Override
+    public final String getAxisLabel(final DiagramGenerator generator) {
+        return generator.msg(DurationCurveGenerator.I18N_YAXIS_LABEL_W);
+    }
+
+    @Override
+    public final boolean canHandle(final String facettype) {
+        return HANDLED_FACET_TYPES.contains(facettype);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Thu Jul 12 18:09:48 2018 +0200
@@ -20,6 +20,7 @@
 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.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
 import org.dive4elements.river.artifacts.sinfo.flood_duration.RiversideRadioChoice.RiversideChoiceKey;
 import org.dive4elements.river.artifacts.states.DefaultState;
@@ -94,7 +95,7 @@
 
             for (int j = 0; j < waterlevelCount; j++) {
 
-                final String waterlevelLabel = result.getMainValueLabel(j);
+                // final String waterlevelLabel = result.getMainValueLabel(j);
                 // FIXME: use label as label for theme
 
                 // final int facetIndex, final int resultIndex, final int dataIndex
@@ -104,6 +105,11 @@
                 themeCount++;
             }
 
+            final String nameW = Resources.getMsg(context.getMeta(), "sinfo.chart.flood_duration.curve.w");
+            final String nameQ = Resources.getMsg(context.getMeta(), "sinfo.chart.flood_duration.curve.q");
+            facets.add(FloodDurationCurveProcessor.createFloodDurationWCurveFacet(context, hash, this.id, result, 0, resultIndex, nameW));
+            facets.add(FloodDurationCurveProcessor.createFloodDurationQCurveFacet(context, hash, this.id, result, 1, resultIndex, nameQ));
+
             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	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Thu Jul 12 18:09:48 2018 +0200
@@ -1153,6 +1153,10 @@
 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})
+sinfo.chart.flood_duration.curve.section.title = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
+sinfo.chart.flood_duration.curve.xaxis.label = \u00dcberflutungsdauer [d/a]
+sinfo.chart.flood_duration.curve.w = Wasserstandsdauerlinie
+sinfo.chart.flood_duration.curve.q = Abflussdauerlinie
 
 bundu_bezugswst = Bezugswasserst\u00e4nde
 bundu_analysis = Fixinganalysis
--- a/artifacts/src/main/resources/messages_de.properties	Thu Jul 12 18:02:58 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Thu Jul 12 18:09:48 2018 +0200
@@ -1153,6 +1153,10 @@
 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})
+sinfo.chart.flood_duration.curve.section.title = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
+sinfo.chart.flood_duration.curve.xaxis.label = \u00dcberflutungsdauer [d/a]
+sinfo.chart.flood_duration.curve.w = Wasserstandsdauerlinie
+sinfo.chart.flood_duration.curve.q = Abflussdauerlinie
 
 bundu_bezugswst = Bezugswasserst\u00e4nde
 bundu_analysis = Fixierungsanalyse
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java	Thu Jul 12 18:02:58 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java	Thu Jul 12 18:09:48 2018 +0200
@@ -1557,6 +1557,8 @@
 
     String sinfo_deactivate_intelligent_datacord();
 
+    String sinfo_floodduration_curve();
+
     String uinfo_salix_dmwspl_short();
 
     String uinfo_salix_invalid_double();
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties	Thu Jul 12 18:02:58 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties	Thu Jul 12 18:09:48 2018 +0200
@@ -814,8 +814,9 @@
 sinfo_collisions = Grundber\u00fchrungen
 sinfo_collision = Grundber\u00fchrungen
 
-sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr
-sinfo_flood_height = H\u00f6he Infrastruktur BWaStr
+sinfo_flood_duration = \u00dcberflutungsdauer Infrastrukturen BWaStr
+sinfo_flood_height = H\u00f6he Infrastrukturen BWaStr
+sinfo_floodduration_curve = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
 
 uinfo = U-INFO
 uinfo_salix_dmwspl_short = \u0394MW [cm]
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties	Thu Jul 12 18:02:58 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties	Thu Jul 12 18:09:48 2018 +0200
@@ -814,8 +814,9 @@
 sinfo_collisions = Grundber\u00fchrungen
 sinfo_collision = Grundber\u00fchrungen
 
-sinfo_flood_duration = \u00dcberflutungsdauer Infrastruktur BWaStr
-sinfo_flood_height = H\u00f6he Infrastruktur BWaStr
+sinfo_flood_duration = \u00dcberflutungsdauer Infrastrukturen BWaStr
+sinfo_flood_height = H\u00f6he Infrastrukturen BWaStr
+sinfo_floodduration_curve = \u00dcberflutungsdauer Infrastrukturen BWaStr - Dauerlinie
 
 uinfo = U-INFO
 uinfo_salix_dmwspl_short = \u0394MW [cm]

http://dive4elements.wald.intevation.org