Mercurial > dive4elements > river
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 :