changeset 402:eb22ffe4d74c

Implemented methods to retrieve and compute the data used to create discharge longitudinal sections. flys-artifacts/trunk@1843 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Fri, 06 May 2011 14:19:27 +0000
parents 34de11dcf355
children 1ed48e2ddc1b
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/artifacts/winfo.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java
diffstat 6 files changed, 402 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Thu May 05 12:34:53 2011 +0000
+++ b/flys-artifacts/ChangeLog	Fri May 06 14:19:27 2011 +0000
@@ -1,3 +1,24 @@
+2011-05-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added the missing Q facet for discharge
+	  longitudinal sections.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: New. A
+	  derived dataset to store W/Q values with corrected Ws for a kilometer
+	  range.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQKms.java: Some new
+	  methods and a new constructor to initialize this data object with a
+	  predefined set of values.
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: New
+	  methods to retrieve the W/Q values for the 'discharge longitudinal
+	  section' computation.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: New
+	  methods to retrieve and compute data used for the 'discharge
+	  longitudinal section' computation.
+
 2011-05-05  Ingo Weinzierl <ingo@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java:
--- a/flys-artifacts/doc/conf/artifacts/winfo.xml	Thu May 05 12:34:53 2011 +0000
+++ b/flys-artifacts/doc/conf/artifacts/winfo.xml	Fri May 06 14:19:27 2011 +0000
@@ -172,6 +172,7 @@
                 <outputmode name="discharge_longitudinal_section" description="output.discharge_longitudinal_section" mime-type="image/png">
                     <facets>
                         <facet name="discharge_longitudinal_section.w"/>
+                        <facet name="discharge_longitudinal_section.q"/>
                     </facets>
                 </outputmode>
             </outputmodes>
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java	Thu May 05 12:34:53 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java	Fri May 06 14:19:27 2011 +0000
@@ -31,6 +31,7 @@
 import de.intevation.artifactdatabase.transition.TransitionEngine;
 
 import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.Range;
 import de.intevation.flys.model.River;
 
 import de.intevation.flys.artifacts.context.FLYSContext;
@@ -492,6 +493,34 @@
 
 
     /**
+     * This method returns the given distance 
+     *
+     * @return an array with lower and upper kilometer range for each
+     * intersected gauge.
+     */
+    public double[][] getSplittedDistance() {
+        double[]    dist   = getDistance();
+        List<Gauge> gauges = getGauges();
+
+        int num = gauges != null ? gauges.size() : 0;
+
+        double[][] res = new double[num][2];
+
+        for (int i = 0; i < num; i++) {
+            Range range = gauges.get(i).getRange();
+
+            double lower = range.getA().doubleValue();
+            double upper = range.getB().doubleValue();
+
+            res[i][0] = dist[0] < lower ? lower : dist[0];
+            res[i][1] = dist[1] > upper ? upper : dist[1];
+        }
+
+        return res;
+    }
+
+
+    /**
      * Returns the selected locations based on a given array of locations.
      *
      * @param locations The StateData that contains the locations.
@@ -546,9 +575,11 @@
     /**
      * Returns the selected Kms.
      *
+     * @param distance An 2dim array with [lower, upper] values.
+     *
      * @return the selected Kms.
      */
-    public double[] getKms() {
+    public double[] getKms(double[] distance) {
         StateData dStep = getData("ld_step");
 
         if (dStep == null) {
@@ -556,9 +587,7 @@
             return null;
         }
 
-        double   step     = Double.parseDouble((String) dStep.getValue());
-        double[] distance = getDistance();
-        double   lower    = distance[0];
+        double step = Double.parseDouble((String) dStep.getValue());
 
         // transform step from 'm' into 'km'
         step = step / 1000;
@@ -572,6 +601,17 @@
 
 
     /**
+     * Returns the selected Kms.
+     *
+     * @return the selected kms.
+     */
+    public double[] getKms() {
+        double[] distance = getDistance();
+        return getKms(distance);
+    }
+
+
+    /**
      * Returns the gauge based on the current distance and river.
      *
      * @return the gauge.
@@ -635,6 +675,56 @@
 
 
     /**
+     * Returns the Q values based on a specified kilometer range.
+     *
+     * @param range A 2dim array with lower and upper kilometer range.
+     *
+     * @return an array of Q values.
+     */
+    public double[] getQs(double[] range) {
+        StateData dMode   = getData("wq_mode");
+        StateData dValues = getData("wq_values");
+
+        String mode = dMode != null ? (String) dMode.getValue() : "";
+
+        // TODO REMOVE THIS HARD CODED MODE VALUE!
+        mode = "Q";
+
+        if (mode.equals("Q")) {
+            return getWQForDist(range);
+        }
+
+        logger.warn("You try to get Qs, but Ws has been inserted.");
+        return null;
+    }
+
+
+    /**
+     * Returns the W values based on a specified kilometer range.
+     *
+     * @param range A 2dim array with lower and upper kilometer range.
+     *
+     * @return an array of W values.
+     */
+    public double[] getWs(double[] range) {
+        StateData dMode   = getData("wq_mode");
+        StateData dValues = getData("wq_values");
+
+        String mode = dMode != null ? (String) dMode.getValue() : "";
+
+        // TODO REMOVE THIS HARD CODED MODE VALUE!
+        mode = "W";
+
+        if (mode.equals("W")) {
+            return getWQForDist(range);
+        }
+
+        logger.warn("You try to get Ws, but Qs has been inserted.");
+        return null;
+    }
+
+
+    /**
      * This method returns the W values.
      *
      * @return the selected W values or null, if no W values are selected.
@@ -682,7 +772,6 @@
 
         for (int i = 0; i < ws.length; i++) {
             qs[i] = dt.getQForW(values, ws[i]);
-            logger.debug("Q for " + ws[i] + " = " + qs[i]);
         }
 
         return qs;
@@ -690,6 +779,57 @@
 
 
     /**
+     * This method returns the given W or Q values for a specific range
+     * (inserted in the WQ input panel for discharge longitudinal sections).
+     *
+     * @param dist A 2dim array with lower und upper kilometer values.
+     *
+     * @return an array of W or Q values.
+     */
+    protected double[] getWQForDist(double[] dist) {
+        logger.debug("Search wq values for range: " + dist[0] + " - " + dist[1]);
+        StateData data = getData("wq_values");
+
+        if (data == null) {
+            logger.warn("Missing wq values!");
+            return null;
+        }
+
+        String dataString = (String) data.getValue();
+        String[]   ranges = dataString.split(":");
+
+        for (String range: ranges) {
+            String[] parts = range.split(";");
+
+            double lower = Double.parseDouble(parts[0]);
+            double upper = Double.parseDouble(parts[1]);
+
+            if (lower <= dist[0] && upper >= dist[1]) {
+                String[] values = parts[2].split(",");
+
+                int      num = values.length;
+                double[] res = new double[num];
+
+                for (int i = 0; i < num; i++) {
+                    try {
+                        res[i] = Double.parseDouble(values[i]);
+                    }
+                    catch (NumberFormatException nfe) {
+                        logger.warn(nfe, nfe);
+                    }
+                }
+
+                return res;
+            }
+        }
+
+        logger.warn("Specified range for WQ not found!");
+
+        return null;
+    }
+
+
+    /**
      * This method returns an array of inserted WQ triples that consist of from,
      * to and the step width.
      *
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Thu May 05 12:34:53 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Fri May 06 14:19:27 2011 +0000
@@ -25,7 +25,9 @@
 
 import de.intevation.flys.artifacts.states.DefaultState;
 import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.math.BackJumpCorrector;
 import de.intevation.flys.artifacts.model.MainValuesFactory;
+import de.intevation.flys.artifacts.model.WQCKms;
 import de.intevation.flys.artifacts.model.WQDay;
 import de.intevation.flys.artifacts.model.WQKms;
 import de.intevation.flys.artifacts.model.WstValueTable;
@@ -444,5 +446,92 @@
 
         return wqkms;
     }
+
+
+    /**
+     * Returns the data computed by the discharge longitudinal section
+     * computation.
+     *
+     * @return an array of WQKms object - one object for each given Q value.
+     */
+    public WQKms[] getDischargeLongitudinalSectionData() {
+        logger.debug("WINFOArtifact.getDischargeLongitudinalSectionData");
+
+        River river = getRiver();
+        if (river == null) {
+            logger.error("No river selected.");
+        }
+
+        WstValueTable wst = WstValueTable.getTable(river);
+        if (wst == null) {
+            logger.error("No Wst found for selected river.");
+        }
+
+        double[][] dist = getSplittedDistance();
+        int        num  = dist != null ? dist.length : 0;
+
+        WQKms[][] wqkms = new WQKms[num][];
+
+        for (int i = 0; i < num; i++) {
+            double[] kms = getKms(dist[i]);
+            if (kms == null) {
+                // XXX maybe we should cancel this operation here.
+                continue;
+            }
+
+            double[] qs = getQs(dist[i]);
+            if (qs == null) {
+                logger.debug("Determine Q values based on a set of W values.");
+
+                double[] ws = getWs(dist[i]);
+                qs = getQsForWs(ws);
+            }
+
+            wqkms[i] = computeWaterlevelData(kms, qs, wst);
+        }
+
+        WQKms[] merged    = WQKms.merge(wqkms);
+        int     numMerged = merged.length;
+        WQKms[] computed  = new WQKms[numMerged];
+
+        for (int i = 0; i < numMerged; i++) {
+            computed[i] = computeDischargeLongitudinalSectionData(merged[i]);
+        }
+
+        // TODO Introduce a caching mechanism here!
+
+        return computed;
+    }
+
+
+    /**
+     * Computes the data used for a discharge longitudinal section based on a
+     * given WQKms object. If there are backjumps while computing the data, a
+     * WQCKms object is returned, otherwise the incoming wqkms object.
+     *
+     * @param wqkms The WQKms object that contains W, Q and Kms.
+     *
+     * @return an instance of WQKms or WQCKms.
+     */
+    public static WQKms computeDischargeLongitudinalSectionData(WQKms wqkms) {
+        logger.info("WINFOArtifact.computeDischargeLongitudinalSectionData");
+
+        BackJumpCorrector bjc = new BackJumpCorrector();
+
+        bjc.doCorrection(wqkms.getKms(), wqkms.getWs());
+
+        if (bjc.hasBackJumps()) {
+            logger.info("Discharge longitudinal section has backjumps.");
+            return new WQCKms(
+                wqkms.getKms(),
+                wqkms.getQs(),
+                wqkms.getWs(),
+                bjc.getCorrected());
+        }
+        else {
+            logger.info("Discharge longitudinal section has no backjumps.");
+            return wqkms;
+        }
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java	Fri May 06 14:19:27 2011 +0000
@@ -0,0 +1,70 @@
+package de.intevation.flys.artifacts.model;
+
+import gnu.trove.TDoubleArrayList;
+
+
+/**
+ * This class represents a pool of data triples that consists of 'W', 'Q' and
+ * 'KM' data with corrected 'W' values computed by a BackJumpCorrector.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class WQCKms extends WQKms {
+
+    protected TDoubleArrayList cw;
+
+
+    public WQCKms(double[] kms, double[] qs, double[] ws, double[] cws) {
+        super(kms, qs, ws);
+
+        this.cw = new TDoubleArrayList(cws);
+    }
+
+
+    /**
+     * Adds a new row to this data pool with corrected W.
+     *
+     * @param w a W.
+     * @param q a Q.
+     * @param kms a Kms.
+     * @param cw The corrected W.
+     */
+    public void add(double w, double q, double kms, double cw) {
+        add(w, q, kms);
+        this.cw.add(cw);
+    }
+
+
+    /**
+     * This method returns a 4dim array of W, Q,Kms and corrected W.
+     *
+     * @param idx The position of the triple.
+     * @param dst destination array
+     *
+     * @return a 4dim array of [W, Q, Kms, CW] in dst.
+     */
+    public double[] get(int idx, double[] dst) {
+        dst = super.get(idx, dst);
+
+        if (dst.length < 4) {
+            return dst;
+        }
+
+        if (cw != null && cw.size() > idx) {
+            dst[3] = cw.get(idx);
+        }
+
+        return dst;
+    }
+
+
+    /**
+     * Returns the double array of corrected W values.
+     *
+     * @return the double array of corrected W values.
+     */
+    public double[] getCWs() {
+        return cw.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/WQKms.java	Thu May 05 12:34:53 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java	Fri May 06 14:19:27 2011 +0000
@@ -4,6 +4,8 @@
 
 import gnu.trove.TDoubleArrayList;
 
+import org.apache.log4j.Logger;
+
 
 /**
  * This class represents a pool of data triples that consists of 'W', 'Q' and
@@ -13,6 +15,9 @@
  */
 public class WQKms implements Serializable {
 
+    private static Logger logger = Logger.getLogger(WQKms.class);
+
+
     /** The array that contains the 'W' values.*/
     protected TDoubleArrayList w;
 
@@ -36,6 +41,13 @@
     }
 
 
+    public WQKms(double[] kms, double[] qs, double[] ws) {
+        this.w   = new TDoubleArrayList(ws);
+        this.q   = new TDoubleArrayList(qs);
+        this.kms = new TDoubleArrayList(kms);
+    }
+
+
     /**
      * Adds a new row to this data pool.
      *
@@ -50,6 +62,13 @@
     }
 
 
+    public void add(double[] w, double[] q, double[] kms) {
+        this.w.add(w);
+        this.q.add(q);
+        this.kms.add(kms);
+    }
+
+
     /**
      * Returns the number of triples stored in this data pool.
      *
@@ -78,5 +97,62 @@
     public double getKms(int idx) {
         return kms.get(idx);
     }
+
+
+    public double[] getKms() {
+        return kms.toNativeArray();
+    }
+
+
+    public double[] getWs() {
+        return w.toNativeArray();
+    }
+
+
+    public double[] getQs() {
+        return q.toNativeArray();
+    }
+
+
+    /**
+     * Returns a string that consist of the first and last kilometer.
+     *
+     * @return a string that consist of the first and last kilometer.
+     */
+    public String toString() {
+        double from = getKms(0);
+        double to   = getKms(size()-1);
+        return Double.toString(from) + " - " + Double.toString(to);
+    }
+
+
+    /**
+     * Merges the WQKms objects of an incoming 2dim array (table) where the
+     * objects of a column belong together.
+     *
+     * @param toMerge The objects that need to be merged.
+     *
+     * @return an array of merged WQKms objects.
+     */
+    public static WQKms[] merge(WQKms[][] toMerge) {
+        int num = toMerge[0].length;
+
+        // TODO IS THE LENGTH CORRECT?
+        WQKms[] merged = new WQKms[num];
+        for (int i = 0; i < num; i++) {
+            merged[i] = new WQKms();
+        }
+
+        for (int i = 0; i < toMerge.length; i++) {
+            WQKms[] tmp = toMerge[i];
+
+            for (int j = 0; j < num; j++) {
+                WQKms toAdd = tmp[j];
+                merged[j].add(toAdd.getWs(), toAdd.getQs(), toAdd.getKms());
+            }
+        }
+
+        return merged;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org