changeset 385:478940d06876

Enabled the WINFO artifact to create duration curves - new OutGenerator, added methods for data computation. flys-artifacts/trunk@1802 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 03 May 2011 12:05:32 +0000
parents 88614ddfc1e3
children da038768330a
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/conf.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java
diffstat 7 files changed, 381 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Tue May 03 09:23:17 2011 +0000
+++ b/flys-artifacts/ChangeLog	Tue May 03 12:05:32 2011 +0000
@@ -1,3 +1,26 @@
+2011-05-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  New. An OutGenerator for creating duration curves.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQDay.java: New. A
+	  model class to store necessary data for creating W and Q facets of a
+	  duration curve. This model stores W, Q and Days.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java:
+	  Added a function to retrieve tuples of (day, q) based on a given gauge -
+	  these tuples are necessary for creating duration curves.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added
+	  methods to compute and retrieve the data necessary for creating duration
+	  curves.
+
+	* src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java:
+	  Bugfix: improved the access to the location array (avoid
+	  NullPointerException).
+
+	* doc/conf/conf.xml: Registered the new OutGenerator for duration curves.
+
 2011-05-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* contrib/visualize-transitions.xsl: State quoting was done wrong.
--- a/flys-artifacts/doc/conf/conf.xml	Tue May 03 09:23:17 2011 +0000
+++ b/flys-artifacts/doc/conf/conf.xml	Tue May 03 12:05:32 2011 +0000
@@ -51,6 +51,7 @@
     <output-generators>
         <output-generator name="discharge_curve">de.intevation.flys.exports.DischargeCurveGenerator</output-generator>
         <output-generator name="longitudinal_section">de.intevation.flys.exports.LongitudinalSectionGenerator</output-generator>
+        <output-generator name="duration_curve">de.intevation.flys.exports.DurationCurveGenerator</output-generator>
     </output-generators>
 
     <rest-server>
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Tue May 03 09:23:17 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Tue May 03 12:05:32 2011 +0000
@@ -20,10 +20,13 @@
 
 import de.intevation.artifacts.common.utils.XMLUtils;
 
+import de.intevation.flys.model.Gauge;
 import de.intevation.flys.model.River;
 
 import de.intevation.flys.artifacts.states.DefaultState;
 import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.model.MainValuesFactory;
+import de.intevation.flys.artifacts.model.WQDay;
 import de.intevation.flys.artifacts.model.WQKms;
 import de.intevation.flys.artifacts.model.WstValueTable;
 
@@ -301,5 +304,77 @@
 
         return wqkms;
     }
+
+
+    /**
+     * Returns the data that is computed by a duration curve computation.
+     *
+     * @return the data computed by a duration curve computation.
+     */
+    public WQDay getDurationCurveData()
+    throws NullPointerException
+    {
+        logger.debug("WINFOArtifact.getDurationCurveData");
+
+        River r = getRiver();
+
+        if (r == null) {
+            throw new NullPointerException("Cannot determine river.");
+        }
+
+        Gauge g = getGauge();
+
+        if (g == null) {
+            throw new NullPointerException("Cannot determine gauge.");
+        }
+
+        double[] locations = getLocations();
+
+        if (locations == null) {
+            throw new NullPointerException("Cannot determine location.");
+        }
+
+        WstValueTable wst = WstValueTable.getTable(r);
+        if (wst == null) {
+            throw new NullPointerException("No Wst found for selected river.");
+        }
+
+        // TODO Introduce a caching mechanism here!
+
+        return computeDurationCurveData(g, wst, locations[0]);
+    }
+
+
+    /**
+     * Computes the data used to create duration curves.
+     *
+     * @param gauge The selected gauge.
+     * @param location The selected location.
+     *
+     * @return the computed data.
+     */
+    public static WQDay computeDurationCurveData(
+        Gauge           gauge,
+        WstValueTable   wst,
+        double          location)
+    {
+        logger.info("WINFOArtifact.computeDurationCurveData");
+
+        Object[] obj = MainValuesFactory.getDurationCurveData(gauge);
+
+        int[]    days = (int[]) obj[0];
+        double[] qs   = (double[]) obj[1];
+
+        double[] interpolatedW = new double[qs.length];
+        interpolatedW          = wst.interpolateW(location, qs, interpolatedW);
+
+        WQDay wqday = new WQDay(qs.length);
+
+        for (int i = 0; i < days.length; i++) {
+            wqday.add(days[i], interpolatedW[i], qs[i]);
+        }
+
+        return wqday;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java	Tue May 03 09:23:17 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java	Tue May 03 12:05:32 2011 +0000
@@ -1,7 +1,10 @@
 package de.intevation.flys.artifacts.model;
 
+import java.math.BigDecimal;
 import java.util.List;
 
+import org.apache.log4j.Logger;
+
 import org.hibernate.Session;
 import org.hibernate.Query;
 
@@ -16,6 +19,8 @@
  */
 public class MainValuesFactory {
 
+    private static Logger logger = Logger.getLogger(MainValuesFactory.class);
+
     public static List<MainValue> getMainValues(Gauge gauge) {
         Session session = SessionHolder.HOLDER.get();
 
@@ -25,5 +30,51 @@
 
         return query.list();
     }
+
+
+    /**
+     * Returns an array of [days, qs] necessary to create duration curves.
+     *
+     * @param gauge The selected gauge.
+     *
+     * @return a 2dim array of [days, qs] where days is an int[] and qs is
+     * an double[].
+     */
+    public static Object[] getDurationCurveData(Gauge gauge) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "select cast(nmv.name as integer) as days, mv.value as q " +
+            "from MainValue as mv " +
+            "join mv.mainValue as nmv " +
+            "join nmv.type mvt " +
+            "where mvt.name = 'D' and mv.gauge.id = :gauge_id " +
+            "order by days");
+
+        query.setParameter("gauge_id", gauge.getId());
+
+        List<Object> results = query.list();
+        int[]        days    = new int[results.size()];
+        double[]     qs      = new double[results.size()];
+
+        int idx = 0;
+
+        for (Object obj: results) {
+            Object[] arr = (Object[]) obj;
+
+            try {
+                int  day = ((Integer)    arr[0]).intValue();
+                double q = ((BigDecimal) arr[1]).doubleValue();
+
+                days[idx] = day;
+                qs[idx++] = q;
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn(nfe, nfe);
+            }
+        }
+
+        return new Object[] { days, qs };
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java	Tue May 03 12:05:32 2011 +0000
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import gnu.trove.TDoubleArrayList;
+import gnu.trove.TIntArrayList;
+
+
+/**
+ * This class represents a pool of data triples that consists of 'W', 'Q' and
+ * 'Day' data.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class WQDay implements Serializable {
+
+    protected TIntArrayList days;
+
+    protected TDoubleArrayList ws;
+
+    protected TDoubleArrayList qs;
+
+
+    public WQDay() {
+        days = new TIntArrayList();
+        ws   = new TDoubleArrayList();
+        qs   = new TDoubleArrayList();
+    }
+
+
+    public WQDay(int capacity) {
+        days = new TIntArrayList(capacity);
+        ws   = new TDoubleArrayList(capacity);
+        qs   = new TDoubleArrayList(capacity);
+    }
+
+
+    public void add(int day, double w, double q) {
+        days.add(day);
+        ws.add(w);
+        qs.add(q);
+    }
+
+
+    public int size() {
+        return days.size();
+    }
+
+
+    public int getDay(int idx) {
+        return days.get(idx);
+    }
+
+
+    public double getW(int idx) {
+        return ws.get(idx);
+    }
+
+
+    public double getQ(int idx) {
+        return qs.get(idx);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java	Tue May 03 09:23:17 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java	Tue May 03 12:05:32 2011 +0000
@@ -60,7 +60,7 @@
         logger.debug("Inserted min location: " + mm[0]);
         logger.debug("Inserted max location: " + mm[mm.length-1]);
 
-        return validateBounds(minmax[0], minmax[1], mm[0], mm[1], 0d);
+        return validateBounds(minmax[0], minmax[1], mm[0], mm[mm.length-1], 0d);
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java	Tue May 03 12:05:32 2011 +0000
@@ -0,0 +1,166 @@
+package de.intevation.flys.exports;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.model.WQDay;
+
+
+/**
+ * An OutGenerator that generates duration curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DurationCurveGenerator extends XYChartGenerator {
+
+    private static Logger logger =
+        Logger.getLogger(DurationCurveGenerator.class);
+
+    /** The storage for the W series to be drawn in this chart.*/
+    protected XYSeriesCollection w;
+
+    /** The storage for the Q series to be drawn in this chart.*/
+    protected XYSeriesCollection q;
+
+
+    public static final String DURATION_CURVE_W =
+        "duration_curve.w";
+
+    public static final String DURATION_CURVE_Q =
+        "duration_curve.q";
+
+
+    public DurationCurveGenerator() {
+        super();
+
+        this.w = new XYSeriesCollection();
+        this.q = new XYSeriesCollection();
+    }
+
+
+    protected String getChartTitle() {
+        // TODO i18n
+        return "Wasserstand für Gewässer";
+    }
+
+
+    protected String getXAxisLabel() {
+        // TODO i18n
+        return "Unterschreitungsdauer [Tagen]";
+    }
+
+
+    protected String getYAxisLabel() {
+        return "W [NN + m]";
+    }
+
+
+    public void addDatasets(JFreeChart chart) {
+        XYPlot plot = (XYPlot) chart.getPlot();
+
+        plot.setDataset(0, w);
+        plot.setDataset(1, q);
+    }
+
+
+    protected void adjustAxes(XYPlot plot) {
+        super.adjustAxes(plot);
+
+        NumberAxis qAxis = new NumberAxis("Q [m³/s]");
+
+        plot.setRangeAxis(2, qAxis);
+        plot.mapDatasetToRangeAxis(1, 2);
+    }
+
+
+    public void doOut(Artifact artifact, String facet, Document attr) {
+        logger.debug("DurationCurveGenerator.doOut: " + facet);
+
+        if (facet == null || facet.length() == 0) {
+            logger.error("No facet given. Cannot create dataset.");
+            return;
+        }
+
+        if (facet.equals(DURATION_CURVE_W)) {
+            doWOut(getDurationCurveData(artifact));
+        }
+        else if (facet.equals(DURATION_CURVE_Q)) {
+            doQOut(getDurationCurveData(artifact));
+        }
+        else {
+            logger.warn("Unknown facet name: " + facet);
+            return;
+        }
+    }
+
+
+    /**
+     * Creates the series for a duration curve's W facet.
+     *
+     * @param wqdays The WQDay store that contains the Ws.
+     */
+    protected void doWOut(WQDay wqdays) {
+        logger.debug("DurationCurveGenerator.doWOut");
+
+        // TODO find the correct series name
+        XYSeries series = new XYSeries("W-1");
+
+        int size = wqdays.size();
+        for (int i = 0; i < size; i++) {
+            int  day = wqdays.getDay(i);
+            double w = wqdays.getW(i);
+
+            series.add((double) day, w);
+        }
+
+        this.w.addSeries(series);
+    }
+
+
+    /**
+     * Creates the series for a duration curve's Q facet.
+     *
+     * @param wqdays The WQDay store that contains the Qs.
+     */
+    protected void doQOut(WQDay wqdays) {
+        logger.debug("DurationCurveGenerator.doQOut");
+
+        // TODO find the correct series name
+        XYSeries series = new XYSeries("Q-1");
+
+        int size = wqdays.size();
+        for (int i = 0; i < size; i++) {
+            int  day = wqdays.getDay(i);
+            double q = wqdays.getQ(i);
+
+            series.add((double) day, q);
+        }
+
+        this.q.addSeries(series);
+    }
+
+
+    /**
+     * Returns the computed data for a duration curve based on the artifact's
+     * computation method.
+     *
+     * @param artifact The WINFO artifact.
+     *
+     * @return the computed data for a duration curve's W and Q facet.
+     */
+    protected WQDay getDurationCurveData(Artifact artifact) {
+        WINFOArtifact winfoArtifact = (WINFOArtifact) artifact;
+        return winfoArtifact.getDurationCurveData();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org