Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 4837:9e25c7523485
Fixed calculation of effective width in MINFO SQ relation.
* Get all (including empty datasets) from db.
* Filter empty datasets when processing data of the same date.
* Added debug outputs.
author | Raimund Renkert <rrenkert@intevation.de> |
---|---|
date | Wed, 23 Jan 2013 11:14:41 +0100 |
parents | 65bfb6faa538 |
children | 298d540f7b70 |
line wrap: on
line source
package de.intevation.flys.artifacts; import de.intevation.artifactdatabase.data.StateData; import de.intevation.artifactdatabase.state.Facet; import de.intevation.artifactdatabase.state.FacetActivity; import de.intevation.artifacts.Artifact; import de.intevation.artifacts.CallContext; import de.intevation.artifacts.common.utils.StringUtils; import de.intevation.flys.artifacts.access.Calculation4Access; import de.intevation.flys.artifacts.geom.Lines; 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.Calculation5; import de.intevation.flys.artifacts.model.Calculation6; 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.FacetTypes; import de.intevation.flys.artifacts.model.WQCKms; import de.intevation.flys.artifacts.model.WQKms; import de.intevation.flys.artifacts.model.WW; import de.intevation.flys.artifacts.model.WstValueTable; import de.intevation.flys.artifacts.model.WstValueTableFactory; import de.intevation.flys.artifacts.model.extreme.ExtremeResult; import de.intevation.flys.artifacts.states.DefaultState.ComputeType; import de.intevation.flys.artifacts.states.LocationDistanceSelect; import de.intevation.flys.model.DischargeTable; import de.intevation.flys.model.FastCrossSectionLine; import de.intevation.flys.model.Gauge; import de.intevation.flys.model.River; import de.intevation.flys.utils.DoubleUtil; import de.intevation.flys.utils.FLYSUtils; import gnu.trove.TDoubleArrayList; import java.awt.geom.Point2D; import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; /** * The default WINFO artifact. * * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ public class WINFOArtifact extends FLYSArtifact implements FacetTypes, WaterLineArtifact { /** The logger for this class. */ private static Logger logger = Logger.getLogger(WINFOArtifact.class); /** 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; private static final String [] INACTIVES = new String[] { LONGITUDINAL_Q, DURATION_Q }; static { // TODO: Move to configuration. FacetActivity.Registry.getInstance().register( ARTIFACT_NAME, new FacetActivity() { @Override public Boolean isInitialActive( Artifact artifact, Facet facet, String outputName ) { String fname = facet.getName(); if ((fname.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) || fname.equals(COMPUTED_DISCHARGE_MAINVALUES_W) || fname.equals(MAINVALUES_Q) || fname.equals(MAINVALUES_W)) && outputName.equals("computed_discharge_curve")) { return Boolean.FALSE; } return !StringUtils.contains(fname, INACTIVES); } }); } /** * The default constructor. */ public WINFOArtifact() { } /** * Returns the name of the concrete artifact. * * @return the name of the concrete artifact. */ @Override public String getName() { return ARTIFACT_NAME; } protected static boolean reportGeneratedWs( Calculation report, double [] ws ) { if (ws == null || ws.length < 2) { return false; } double lastW = ws[0]; boolean alreadyReported = false; for (int i = 1; i < ws.length; ++i) { if (Math.abs(lastW - ws[i]) < 1e-5) { if (!alreadyReported) { alreadyReported = true; report.addProblem("more.than.one.q.for.w", ws[i]); } } else { alreadyReported = false; } lastW = ws[i]; } return true; } // // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES // // /** * Returns the data that is computed by a waterlevel computation. * * @return an array of data triples that consist of W, Q and Kms. */ public CalculationResult getWaterlevelData() { return this.getWaterlevelData(null); } // THIS IS FREAKY BULLSHIT! Felix, why do you call the calculation directly???? protected CalculationResult getDischargeLongitudinalSectionData() { // XXX: THIS AN _EXPENSIVE_ CALCULATION! CACHE IT! return new Calculation4(new Calculation4Access(this)).calculate(); } /** * Returns the data that is computed by a waterlevel computation. * * @return an array of data triples that consist of W, Q and Kms. */ public CalculationResult getWaterlevelData(CallContext context) { logger.debug("WINFOArtifact.getWaterlevelData"); String calculationMode = getDataAsString("calculation_mode"); if (calculationMode.equals("calc.discharge.longitudinal.section") ) { return getDischargeLongitudinalSectionData(); } else if (calculationMode.equals("calc.extreme.curve")) { return (CalculationResult) this.compute(context, ComputeType.ADVANCE, false); } River river = FLYSUtils.getRiver(this); if (river == null) { return error(new WQKms[0], "no.river.selected"); } double[] kms = getKms(); if (kms == null) { return error(new WQKms[0], "no.kms.selected"); } double[] qs = getQs(); double[] ws = null; boolean qSel = true; Calculation report = new Calculation(); if (qs == null) { logger.debug("Determine Q values based on a set of W values."); qSel = false; ws = getWs(); double [][] qws = getQsForWs(ws); if (qws == null || qws.length == 0) { return error(new WQKms[0], "converting.ws.to.qs.failed"); } qs = qws[0]; if (reportGeneratedWs(report, qws[1])) { ws = qws[1]; } } WstValueTable wst = WstValueTableFactory.getTable(river); if (wst == null) { return error(new WQKms[0], "no.wst.for.selected.river"); } double [] range = FLYSUtils.getKmRange(this); if (range == null) { return error(new WQKms[0], "no.range.found"); } double refKm; if (isFreeQ() || isFreeW()) { refKm = range[0]; logger.debug("'free' calculation (km " + refKm + ")"); } else { Gauge gauge = river.determineGaugeByPosition(range[0]); if (gauge == null) { return error( new WQKms[0], "no.gauge.found.for.km"); } refKm = gauge.getStation().doubleValue(); logger.debug( "reference gauge: " + gauge.getName() + " (km " + refKm + ")"); } return computeWaterlevelData(kms, qs, ws, wst, refKm, report); } /** * Computes the data of a waterlevel computation based on the interpolation * in WstValueTable. * * @param kms The kilometer values. * @param qs The discharge values. * @param wst The WstValueTable used for the interpolation. * * @return an array of data triples that consist of W, Q and Kms. */ public static CalculationResult computeWaterlevelData( double [] kms, double [] qs, double [] ws, WstValueTable wst, double refKm, Calculation report ) { logger.info("WINFOArtifact.computeWaterlevelData"); Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm); if (report != null) { calc1.addProblems(report); } return calc1.calculate(wst); } /** * Returns the data that is computed by a duration curve computation. * * @return the data computed by a duration curve computation. */ public CalculationResult getDurationCurveData() { logger.debug("WINFOArtifact.getDurationCurveData"); River r = FLYSUtils.getRiver(this); if (r == null) { return error(null, "no.river.selected"); } Gauge g = getGauge(); if (g == null) { return error(null, "no.gauge.selected"); } double[] locations = FLYSUtils.getLocations(this); if (locations == null) { return error(null, "no.locations.selected"); } WstValueTable wst = WstValueTableFactory.getTable(r); if (wst == null) { return error(null, "no.wst.for.river"); } 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 CalculationResult computeDurationCurveData( Gauge gauge, WstValueTable wst, double location) { logger.info("WINFOArtifact.computeDurationCurveData"); Object[] obj = gauge.fetchDurationCurveData(); int[] days = (int[]) obj[0]; double[] qs = (double[]) obj[1]; Calculation3 calculation = new Calculation3(location, days, qs); return calculation.calculate(wst); } /** * Returns the data that is computed by a discharge curve computation. * * @return the data computed by a discharge curve computation. */ public CalculationResult getComputedDischargeCurveData() throws NullPointerException { logger.debug("WINFOArtifact.getComputedDischargeCurveData"); River r = FLYSUtils.getRiver(this); if (r == null) { return error(new WQKms[0], "no.river.selected"); } double[] locations = FLYSUtils.getLocations(this); if (locations == null) { return error(new WQKms[0], "no.locations.selected"); } WstValueTable wst = WstValueTableFactory.getTable(r); if (wst == null) { return error(new WQKms[0], "no.wst.for.river"); } return computeDischargeCurveData(wst, locations[0]); } /** * Computes the data used to create computed discharge curves. * * @param wst The WstValueTable that is used for the interpolation (river- * bound). * @param location The location where the computation should be based on. * * @return an object that contains tuples of W/Q values at the specified * location. */ public static CalculationResult computeDischargeCurveData( WstValueTable wst, double location) { logger.info("WINFOArtifact.computeDischargeCurveData"); Calculation2 calculation = new Calculation2(location); return calculation.calculate(wst); } /** Create CalculationResult with data and message. */ protected static final CalculationResult error(Object data, String msg) { return new CalculationResult(data, new Calculation(msg)); } /** * Returns the data that is computed by a reference curve computation. * * @return the data computed by a reference curve computation. */ public CalculationResult getReferenceCurveData(CallContext context) { Double startKm = getReferenceStartKm(); if (startKm == null) { return error(new WW[0], "no.reference.start.km"); } double [] endKms = getReferenceEndKms(); if (endKms == null || endKms.length == 0) { return error(new WW[0], "no.reference.end.kms"); } Calculation5 calc5 = new Calculation5(startKm, endKms); River r = FLYSUtils.getRiver(this); if (r == null) { return error(new WW[0], "no.river.found"); } WstValueTable wst = WstValueTableFactory.getTable(r); if (wst == null) { return error(new WW[0], "no.wst.for.river"); } Map<Double, Double> kms2gaugeDatums = r.queryGaugeDatumsKMs(); return calc5.calculate(wst, kms2gaugeDatums, context); } /** Get reference (start) km. */ public Double getReferenceStartKm() { StateData sd = getData("reference_startpoint"); if (sd == null) { logger.warn("no reference start given."); return null; } logger.debug("Reference start km given: " + sd.getValue()); String input = (String) sd.getValue(); if (input == null || (input = input.trim()).length() == 0) { logger.warn("reference start string is empty."); return null; } try { return Double.valueOf(input); } catch (NumberFormatException nfe) { logger.warn("reference start string is not numeric."); } return null; } /** * Get end kms for reference curve (null if none). */ public double [] getReferenceEndKms() { StateData sd = getData("reference_endpoint"); if (sd == null) { logger.warn("no reference end given."); return null; } else { logger.debug("Reference end km : " + sd.getValue()); } String input = (String) sd.getValue(); if (input == null || (input = input.trim()).length() == 0) { logger.warn("reference end string is empty."); return null; } TDoubleArrayList endKms = new TDoubleArrayList(); for (String part: input.split("\\s+")) { try { double km = Double.parseDouble(part); if (!endKms.contains(km)) { endKms.add(km); } } catch (NumberFormatException nfe) { logger.warn("reference end string is not numeric."); } } return endKms.toNativeArray(); } public CalculationResult getHistoricalDischargeData() { Gauge gauge = FLYSUtils.getReferenceGauge(this); String rawTimerange = getDataAsString("year_range"); String rawValues = getDataAsString("historical_values"); int mode = getDataAsInteger("historical_mode"); long[] timerange = FLYSUtils.longArrayFromString(rawTimerange); double[] values = FLYSUtils.doubleArrayFromString(rawValues); Calendar start = new GregorianCalendar(); start.setTimeInMillis(timerange[0]); Calendar end = new GregorianCalendar(); end.setTimeInMillis(timerange[1]); Calculation6 calc = new Calculation6( mode, new long[] { start.getTimeInMillis(), end.getTimeInMillis() }, values); return calc.calculate(gauge); } /** * Get corrected waterline against surface/profile. */ public Lines.LineData waterLineC(int idx, FastCrossSectionLine csl) { List<Point2D> points = csl.getPoints(); WQKms[] wqckms = (WQKms[]) getDischargeLongitudinalSectionData().getData(); // Find index of km. double wishKM = csl.getKm(); // Find W/C at km, linear naive approach. WQCKms triple = (WQCKms) wqckms[idx-1]; int old_idx = 0; if (triple.size() == 0) { logger.warn("Calculation of c/waterline is empty."); return Lines.createWaterLines(points, 0.0f); } // Linear seach in WQKms for closest km. double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); double last_c = triple.getC(0); for (int i = 0, T = triple.size(); i < T; i++) { double diff = Math.abs(wishKM - triple.getKm(i)); if (diff > old_dist_wish) { break; } last_c = triple.getC(i); old_dist_wish = diff; } return Lines.createWaterLines(points, last_c); } /** * Get points of line describing the surface of water at cross section. * * @param idx Index for getWaterlevelData. * @param csl The profile/surface to fill with water. * @param nextIgnored Ignored in this implementation of WaterLineArtifact. * @param prevIgnored Ignored in this implementation of WaterLineArtifact. * * @return an array holding coordinates of points of surface of water ( * in the form {{x1, x2} {y1, y2}} ). */ @Override public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, double nextIgnored, double prevIgnored, CallContext context) { logger.debug("getWaterLines(" + idx + ")"); List<Point2D> points = csl.getPoints(); // Need W at km Object waterlevelResult = getWaterlevelData(context).getData(); WQKms [] wqkms; if (waterlevelResult instanceof ExtremeResult) { wqkms = ((ExtremeResult) waterlevelResult).getWQKms(); } else { wqkms = (WQKms[]) waterlevelResult; } if (wqkms.length == 0) { logger.error("No WQKms found."); return Lines.createWaterLines(points, 0.0f); } if (wqkms.length <= idx) { logger.error("getWaterLines() requested index (" + idx + " not found."); return waterLineC(idx, csl); } // Find W at km, linear naive approach. WQKms triple = wqkms[idx]; // Find index of km. double wishKM = csl.getKm(); if (triple.size() == 0) { logger.warn("Calculation of waterline is empty."); return Lines.createWaterLines(points, 0.0f); } // Early abort if we would need to extrapolate. int T = triple.size(); double max_km = triple.getKm(T-1), min_km = triple.getKm(0); if (wishKM < min_km || wishKM > max_km) { // TODO Does this have to be done in the other WaterlineArtifact // implementations, too? logger.warn("Will not extrapolate waterlevels."); return Lines.createWaterLines(points, 0.0f); } int old_idx = 0; // Linear seach in WQKms for closest km. double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); double last_w = triple.getW(0); for (int i = 0; i < T; i++) { double diff = Math.abs(wishKM - triple.getKm(i)); if (diff > old_dist_wish) { break; } last_w = triple.getW(i); old_dist_wish = diff; } return Lines.createWaterLines(points, last_w); } /** * 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) { if (ws == null) { logger.error("getQsForWs: ws == null"); return null; } boolean debug = logger.isDebugEnabled(); if (debug) { logger.debug("FLYSArtifact.getQsForWs"); } River r = FLYSUtils.getRiver(this); if (r == null) { logger.warn("no river found"); return null; } double [] range = FLYSUtils.getKmRange(this); if (range == null) { logger.warn("no ranges found"); return null; } if (isFreeW()) { logger.debug("Bezugslinienverfahren I: W auf freier Strecke"); // The simple case of the "Bezugslinienverfahren" // "W auf freier Strecke". WstValueTable wst = WstValueTableFactory.getTable(r); if (wst == null) { logger.warn("no wst value table found"); return null; } double km = range[0]; TDoubleArrayList outQs = new TDoubleArrayList(ws.length); TDoubleArrayList outWs = new TDoubleArrayList(ws.length); boolean generatedWs = false; for (int i = 0; i < ws.length; ++i) { double w = ws[i]; if (debug) { logger.debug("getQsForWs: lookup Q for W: " + w); } // There could bemore than one Q per W. double [] qs = wst.findQsForW(km, w); for (int j = 0; j < qs.length; ++j) { outWs.add(ws[i]); outQs.add(qs[j]); } generatedWs |= qs.length != 1; } if (debug) { logger.debug("getQsForWs: number of Qs: " + outQs.size()); } return new double [][] { outQs.toNativeArray(), generatedWs ? outWs.toNativeArray() : 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() + "'"); } DischargeTable dt = g.fetchMasterDischargeTable(); if (dt == null) { logger.warn("No master discharge table found for gauge '" + g.getName() + "'"); return null; } double [][] values = DischargeTables.loadDischargeTableValues(dt, 1); TDoubleArrayList wsOut = new TDoubleArrayList(ws.length); TDoubleArrayList qsOut = new TDoubleArrayList(ws.length); boolean generatedWs = false; for (int i = 0; i < ws.length; i++) { if (Double.isNaN(ws[i])) { logger.warn("W is NaN: ignored"); continue; } double w = ws[i] / 100d; double [] qs = DischargeTables.getQsForW(values, w); if (qs.length == 0) { logger.warn("No Qs found for W = " + ws[i]); } else { for (double q: qs) { wsOut.add(ws[i]); qsOut.add(q * 100d); } } generatedWs |= qs.length != 1; } return new double [][] { qsOut.toNativeArray(), generatedWs ? wsOut.toNativeArray() : 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 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 = FLYSUtils.getKmRange(this); return getKms(distance); } else { return LocationDistanceSelect.getLocations(this); } } public double [] getFromToStep() { if (!isRange()) { return null; } double [] fromTo = FLYSUtils.getKmRange(this); 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() { return FLYSUtils.getGauge(this); } /** * 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_isq"); StateData dSelection = getData("wq_isrange"); boolean isRange = dSelection != null ? Boolean.valueOf((String)dSelection.getValue()) : false; if (isQ()) { if (!isRange) { 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_isq"); String value = (mode != null) ? (String) mode.getValue() : null; return value != null ? Boolean.valueOf(value) : false; } public boolean isW() { StateData mode = getData("wq_isq"); String value = (mode != null) ? (String) mode.getValue() : null; return value != null ? !Boolean.valueOf(value) : false; } public boolean isFreeW() { if(!isW()) { return false; } StateData mode = getData("wq_isfree"); String value = (mode != null) ? (String) mode.getValue() : null; return value != null ? Boolean.valueOf(value) : false; } /** * 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() { if(!isQ()) { return false; } StateData mode = getData("wq_isfree"); String value = (mode != null) ? (String) mode.getValue() : null; logger.debug("isFreeQ: " + value); return value != null && 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_isq"); if (isQ()) { 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) { if (isW()) { 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() { if (isW()) { StateData dSingle = getData("wq_single"); if (dSingle != null) { return getSingleWQValues(); } else { return getWQTriple(); } } else { logger.warn("You try to get Ws, but Q 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(); } /** * Returns the WstValueTable of current river. */ public WstValueTable getWstValueTable() { River r = FLYSUtils.getRiver(this); return WstValueTableFactory.getTable(r); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :