changeset 2311:b8df8d1476ba

Compute differences between discharge table values and reference discharge table values in historical discharge curve calculation. flys-artifacts/trunk@3991 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Thu, 09 Feb 2012 10:57:35 +0000
parents ecb76933362f
children f911ddd93f58
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/artifacts/winfo.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation6.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeDifferenceFacet.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HistoricalWQTimerange.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java flys-artifacts/src/main/resources/messages.properties flys-artifacts/src/main/resources/messages_de.properties flys-artifacts/src/main/resources/messages_de_DE.properties flys-artifacts/src/main/resources/messages_en.properties
diffstat 14 files changed, 319 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/ChangeLog	Thu Feb 09 10:57:35 2012 +0000
@@ -1,3 +1,42 @@
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Registered a new facet for difference curves
+	  to the historical discharge output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/HistoricalWQTimerange.java:
+	  New model that is able to store a further double value "diff" besides a W,
+	  Q and a Timerange.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Create
+	  new HistoricalWQTimerange instances with difference between the reference
+	  discharge table and the historical discharge tables.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: New type
+	  for historical differences.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java: Cast
+	  Timerange array in getTimeranges().
+
+	* src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeDifferenceFacet.java:
+	  New Facet for historical discharge difference curves.
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java:
+	  Create new Facets for the difference curves if the processed data are from
+	  type HistoricalWQTimerange.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Added doOut() path for difference curves.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java:
+	  Increased the size of a double array to be able to get results from
+	  HistoricalWQTimerange.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Added translation for warning
+	  if no reference discharge table was found for the specified gauge.
+
 2012-02-09  Raimund Renkert <raimund.renkert@intevation.de>
 
 	Added PDF export to reference curve calculation.
--- a/flys-artifacts/doc/conf/artifacts/winfo.xml	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/doc/conf/artifacts/winfo.xml	Thu Feb 09 10:57:35 2012 +0000
@@ -510,6 +510,7 @@
                 <outputmode name="historical_discharge" description="output.historical_discharge.description" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="historical_discharge.historicalq"/>
+                        <facet name="historical_discharge.historicalq.diff"/>
                     </facets>
                 </outputmode>
                 <outputmode name="historical_discharge_export" description="output.historical_discharge.export" mime-type="text/plain" type="export">
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation6.java	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation6.java	Thu Feb 09 10:57:35 2012 +0000
@@ -47,6 +47,7 @@
             debug();
         }
 
+        DischargeTable  refTable = fetchReferenceTable(gauge);
         List<DischargeTable> dts = fetchDischargeTables(gauge);
 
         int numTables = dts.size();
@@ -57,7 +58,7 @@
             addProblem("cannot.find.hist.q.tables");
         }
 
-        WQTimerange[] wqt = prepareCalculationData(dts);
+        WQTimerange[] wqt = prepareCalculationData(refTable, dts);
 
         logger.debug("Number of calculation results: " + wqt.length);
 
@@ -85,6 +86,11 @@
     }
 
 
+    protected DischargeTable fetchReferenceTable(Gauge gauge) {
+        return gauge.fetchMasterDischargeTable();
+    }
+
+
     protected List<DischargeTable> fetchDischargeTables(Gauge gauge) {
         List<DischargeTable> relevant = new ArrayList<DischargeTable>();
         List<DischargeTable> all      = gauge.getDischargeTables();
@@ -122,15 +128,30 @@
     }
 
 
-    protected WQTimerange[] prepareCalculationData(List<DischargeTable> dts) {
-        List<WQTimerange> wqts = new ArrayList<WQTimerange>(values.length);
+    protected WQTimerange[] prepareCalculationData(
+        DischargeTable       refTable,
+        List<DischargeTable> dts
+    ) {
+        if (refTable == null) {
+            addProblem("cannot.find.hist.q.reftable");
+            return prepareSimpleData(dts);
+        }
+        else {
+            return prepareData(refTable, dts);
+        }
+    }
+
+
+    protected WQTimerange[] prepareSimpleData(List<DischargeTable> dts) {
+        List<WQTimerange> wqts =
+            new ArrayList<WQTimerange>(values.length);
 
         boolean debug = logger.isDebugEnabled();
 
         for (double value: values) {
             logger.debug("Prepare data for value: " + value);
 
-            String      name = mode == MODE_W ? "W=" + value : "Q=" + value;
+            String name      = mode == MODE_W ? "W=" + value : "Q=" + value;
             WQTimerange wqt  = null;
 
             for (DischargeTable dt: dts) {
@@ -184,6 +205,85 @@
     }
 
 
+    protected HistoricalWQTimerange[] prepareData(
+        DischargeTable       refTable,
+        List<DischargeTable> dts
+    ) {
+        List<HistoricalWQTimerange> wqts =
+            new ArrayList<HistoricalWQTimerange>(values.length);
+
+        boolean debug = logger.isDebugEnabled();
+
+        for (double value: values) {
+            logger.debug("Prepare data plus diff for value: " + value);
+
+            String name = mode == MODE_W ? "W=" + value : "Q=" + value;
+            HistoricalWQTimerange wqt  = null;
+
+            double ref;
+
+            if (refTable != null && mode == MODE_W) {
+                ref = findValueForW(refTable, value);
+            }
+            else if (refTable != null) {
+                ref = findValueForQ(refTable, value);
+            }
+            else {
+                ref = Double.NaN;
+            }
+
+            for (DischargeTable dt: dts) {
+                TimeInterval ti = dt.getTimeInterval();
+
+                Date start = ti.getStartTime();
+                Date end   = ti.getStopTime();
+
+                if (end == null) {
+                    logger.warn("TimeInterval has no stop time set!");
+
+                    end = new Date();
+                }
+
+                Timerange t = new Timerange(ti.getStartTime(),ti.getStopTime());
+                double    w;
+                double    q;
+
+                if (mode == MODE_W) {
+                    w = value;
+                    q = findValueForW(dt, w);
+
+                    if (Double.isNaN(q)) {
+                        logger.warn("Cannot find Q for W: " + w);
+                        addProblem("cannot.find.hist.q.for.w", w, start, end);
+                        continue;
+                    }
+                }
+                else {
+                    q = value;
+                    w = findValueForQ(dt, q);
+                }
+
+                if (debug) {
+                    logger.debug("Q=" + q + " | W=" + w);
+                }
+
+                if (wqt == null) {
+                    wqt = new HistoricalWQTimerange(name);
+                }
+
+                wqt.add(w, q, ref-value, t);
+            }
+
+            if (wqt != null) {
+                wqts.add(wqt);
+            }
+        }
+
+        return (HistoricalWQTimerange[])
+            wqts.toArray(new HistoricalWQTimerange[wqts.size()]);
+    }
+
+
     protected double findValueForW(DischargeTable dt, double w) {
         double[][] vs = DischargeTables.loadDischargeTableValues(dt,SCALE,true);
         return DischargeTables.getQForW(vs, w);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Thu Feb 09 10:57:35 2012 +0000
@@ -124,7 +124,8 @@
 
     String REPORT = "report";
 
-    String HISTORICAL_DISCHARGE_Q = "historical_discharge.historicalq";
+    String HISTORICAL_DISCHARGE_Q      = "historical_discharge.historicalq";
+    String HISTORICAL_DISCHARGE_Q_DIFF = "historical_discharge.historicalq.diff";
 
     String REFERENCE_CURVE = "reference_curve";
     String REFERENCE_CURVE_NORMALIZED = "reference_curve_normalized";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeDifferenceFacet.java	Thu Feb 09 10:57:35 2012 +0000
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeDifferenceFacet
+extends      HistoricalDischargeFacet
+{
+    private static final Logger logger =
+        Logger.getLogger(HistoricalDischargeDifferenceFacet.class);
+
+
+    public HistoricalDischargeDifferenceFacet(
+        int    index,
+        String name,
+        String desc
+    ) {
+        super(index, name, desc, ComputeType.ADVANCE, null, null);
+    }
+
+
+    public HistoricalDischargeDifferenceFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+
+    ) {
+        super(index, name, description, type, hash, stateID);
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Get data for historical discharge difference curves" +
+                " at index: " + index + " / stateId: " + stateId);
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult)
+            flys.compute(context, hash, stateId, type,  false);
+
+        HistoricalWQTimerange[] wqts = (HistoricalWQTimerange[]) res.getData();
+
+        return wqts[index];
+    }
+}
+// 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/HistoricalWQTimerange.java	Thu Feb 09 10:57:35 2012 +0000
@@ -0,0 +1,49 @@
+package de.intevation.flys.artifacts.model;
+
+import gnu.trove.TDoubleArrayList;
+
+
+/**
+ * A subclass of WQTimerange that stores besides W, Q and Timerange values
+ * another double value.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalWQTimerange extends WQTimerange {
+
+    protected TDoubleArrayList diffs;
+
+
+    public HistoricalWQTimerange(String name) {
+        super(name);
+
+        diffs = new TDoubleArrayList();
+    }
+
+
+    public void add(double w, double q, double diff, Timerange t) {
+        ws.add(w);
+        qs.add(q);
+        ts.add(t);
+        diffs.add(diff);
+    }
+
+
+    /**
+     * This method requires a 3dim double array for <i>res</i>!
+     */
+    @Override
+    public double[] get(int idx, double[] res) {
+        res[0] = ws.getQuick(idx);
+        res[1] = qs.getQuick(idx);
+        res[2] = diffs.getQuick(idx);
+
+        return res;
+    }
+
+
+    public double[] getDiffs() {
+        return diffs.toNativeArray();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java	Thu Feb 09 10:57:35 2012 +0000
@@ -36,7 +36,7 @@
 
 
     public Timerange[] getTimeranges() {
-        return (Timerange[]) ts.toArray();
+        return (Timerange[]) ts.toArray(new Timerange[ts.size()]);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java	Thu Feb 09 10:57:35 2012 +0000
@@ -19,6 +19,8 @@
 import de.intevation.flys.artifacts.model.DataFacet;
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.HistoricalDischargeFacet;
+import de.intevation.flys.artifacts.model.HistoricalDischargeDifferenceFacet;
+import de.intevation.flys.artifacts.model.HistoricalWQTimerange;
 import de.intevation.flys.artifacts.model.ReportFacet;
 import de.intevation.flys.artifacts.model.WQTimerange;
 
@@ -98,9 +100,20 @@
             // TODO CREATE BETTER TITLE FOR FACETS
 
             facets.add(new HistoricalDischargeFacet(
-                i++,
+                i,
                 HISTORICAL_DISCHARGE_Q,
                 wqt.getName()));
+
+            if (wqt instanceof HistoricalWQTimerange) {
+                logger.debug("Create another facet for historical differences.");
+
+                facets.add(new HistoricalDischargeDifferenceFacet(
+                    i,
+                    HISTORICAL_DISCHARGE_Q_DIFF,
+                    "DIFF: " + wqt.getName()));
+            }
+
+            i++;
         }
     }
 }
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java	Thu Feb 09 10:57:35 2012 +0000
@@ -153,7 +153,7 @@
         NumberFormat wf = Formatter.getHistoricalDischargeW(context);
         NumberFormat qf = Formatter.getHistoricalDischargeQ(context);
 
-        double[] wq = new double[2];
+        double[] wq = new double[3];
 
         String gaugeName = getReferenceGaugename();
 
@@ -168,7 +168,7 @@
                 df.format(start) + " - " + df.format(end),
                 wf.format(wq[0]),
                 qf.format(wq[1]),
-                "TODO: Difference to reference curve",
+                qf.format(wq[2]),
                 gaugeName
             });
         }
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java	Thu Feb 09 10:57:35 2012 +0000
@@ -21,6 +21,7 @@
 
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.HistoricalWQTimerange;
 import de.intevation.flys.artifacts.model.Timerange;
 import de.intevation.flys.artifacts.model.WQTimerange;
 import de.intevation.flys.utils.FLYSUtils;
@@ -168,6 +169,15 @@
                 theme,
                 visible);
         }
+        else if (name.equals(HISTORICAL_DISCHARGE_Q_DIFF)) {
+            doHistoricalDischargeDifferenceOut(
+                (FLYSArtifact) artifactFacet.getArtifact(),
+                artifactFacet.getData(context),
+                artifactFacet.getFacetDescription(),
+                theme,
+                visible);
+        }
+        // TODO ADD THE CASE FOR DISPLAYING W VALUES
         else {
            logger.warn("doOut(): unknown facet name: " + name);
            return;
@@ -186,7 +196,30 @@
 
         WQTimerange wqt = (WQTimerange) data;
 
-        TimeSeriesCollection tsc = newTimeSeriesCollection(wqt, desc);
+        TimeSeriesCollection tsc = newTimeSeriesCollection(
+            wqt.getTimeranges(),
+            wqt.getQs(),
+            desc);
+
+        addAxisDataset(tsc, 0, visible);
+    }
+
+
+    protected void doHistoricalDischargeDifferenceOut(
+        FLYSArtifact artifact,
+        Object       data,
+        String       desc,
+        Document     theme,
+        boolean      visible
+    ) {
+        logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc);
+
+        HistoricalWQTimerange wqt = (HistoricalWQTimerange) data;
+
+        TimeSeriesCollection tsc = newTimeSeriesCollection(
+            wqt.getTimeranges(),
+            wqt.getDiffs(),
+            desc);
 
         addAxisDataset(tsc, 0, visible);
     }
@@ -199,7 +232,8 @@
      * looks like a "step chart".
      */
     protected TimeSeriesCollection newTimeSeriesCollection(
-        WQTimerange wqt,
+        Timerange[] timeranges,
+        double[]    values,
         String      desc
     ) {
         logger.debug("Create new TimeSeriesCollection for: " + desc);
@@ -207,30 +241,22 @@
         TimeSeriesCollection tsc = new TimeSeriesCollection();
         TimeSeries        series = new TimeSeries(desc);
 
-        Timerange tr = null;
-        double[] res = new double[2];
-
-        for (int i = 0, n = wqt.size(); i < n; i++) {
-            res = wqt.get(i, res);
-
-            RegularTimePeriod[] rtp = newRegularTimePeriod(wqt.getTimerange(i));
+        for (int i = 0, n = timeranges.length; i < n; i++) {
+            RegularTimePeriod[] rtp = newRegularTimePeriod(timeranges[i]);
 
             try {
-                // TODO WHICH (W/Q) IS REQUIRED?
-                double y = res[1];
-
-                if (Double.isNaN(y)) {
+                if (Double.isNaN(values[i])) {
                     logger.warn("Skip TimePeriod because value is NaN.");
                     continue;
                 }
 
-                series.add(rtp[0], y);
-                series.add(rtp[1], y);
+                series.add(rtp[0], values[i]);
+                series.add(rtp[1], values[i]);
 
                 if (logger.isDebugEnabled()) {
                     logger.debug("added Item to TimeSeries:");
                     logger.debug("   TimePeriod: " + rtp[0] + " - " + rtp[1]);
-                    logger.debug("   Value:      " + res[1]);
+                    logger.debug("   Value:      " + values[i]);
                 }
             }
             catch (SeriesException se) {
--- a/flys-artifacts/src/main/resources/messages.properties	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages.properties	Thu Feb 09 10:57:35 2012 +0000
@@ -181,6 +181,7 @@
 relating.w.w.failed = Relating W with W failed.
 cannot.find.hist.q.for.w = Cannot find Q for W = {0,number,#.##} in timerange {1, date} - {2, date}
 cannot.find.hist.q.tables = Cannot find Discharge Tables for given timerange.
+cannot.find.hist.q.reftable = Cannot find reference Discharge Table for specified Gauge.
 
 no.river.selected = No river selected.
 no.gauge.selected = No gauge selected.
--- a/flys-artifacts/src/main/resources/messages_de.properties	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages_de.properties	Thu Feb 09 10:57:35 2012 +0000
@@ -181,6 +181,7 @@
 relating.w.w.failed = W-zu-W-Zuordnung fehlgeschlagen.
 cannot.find.hist.q.for.w = Konnte zu W = {0,number,#.##} im Zeitraum ({1,date} - {2,date}) kein Abfluss ermitteln.
 cannot.find.hist.q.tables = Konnte f\u00fcr den angegebenen Zeitraum keine Abflusstafeln finden.
+cannot.find.hist.q.reftable = Konnte f\u00fcr den gew\u00e4hlten Pegel keine Bezugs-Abflusstafel ermitteln.
 
 no.river.selected = Kein Gew\u00e4sser ausgew\u00e4hlt.
 no.gauge.selected = Kein Pegel ausgew\u00e4hlt.
--- a/flys-artifacts/src/main/resources/messages_de_DE.properties	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages_de_DE.properties	Thu Feb 09 10:57:35 2012 +0000
@@ -181,6 +181,7 @@
 relating.w.w.failed = W-zu-W-Zuordnung fehlgeschlagen.
 cannot.find.hist.q.for.w = Konnte zu W = {0,number,#.##} im Zeitraum ({1,date} - {2,date}) kein Abfluss ermitteln.
 cannot.find.hist.q.tables = Konnte f\u00fcr den angegebenen Zeitraum keine Abflusstafeln finden.
+cannot.find.hist.q.reftable = Konnte f\u00fcr den gew\u00e4hlten Pegel keine Bezugs-Abflusstafel ermitteln.
 
 no.river.selected = Kein Gew\u00e4sser ausgew\u00e4hlt.
 no.gauge.selected = Kein Pegel ausgew\u00e4hlt.
--- a/flys-artifacts/src/main/resources/messages_en.properties	Thu Feb 09 10:21:16 2012 +0000
+++ b/flys-artifacts/src/main/resources/messages_en.properties	Thu Feb 09 10:57:35 2012 +0000
@@ -177,6 +177,7 @@
 relating.w.w.failed = Relating W with W failed.
 cannot.find.hist.q.for.w = Cannot find Q for W = {0,number,#.##} in timerange {1, date} - {2, date}
 cannot.find.hist.q.tables = Cannot find Discharge Tables for given timerange.
+cannot.find.hist.q.reftable = Cannot find reference Discharge Table for specified Gauge.
 
 no.river.selected = No river selected.
 no.gauge.selected = No gauge selected.

http://dive4elements.wald.intevation.org