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