diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 1055:61c051e53f9b

Moved WINFO specific stuff from FLYS into WINFO artifact. flys-artifacts/trunk@2525 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 22 Aug 2011 15:25:48 +0000
parents eccf966fb677
children f465785ed1ae
line wrap: on
line diff
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Mon Aug 22 13:07:26 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Mon Aug 22 15:25:48 2011 +0000
@@ -1,47 +1,59 @@
 package de.intevation.flys.artifacts;
 
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import de.intevation.artifactdatabase.ProtocolUtils;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
+import de.intevation.artifactdatabase.data.StateData;
 
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifactdatabase.ProtocolUtils;
 import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifactdatabase.state.Output;
 import de.intevation.artifactdatabase.state.State;
 import de.intevation.artifactdatabase.state.StateEngine;
+
 import de.intevation.artifactdatabase.transition.TransitionEngine;
 
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+
 import de.intevation.artifacts.common.utils.XMLUtils;
 
+import de.intevation.flys.artifacts.context.FLYSContext;
+
+import de.intevation.flys.artifacts.model.Calculation1;
+import de.intevation.flys.artifacts.model.Calculation2;
+import de.intevation.flys.artifacts.model.Calculation3;
+import de.intevation.flys.artifacts.model.Calculation4;
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DischargeTables;
+import de.intevation.flys.artifacts.model.MainValuesFactory;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.artifacts.model.Segment;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WstValueTable;
+import de.intevation.flys.artifacts.model.WstValueTableFactory;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.artifacts.states.LocationDistanceSelect;
+
 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.utils.DoubleUtil;
 
-import de.intevation.flys.artifacts.model.DischargeTables;
-import de.intevation.flys.artifacts.model.MainValuesFactory;
-import de.intevation.flys.artifacts.model.WQKms;
-import de.intevation.flys.artifacts.model.WstValueTable;
-import de.intevation.flys.artifacts.model.WstValueTableFactory;
-import de.intevation.flys.artifacts.model.Calculation;
-import de.intevation.flys.artifacts.model.Calculation1;
-import de.intevation.flys.artifacts.model.Calculation2;
-import de.intevation.flys.artifacts.model.Calculation3;
-import de.intevation.flys.artifacts.model.Calculation4;
-import de.intevation.flys.artifacts.model.CalculationResult;
-import de.intevation.flys.artifacts.model.Segment;
+import gnu.trove.TDoubleArrayList;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 
 /**
  * The default WINFO artifact.
@@ -57,9 +69,17 @@
     /** The name of the artifact. */
     public static final String ARTIFACT_NAME = "winfo";
 
+
     /** XPath */
     public static final String XPATH_STATIC_UI ="/art:result/art:ui/art:static";
 
+    /** The default number of steps between the start end end of a selected Q
+     * range.*/
+    public static final int DEFAULT_Q_STEPS = 30;
+
+    /** The default step width between the start end end kilometer.*/
+    public static final double DEFAULT_KM_STEPS = 0.1;
+
 
     /**
      * The default constructor.
@@ -561,5 +581,578 @@
 
         return calc4.calculate(table, range[0], range[1], range[2]);
     }
+
+    public List<Segment> getSegments() {
+        StateData wqValues = getData("wq_values");
+        if (wqValues == null) {
+            logger.warn("no wq_values given");
+            return Collections.emptyList();
+        }
+        String input = (String)wqValues.getValue();
+        if (input == null || (input = input.trim()).length() == 0) {
+            logger.warn("wq_values are empty");
+            return Collections.emptyList();
+        }
+        return Segment.parseSegments(input);
+    }
+
+
+    /**
+     * Returns the Qs for a number of Ws. This method makes use of
+     * DischargeTables.getQForW().
+     *
+     * @param ws An array of W values.
+     *
+     * @return an array of Q values.
+     */
+    public double[] getQsForWs(double[] ws) {
+
+        boolean debug = logger.isDebugEnabled();
+
+        if (debug) {
+            logger.debug("FLYSArtifact.getQsForWs");
+        }
+
+        River r = getRiver();
+        if (r == null) {
+            logger.warn("no river found");
+            return null;
+        }
+
+        double [] range = getDistance();
+        if (range == null) {
+            logger.warn("no ranges found");
+            return null;
+        }
+
+        if (debug) {
+            logger.debug("range: " + Arrays.toString(range));
+        }
+
+        Gauge g = r.determineGaugeByPosition(range[0]);
+        if (g == null) {
+            logger.warn("no gauge found for km: " + range[0]);
+            return null;
+        }
+
+        if (debug) {
+            logger.debug("convert w->q with gauge '" + g.getName() + "'");
+        }
+
+        DischargeTables dt = new DischargeTables(r.getName(), g.getName());
+        Map<String, double [][]>  tmp = dt.getValues();
+
+        double[][] values = tmp.get(g.getName());
+        double[]   qs     = new double[ws.length];
+
+        for (int i = 0; i < ws.length; i++) {
+            qs[i] = dt.getQForW(values, ws[i]);
+            if (debug) {
+                logger.debug("w: " + ws[i] + " -> q: " + qs[i]);
+            }
+        }
+
+        return qs;
+    }
+
+    /**
+     * Returns the selected River object based on the 'river' data that might
+     * have been inserted by the user.
+     *
+     * @return the selected River or null if no river has been chosen yet.
+     */
+    public River getRiver() {
+        StateData dRiver = getData("river");
+
+        return dRiver != null
+            ? RiverFactory.getRiver((String) dRiver.getValue())
+            : null;
+    }
+
+
+    /**
+     * Returns the selected distance of points.
+     *
+     * @return the selected distance or points.
+     */
+    public double[] getDistance() {
+        StateData dMode      = getData("ld_mode");
+        StateData dFrom      = getData("ld_from");
+        StateData dTo        = getData("ld_to");
+        StateData dLocations = getData("ld_locations");
+
+        if (dMode != null) {
+            String mode = (String)dMode.getValue();
+            if ("location".equals(mode)) {
+                double[] locations = getLocations();
+                return new double[] { locations[0], locations[locations.length-1] };
+            }
+            if (dFrom != null && dTo != null) {
+                return getDistanceByRange(dFrom, dTo);
+            }
+        }
+
+        if (dLocations != null) {
+            double[] locations = getLocations();
+            return new double[] { locations[0], locations[locations.length-1] };
+        }
+
+        if (dFrom != null && dTo != null) {
+            return getDistanceByRange(dFrom, dTo);
+        }
+
+        logger.warn("No data found for distance determination!");
+
+        return null;
+    }
+
+
+    /**
+     * Determines the selected mode of distance/range input.
+     *
+     * @return true, if the range mode is selected otherwise false.
+     */
+    public boolean isRange() {
+        StateData mode = getData("ld_mode");
+
+        if (mode == null) {
+            logger.warn("No mode location/range chosen. Defaults to range.");
+            return true;
+        }
+
+        String value = (String) mode.getValue();
+
+        return value.equals("distance");
+    }
+
+
+    /**
+     * Returns the selected locations based on a given array of locations.
+     *
+     * @param locations The StateData that contains the locations.
+     *
+     * @return the selected locations.
+     */
+    public double[] getLocations() {
+        StateData dLocations  = getData("ld_locations");
+        String    locationStr = dLocations != null
+            ? (String) dLocations.getValue()
+            : "";
+
+        if (locationStr == null || locationStr.length() == 0) {
+            logger.warn("No valid location string found!");
+            return null;
+        }
+
+        String[] tmp               = locationStr.split(" ");
+        TDoubleArrayList locations = new TDoubleArrayList();
+
+        for (String l: tmp) {
+            try {
+                locations.add(Double.parseDouble(l));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn(nfe, nfe);
+            }
+        }
+
+        locations.sort();
+
+        return locations.toNativeArray();
+    }
+
+
+    /**
+     * Returns the selected distance based on a given range (from, to).
+     *
+     * @param dFrom The StateData that contains the lower value.
+     * @param dTo The StateData that contains the upper value.
+     *
+     * @return the selected distance.
+     */
+    protected double[] getDistanceByRange(StateData dFrom, StateData dTo) {
+        double from = Double.parseDouble((String) dFrom.getValue());
+        double to   = Double.parseDouble((String) dTo.getValue());
+
+        return new double[] { from, to };
+    }
+
+
+    /**
+     * Returns the selected Kms.
+     *
+     * @param distance An 2dim array with [lower, upper] values.
+     *
+     * @return the selected Kms.
+     */
+    public double[] getKms(double[] distance) {
+        StateData dStep = getData("ld_step");
+
+        if (dStep == null) {
+            logger.warn("No step width given. Cannot compute Kms.");
+            return null;
+        }
+
+        double step = Double.parseDouble((String) dStep.getValue());
+
+        // transform step from 'm' into 'km'
+        step = step / 1000;
+
+        if (step == 0d) {
+            step = DEFAULT_KM_STEPS;
+        }
+
+        return DoubleUtil.explode(distance[0], distance[1], step);
+    }
+
+
+    /**
+     * Returns the selected Kms.
+     *
+     * @return the selected kms.
+     */
+    public double[] getKms() {
+        if (isRange()) {
+            double[] distance = getDistance();
+            return getKms(distance);
+
+        }
+        else {
+            return LocationDistanceSelect.getLocations(this);
+        }
+    }
+
+    public double [] getFromToStep() {
+        if (!isRange()) {
+            return null;
+        }
+        double [] fromTo = getDistance();
+
+        if (fromTo == null) {
+            return null;
+        }
+
+        StateData dStep = getData("ld_step");
+        if (dStep == null) {
+            return null;
+        }
+
+        double [] result = new double[3];
+        result[0] = fromTo[0];
+        result[1] = fromTo[1];
+
+        try {
+            String step = (String)dStep.getValue();
+            result[2] = DoubleUtil.round(Double.parseDouble(step) / 1000d);
+        }
+        catch (NumberFormatException nfe) {
+            return null;
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Returns the gauge based on the current distance and river.
+     *
+     * @return the gauge.
+     */
+    public Gauge getGauge() {
+        River    river = getRiver();
+
+        if (river == null) {
+            logger.debug("no river found");
+            return null;
+        }
+
+        double[] dist  = getDistance();
+
+        if (dist == null) {
+            logger.debug("no range found");
+            return null;
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Determine gauge for:");
+            logger.debug("... river: " + river.getName());
+            logger.debug("... distance: " + dist[0] + " - " + dist[1]);
+        }
+
+        Gauge gauge = river.determineGauge(dist[0], dist[1]);
+
+        String name = gauge != null ? gauge.getName() : "'n/a";
+        logger.debug("Found gauge: " + name);
+
+        return gauge;
+    }
+
+
+    /**
+     * Returns the gauges that match the selected kilometer range.
+     *
+     * @return the gauges based on the selected kilometer range.
+     */
+    public List<Gauge> getGauges() {
+
+        River river = getRiver();
+        if (river == null) {
+            return null;
+        }
+
+        double [] dist  = getDistance();
+        if (dist == null) {
+            return null;
+        }
+
+        return river.determineGauges(dist[0], dist[1]);
+    }
+
+
+    /**
+     * This method returns the Q values.
+     *
+     * @return the selected Q values or null, if no Q values are selected.
+     */
+    public double[] getQs() {
+        StateData dMode      = getData("wq_mode");
+        StateData dSelection = getData("wq_selection");
+
+        String mode = dMode != null ? (String) dMode.getValue() : "";
+        String sel  = dSelection != null ? (String)dSelection.getValue() : null;
+
+        if (mode.equals("Q")) {
+            if (sel != null && sel.equals("single")) {
+                return getSingleWQValues();
+            }
+            else {
+                return getWQTriple();
+            }
+        }
+        else {
+            logger.warn("You try to get Qs, but W has been inserted.");
+            return null;
+        }
+    }
+
+
+    public boolean isQ() {
+        StateData mode = getData("wq_mode");
+        return mode != null && mode.getValue().equals("Q");
+    }
+
+
+    /**
+     * Returns true, if the parameter is set to compute data on a free range.
+     * Otherwise it returns false, which tells the calculation that it is bound
+     * to a gauge.
+     *
+     * @return true, if the calculation should compute on a free range otherwise
+     * false and the calculation is bound to a gauge.
+     */
+    public boolean isFreeQ() {
+        StateData mode  = getData("wq_free");
+        String    value = mode != null ? (String) mode.getValue() : null;
+
+        logger.debug("isFreeQ: " + value);
+
+        if (value == null) {
+            return false;
+        }
+
+        return Boolean.valueOf(value);
+    }
+
+
+    /**
+     * 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() : "";
+
+        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() : "";
+
+        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.
+     */
+    public double[] getWs() {
+        StateData dMode   = getData("wq_mode");
+        StateData dSingle = getData("wq_single");
+
+        String mode = dMode != null ? (String) dMode.getValue() : "";
+
+        if (mode.equals("W")) {
+            if (dSingle != null) {
+                return getSingleWQValues();
+            }
+            else {
+                return getWQTriple();
+            }
+        }
+        else {
+            logger.warn("You try to get Qs, but W has been inserted.");
+            return null;
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @return an array of from, to and step width.
+     */
+    protected double[] getWQTriple() {
+        StateData dFrom = getData("wq_from");
+        StateData dTo   = getData("wq_to");
+
+        if (dFrom == null || dTo == null) {
+            logger.warn("Missing start or end value for range.");
+            return null;
+        }
+
+        double from = Double.parseDouble((String) dFrom.getValue());
+        double to   = Double.parseDouble((String) dTo.getValue());
+
+        StateData dStep = getData("wq_step");
+
+        if (dStep == null) {
+            logger.warn("No step width given. Cannot compute Qs.");
+            return null;
+        }
+
+        double step  = Double.parseDouble((String) dStep.getValue());
+
+        // if no width is given, the DEFAULT_Q_STEPS is used to compute the step
+        // width. Maybe, we should round the value to a number of digits.
+        if (step == 0d) {
+            double diff = to - from;
+            step = diff / DEFAULT_Q_STEPS;
+        }
+
+        return DoubleUtil.explode(from, to, step);
+    }
+
+
+    /**
+     * Returns an array of inserted WQ double values stored as whitespace
+     * separated list.
+     *
+     * @return an array of W or Q values.
+     */
+    protected double[] getSingleWQValues() {
+        StateData dSingle = getData("wq_single");
+
+        if (dSingle == null) {
+            logger.warn("Cannot determine single WQ values. No data given.");
+            return null;
+        }
+
+        String   tmp       = (String) dSingle.getValue();
+        String[] strValues = tmp.split(" ");
+
+        TDoubleArrayList values = new TDoubleArrayList();
+
+        for (String strValue: strValues) {
+            try {
+                values.add(Double.parseDouble(strValue));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn(nfe, nfe);
+            }
+        }
+
+        values.sort();
+
+        return values.toNativeArray();
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org