Mercurial > dive4elements > river
changeset 686:3dc61e00385e facets-slt
Merged with trunk and introduced hashing of computed values.
flys-artifacts/branches/facets-slt@2126 c6561f87-3c4e-4783-a992-168aeb5c3f6f
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/ChangeLog Wed Jun 15 15:28:54 2011 +0000 @@ -1,3 +1,160 @@ +2011-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Got rid of namespace in result document. + +2011-06-14 Ingo Weinzierl <ingo@intevation.de> + + flys/issue77 (Diagramm: Beschriftung der Kurven bei Dauerlinien) + + * src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Give the curves in the chart names. + + * src/main/resources/messages.properties, + src/main/resources/messages_de_DE.properties, + src/main/resources/messages_en.properties, + src/main/resources/messages_de.properties: Added titles for duration + chart curves. + +2011-06-14 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: + Write top 'Oberkante' and bottom 'Unterkante' to out going XML + if they exist. + +2011-06-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java: + Write the min/max W/Q ranges as art:range elements into the DESCRIBE. + +2011-06-14 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java: + This state that is used to retrieve locations will now write the + kilometer range of the selected river into the DESCRIBE document. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation1.java: + New. Factored out version of "Wasserspiegellage" calculation. + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java: + + Removed some dead code. + + * src/main/java/de/intevation/flys/artifacts/model/WQCKms.java: + Added Override annotation and used quick access method. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Looped through error reporting use by interpolate. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Used factored out version of calculation 1. Removed dead code. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation2.java: + New. Factored out version of "Abflusskurve". + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Loop errors through w/q at km interpolation. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use factored out version of calculation 2. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation3.java: + New. Factored out version of "Dauerzahlen". + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Loop errors through for q->w interpolations. + + * src/main/java/de/intevation/flys/artifacts/model/WQDay.java: + Added constructor to directly create with calculated results. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + Added method to return the number of problems. + + * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Use factored out version of calculation 3. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/WQKms.java, + src/main/java/de/intevation/flys/artifacts/model/WQCKms.java, + src/main/java/de/intevation/flys/artifacts/model/WQDay.java: + Added methods to remove NaN values. + +2011-06-10 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation.java: + New. Base class for calculations. Used to collect problems occuring + during calculation. + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Extends Calculation now. Looped through the problem reports to + base class. + + * src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java: + Looped through the problem reports. + +2011-06-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: + Append the min/max range and a transformation matrix for each axis. + + * src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: + Instantiate the InfoGeneratorHelper with a XYChartGenerator instance. + + * src/main/java/de/intevation/flys/exports/XYChartGenerator.java: + Changed the zoom operation. The zoom values defined in the chart request + document are no longer absolute values for a specific axis. Those values + represent percental values for the start and end point of x and y axes. + E.g. a chart has three axes with the following ranges: + - x axis : 0 - 10 + - y axis 1: 20 - 40 + - y axis 2: 40 - 90 + - zoom values for x: 0.1 - 0.9 (10% - 90%) + - zoom values for y: 0.2 - 0.8 (20% - 80%) + The produced chart will have the following ranges: + - x axis : 1 - 9 + - y axis 1: 24 - 36 + y axis 2: 50 - 80 + +2011-06-09 Ingo Weinzierl <ingo@intevation.de> + + * src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java, + src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java: + Map datasets to axes correctly. + +2011-06-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Determine the gauges by their station positions. This hopfully + fixes the problem with wrong assigned gauges and invalid segments. + +2011-06-08 Sascha L. Teichmann <sascha.teichmann@intevation.de> + + * src/main/java/de/intevation/flys/artifacts/model/Segment.java, + src/main/java/de/intevation/flys/artifacts/model/Calculation4.java: + Added more debug output. + +2011-06-08 Ingo Weinzierl <ingo@intevation.de> + + flys/issue103 PART 1 (WINFO: Wasserspiegellagenberechnung / Layout-Inkonsistenz) + + * src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: + Selected values are formatted with the current locale. The static part + of the DESCRIBE document will now contain i18n formatted numbers. + +2011-06-08 Ingo Weinzierl <ingo@intevation.de> + + flys/issue93 (WINFO: Benennung der Berechnungsart korrigieren) + + * src/main/resources/messages_de_DE.properties, + src/main/resources/messages_de.properties: Changed the name of + calculation 4. + 2011-06-08 Ingo Weinzierl <ingo@intevation.de> * src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
--- a/flys-artifacts/doc/conf/cache.xml Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/doc/conf/cache.xml Wed Jun 15 15:28:54 2011 +0000 @@ -36,4 +36,14 @@ timeToLiveSeconds="86400" memoryStoreEvictionPolicy="LFU" /> + + <!-- This one is used to cache the computed values.--> + <cache name="computed.values" + maxElementsInMemory="1000" + eternal="false" + timeToLiveSeconds="172800" + overflowToDisk="true" + diskPersistent="true" + memoryStoreEvictionPolicy="LFU" + /> </ehcache>
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java Wed Jun 15 15:28:54 2011 +0000 @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; +import java.util.TreeMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -12,6 +12,8 @@ import gnu.trove.TDoubleArrayList; +import net.sf.ehcache.Cache; + import org.apache.log4j.Logger; import org.w3c.dom.Document; @@ -40,6 +42,9 @@ import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.artifacts.model.ComputeCallback; import de.intevation.flys.artifacts.model.DischargeTables; import de.intevation.flys.artifacts.model.RiverFactory; import de.intevation.flys.artifacts.model.Segment; @@ -59,6 +64,8 @@ private static Logger logger = Logger.getLogger(FLYSArtifact.class); + public static final String COMPUTING_CACHE = "computed.values"; + /** The XPath that points to the input data elements of the FEED document.*/ public static final String XPATH_FEED_INPUT = "/art:action/art:data/art:input"; @@ -98,7 +105,7 @@ * The default constructor that creates an empty FLYSArtifact. */ public FLYSArtifact() { - data = new HashMap<String, StateData>(); + data = new TreeMap<String, StateData>(); previousStateIds = new ArrayList<String>(); } @@ -1001,6 +1008,54 @@ return DoubleUtil.explode(from, to, step); } + + /** + * Computes the hash code of the entered values. + * + * @return a hash code. + */ + @Override + public String hash() { + Set<Map.Entry<String, StateData>> entries = data.entrySet(); + + int hash = 0; + int shift = 3; + + for (Map.Entry<String, StateData> entry: entries) { + String key = entry.getKey(); + Object value = entry.getValue().getValue(); + + hash ^= (key.hashCode() << shift) | (value.hashCode() << 2 * shift); + shift += 2; + } + + return getCurrentStateId() + hash; + } + + + public Object compute(String key, ComputeCallback callback) { + Cache cache = CacheFactory.getCache(COMPUTING_CACHE); + + if (cache == null) { + return callback.compute(); + } + + net.sf.ehcache.Element element = cache.get(key); + if (element != null) { + logger.debug("Got computation values from cache."); + return element.getValue(); + } + + Object result = callback.compute(); + + if (result != null) { + cache.put(new net.sf.ehcache.Element(key, result)); + } + + return result; + } + + /** * Method to dump the artifacts state/data. */
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Wed Jun 15 15:28:54 2011 +0000 @@ -1,9 +1,6 @@ package de.intevation.flys.artifacts; import java.util.List; -import java.util.Set; -import java.util.HashSet; -import java.util.ArrayList; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -25,15 +22,19 @@ import de.intevation.flys.model.Gauge; import de.intevation.flys.model.River; +import de.intevation.flys.artifacts.states.CalculationSelect; import de.intevation.flys.artifacts.states.DefaultState; import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.model.ComputeCallback; import de.intevation.flys.artifacts.model.MainValuesFactory; import de.intevation.flys.artifacts.model.WQDay; import de.intevation.flys.artifacts.model.WQKms; import de.intevation.flys.artifacts.model.WstValueTable; -import de.intevation.flys.artifacts.model.WstValueTable.QPosition; import de.intevation.flys.artifacts.model.WstValueTableFactory; +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.Segment; @@ -241,6 +242,76 @@ // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES // + + public Object compute() { + return compute(hash()); + } + + + public Object compute(String hash) { + String calc = (String) getData(CalculationSelect.FIELD_MODE).getValue(); + + ComputeCallback callback = null; + + if (calc.equals(CalculationSelect.CALCULATION_SURFACE_CURVE)) { + callback = createSurfaceCurveCallback(); + } + else if (calc.equals(CalculationSelect.CALCULATION_DURATION_CURVE)) { + callback = createDurationCurveCallback(); + } + else if ( + calc.equals( + CalculationSelect.CALCULATION_DISCHARGE_LONGITUDINAL_CURVE)) + { + callback = createDischargeLongitudinalCurveCallback(); + } + else if (calc.equals(CalculationSelect.CALCULATION_DISCHARGE_CURVE)) { + callback = createDischargeCurveCallback(); + } + else { + return null; + } + + return compute(hash, callback); + } + + + protected ComputeCallback createSurfaceCurveCallback() { + return new ComputeCallback() { + public Object compute() { + return getWaterlevelData(); + } + }; + } + + + protected ComputeCallback createDurationCurveCallback() { + return new ComputeCallback() { + public Object compute() { + return getDurationCurveData(); + } + }; + } + + + protected ComputeCallback createDischargeLongitudinalCurveCallback() { + return new ComputeCallback() { + public Object compute() { + return getDischargeLongitudinalSectionData(); + } + }; + } + + + protected ComputeCallback createDischargeCurveCallback() { + return new ComputeCallback() { + public Object compute() { + return getComputedDischargeCurveData(); + } + }; + } + + /** * Returns the data that is computed by a waterlevel computation. * @@ -277,43 +348,12 @@ throw new NullPointerException("No Wst found for selected river."); } - HashSet<Integer> failed = new HashSet<Integer>(); - WQKms[] results = computeWaterlevelData( - kms, qs, wst, river.getKmUp(), failed); - - // TODO Introduce a caching mechanism here! - - setWaterlevelNames( - results, qSel ? qs : ws, qSel ? "Q" : "W", failed); + kms, qs, ws, wst, river.getKmUp()); return results; } - - /** - * Sets the name for waterlevels where each WQKms in <i>r</i> represents a - * column. - * - * @param r The waterlevel columns. - * @param v The input values of the computations. - * @param wq The WQ mode - can be one of "W" or "Q". - */ - public static void setWaterlevelNames( - WQKms[] r, - double[] v, - String wq, - Set failed - ) { - int pos = 0; - for (int i = 0; i < v.length; i++) { - if (!failed.contains(i)) { - r[pos++].setName(wq + "=" + v[i]); - } - } - } - - /** * Computes the data of a waterlevel computation based on the interpolation * in WstValueTable. @@ -325,35 +365,19 @@ * @return an array of data triples that consist of W, Q and Kms. */ public static WQKms[] computeWaterlevelData( - double[] kms, - double[] qs, + double [] kms, + double [] qs, + double [] ws, WstValueTable wst, - boolean up, - Set<Integer> failed + boolean up ) { logger.info("WINFOArtifact.computeWaterlevelData"); - WQKms[] wqkms = new WQKms[qs.length]; - - ArrayList<WQKms> results = new ArrayList<WQKms>(); - - int referenceIndex = up ? 0 : kms.length-1; + Calculation1 calculation = new Calculation1(kms, qs, ws, up); - for (int i = 0; i < qs.length; i++) { - double [] oqs = new double[kms.length]; - double [] ows = new double[kms.length]; - WstValueTable.QPosition qPosition = - wst.interpolate(qs[i], kms[referenceIndex], kms, ows, oqs); - if (qPosition != null) { - results.add(new WQKms(kms, oqs, ows)); - } - else { - logger.warn("interpolation failed for q = " + qs[i]); - failed.add(i); - } - } + WQKms[] wqkms = calculation.calculate(wst); - return results.toArray(new WQKms[results.size()]); + return wqkms; } @@ -390,8 +414,6 @@ throw new NullPointerException("No Wst found for selected river."); } - // TODO Introduce a caching mechanism here! - return computeDurationCurveData(g, wst, locations[0]); } @@ -416,16 +438,10 @@ int[] days = (int[]) obj[0]; double[] qs = (double[]) obj[1]; - double[] interpolatedW = new double[qs.length]; - interpolatedW = wst.interpolateW(location, qs, interpolatedW); - - WQDay wqday = new WQDay(qs.length); + Calculation3 calculation = new Calculation3(location, days, qs); - for (int i = 0; i < days.length; i++) { - wqday.add(days[i], interpolatedW[i], qs[i]); - } - - return wqday; + // TODO: report the errors to the user. + return calculation.calculate(wst); } @@ -458,26 +474,11 @@ WQKms wqkms = computeDischargeCurveData(wst, locations[0]); - // TODO Introduce a caching mechanism here! - - setComputedDischargeCurveNames(wqkms, locations[0]); - return wqkms; } /** - * Sets the name of the computed discharge curve data. - * - * @param wqkms The computed WQKms object. - * @param l The location used for the computation. - */ - public static void setComputedDischargeCurveNames(WQKms wqkms, double l) { - wqkms.setName(Double.toString(l)); - } - - - /** * Computes the data used to create computed discharge curves. * * @param wst The WstValueTable that is used for the interpolation. @@ -492,21 +493,11 @@ { logger.info("WINFOArtifact.computeDischargeCurveData"); - double[][] wqs = wst.interpolateWQ(location); - - if (wqs == null) { - logger.error("Cannot compute discharge curve data."); - return null; - } + Calculation2 calculation = new Calculation2(location); - double[] ws = wqs[0]; - double[] qs = wqs[1]; + WQKms wqkms = calculation.calculate(wst); - WQKms wqkms = new WQKms(ws.length); - - for (int i = 0; i < ws.length; i++) { - wqkms.add(ws[i], qs[i], location); - } + // TODO: Report errors to the user return wqkms; }
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java Wed Jun 15 15:28:54 2011 +0000 @@ -15,6 +15,8 @@ import org.apache.log4j.Logger; +import de.intevation.flys.artifacts.model.Calculation; + public class BackJumpCorrector implements Serializable { @@ -40,8 +42,11 @@ return corrected; } - public boolean doCorrection(double [] km, double [] ws) { - + public boolean doCorrection( + double [] km, + double [] ws, + Calculation errors + ) { boolean wsUp = isIncreasing(ws); if (wsUp) { @@ -62,7 +67,7 @@ log.debug("BackJumpCorrector.doCorrection ------- leave"); } - boolean hasBackJumps = doCorrectionClean(km, ws); + boolean hasBackJumps = doCorrectionClean(km, ws, errors); if (hasBackJumps && wsUp) { // mirror back @@ -72,7 +77,11 @@ return hasBackJumps; } - protected boolean doCorrectionClean(double [] km, double [] ws) { + protected boolean doCorrectionClean( + double [] km, + double [] ws, + Calculation errors + ) { int N = km.length; if (N != ws.length) { @@ -201,6 +210,8 @@ spline = interpolator.interpolate(x, y); } catch (MathIllegalArgumentException miae) { + // TODO: I18N + errors.addProblem("creating spline interpolation failed."); log.error(miae); continue; } @@ -226,6 +237,8 @@ } } catch (ArgumentOutsideDomainException aode) { + // TODO: I18N + errors.addProblem("spline interpolation failed."); log.error("spline interpolation failed", aode); } } // for all km
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation.java Wed Jun 15 15:28:54 2011 +0000 @@ -0,0 +1,87 @@ +package de.intevation.flys.artifacts.model; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; +import java.util.ArrayList; + +import java.io.Serializable; + +public class Calculation +implements Serializable +{ + public static class Problem + implements Serializable + { + protected Double km; + protected String msg; + + public Problem() { + } + + public Problem(String msg) { + this.msg = msg; + } + + public Problem(double km, String msg) { + this.km = km; + this.msg = msg; + } + + public Element toXML(Document document) { + Element problem = document.createElement("problem"); + if (km != null) { + problem.setAttribute("km", String.valueOf(km)); + } + problem.setTextContent(msg); + return problem; + } + } // class Problem + + protected List<Problem> problems; + + public Calculation() { + } + + protected List<Problem> checkProblems() { + if (problems == null) { + problems = new ArrayList<Problem>(); + } + return problems; + } + + public void addProblem(String msg) { + checkProblems().add(new Problem(msg)); + } + + public void addProblem(double km, String msg) { + checkProblems().add(new Problem(km, msg)); + } + + public boolean hasProblems() { + return problems != null && !problems.isEmpty(); + } + + public int numProblems() { + return problems != null ? problems.size() : 0; + } + + public List<Problem> getProblems() { + return problems; + } + + public void toXML(Document document) { + + Element root = document.createElement("problems"); + + if (hasProblems()) { + for (Problem problem: problems) { + root.appendChild(problem.toXML(document)); + } + } + + document.appendChild(root); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation1.java Wed Jun 15 15:28:54 2011 +0000 @@ -0,0 +1,73 @@ +package de.intevation.flys.artifacts.model; + +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +public class Calculation1 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation1.class); + + protected double [] kms; + protected double [] qs; + protected double [] ws; + protected boolean up; + + public Calculation1() { + } + + public Calculation1( + double [] kms, + double [] qs, + double [] ws, + boolean up + ) { + this.kms = kms; + this.qs = qs; + this.ws = ws; + this.up = up; + } + + public WQKms [] calculate(WstValueTable wst) { + + ArrayList<WQKms> results = new ArrayList<WQKms>(); + + double ref = kms[up ? 0 : kms.length-1]; + + String prefix; + double [] origData; + + if (ws != null) { prefix = "W="; origData = ws; } + else { prefix = "Q="; origData = qs; } + + int oldNumProblems = numProblems(); + + for (int i = 0; i < qs.length; i++) { + + double [] oqs = new double[kms.length]; + double [] ows = new double[kms.length]; + + boolean success = + wst.interpolate(qs[i], ref, kms, ows, oqs, this) != null; + + int newNumProblems = numProblems(); + + if (success) { + WQKms result = new WQKms(kms, oqs, ows, prefix + origData[i]); + if (oldNumProblems != newNumProblems) { + logger.debug( + qs[i] + " caused " + (newNumProblems-oldNumProblems) + + " new problem(s)."); + result.removeNaNs(); + } + results.add(result); + } + + oldNumProblems = newNumProblems; + } + + return results.toArray(new WQKms[results.size()]); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation2.java Wed Jun 15 15:28:54 2011 +0000 @@ -0,0 +1,48 @@ +package de.intevation.flys.artifacts.model; + +import java.util.Arrays; + +import org.apache.log4j.Logger; + +public class Calculation2 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation2.class); + + protected double km; + + public Calculation2() { + } + + public Calculation2(double km) { + this.km = km; + } + + public WQKms calculate(WstValueTable wst) { + + logger.debug("Calculation2.calculate"); + + double [][] wqs = wst.interpolateWQ(km, this); + + if (wqs == null || wqs[0].length == 0) { + logger.debug("Cannot compute discharge curve data."); + return null; + } + + double [] ws = wqs[0]; + double [] qs = wqs[1]; + double [] kms = new double[ws.length]; + + Arrays.fill(kms, km); + + WQKms wqkms = new WQKms(kms, qs, ws, String.valueOf(km)); + + if (hasProblems()) { + logger.debug("found + "+numProblems()+" problems."); + wqkms.removeNaNs(); + } + + return wqkms; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation3.java Wed Jun 15 15:28:54 2011 +0000 @@ -0,0 +1,37 @@ +package de.intevation.flys.artifacts.model; + +import org.apache.log4j.Logger; + +public class Calculation3 +extends Calculation +{ + private static Logger logger = Logger.getLogger(Calculation3.class); + + protected double km; + protected int [] days; + protected double [] qs; + + public Calculation3() { + } + + public Calculation3(double km, int [] days, double [] qs) { + this.km = km; + this.days = days; + this.qs = qs; + } + + public WQDay calculate(WstValueTable wst) { + + double [] ws = wst.interpolateW(km, qs, new double[qs.length], this); + + WQDay wqday = new WQDay(days, ws, qs); + + if (hasProblems()) { + logger.debug("calculation caused "+numProblems()+" problem(s)."); + wqday.removeNaNs(); + } + + return wqday; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java Wed Jun 15 15:28:54 2011 +0000 @@ -20,6 +20,7 @@ import org.apache.log4j.Logger; public class Calculation4 +extends Calculation { private static Logger logger = Logger.getLogger(Calculation4.class); @@ -50,7 +51,7 @@ // assign reference points for (Segment segment: segments) { - Gauge gauge = river.determineGauge( + Gauge gauge = river.determineGaugeByStation( segment.getFrom(), segment.getTo()); segment.setReferencePoint(gauge != null @@ -93,10 +94,15 @@ logger.debug( "calculate from " + from + " to " + to + " step " + step); logger.debug("# segments: " + segments.size()); + for (Segment segment: segments) { + logger.debug(" " + segment); + } } if (segments.isEmpty()) { logger.debug("no segments found"); + // TODO: I18N + addProblem("no segments found"); return new WQKms[0]; } @@ -104,14 +110,13 @@ if (numResults < 1) { logger.debug("no values given"); + // TODO: I18N + addProblem("no values given"); return new WQKms[0]; } WQKms [] results = new WQKms[numResults]; - if (debug) { - logger.debug("after last segment -> gleichwertig"); - } for (int i = 0; i < results.length; ++i) { results[i] = new WQKms(); } @@ -213,7 +218,8 @@ anchor.values[i]); if ((qPositions[i] = qi) == null) { - // TODO: error report + // TODO: I18N + addProblem(pos, "cannot find q = " + anchor.values[i]); functions[i] = Identity.IDENTITY; } else { @@ -225,6 +231,14 @@ : new Linear( qA, qF, anchor.values[i], free.values[i]); + + if (debug) { + logger.debug( + anchor.referencePoint + ": " + + qA + " -> " + functions[i].value(qA) + + " / " + free.referencePoint + ": " + + qF + " -> " + functions[i].value(qF)); + } } } // build transforms } // "ungleichwertiges" interval @@ -241,7 +255,8 @@ results[i].add(out[0], out[1], pos); } else { - // TODO: error report + // TODO: I18N + addProblem(pos, "cannot interpolate w/q"); } } } @@ -253,10 +268,9 @@ double [] ws = results[i].getWs(); double [] kms = results[i].getKms(); - if (bjc.doCorrection(kms, ws)) { + if (bjc.doCorrection(kms, ws, this)) { results[i] = new WQCKms(results[i], bjc.getCorrected()); } - // TODO: error report } // name the curves @@ -268,7 +282,7 @@ } protected String createName(int index) { - // TODO: i18n + // TODO: I18N StringBuilder sb = new StringBuilder(isQ ? "Q" : "W"); sb.append(" benutzerdefiniert ("); for (int i = 0, N = segments.size(); i < N; ++i) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ComputeCallback.java Wed Jun 15 15:28:54 2011 +0000 @@ -0,0 +1,7 @@ +package de.intevation.flys.artifacts.model; + +public interface ComputeCallback { + + Object compute(); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Segment.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Segment.java Wed Jun 15 15:28:54 2011 +0000 @@ -42,7 +42,9 @@ public String toString() { StringBuilder sb = new StringBuilder("Segment: ["); sb.append("from: ").append(from).append("; to: ") - .append(to).append("; values: ("); + .append(to) + .append("; ref: ").append(referencePoint) + .append("; values: ("); for (int i = 0; i < values.length; ++i) { if (i > 0) sb.append(", "); sb.append(values[i]);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java Wed Jun 15 15:28:54 2011 +0000 @@ -30,6 +30,11 @@ this.cw = new TDoubleArrayList(cws); } + @Override + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { w, q, cw, kms }); + } + /** * Adds a new row to this data pool with corrected W. @@ -53,6 +58,7 @@ * * @return a 4dim array of [W, Q, Kms, CW] in dst. */ + @Override public double[] get(int idx, double[] dst) { dst = super.get(idx, dst); @@ -61,7 +67,7 @@ } if (cw != null && cw.size() > idx) { - dst[3] = cw.get(idx); + dst[3] = cw.getQuick(idx); } return dst;
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java Wed Jun 15 15:28:54 2011 +0000 @@ -34,6 +34,12 @@ qs = new TDoubleArrayList(capacity); } + public WQDay(int [] days, double [] ws, double [] qs) { + this.days = new TIntArrayList(days); + this.ws = new TDoubleArrayList(ws); + this.qs = new TDoubleArrayList(qs); + } + public void add(int day, double w, double q) { days.add(day); @@ -48,17 +54,43 @@ public int getDay(int idx) { - return days.get(idx); + return days.getQuick(idx); } public double getW(int idx) { - return ws.get(idx); + return ws.getQuick(idx); } public double getQ(int idx) { - return qs.get(idx); + return qs.getQuick(idx); + } + + public void removeNaNs() { + + int dest = 0; + int N = ws.size(); + + for (int i = 0; i < N; ++i) { + double w = ws.getQuick(i); + double q = qs.getQuick(i); + + if (Double.isNaN(w) || Double.isNaN(q)) { + continue; + } + + days.setQuick(dest, days.getQuick(i)); + ws.setQuick(dest, w); + qs.setQuick(dest, q); + ++dest; + } + + if (dest < N) { + days.remove(dest, N-dest); + ws .remove(dest, N-dest); + qs .remove(dest, N-dest); + } } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java Wed Jun 15 15:28:54 2011 +0000 @@ -53,6 +53,36 @@ this.kms = new TDoubleArrayList(capacity); } + public static void removeNaNs(TDoubleArrayList [] arrays) { + + int dest = 0; + + int A = arrays.length; + int N = arrays[0].size(); + + OUTER: for (int i = 0; i < N; ++i) { + for (int j = 0; j < A; ++j) { + TDoubleArrayList a = arrays[j]; + double v = a.getQuick(i); + if (Double.isNaN(v)) { + continue OUTER; + } + a.setQuick(dest, v); + } + ++dest; + } + + if (dest < N) { + for (int i = 0; i < A; ++i) { + arrays[i].remove(dest, N-dest); + } + } + } + + public void removeNaNs() { + removeNaNs(new TDoubleArrayList [] { w, q, kms }); + } + public WQKms(double[] kms, double[] qs, double[] ws) { this(kms, qs, ws, ""); @@ -81,14 +111,6 @@ this.kms.add(kms); } - - 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. * @@ -107,15 +129,15 @@ * @return a triple of [W, Q, Kms] in dst. */ public double[] get(int idx, double [] dst) { - dst[0] = w .get(idx); - dst[1] = q .get(idx); - dst[2] = kms.get(idx); + dst[0] = w .getQuick(idx); + dst[1] = q .getQuick(idx); + dst[2] = kms.getQuick(idx); return dst; } public double getKms(int idx) { - return kms.get(idx); + return kms.getQuick(idx); } @@ -142,37 +164,7 @@ 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; + return from + " - " + to; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Wed Jun 15 15:28:54 2011 +0000 @@ -18,6 +18,8 @@ import org.apache.commons.math.ArgumentOutsideDomainException; +import org.apache.commons.math.exception.MathIllegalArgumentException; + public class WstValueTable implements Serializable { @@ -107,7 +109,8 @@ double km, double [] iqs, double [] ows, - WstValueTable table + WstValueTable table, + Calculation errors ) { double kmWeight = Linear.factor(km, this.km, other.km); @@ -117,9 +120,23 @@ if (table.getQPosition(km, iqs[i], qPosition) != null) { double wt = getW(qPosition); double wo = other.getW(qPosition); - ows[i] = Linear.weight(kmWeight, wt, wo); + if (Double.isNaN(wt) || Double.isNaN(wo)) { + if (errors != null) { + // TODO: I18N + errors.addProblem( + km, "cannot find w for q = " + iqs[i]); + } + ows[i] = Double.NaN; + } + else { + ows[i] = Linear.weight(kmWeight, wt, wo); + } } else { + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "cannot find q = " + iqs[i]); + } ows[i] = Double.NaN; } } @@ -129,11 +146,16 @@ Row other, double km, int steps, - WstValueTable table + WstValueTable table, + Calculation errors ) { int W = Math.min(ws.length, other.ws.length); if (W < 1) { + if (errors != null) { + // TODO: I18N + errors.addProblem("no ws found"); + } return new double[2][0]; } @@ -152,21 +174,44 @@ table.getQIndex(i, km), table.getQIndex(i, other.km)); + if (Double.isNaN(wws) || Double.isNaN(wqs)) { + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "cannot find w or q"); + } + } + else { + if (wqs < minQ) minQ = wqs; + if (wqs > maxQ) maxQ = wqs; + } + splineW[i] = wws; splineQ[i] = wqs; - if (wqs < minQ) minQ = wqs; - if (wqs > maxQ) maxQ = wqs; } double stepWidth = (maxQ - minQ)/steps; SplineInterpolator interpolator = new SplineInterpolator(); - PolynomialSplineFunction spline = - interpolator.interpolate(splineQ, splineW); + PolynomialSplineFunction spline; + + try { + spline = interpolator.interpolate(splineQ, splineW); + } + catch (MathIllegalArgumentException miae) { + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "spline creation failed"); + } + log.error("spline creation failed"); + return new double[2][0]; + } double [] outWs = new double[steps]; double [] outQs = new double[steps]; + Arrays.fill(outWs, Double.NaN); + Arrays.fill(outQs, Double.NaN); + try { double q = minQ; for (int i = 0; i < outWs.length; ++i, q += stepWidth) { @@ -174,17 +219,28 @@ } } catch (ArgumentOutsideDomainException aode) { - log.error("Spline interpolation failed.", aode); + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "spline interpolation failed"); + } + log.error("spline interpolation failed", aode); } return new double [][] { outWs, outQs }; } - public double [][] interpolateWQ(int steps, WstValueTable table) { - + public double [][] interpolateWQ( + int steps, + WstValueTable table, + Calculation errors + ) { int W = ws.length; if (W < 1) { + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "no ws found"); + } return new double[2][0]; } @@ -193,24 +249,46 @@ double minQ = Double.MAX_VALUE; double maxQ = -Double.MAX_VALUE; - QPosition qPosition = new QPosition(); - for (int i = 0; i < W; ++i) { - splineQ[i] = table.getQIndex(i, km); - if (splineQ[i] < minQ) minQ = splineQ[i]; - if (splineQ[i] > maxQ) maxQ = splineQ[i]; + double sq = table.getQIndex(i, km); + if (Double.isNaN(sq)) { + if (errors != null) { + // TODO: I18N + errors.addProblem( + km, "no q found in " + (i+1) + " column"); + } + } + else { + if (sq < minQ) minQ = sq; + if (sq > maxQ) maxQ = sq; + } + splineQ[i] = sq; } double stepWidth = (maxQ - minQ)/steps; SplineInterpolator interpolator = new SplineInterpolator(); - PolynomialSplineFunction spline = - interpolator.interpolate(splineQ, ws); + PolynomialSplineFunction spline; + + try { + spline = interpolator.interpolate(splineQ, ws); + } + catch (MathIllegalArgumentException miae) { + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "spline creation failed"); + } + log.error("spline creation failed"); + return new double[2][0]; + } double [] outWs = new double[steps]; double [] outQs = new double[steps]; + Arrays.fill(outWs, Double.NaN); + Arrays.fill(outQs, Double.NaN); + try { double q = minQ; for (int i = 0; i < outWs.length; ++i, q += stepWidth) { @@ -218,7 +296,11 @@ } } catch (ArgumentOutsideDomainException aode) { - log.error("Spline interpolation failed.", aode); + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "spline interpolation failed"); + } + log.error("spline interpolation failed.", aode); } return new double [][] { outWs, outQs }; @@ -282,7 +364,15 @@ } public double [] interpolateW(double km, double [] qs, double [] ws) { + return interpolateW(km, qs, ws, null); + } + public double [] interpolateW( + double km, + double [] qs, + double [] ws, + Calculation errors + ) { int rowIndex = Collections.binarySearch(rows, new Row(km)); QPosition qPosition = new QPosition(); @@ -290,9 +380,21 @@ if (rowIndex >= 0) { // direct row match Row row = rows.get(rowIndex); for (int i = 0; i < qs.length; ++i) { - ws[i] = getQPosition(km, qs[i], qPosition) != null - ? row.getW(qPosition) - : Double.NaN; + if (getQPosition(km, qs[i], qPosition) == null) { + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "cannot find q = " + qs[i]); + } + ws[i] = Double.NaN; + } + else { + if (Double.isNaN(ws[i] = row.getW(qPosition)) + && errors != null) { + // TODO: I18N + errors.addProblem( + km, "cannot find w for q = " + qs[i]); + } + } } } else { // needs bilinear interpolation @@ -301,11 +403,15 @@ if (rowIndex < 1 || rowIndex >= rows.size()) { // do not extrapolate Arrays.fill(ws, Double.NaN); + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "km not found"); + } } else { Row r1 = rows.get(rowIndex-1); Row r2 = rows.get(rowIndex); - r1.interpolateW(r2, km, qs, ws, this); + r1.interpolateW(r2, km, qs, ws, this, errors); } } @@ -313,29 +419,37 @@ } public double [][] interpolateWQ(double km) { - return interpolateWQ(km, DEFAULT_Q_STEPS); + return interpolateWQ(km, null); } - public double [][] interpolateWQ(double km, int steps) { + public double [][] interpolateWQ(double km, Calculation errors) { + return interpolateWQ(km, DEFAULT_Q_STEPS, errors); + } + + public double [][] interpolateWQ(double km, int steps, Calculation errors) { int rowIndex = Collections.binarySearch(rows, new Row(km)); if (rowIndex >= 0) { // direct row match Row row = rows.get(rowIndex); - return row.interpolateWQ(steps, this); + return row.interpolateWQ(steps, this, errors); } rowIndex = -rowIndex -1; if (rowIndex < 1 || rowIndex >= rows.size()) { // do not extrapolate + if (errors != null) { + // TODO: I18N + errors.addProblem(km, "km not found"); + } return new double[2][0]; } Row r1 = rows.get(rowIndex-1); Row r2 = rows.get(rowIndex); - return r1.interpolateWQ(r2, km, steps, this); + return r1.interpolateWQ(r2, km, steps, this, errors); } public boolean interpolate( @@ -380,28 +494,36 @@ } public QPosition interpolate( - double q, - double referenceKm, - double [] kms, - double [] ws, - double [] qs + double q, + double referenceKm, + double [] kms, + double [] ws, + double [] qs, + Calculation errors ) { - return interpolate(q, referenceKm, kms, ws, qs, 0, kms.length); + return interpolate( + q, referenceKm, kms, ws, qs, 0, kms.length, errors); } public QPosition interpolate( - double q, - double referenceKm, - double [] kms, - double [] ws, - double [] qs, - int startIndex, - int length + double q, + double referenceKm, + double [] kms, + double [] ws, + double [] qs, + int startIndex, + int length, + Calculation errors ) { QPosition qPosition = getQPosition(referenceKm, q); if (qPosition == null) { // we cannot locate q at km + Arrays.fill(ws, Double.NaN); + Arrays.fill(qs, Double.NaN); + if (errors != null) { + errors.addProblem(referenceKm, "cannot find q"); + } return null; } @@ -410,15 +532,24 @@ int R1 = rows.size()-1; for (int i = startIndex, end = startIndex+length; i < end; ++i) { - kmKey.km = kms[i]; + if (Double.isNaN(qs[i] = getQ(qPosition, kms[i]))) { + if (errors != null) { + errors.addProblem(kms[i], "cannot find q"); + } + ws[i] = Double.NaN; + continue; + } + + kmKey.km = kms[i]; int rowIndex = Collections.binarySearch(rows, kmKey); - qs[i] = getQ(qPosition, kms[i]); - if (rowIndex >= 0) { // direct row match - ws[i] = rows.get(rowIndex).getW(qPosition); + if (Double.isNaN(ws[i] = rows.get(rowIndex).getW(qPosition)) + && errors != null) { + errors.addProblem(kms[i], "cannot find w"); + } continue; } @@ -426,13 +557,19 @@ if (rowIndex < 1 || rowIndex >= R1) { // do not extrapolate + if (errors != null) { + errors.addProblem(kms[i], "cannot find km"); + } ws[i] = Double.NaN; continue; } Row r1 = rows.get(rowIndex-1); Row r2 = rows.get(rowIndex); - ws[i] = r1.getW(r2, kms[i], qPosition); + if (Double.isNaN(ws[i] = r1.getW(r2, kms[i], qPosition)) + && errors != null) { + errors.addProblem(kms[i], "cannot find w"); + } } return qPosition;
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java Wed Jun 15 15:28:54 2011 +0000 @@ -12,7 +12,6 @@ import de.intevation.artifacts.common.ArtifactNamespaceContext; import de.intevation.artifacts.common.utils.XMLUtils; -import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; import de.intevation.artifactdatabase.DefaultService; @@ -21,6 +20,7 @@ import de.intevation.flys.model.Attribute; import de.intevation.flys.model.Position; import de.intevation.flys.model.Range; +import de.intevation.flys.model.Edge; import de.intevation.flys.artifacts.model.AnnotationsFactory; @@ -98,22 +98,17 @@ Document result = XMLUtils.newDocument(); - ElementCreator ec = new ElementCreator( - result, - ArtifactNamespaceContext.NAMESPACE_URI, - ArtifactNamespaceContext.NAMESPACE_PREFIX); - Session session = SessionHolder.acquire(); try { Iterator<Annotation> iter = AnnotationsFactory.getAnnotationsIterator(river); - Element all = ec.create("distances"); + Element all = result.createElement("distances"); while (iter.hasNext()) { Annotation a = iter.next(); - Element distance = buildDistanceNode(ec, a); + Element distance = buildDistanceNode(result, a); all.appendChild(distance); } @@ -136,19 +131,43 @@ * * @return an Element that contains information about a distance. */ - protected static Element buildDistanceNode(ElementCreator ec, Annotation anno) { - Position pos = anno.getPosition(); - Range range = anno.getRange(); - Attribute attr = anno.getAttribute(); + protected static Element buildDistanceNode( + Document document, + Annotation anno + ) { + Position pos = anno.getPosition(); + Range range = anno.getRange(); + Attribute attr = anno.getAttribute(); + Edge edge = anno.getEdge(); + BigDecimal a = range.getA(); + BigDecimal b = range.getB(); - BigDecimal a = range.getA(); - BigDecimal b = range.getB(); + Element distance = document.createElement("distance"); - Element distance = ec.create("distance"); - ec.addAttr(distance, "description", pos.getValue(), true); - ec.addAttr(distance, "from", a != null ? a.toString() : "", true); - ec.addAttr(distance, "to", b != null ? b.toString() : "", true); - ec.addAttr(distance, "riverside", attr.getValue(), true); + distance.setAttribute("description", pos.getValue()); + + String riverSide = attr.getValue(); + + if (riverSide != null && riverSide.length() > 0) { + distance.setAttribute("riverside", riverSide); + } + + if (a != null) { + distance.setAttribute("from", a.toString()); + } + if (b != null) { + distance.setAttribute("to", b.toString()); + } + if (edge != null) { + BigDecimal bottom = edge.getBottom(); + BigDecimal top = edge.getTop(); + if (bottom != null) { + distance.setAttribute("bottom", bottom.toString()); + } + if (top != null) { + distance.setAttribute("top", top.toString()); + } + } return distance; }
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DefaultState.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DefaultState.java Wed Jun 15 15:28:54 2011 +0000 @@ -1,6 +1,8 @@ package de.intevation.flys.artifacts.states; +import java.text.NumberFormat; import java.util.Iterator; +import java.util.Locale; import java.util.Map; import org.apache.log4j.Logger; @@ -84,11 +86,22 @@ Element itemElement = creator.create("item"); creator.addAttr(itemElement, "value", value, true); - creator.addAttr( - itemElement, - "label", - Resources.getMsg(meta, value, value), - true); + + String attrValue = ""; + try { + // XXX A better way to format the output would be to use the + // 'type' value if the data objects. + double doubleVal = Double.valueOf(value); + Locale l = Resources.getLocale(meta); + NumberFormat nf = NumberFormat.getInstance(l); + + attrValue = nf.format(doubleVal); + } + catch (NumberFormatException nfe) { + attrValue = Resources.getMsg(meta, value, value); + } + + creator.addAttr(itemElement, "label", attrValue, true); dataElement.appendChild(itemElement); ui.appendChild(dataElement);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java Wed Jun 15 15:28:54 2011 +0000 @@ -4,9 +4,13 @@ import org.apache.log4j.Logger; +import org.w3c.dom.Element; + import de.intevation.artifacts.Artifact; import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.common.utils.XMLUtils; + import de.intevation.artifactdatabase.data.StateData; import de.intevation.flys.artifacts.FLYSArtifact; @@ -40,6 +44,42 @@ @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + double[] minmax = getMinMaxDistance(artifact); + + double minVal = Double.MIN_VALUE; + double maxVal = Double.MAX_VALUE; + + if (minmax != null) { + minVal = minmax[0]; + maxVal = minmax[1]; + } + else { + logger.warn("Could not read min/max distance values!"); + } + + if (name.equals(FIELD_LOCATIONS)) { + Element min = createItem( + cr, + new String[] {"min", new Double(minVal).toString()}); + + Element max = createItem( + cr, + new String[] {"max", new Double(maxVal).toString()}); + + return new Element[] { min, max }; + } + + return null; + } + + + @Override public boolean validate(Artifact artifact, CallContext context) throws IllegalArgumentException {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java Wed Jun 15 15:28:54 2011 +0000 @@ -121,6 +121,8 @@ FLYSArtifact flysArtifact = (FLYSArtifact) artifact; double[] dist = flysArtifact.getDistance(); + River river = flysArtifact.getRiver(); + Wst wst = WstFactory.getWst(river); List<Gauge> gauges = flysArtifact.getGauges(); int num = gauges != null ? gauges.size() : 0; @@ -147,8 +149,11 @@ double from = lower < rangeFrom ? rangeFrom : lower; double to = upper > rangeTo ? rangeTo : upper; + double[] mmQ = determineMinMaxQ(gauge, wst); + double[] mmW = gauge.determineMinMaxW(); + elements[idx++] = createItem( - cr, new String[] { from + ";" + to, ""}); + cr, new String[] { from + ";" + to, ""}, mmQ, mmW); } } else { @@ -173,6 +178,16 @@ protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + return createItem(cr, obj, null, null); + } + + + protected Element createItem( + XMLUtils.ElementCreator cr, + Object obj, + double[] q, + double[] w) + { Element item = ProtocolUtils.createArtNode(cr, "item", null, null); Element label = ProtocolUtils.createArtNode(cr, "label", null, null); Element value = ProtocolUtils.createArtNode(cr, "value", null, null); @@ -185,10 +200,67 @@ item.appendChild(label); item.appendChild(value); + if (q != null) { + Element qRange = createRangeElement(cr, q, "Q"); + item.appendChild(qRange); + } + + if (w != null) { + Element wRange = createRangeElement(cr, w, "W"); + item.appendChild(wRange); + } + return item; } + protected Element createRangeElement( + XMLUtils.ElementCreator cr, + double[] mm, + String type) + { + Element range = ProtocolUtils.createArtNode( + cr, "range", + new String[] {"type"}, + new String[] {type}); + + Element min = ProtocolUtils.createArtNode(cr, "min", null, null); + min.setTextContent(String.valueOf(mm[0])); + + Element max = ProtocolUtils.createArtNode(cr, "max", null, null); + max.setTextContent(String.valueOf(mm[1])); + + range.appendChild(min); + range.appendChild(max); + + return range; + } + + + /** + * Determines the min and max Q value for the given gauge. If no min and + * max values could be determined, this method will return + * [Double.MIN_VALUE, Double.MAX_VALUE]. + * + * @param gauge + * @param wst + * + * @return the min and max Q values for the given gauge. + */ + protected double[] determineMinMaxQ(Gauge gauge, Wst wst) { + logger.debug("WQAdapted.determineMinMaxQ"); + + double[] minmaxQ = gauge != null + ? wst.determineMinMaxQ(gauge.getRange()) + : null; + + double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE; + double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE; + + return new double[] { minQ, maxQ }; + } + + @Override protected String getUIProvider() { return "wq_panel_adapted";
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java Wed Jun 15 15:28:54 2011 +0000 @@ -101,7 +101,8 @@ chart.createBufferedImage(size[0], size[1], Transparency.BITMASK, info); - Document doc = InfoGeneratorHelper.createInfoDocument(chart, info); + InfoGeneratorHelper helper = new InfoGeneratorHelper(generator); + Document doc = helper.createInfoDocument(chart, info); XMLUtils.toStream(doc, out); }
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java Wed Jun 15 15:28:54 2011 +0000 @@ -83,6 +83,13 @@ } + protected void adjustAxes(XYPlot plot) { + super.adjustAxes(plot); + + plot.mapDatasetToRangeAxis(2, 1); + } + + @Override public void doOut(Artifact artifact, String facet, Document attr) {
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java Wed Jun 15 15:28:54 2011 +0000 @@ -16,8 +16,11 @@ import de.intevation.artifacts.Artifact; +import de.intevation.flys.model.River; + import de.intevation.flys.artifacts.WINFOArtifact; import de.intevation.flys.artifacts.model.WQDay; +import de.intevation.flys.artifacts.resources.Resources; /** @@ -27,6 +30,9 @@ */ public class DurationCurveGenerator extends XYChartGenerator { + public static final String I18N_DURATION_W = "chart.duration.curve.curve.w"; + public static final String I18N_DURATION_Q = "chart.duration.curve.curve.q"; + private static Logger logger = Logger.getLogger(DurationCurveGenerator.class); @@ -146,8 +152,8 @@ NumberAxis qAxis = new NumberAxis("Q [m\u00b3/s]"); - plot.setRangeAxis(2, qAxis); - plot.mapDatasetToRangeAxis(1, 2); + plot.setRangeAxis(1, qAxis); + plot.mapDatasetToRangeAxis(1, 1); } @@ -159,11 +165,14 @@ return; } + WINFOArtifact winfo = (WINFOArtifact) artifact; + River river = winfo.getRiver(); + if (facet.equals(DURATION_CURVE_W)) { - doWOut(getDurationCurveData(artifact)); + doWOut(getDurationCurveData(artifact), river.getName()); } else if (facet.equals(DURATION_CURVE_Q)) { - doQOut(getDurationCurveData(artifact)); + doQOut(getDurationCurveData(artifact), river.getName()); } else { logger.warn("Unknown facet name: " + facet); @@ -176,12 +185,14 @@ * Creates the series for a duration curve's W facet. * * @param wqdays The WQDay store that contains the Ws. + * @param river The name of the river. */ - protected void doWOut(WQDay wqdays) { + protected void doWOut(WQDay wqdays, String river) { logger.debug("DurationCurveGenerator.doWOut"); // TODO find the correct series name - XYSeries series = new XYSeries("W-1"); + XYSeries series = new XYSeries( + getSeriesName(river, DURATION_CURVE_W)); int size = wqdays.size(); for (int i = 0; i < size; i++) { @@ -199,12 +210,14 @@ * Creates the series for a duration curve's Q facet. * * @param wqdays The WQDay store that contains the Qs. + * @param river The name of the river. */ - protected void doQOut(WQDay wqdays) { + protected void doQOut(WQDay wqdays, String river) { logger.debug("DurationCurveGenerator.doQOut"); // TODO find the correct series name - XYSeries series = new XYSeries("Q-1"); + XYSeries series = new XYSeries( + getSeriesName(river, DURATION_CURVE_Q)); int size = wqdays.size(); for (int i = 0; i < size; i++) { @@ -230,5 +243,32 @@ WINFOArtifact winfoArtifact = (WINFOArtifact) artifact; return winfoArtifact.getDurationCurveData(); } + + + protected String getSeriesName(String river, String type) { + Object[] args = new Object[] { river }; + + if (type == null || type.length() == 0) { + logger.warn("No duration curve type given."); + return "n/a"; + } + else if (type.equals(DURATION_CURVE_W)) { + return Resources.getMsg( + context.getMeta(), + I18N_DURATION_W, + "W", + args); + } + else if (type.equals(DURATION_CURVE_Q)) { + return Resources.getMsg( + context.getMeta(), + I18N_DURATION_Q, + "W", + args); + } + + logger.warn("Could not determine chart curve type: " + type); + return type; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java Wed Jun 15 15:28:54 2011 +0000 @@ -14,6 +14,7 @@ import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.data.Range; +import org.jfree.data.xy.XYDataset; import de.intevation.artifacts.common.ArtifactNamespaceContext; import de.intevation.artifacts.common.utils.XMLUtils; @@ -31,7 +32,11 @@ Logger.getLogger(InfoGeneratorHelper.class); - private InfoGeneratorHelper() { + protected XYChartGenerator generator; + + + public InfoGeneratorHelper(XYChartGenerator generator) { + this.generator = generator; } @@ -43,7 +48,7 @@ * * @return the info document. */ - public static Document createInfoDocument( + public Document createInfoDocument( JFreeChart chart, ChartRenderingInfo info) { @@ -59,7 +64,7 @@ Element chartinfo = cr.create("chartinfo"); chartinfo.appendChild(createAxesElements(cr, chart)); - chartinfo.appendChild(createTransformationElement(cr, chart, info)); + chartinfo.appendChild(createTransformationElements(cr, chart, info)); doc.appendChild(chartinfo); @@ -76,7 +81,7 @@ * * @return an element with axes information. */ - protected static Element createAxesElements( + protected Element createAxesElements( ElementCreator cr, JFreeChart chart) { @@ -89,8 +94,10 @@ int dAxisCount = plot.getDomainAxisCount(); for (int i = 0; i < dAxisCount; i++) { ValueAxis axis = plot.getDomainAxis(i); + XYDataset data = plot.getDataset(i); + if (axis != null) { - Element e = createAxisElement(cr, axis, "domain", i); + Element e = createAxisElement(cr, axis, data, "domain", i); axes.appendChild(e); } } @@ -98,10 +105,15 @@ int rAxisCount = plot.getRangeAxisCount(); for (int i = 0; i < rAxisCount; i++) { ValueAxis axis = plot.getRangeAxis(i); - if (axis != null) { - Element e = createAxisElement(cr, axis, "range", i); - axes.appendChild(e); + XYDataset data = plot.getDataset(i); + + if (axis == null || data == null) { + logger.warn("Axis or dataset is empty at pos: " + i); + continue; } + + Element e = createAxisElement(cr, axis, data, "range", i); + axes.appendChild(e); } return axes; @@ -114,14 +126,16 @@ * * @param cr The ElementCreator * @param axis The axis that provides range information. + * @param dataset The dataset for min/max determination. * @param type The axis type ('domain' or 'range'). * @param pos The position in the chart. * * @return An element that contains range information of a given axis. */ - protected static Element createAxisElement( + protected Element createAxisElement( ElementCreator cr, ValueAxis axis, + XYDataset dataset, String type, int pos) { @@ -132,6 +146,19 @@ cr.addAttr(e, "from", String.valueOf(range.getLowerBound()), true); cr.addAttr(e, "to", String.valueOf(range.getUpperBound()), true); + Range[] rs = generator.getRangesForDataset(dataset); + Range r = null; + + if (type.equals("range")) { + r = rs[1]; + } + else { + r = rs[0]; + } + + cr.addAttr(e, "min", String.valueOf(r.getLowerBound()), true); + cr.addAttr(e, "max", String.valueOf(r.getUpperBound()), true); + return e; } @@ -146,12 +173,12 @@ * * @return an element that contains one or more transformation matrix. */ - protected static Element createTransformationElement( + protected Element createTransformationElements( ElementCreator cr, JFreeChart chart, ChartRenderingInfo info) { - logger.debug("InfoGeneratorHelper.createTransformationElement"); + logger.debug("InfoGeneratorHelper.createTransformationElements"); Element tf = cr.create("transformation-matrix"); @@ -159,16 +186,60 @@ XYPlot plot = (XYPlot) chart.getPlot(); ValueAxis xAxis = plot.getDomainAxis(); - ValueAxis yAxis = plot.getRangeAxis(); + if (xAxis == null) { + logger.error("There is no x axis in the chart!"); + return null; + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis yAxis = plot.getRangeAxis(i); + + if (yAxis == null) { + logger.warn("No y axis at pos " + i + " existing."); + continue; + } + + Element matrix = createTransformationElement( + cr, xAxis, yAxis, dataArea, i); + + tf.appendChild(matrix); + } + + return tf; + } + + + /** + * Creates an element that contains values used to transform coordinates + * of a coordinate system A into a coordinate system B. + * + * @param cr The ElementCreator. + * @param xAxis The x axis of the target coordinate system. + * @param yAxis The y axis of the target coordinate system. + * @param dataArea The pixel coordinates of the chart image. + * @param pos The dataset position. + * + * @return an element that contains transformation matrix values. + */ + protected Element createTransformationElement( + ElementCreator cr, + ValueAxis xAxis, + ValueAxis yAxis, + Rectangle2D dataArea, + int pos) + { double[] tm = createTransformationMatrix(dataArea, xAxis, yAxis); - cr.addAttr(tf, "sx", String.valueOf(tm[0]), true); - cr.addAttr(tf, "sy", String.valueOf(tm[1]), true); - cr.addAttr(tf, "tx", String.valueOf(tm[2]), true); - cr.addAttr(tf, "ty", String.valueOf(tm[3]), true); + Element matrix = cr.create("matrix"); - return tf; + cr.addAttr(matrix, "pos", String.valueOf(pos), true); + cr.addAttr(matrix, "sx", String.valueOf(tm[0]), true); + cr.addAttr(matrix, "sy", String.valueOf(tm[1]), true); + cr.addAttr(matrix, "tx", String.valueOf(tm[2]), true); + cr.addAttr(matrix, "ty", String.valueOf(tm[3]), true); + + return matrix; }
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java Wed Jun 15 15:28:54 2011 +0000 @@ -106,7 +106,7 @@ addSubtitles(chart); adjustPlot(plot); adjustAxes(plot); - zoom(plot); + autoZoom(plot); return chart; } @@ -121,35 +121,28 @@ * * @param plot The XYPlot. */ - protected void zoom(XYPlot plot) { + protected void autoZoom(XYPlot plot) { logger.debug("Zoom to specified ranges."); - Range[] ranges = null; - - boolean x = zoomX(plot); - if (!x) { - XYDataset dataset = plot.getDataset(); - - ranges = getRangesForDataset(dataset); - - logger.debug("No x range specified. Set manually: " + ranges[0]); + Range xrange = getDomainAxisRange(); + Range yrange = getValueAxisRange(); - ValueAxis axis = plot.getDomainAxis(); - axis.setRange(ranges[0]); - } + for (int i = 0, num = plot.getDatasetCount(); i < num; i++) { + XYDataset dataset = plot.getDataset(i); + Range[] ranges = getRangesForDataset(dataset); - boolean y = zoomY(plot); - if (!y) { - XYDataset dataset = plot.getDataset(); - - if (ranges == null) { - ranges = getRangesForDataset(dataset); + if (i == 0) { + ValueAxis xaxis = plot.getDomainAxis(); + zoom(plot, xaxis, ranges[0], xrange); } - logger.debug("No y range specified. Set manually: " + ranges[1]); + ValueAxis yaxis = plot.getRangeAxis(i); - ValueAxis axis = plot.getRangeAxis(); - axis.setRange(ranges[1]); + if (yaxis == null) { + continue; + } + + zoom(plot, yaxis, ranges[1], yrange); } } @@ -158,42 +151,30 @@ * Zooms the x axis to the range specified in the attribute document. * * @param plot The XYPlot. + * @param axis The axis the shoud be modified. + * @param range The whole range specified by a dataset. + * @param x A user defined range (null permitted). * * @return true, if a zoom range was specified, otherwise false. */ - protected boolean zoomX(XYPlot plot) { - Range xrange = getDomainAxisRange(); - if (xrange != null) { - ValueAxis xaxis = plot.getDomainAxis(); - xaxis.setRange(xrange); + protected boolean zoom(XYPlot plot, ValueAxis axis, Range range, Range x) { + if (x != null) { + double min = range.getLowerBound(); + double max = range.getUpperBound(); + double diff = max > min ? max - min : min - max; - logger.debug("Zoom chart to X: " + xrange); + Range computed = new Range( + min + x.getLowerBound() * diff, + min + x.getUpperBound() * diff); + + axis.setRange(computed); + + logger.debug("Zoom axis to: " + computed); return true; } - return false; - } - - - /** - * Zooms the y axis to the range specified in the attribute document. - * - * @param plot The XYPlot. - * - * @return true, if a zoom range was specified, otherwise false. - */ - protected boolean zoomY(XYPlot plot) { - Range yrange = getValueAxisRange(); - if (yrange != null) { - ValueAxis yaxis = plot.getRangeAxis(); - yaxis.setRange(yrange); - - logger.debug("Zoom chart to Y: " + yrange); - - return true; - } - + axis.setRange(range); return false; } @@ -205,7 +186,7 @@ * * @return a Range[] as follows: [x-Range, y-Range]. */ - protected Range[] getRangesForDataset(XYDataset dataset) { + public static Range[] getRangesForDataset(XYDataset dataset) { double[] xr = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE }; double[] yr = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE };
--- a/flys-artifacts/src/main/resources/messages.properties Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/resources/messages.properties Wed Jun 15 15:28:54 2011 +0000 @@ -33,6 +33,8 @@ chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days] chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Waterlevel duration curve for {0} +chart.duration.curve.curve.q = Discharge duration curve for {0} export.waterlevel.csv.header.km = River-Km export.waterlevel.csv.header.w = W [NN + m]
--- a/flys-artifacts/src/main/resources/messages_de.properties Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/resources/messages_de.properties Wed Jun 15 15:28:54 2011 +0000 @@ -9,7 +9,7 @@ calc.flood.map = \u00dcberschwemmungsfl\u00e4che calc.discharge.curve = Abflusskurve/Abflusstafel calc.duration.curve = Dauerlinie -calc.discharge.longitudinal.section = W bei ungleichm\u00e4\u00dfigem Abflussl\u00e4ngsschnitt +calc.discharge.longitudinal.section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt river = Fluss calculation_mode = Berechnungsart @@ -33,6 +33,8 @@ chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage] chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0} +chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0} export.waterlevel.csv.header.km = Fluss-Km export.waterlevel.csv.header.w = W [NN + m]
--- a/flys-artifacts/src/main/resources/messages_de_DE.properties Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/resources/messages_de_DE.properties Wed Jun 15 15:28:54 2011 +0000 @@ -9,7 +9,7 @@ calc.flood.map = \u00dcberschwemmungsfl\u00e4che calc.discharge.curve = Abflusskurve/Abflusstafel calc.duration.curve = Dauerlinie -calc.discharge.longitudinal.section = W bei ungleichm\u00e4\u00dfigem Abflussl\u00e4ngsschnitt +calc.discharge.longitudinal.section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt river = Fluss calculation_mode = Berechnungsart @@ -33,6 +33,8 @@ chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage] chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0} +chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0} export.waterlevel.csv.header.km = Fluss-Km export.waterlevel.csv.header.w = W [NN + m]
--- a/flys-artifacts/src/main/resources/messages_en.properties Wed Jun 08 13:03:21 2011 +0000 +++ b/flys-artifacts/src/main/resources/messages_en.properties Wed Jun 15 15:28:54 2011 +0000 @@ -33,6 +33,8 @@ chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days] chart.duration.curve.yaxis.label = W [NN + m] +chart.duration.curve.curve.w = Waterlevel duration curve for {0} +chart.duration.curve.curve.q = Discharge duration curve for {0} export.waterlevel.csv.header.km = River-Km export.waterlevel.csv.header.w = W [NN + m]