Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 2230:59af81364eb1
Improved the 'historical discharge' calculation: implemented findValueForW().
flys-artifacts/trunk@3872 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Wed, 01 Feb 2012 15:41:11 +0000 |
parents | 9dc81827b187 |
children | c9c788eea200 |
line wrap: on
line source
package de.intevation.flys.artifacts; import de.intevation.artifactdatabase.ProtocolUtils; import de.intevation.artifactdatabase.data.StateData; 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.Message; import de.intevation.artifacts.common.ArtifactNamespaceContext; import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; 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.Calculation5; import de.intevation.flys.artifacts.model.Calculation6; import de.intevation.flys.artifacts.model.Calculation; import de.intevation.flys.artifacts.model.CalculationMessage; 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.MainValuesFactory; import de.intevation.flys.artifacts.model.Segment; 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.states.DefaultState; import de.intevation.flys.artifacts.states.LocationDistanceSelect; import de.intevation.flys.geom.Lines; 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.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.GregorianCalendar; import java.util.LinkedList; 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. * * @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; /** * The default constructor. */ public WINFOArtifact() { } /** * This method returns a description of this artifact. * * @param data Some data. * @param context The CallContext. * * @return the description of this artifact. */ public Document describe(Document data, CallContext context) { logger.debug("Describe: the current state is: " + getCurrentStateId()); if (logger.isDebugEnabled()) { dumpArtifact(); } FLYSContext flysContext = FLYSUtils.getFlysContext(context); StateEngine stateEngine = (StateEngine) flysContext.get( FLYSContext.STATE_ENGINE_KEY); TransitionEngine transitionEngine = (TransitionEngine) flysContext.get( FLYSContext.TRANSITION_ENGINE_KEY); List<State> reachable = transitionEngine.getReachableStates( this, getCurrentState(context), stateEngine); Document description = XMLUtils.newDocument(); XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( description, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); Element root = ProtocolUtils.createRootNode(creator); description.appendChild(root); State current = getCurrentState(context); ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash()); ProtocolUtils.appendState(creator, root, current); ProtocolUtils.appendReachableStates(creator, root, reachable); appendBackgroundActivity(creator, root, context); Element name = ProtocolUtils.createArtNode( creator, "name", new String[] { "value" }, new String[] { getName() }); Element ui = ProtocolUtils.createArtNode( creator, "ui", null, null); Element staticUI = ProtocolUtils.createArtNode( creator, "static", null, null); Element outs = ProtocolUtils.createArtNode( creator, "outputmodes", null, null); appendOutputModes(description, outs, context, identifier()); appendStaticUI(description, staticUI, context, identifier()); Element dynamic = current.describe( this, description, root, context, identifier()); if (dynamic != null) { ui.appendChild(dynamic); } ui.appendChild(staticUI); root.appendChild(name); root.appendChild(ui); root.appendChild(outs); return description; } /** * Returns the name of the concrete artifact. * * @return the name of the concrete artifact. */ public String getName() { return ARTIFACT_NAME; } protected static void appendBackgroundActivity( ElementCreator cr, Element root, CallContext context ) { Element inBackground = cr.create("background-processing"); root.appendChild(inBackground); cr.addAttr( inBackground, "value", String.valueOf(context.isInBackground()), true); LinkedList<Message> messages = context.getBackgroundMessages(); if (messages == null) { return; } CalculationMessage message = (CalculationMessage) messages.getLast(); cr.addAttr( inBackground, "steps", String.valueOf(message.getSteps()), true); cr.addAttr( inBackground, "currentStep", String.valueOf(message.getCurrentStep()), true); inBackground.setTextContent(message.getMessage()); } /** * Append output mode nodes to a document. */ protected void appendOutputModes( Document doc, Element outs, CallContext context, String uuid) { List<String> stateIds = getPreviousStateIds(); XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); FLYSContext flysContext = FLYSUtils.getFlysContext(context); StateEngine engine = (StateEngine) flysContext.get( FLYSContext.STATE_ENGINE_KEY); for (String stateId: stateIds) { logger.debug("Append output modes for state: " + stateId); DefaultState state = (DefaultState) engine.getState(stateId); List<Output> list = state.getOutputs(); if (list == null || list.size() == 0) { logger.debug("-> No output modes for this state."); continue; } List<Facet> fs = facets.get(stateId); if (fs == null || fs.size() == 0) { logger.debug("No facets for previous state found."); continue; } logger.debug("Found " + fs.size() + " facets in previous states."); List<Output> generated = generateOutputs(list, fs); ProtocolUtils.appendOutputModes(doc, outs, generated); } try { DefaultState cur = (DefaultState) getCurrentState(context); if (cur.validate(this)) { List<Output> list = cur.getOutputs(); if (list != null && list.size() > 0) { logger.debug( "Append output modes for current state: " + cur.getID()); List<Facet> fs = facets.get(cur.getID()); if (fs != null && fs.size() > 0) { List<Output> generated = generateOutputs(list, fs); logger.debug("Found " + fs.size() + " current facets."); if (!generated.isEmpty()) { ProtocolUtils.appendOutputModes( doc, outs, generated); } } else { logger.debug("No facets found for the current state."); } } } } catch (IllegalArgumentException iae) { // state is not valid, so we do not append its outputs. } } /** * This method appends the static data - that has already been inserted by * the user - to the static node of the DESCRIBE document. * * @param doc The document. * @param ui The root node. * @param context The CallContext. * @param uuid The identifier of the artifact. */ protected void appendStaticUI( Document doc, Node ui, CallContext context, String uuid) { List<String> stateIds = getPreviousStateIds(); FLYSContext flysContext = FLYSUtils.getFlysContext(context); StateEngine engine = (StateEngine) flysContext.get( FLYSContext.STATE_ENGINE_KEY); for (String stateId: stateIds) { logger.debug("Append static data for state: " + stateId); DefaultState state = (DefaultState) engine.getState(stateId); ui.appendChild(state.describeStatic(this, doc, ui, context, uuid)); } } // // 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() { logger.debug("WINFOArtifact.getWaterlevelData"); 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; 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) { return error(new WQKms[0], "converting.ws.to.qs.failed"); } qs = qws[0]; if (qws[1] != null) { // If new ws where generated. // TODO: Inform user! 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); } /** * Computes the data of a waterlevel computation based on the interpolation * in WstValueTable. * * @param kms The kilometer values. * @param qa 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 ) { logger.info("WINFOArtifact.computeWaterlevelData"); Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm); 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 = MainValuesFactory.getDurationCurveData(gauge); 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 used to create discharge curves. * */ public CalculationResult getDischargeCurveData() { River river = FLYSUtils.getRiver(this); if (river == null) { return error(new WQKms[0], "no.river.selected"); } double [] distance = FLYSUtils.getKmRange(this); if (distance == null) { return error(new WQKms[0], "no.range.found"); } List<Gauge> gauges = river.determineGauges(distance[0], distance[1]); if (gauges.isEmpty()) { return error(new WQKms[0], "no.gauge.selected"); } String [] names = new String[gauges.size()]; for (int i = 0; i < names.length; ++i) { names[i] = gauges.get(i).getName(); } DischargeTables dt = new DischargeTables(river.getName(), names); Map<String, double [][]> map = dt.getValues(100d); ArrayList<WQKms> res = new ArrayList<WQKms>(); for (Gauge gauge: gauges) { String name = gauge.getName(); double [][] values = map.get(name); if (values == null) { continue; } double [] kms = new double[values[0].length]; Arrays.fill(kms, gauge.getStation().doubleValue()); res.add(new WQKms(kms, values[0], values[1], name)); } return new CalculationResult( res.toArray(new WQKms[res.size()]), new Calculation()); } /** * 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. * @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); } protected static final CalculationResult error(Object data, String msg) { return new CalculationResult(data, new Calculation(msg)); } /** * Returns the data computed by the discharge longitudinal section * computation. * * @return an array of WQKms object - one object for each given Q value. */ public CalculationResult getDischargeLongitudinalSectionData() { logger.debug("WINFOArtifact.getDischargeLongitudinalSectionData"); River river = FLYSUtils.getRiver(this); if (river == null) { logger.debug("No river selected."); return error(new WQKms[0], "no.river.selected"); } WstValueTable table = WstValueTableFactory.getTable(river); if (table == null) { logger.debug("No wst found for selected river."); return error(new WQKms[0], "no.wst.for.river"); } List<Segment> segments = getSegments(); if (segments == null) { logger.debug("Cannot create segments."); return error(new WQKms[0], "cannot.create.segments"); } double [] range = getFromToStep(); if (range == null) { logger.debug("Cannot figure out range."); return error(new WQKms[0], "no.range.found"); } Calculation4 calc4 = new Calculation4(segments, river, isQ()); return calc4.calculate(table, range[0], range[1], range[2]); } /** * Returns the data that is computed by a reference curve computation. * * @return the data computed by a reference curve computation. */ public CalculationResult getReferenceCurveData() { 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"); } return calc5.calculate(wst); } protected Double getReferenceStartKm() { if (true) { return FLYSUtils.getLocations(this)[0]; } StateData sd = getData("reference_start"); if (sd == null) { logger.warn("no reference start given."); return null; } 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; } protected double [] getReferenceEndKms() { StateData sd = getData("reference_end"); if(true) return new double[] {getReferenceStartKm() + 2.0d}; if (sd == null) { logger.warn("no reference end given."); return null; } 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 { endKms.add(Double.parseDouble(part)); } 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"); int[] timerange = FLYSUtils.intArrayFromString(rawTimerange); double[] values = FLYSUtils.doubleArrayFromString(rawValues); Calendar start = new GregorianCalendar(timerange[0], 0, 1); Calendar end = new GregorianCalendar(timerange[1], 0, 1); Calculation6 calc = new Calculation6( mode, new long[] { start.getTimeInMillis(), end.getTimeInMillis() }, values); return calc.calculate(gauge); } 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); } /** * Get points of line describing the surface of water at cross section. * * @return an array holding coordinates of points of surface of water ( * in the form {{x1, x2} {y1, y2}} ). */ public double [][] getWaterLines(int idx, FastCrossSectionLine csl) { logger.debug("getWaterLines(" + idx + ")"); List<Point2D> points = csl.getPoints(); // Need W at km WQKms [] wqkms = (WQKms[]) getWaterlevelData().getData(); 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."); } // Find W at km, linear naive approach. WQKms triple = wqkms[idx]; // Find index of km. double wishKM = csl.getKm(); int old_idx = 0; if (triple.size() == 0) { logger.warn("Calculation of 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_w = triple.getW(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_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) { 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()) { // 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) { // There could bemore than one Q per W. double [] qs = wst.findQsForW(km, ws[i]); for (int j = 0; j < qs.length; ++j) { outWs.add(ws[i]); outQs.add(qs[j]); } generatedWs |= qs.length != 1; } 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() + "'"); } 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 new double [][] { qs, 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); } /** * Returns the gauges that match the selected kilometer range. * * @return the gauges based on the selected kilometer range. */ public List<Gauge> getGauges() { River river = FLYSUtils.getRiver(this); if (river == null) { return null; } double [] dist = FLYSUtils.getKmRange(this); 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"); } public boolean isFreeW() { StateData mode = getData("wq_mode"); return mode != null && mode.getValue().equals("FREEW"); } /** * 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); 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_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(); } /** * Determines Facets initial disposition regarding activity (think of * selection in Client ThemeList GUI). This will be checked one time * when the facet enters a collections describe document. * * @param facetName name of the facet. * @param index index of the facet. * @return 0 if not active */ @Override public int getInitialFacetActivity(String outputName, String facetName, int index) { String [] inactives = new String[] { LONGITUDINAL_Q, DURATION_Q }; logger.debug("WINFOArtifact.active?: " + outputName + "/" + facetName); if (facetName.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) || facetName.equals(COMPUTED_DISCHARGE_MAINVALUES_W) && outputName.equals("computed_discharge_curve")) { return 0; } return Arrays.asList(inactives).contains(facetName) ? 0 : 1; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :