# HG changeset patch # User Sascha L. Teichmann # Date 1306337485 0 # Node ID d08f77e7f7e8f5ed164582ee7cc492007b7db8ca # Parent 07640ab913fd5f238042a0b71c19c5562f0f4776 WST value table: Qs are now stored in ranges for each column. flys-artifacts/trunk@2006 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 07640ab913fd -r d08f77e7f7e8 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Tue May 24 14:46:45 2011 +0000 +++ b/flys-artifacts/ChangeLog Wed May 25 15:31:25 2011 +0000 @@ -1,3 +1,20 @@ +2011-05-25 Sascha L. Teichmann + + Qs are now stored in ranges for each column. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory2.java: + Deleted. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: + Was WstValueTableFactory2. + + * src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java: Fixed + node linking bug. Removed dead code. + + * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: + Q values are now stored in range trees by each column. The qs of the rows + are removed and the calculations are adjusted. Removed dead code. + 2011-05-24 Sascha L. Teichmann * src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java: diff -r 07640ab913fd -r d08f77e7f7e8 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java Tue May 24 14:46:45 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java Wed May 25 15:31:25 2011 +0000 @@ -2,16 +2,15 @@ import java.io.Serializable; -import java.math.BigDecimal; - import java.util.List; -import de.intevation.flys.model.WstQRange; -import de.intevation.flys.model.Range; +import org.apache.log4j.Logger; public class QRangeTree implements Serializable { + private static Logger log = Logger.getLogger(QRangeTree.class); + public static class Node implements Serializable { @@ -75,6 +74,7 @@ } public double findQ(double pos) { + Node current = this; for (;;) { if (pos < current.a) { @@ -82,7 +82,7 @@ current = current.left; continue; } - return current.left != null + return current.prev != null ? current.interpolatePrev(pos) : Double.NaN; } @@ -91,7 +91,7 @@ current = current.right; continue; } - return current.right != null + return current.next != null ? current.interpolateNext(pos) : Double.NaN; } @@ -106,27 +106,6 @@ } /** wstQRanges need to be sorted by range.a */ - public QRangeTree(List wstQRanges) { - - if (wstQRanges.isEmpty()) { - return; - } - - Node [] nodes = new Node[wstQRanges.size()]; - for (int i = 0; i < nodes.length; ++i) { - WstQRange wstQRange = wstQRanges.get(i); - Range range = wstQRange.getRange(); - BigDecimal a = range.getA(); - BigDecimal b = range.getB(); - nodes[i] = new Node( - a != null ? a.doubleValue() : -Double.MAX_VALUE, - b != null ? b.doubleValue() : Double.MAX_VALUE, - wstQRange.getQ().doubleValue()); - } - - root = wireTree(nodes); - } - public QRangeTree(List qRanges, int start, int stop) { if (stop <= start) { diff -r 07640ab913fd -r d08f77e7f7e8 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Tue May 24 14:46:45 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Wed May 25 15:31:25 2011 +0000 @@ -25,8 +25,8 @@ public static final int DEFAULT_Q_STEPS = 500; - public static class Column - implements Serializable + public static final class Column + implements Serializable { protected String name; @@ -54,32 +54,34 @@ public void setQRangeTree(QRangeTree qRangeTree) { this.qRangeTree = qRangeTree; } - } - // class Column + } // class Column - public static class QPosition { + public static final class QPosition { - protected double q; protected int index; protected double weight; public QPosition() { } - public QPosition(double q, int index, double weight) { + public QPosition(int index, double weight) { this.index = index; this.weight = weight; } + public QPosition set(int index, double weight) { + this.index = index; + this.weight = weight; + return this; + } + } // class Position - public static class Row - implements Serializable, Comparable + public static final class Row + implements Serializable, Comparable { double km; double [] ws; - double [] qs; - boolean qSorted; public Row() { } @@ -88,110 +90,9 @@ this.km = km; } - public Row(double km, double [] ws, double [] qs) { + public Row(double km, double [] ws) { this(km); this.ws = ws; - this.qs = qs; - } - - public static final double linear( - double x, - double x1, double x2, - double y1, double y2 - ) { - // y1 = m*x1 + b - // y2 = m*x2 + b - // y2 - y1 = m*(x2 - x1) - // m = (y2 - y1)/(x2 - x1) # x2 != x1 - // b = y1 - m*x1 - - if (x1 == x2) { - return 0.5*(y1 + y2); - } - double m = (y2 - y1)/(x2 - x1); - double b = y1 - m*x1; - return x*m + b; - } - - public static final double factor(double x, double p1, double p2) { - // 0 = m*p1 + b <=> b = -m*p1 - // 1 = m*p2 + b - // 1 = m*(p2 - p1) - // m = 1/(p2 - p1) # p1 != p2 - // f(x) = x/(p2-p1) - p1/(p2-p1) <=> (x-p1)/(p2-p1) - - return p1 == p2 ? 0.0 : (x-p1)/(p2-p1); - } - - public static final double weight(double factor, double a, double b) { - return (1.0-factor)*a + factor*b; - } - - public void interpolateW( - Row other, - double km, - double [] input, - double [] output - ) { - double factor = factor(km, this.km, other.km); - - for (int i = 0; i < input.length; ++i) { - double q = input[i]; - int idx1 = getQIndex(q); - int idx2 = other.getQIndex(q); - - double w1 = idx1 >= 0 - ? ws[idx1] - : interpolateW(-idx1-1, q); - - double w2 = idx2 >= 0 - ? other.ws[idx2] - : other.interpolateW(-idx2-1, q); - - output[i] = weight(factor, w1, w2); - } - } - - public double interpolateW(int idx, double q) { - return idx < 1 || idx >= qs.length - ? Double.NaN // do not extrapolate - : linear(q, qs[idx-1], qs[idx], ws[idx-1], ws[idx]); - } - - public double interpolateW(double q) { - if (Double.isNaN(q)) return Double.NaN; - int index = getQIndex(q); - return index >= 0 ? ws[index] : interpolateW(-index -1, q); - } - - public int getQIndex(double q) { - return qSorted ? binaryQIndex(q) : linearQIndex(q); - } - - public int binaryQIndex(double q) { - return Arrays.binarySearch(qs, q); - } - - public int linearQIndex(double q) { - switch (qs.length) { - case 0: break; - case 1: - if (qs[0] == q) return 0; - if (qs[0] < q) return -(1+1); - return -(0+1); - default: - for (int i = 1; i < qs.length; ++i) { - double qa = qs[i-1]; - double qb = qs[i]; - if (qa == q) return i-1; - if (qb == q) return i; - if (qa > qb) { double t = qa; qa = qb; qb = t; } - if (q > qa && q < qb) return -(i+1); - } - return -qs.length; - } - - return -1; } public int compareTo(Row other) { @@ -201,8 +102,35 @@ return 0; } - public double [][] interpolateWQ(Row other, double km, int steps) { + public void interpolateW( + Row other, + double km, + double [] iqs, + double [] ows, + WstValueTable table + ) { + double kmWeight = factor(km, this.km, other.km); + QPosition qPosition = new QPosition(); + + for (int i = 0; i < iqs.length; ++i) { + if (table.getQPosition(km, iqs[i], qPosition) != null) { + double wt = getW(qPosition); + double wo = other.getW(qPosition); + ows[i] = weight(kmWeight, wt, wo); + } + else { + ows[i] = Double.NaN; + } + } + } + + public double [][] interpolateWQ( + Row other, + double km, + int steps, + WstValueTable table + ) { int W = Math.min(ws.length, other.ws.length); if (W < 1) { @@ -219,7 +147,11 @@ for (int i = 0; i < W; ++i) { double wws = weight(factor, ws[i], other.ws[i]); - double wqs = weight(factor, qs[i], other.qs[i]); + double wqs = weight( + factor, + table.getQIndex(i, km), + table.getQIndex(i, other.km)); + splineW[i] = wws; splineQ[i] = wqs; if (wqs < minQ) minQ = wqs; @@ -248,7 +180,7 @@ return new double [][] { outWs, outQs }; } - public double [][] interpolateWQ(int steps) { + public double [][] interpolateWQ(int steps, WstValueTable table) { int W = ws.length; @@ -256,17 +188,17 @@ return new double[2][0]; } - double [] splineW = new double[W]; double [] splineQ = new double[W]; double minQ = Double.MAX_VALUE; double maxQ = -Double.MAX_VALUE; + QPosition qPosition = new QPosition(); + for (int i = 0; i < W; ++i) { - splineW[i] = ws[i]; - splineQ[i] = qs[i]; - if (qs[i] < minQ) minQ = qs[i]; - if (qs[i] > maxQ) maxQ = qs[i]; + splineQ[i] = table.getQIndex(i, km); + if (splineQ[i] < minQ) minQ = splineQ[i]; + if (splineQ[i] > maxQ) maxQ = splineQ[i]; } double stepWidth = (maxQ - minQ)/steps; @@ -274,7 +206,7 @@ SplineInterpolator interpolator = new SplineInterpolator(); PolynomialSplineFunction spline = - interpolator.interpolate(splineQ, splineW); + interpolator.interpolate(splineQ, ws); double [] outWs = new double[steps]; double [] outQs = new double[steps]; @@ -292,153 +224,40 @@ return new double [][] { outWs, outQs }; } - public QPosition getQPosition(double q) { - int qIndex = getQIndex(q); - - if (qIndex >= 0) { - // direct column match - return new QPosition(q, qIndex, 1.0); - } - qIndex = -qIndex -1; + public double getW(QPosition qPosition) { + int index = qPosition.index; + double weight = qPosition.weight; - if (qIndex < 0 || qIndex >= qs.length-1) { - // do not extrapolate - return null; - } - - return new QPosition( - q, qIndex, factor(q, qs[qIndex-1], qs[qIndex])); + return weight == 1.0 + ? ws[index] + : weight(weight, ws[index-1], ws[index]); } - public QPosition getQPosition(Row other, double km, double q) { - - QPosition qpt = getQPosition(q); - QPosition qpo = other.getQPosition(q); - - if (qpt == null || qpo == null) { - return null; - } - - double kmWeight = factor(km, this.km, other.km); - - // XXX: Index interpolation is a bit sticky here! - - int index = (int)Math.round( - weight(kmWeight, qpt.index, qpo.index)); - - double weight = weight(kmWeight, qpt.weight, qpo.weight); - - return new QPosition(q, index, weight); - } - - public void storeWQ( - QPosition qPosition, - double [] ows, - double [] oqs, - int index - ) { - int qIdx = qPosition.index; - double qWeight = qPosition.weight; - - if (qWeight == 1.0) { - oqs[index] = qs[qIdx]; - ows[index] = ws[qIdx]; - } - else { - oqs[index] = weight(qWeight, qs[qIdx-1], qs[qIdx]); - ows[index] = weight(qWeight, ws[qIdx-1], ws[qIdx]); - } - } - - public void storeWQ( + public double getW( Row other, double km, - QPosition qPosition, - double [] ows, - double [] oqs, - int index + QPosition qPosition ) { double kmWeight = factor(km, this.km, other.km); - double tq, tw; - double oq, ow; + int index = qPosition.index; + double weight = qPosition.weight; - int qIdx = qPosition.index; - double qWeight = qPosition.weight; + double tw, ow; - if (qWeight == 1.0) { - tq = qs[qIdx]; - tw = ws[qIdx]; - oq = other.qs[qIdx]; - ow = other.ws[qIdx]; + if (weight == 1.0) { + tw = ws[index]; + ow = other.ws[index]; } else { - tq = weight(qWeight, qs[qIdx-1], qs[qIdx]); - tw = weight(qWeight, ws[qIdx-1], ws[qIdx]); - oq = weight(qWeight, other.qs[qIdx-1], other.qs[qIdx]); - ow = weight(qWeight, other.ws[qIdx-1], other.ws[qIdx]); + tw = weight(weight, ws[index-1], ws[index]); + ow = weight(weight, other.ws[index-1], other.ws[index]); } - oqs[index] = weight(kmWeight, tq, oq); - ows[index] = weight(kmWeight, tw, ow); - } - - public void storeWQ( - QPosition qPosition, - LinearRemap remap, - double [] ows, - double [] oqs, - int index - ) { - int qIdx = qPosition.index; - double qWeight = qPosition.weight; - - oqs[index] = remap.eval(km, qWeight == 1.0 - ? qs[qIdx] - : weight(qWeight, qs[qIdx-1], qs[qIdx])); - - ows[index] = interpolateW(oqs[index]); + return weight(kmWeight, tw, ow); } - - public void storeWQ( - Row other, - double km, - QPosition qPosition, - LinearRemap remap, - double [] ows, - double [] oqs, - int index - ) { - double kmWeight = factor(km, this.km, other.km); - - double tq, tw; - double oq, ow; - - int qIdx = qPosition.index; - double qWeight = qPosition.weight; - - if (qWeight == 1.0) { - tq = remap.eval(this.km, qs[qIdx]); - oq = remap.eval(other.km, other.qs[qIdx]); - } - else { - tq = remap.eval( - this.km, - weight(qWeight, qs[qIdx-1], qs[qIdx])); - oq = remap.eval( - other.km, - weight(qWeight, other.qs[qIdx-1], other.qs[qIdx])); - } - - tw = interpolateW(tq); - ow = other.interpolateW(oq); - - oqs[index] = weight(kmWeight, tq, oq); - ows[index] = weight(kmWeight, tw, ow); - } - } - // class Row + } // class Row protected List rows; @@ -453,23 +272,27 @@ this.columns = columns; } + public WstValueTable(Column [] columns, List rows) { + this.columns = columns; + this.rows = rows; + } + public void sortRows() { Collections.sort(rows); } - - public double [] interpolateW(double km, double [] qs) { - return interpolateW(km, qs, new double[qs.length]); - } - public double [] interpolateW(double km, double [] qs, double [] ws) { int rowIndex = Collections.binarySearch(rows, new Row(km)); + QPosition qPosition = new QPosition(); + if (rowIndex >= 0) { // direct row match Row row = rows.get(rowIndex); for (int i = 0; i < qs.length; ++i) { - ws[i] = row.interpolateW(qs[i]); + ws[i] = getQPosition(km, qs[i], qPosition) != null + ? row.getW(qPosition) + : Double.NaN; } } else { // needs bilinear interpolation @@ -480,16 +303,15 @@ Arrays.fill(ws, Double.NaN); } else { - rows.get(rowIndex-1).interpolateW( - rows.get(rowIndex), - km, qs, ws); + Row r1 = rows.get(rowIndex-1); + Row r2 = rows.get(rowIndex); + r1.interpolateW(r2, km, qs, ws, this); } } return ws; } - public double [][] interpolateWQ(double km) { return interpolateWQ(km, DEFAULT_Q_STEPS); } @@ -500,7 +322,7 @@ if (rowIndex >= 0) { // direct row match Row row = rows.get(rowIndex); - return row.interpolateWQ(steps); + return row.interpolateWQ(steps, this); } rowIndex = -rowIndex -1; @@ -513,7 +335,7 @@ Row r1 = rows.get(rowIndex-1); Row r2 = rows.get(rowIndex); - return r1.interpolateWQ(r2, km, steps); + return r1.interpolateWQ(r2, km, steps, this); } public void interpolate( @@ -526,13 +348,24 @@ int R1 = rows.size()-1; Row kmKey = new Row(); + + QPosition nPosition = new QPosition(); + for (int i = 0; i < kms.length; ++i) { kmKey.km = kms[i]; + + qs[i] = remap.eval(kms[i], getQ(qPosition, kms[i])); + + if (getQPosition(kms[i], qs[i], nPosition) == null) { + ws[i] = Double.NaN; + continue; + } + int rowIndex = Collections.binarySearch(rows, kmKey); if (rowIndex >= 0) { // direct row match - rows.get(rowIndex).storeWQ(qPosition, remap, ws, qs, i); + ws[i] = rows.get(rowIndex).getW(nPosition); continue; } @@ -540,12 +373,12 @@ if (rowIndex < 1 || rowIndex >= R1) { // do not extrapolate - ws[i] = qs[i] = Double.NaN; + ws[i] = Double.NaN; continue; } Row r1 = rows.get(rowIndex-1); Row r2 = rows.get(rowIndex); - r1.storeWQ(r2, kms[i], qPosition, remap, ws, qs, i); + ws[i] = r1.getW(r2, kms[i], nPosition); } } @@ -562,28 +395,10 @@ int R1 = rows.size()-1; - QPosition qPosition = null; - - if (rowIndex >= 0) { // direct row match - qPosition = rows.get(rowIndex).getQPosition(q); - } - else { - rowIndex = -rowIndex -1; - - if (rowIndex < 1 || rowIndex >= R1) { - // do not extrapolate - return null; - } - - // interpolation case - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); - - qPosition = r1.getQPosition(r2, kms[referenceIndex], q); - } + QPosition qPosition = getQPosition(kms[referenceIndex], q); if (qPosition == null) { - // we cannot locate q in reference row + // we cannot locate q at km return null; } @@ -592,9 +407,11 @@ rowIndex = Collections.binarySearch(rows, kmKey); + qs[i] = getQ(qPosition, kms[i]); + if (rowIndex >= 0) { // direct row match - rows.get(rowIndex).storeWQ(qPosition, ws, qs, i); + ws[i] = rows.get(rowIndex).getW(qPosition); continue; } @@ -602,15 +419,102 @@ if (rowIndex < 1 || rowIndex >= R1) { // do not extrapolate - ws[i] = qs[i] = Double.NaN; + ws[i] = Double.NaN; continue; } Row r1 = rows.get(rowIndex-1); Row r2 = rows.get(rowIndex); - r1.storeWQ(r2, kms[i], qPosition, ws, qs, i); + + ws[i] = r1.getW(r2, kms[i], qPosition); } return qPosition; } + + public QPosition getQPosition(double km, double q) { + return getQPosition(km, q, new QPosition()); + } + + public QPosition getQPosition(double km, double q, QPosition qPosition) { + + if (columns.length == 0) { + return null; + } + + double qLast = columns[0].getQRangeTree().findQ(km); + + if (Math.abs(qLast - q) < 0.00001) { + return qPosition.set(0, 1d); + } + + for (int i = 1; i < columns.length; ++i) { + double qCurrent = columns[i].getQRangeTree().findQ(km); + if (Math.abs(qCurrent - q) < 0.00001) { + return qPosition.set(i, 1d); + } + + double qMin, qMax; + if (qLast < qCurrent) { qMin = qLast; qMax = qCurrent; } + else { qMin = qCurrent; qMax = qLast; } + + if (q > qMin && q < qMax) { + double weight = factor(q, qLast, qCurrent); + return qPosition.set(i, weight); + } + qLast = qCurrent; + } + + return null; + } + + public double getQIndex(int index, double km) { + return columns[index].getQRangeTree().findQ(km); + } + + public double getQ(QPosition qPosition, double km) { + int index = qPosition.index; + double weight = qPosition.weight; + + if (weight == 1d) { + return columns[index].getQRangeTree().findQ(km); + } + double q1 = columns[index-1].getQRangeTree().findQ(km); + double q2 = columns[index ].getQRangeTree().findQ(km); + return weight(weight, q1, q2); + } + + public static final double linear( + double x, + double x1, double x2, + double y1, double y2 + ) { + // y1 = m*x1 + b + // y2 = m*x2 + b + // y2 - y1 = m*(x2 - x1) + // m = (y2 - y1)/(x2 - x1) # x2 != x1 + // b = y1 - m*x1 + + if (x1 == x2) { + return 0.5*(y1 + y2); + } + double m = (y2 - y1)/(x2 - x1); + double b = y1 - m*x1; + return x*m + b; + } + + public static final double factor(double x, double p1, double p2) { + // 0 = m*p1 + b <=> b = -m*p1 + // 1 = m*p2 + b + // 1 = m*(p2 - p1) + // m = 1/(p2 - p1) # p1 != p2 + // f(x) = x/(p2-p1) - p1/(p2-p1) <=> (x-p1)/(p2-p1) + + return p1 == p2 ? 0.0 : (x-p1)/(p2-p1); + } + + public static final double weight(double factor, double a, double b) { + //return (1.0-factor)*a + factor*b; + return a + factor*(b-a); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 07640ab913fd -r d08f77e7f7e8 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java Tue May 24 14:46:45 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java Wed May 25 15:31:25 2011 +0000 @@ -1,9 +1,19 @@ package de.intevation.flys.artifacts.model; +import java.util.List; import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Collections; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.Element; + +import de.intevation.flys.artifacts.cache.CacheFactory; + +import de.intevation.flys.backend.SessionHolder; + +import org.apache.log4j.Logger; + +import de.intevation.flys.model.River; +import de.intevation.flys.model.Wst; import org.hibernate.Session; import org.hibernate.Query; @@ -11,34 +21,34 @@ import org.hibernate.type.StandardBasicTypes; -import net.sf.ehcache.Cache; -import net.sf.ehcache.Element; - -import org.apache.log4j.Logger; - -import de.intevation.flys.model.River; -import de.intevation.flys.model.Wst; -import de.intevation.flys.model.WstColumn; - -import de.intevation.flys.artifacts.cache.CacheFactory; - -import de.intevation.flys.backend.SessionHolder; - public class WstValueTableFactory { private static Logger log = Logger.getLogger(WstValueTableFactory.class); + public static final int DEFAULT_KIND = 0; + // TODO: put this into a property file - public static final String SQL_POS_WQ = - "SELECT position, w, q, column_pos" + - " FROM wst_value_table" + - " WHERE wst_id = :wst_id"; + + public static final String HQL_WST = + "from Wst where river=:river and kind=:kind"; + + public static final String SQL_SELECT_NAMES_POS = + "SELECT position, name FROM wst_columns " + + "WHERE wst_id = :wst_id ORDER BY position"; + + public static final String SQL_SELECT_QS = + "SELECT column_pos, q, a, b FROM wst_q_values " + + "WHERE wst_id = :wst_id"; + + public static final String SQL_SELECT_WS = + "SELECT km, w, column_pos FROM wst_w_values " + + "WHERE wst_id = :wst_id"; private WstValueTableFactory() { } public static WstValueTable getTable(River river) { - return getTable(river, 0); + return getTable(river, DEFAULT_KIND); } public static WstValueTable getTable(River river, int kind) { @@ -70,99 +80,165 @@ return valueTable; } + public static WstValueTable getTableUncached(River river) { + return getTableUncached(river, DEFAULT_KIND); + } + public static WstValueTable getTableUncached(River river, int kind) { Session session = SessionHolder.HOLDER.get(); - Query query = session.createQuery( - "from Wst where river=:river and kind=:kind"); + Wst wst = loadWst(session, river, kind); + + if (wst == null) { + return null; + } + + WstValueTable.Column [] columns = loadColumns(session, wst); + + loadQRanges(session, columns, wst); + + List rows = loadRows(session, wst, columns.length); + + return new WstValueTable(columns, rows); + } + + protected static Wst loadWst(Session session, River river, int kind) { + Query query = session.createQuery(HQL_WST); query.setParameter("river", river); query.setInteger("kind", kind); List wsts = query.list(); - if (wsts.isEmpty()) { - return null; - } - - Wst wst = wsts.get(0); + return wsts.isEmpty() ? null : wsts.get(0); + } - // TODO: Do this sorting at database level - List wstColumns = new ArrayList(wst.getColumns()); - Collections.sort(wstColumns, new Comparator() { - public int compare(WstColumn a, WstColumn b) { - int pa = a.getPosition(); - int pb = b.getPosition(); - if (pa < pb) return -1; - if (pa > pb) return +1; - return 0; - } - }); - - WstValueTable.Column [] columns = - new WstValueTable.Column[wstColumns.size()]; - - for (int i = 0; i < columns.length; ++i) { - columns[i] = new WstValueTable.Column(wstColumns.get(i).getName()); - } - - // using native SQL here to avoid myriad of small objects. - SQLQuery sqlQuery = session.createSQLQuery(SQL_POS_WQ) - .addScalar("position", StandardBasicTypes.DOUBLE) + protected static List loadRows( + Session session, + Wst wst, + int numColumns + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_WS) + .addScalar("km", StandardBasicTypes.DOUBLE) .addScalar("w", StandardBasicTypes.DOUBLE) - .addScalar("q", StandardBasicTypes.DOUBLE) .addScalar("column_pos", StandardBasicTypes.INTEGER); sqlQuery.setInteger("wst_id", wst.getId()); - WstValueTable valueTable = new WstValueTable(columns); - - int lastColumnNo = -1; - WstValueTable.Row row = null; - - Double lastQ = -Double.MAX_VALUE; - boolean qSorted = true; - - for (Object r: sqlQuery.list()) { - Object[] result = (Object[]) r; + List results = sqlQuery.list(); - double km = (Double) result[0]; - Double w = (Double) result[1]; - Double q = (Double) result[2]; - int columnNo = (Integer)result[3]; + int lastColumn = Integer.MAX_VALUE; + double [] ws = null; - if (columnNo > lastColumnNo) { // new row - if (row != null) { - row.qSorted = qSorted; - valueTable.rows.add(row); - } - row = new WstValueTable.Row( - km, - new double[columnNo+1], - new double[columnNo+1]); - lastQ = -Double.MAX_VALUE; - qSorted = true; + ArrayList rows = new ArrayList(); + + for (Object [] result: results) { + int column = (Integer)result[2]; + if (column < lastColumn) { + ws = new double[numColumns]; + WstValueTable.Row row = + new WstValueTable.Row((Double)result[0], ws); + rows.add(row); + } + Double w = (Double)result[1]; + ws[column] = w != null ? w : Double.NaN; + lastColumn = column; + } + + rows.trimToSize(); + return rows; + } + + protected static WstValueTable.Column [] loadColumns( + Session session, + Wst wst + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_NAMES_POS) + .addScalar("position", StandardBasicTypes.INTEGER) + .addScalar("name", StandardBasicTypes.STRING); + + sqlQuery.setInteger("wst_id", wst.getId()); + + List columnNames = sqlQuery.list(); + + WstValueTable.Column [] columns = + new WstValueTable.Column[columnNames.size()]; + + for (int i = 0; i < columns.length; ++i) { + columns[i] = new WstValueTable.Column( + (String)columnNames.get(i)[1]); + } + return columns; + } + + protected static void loadQRanges( + Session session, + WstValueTable.Column [] columns, + Wst wst + ) { + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_QS) + .addScalar("column_pos", StandardBasicTypes.INTEGER) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("a", StandardBasicTypes.DOUBLE) + .addScalar("b", StandardBasicTypes.DOUBLE); + + sqlQuery.setInteger("wst_id", wst.getId()); + + List qRanges = sqlQuery.list(); + + int start = -1; + int Q = qRanges.size(); + Integer lastColumn = null; + + for (int i = 0; i < Q; ++i) { + Object [] qRange = qRanges.get(i); + Integer columnId = (Integer)qRange[0]; + if (lastColumn == null) { + lastColumn = columnId; + start = i; + } + else if (!lastColumn.equals(columnId)) { + QRangeTree qRangeTree = new QRangeTree(qRanges, start, i); + columns[lastColumn].setQRangeTree(qRangeTree); + lastColumn = columnId; + start = i; + } + } + + if (start != -1) { + QRangeTree qRangeTree = new QRangeTree(qRanges, start, Q); + columns[lastColumn].setQRangeTree(qRangeTree); + } + + /* This is debug code to visualize the q ranges trees + + java.io.PrintWriter out = null; + try { + out = new java.io.PrintWriter( + new java.io.FileWriter( + "/tmp/qranges" + System.currentTimeMillis() + ".dot")); + + out.println("graph \"Q ranges trees\" {"); + + for (int i = 0; i < columns.length; ++i) { + QRangeTree tree = columns[i].getQRangeTree(); + out.println(tree.toGraph()); } - row.ws[columnNo] = w != null ? w : Double.NaN; - row.qs[columnNo] = q != null ? q : Double.NaN; + out.println("}"); - if (qSorted && (q == null || lastQ > q)) { - qSorted = false; - } - lastQ = q; - - lastColumnNo = columnNo; + out.flush(); } - - if (row != null) { - valueTable.rows.add(row); + catch (java.io.IOException ioe) { + log.error(ioe); } + finally { + if (out != null) { + out.close(); + } + } + */ + } - // XXX: should not be necessary - valueTable.sortRows(); - - return valueTable; - } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 07640ab913fd -r d08f77e7f7e8 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory2.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory2.java Tue May 24 14:46:45 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -package de.intevation.flys.artifacts.model; - -import java.util.List; - -import net.sf.ehcache.Cache; -import net.sf.ehcache.Element; - -import de.intevation.flys.artifacts.cache.CacheFactory; - -import de.intevation.flys.backend.SessionHolder; - -import org.apache.log4j.Logger; - -import de.intevation.flys.model.River; -import de.intevation.flys.model.Wst; - -import org.hibernate.Session; -import org.hibernate.Query; -import org.hibernate.SQLQuery; - -import org.hibernate.type.StandardBasicTypes; - -public class WstValueTableFactory2 -{ - private static Logger log = Logger.getLogger(WstValueTableFactory2.class); - - public static final int DEFAULT_KIND = 0; - - // TODO: put this into a property file - - public static final String HQL_WST = - "from Wst where river=:river and kind=:kind"; - - public static final String SQL_SELECT_NAMES_POS = - "SELECT position, name FROM wst_columns " + - "WHERE wst_id = :wst_id ORDER BY position"; - - public static final String SQL_SELECT_QS = - "SELECT column_pos, q, a, b FROM wst_q_values " + - "WHERE wst_id = :wst_id"; - - public static final String SQL_SELECT_WS = - "SELECT km, w, column_pos FROM wst_w_values " + - "WHERE wst_id = :wst_id"; - - private WstValueTableFactory2() { - } - - public static WstValueTable getTable(River river) { - return getTable(river, DEFAULT_KIND); - } - - public static WstValueTable getTable(River river, int kind) { - - Cache cache = CacheFactory.getCache(WstValueTableCacheKey.CACHE_NAME); - - WstValueTableCacheKey cacheKey; - - if (cache != null) { - cacheKey = new WstValueTableCacheKey(river.getId(), kind); - Element element = cache.get(cacheKey); - if (element != null) { - log.debug("got wst value table from cache"); - return (WstValueTable)element.getValue(); - } - } - else { - cacheKey = null; - } - - WstValueTable valueTable = getTableUncached(river, kind); - - if (valueTable != null && cacheKey != null) { - log.debug("store wst value table in cache"); - Element element = new Element(cacheKey, valueTable); - cache.put(element); - } - - return valueTable; - } - - public static WstValueTable getTableUncached(River river) { - return getTableUncached(river, DEFAULT_KIND); - } - - public static WstValueTable getTableUncached(River river, int kind) { - - Session session = SessionHolder.HOLDER.get(); - - Query query = session.createQuery(HQL_WST); - query.setParameter("river", river); - query.setInteger("kind", kind); - - List wsts = query.list(); - - if (wsts.isEmpty()) { - return null; - } - - Wst wst = wsts.get(0); - - SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_NAMES_POS) - .addScalar("position", StandardBasicTypes.INTEGER) - .addScalar("name", StandardBasicTypes.STRING); - - sqlQuery.setInteger("wst_id", wst.getId()); - - List columnNames = sqlQuery.list(); - - WstValueTable.Column [] columns = - new WstValueTable.Column[columnNames.size()]; - - for (int i = 0; i < columns.length; ++i) { - columns[i] = new WstValueTable.Column( - (String)columnNames.get(i)[1]); - } - - sqlQuery = session.createSQLQuery(SQL_SELECT_QS) - .addScalar("column_pos", StandardBasicTypes.INTEGER) - .addScalar("q", StandardBasicTypes.DOUBLE) - .addScalar("a", StandardBasicTypes.DOUBLE) - .addScalar("b", StandardBasicTypes.DOUBLE); - - sqlQuery.setInteger("wst_id", wst.getId()); - - Integer lastColumn = null; - - List qRanges = sqlQuery.list(); - int start = -1; - - int Q = qRanges.size(); - - for (int i = 0; i < Q; ++i) { - Object [] qRange = qRanges.get(i); - Integer columnId = (Integer)qRange[0]; - if (lastColumn == null) { - lastColumn = columnId; - start = i; - } - else if (!lastColumn.equals(columnId)) { - QRangeTree qRangeTree = new QRangeTree(qRanges, start, i); - columns[lastColumn].setQRangeTree(qRangeTree); - lastColumn = columnId; - start = i; - } - } - - if (start != -1) { - QRangeTree qRangeTree = new QRangeTree(qRanges, start, Q); - columns[lastColumn].setQRangeTree(qRangeTree); - } - - /* This is debug code to visualize the q ranges trees - - java.io.PrintWriter out = null; - try { - out = new java.io.PrintWriter( - new java.io.FileWriter( - "/tmp/qranges" + System.currentTimeMillis() + ".dot")); - - out.println("graph \"Q ranges trees\" {"); - - for (int i = 0; i < columns.length; ++i) { - QRangeTree tree = columns[i].getQRangeTree(); - out.println(tree.toGraph()); - } - - out.println("}"); - - out.flush(); - } - catch (java.io.IOException ioe) { - log.error(ioe); - } - finally { - if (out != null) { - out.close(); - } - } - */ - // TODO: Implement me! - - return null; - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :