Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java @ 3318:dbe2f85bf160
merged flys-artifacts/2.8
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:35 +0200 |
parents | b2ea89a665bc |
children | 1d9c9a3493ea |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java Fri Sep 28 12:14:35 2012 +0200 @@ -0,0 +1,235 @@ +package de.intevation.flys.artifacts.model; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; + +import java.io.Serializable; + +import org.hibernate.Session; +import org.hibernate.Query; + +import org.apache.log4j.Logger; + +import de.intevation.flys.backend.SessionHolder; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.DischargeTable; +import de.intevation.flys.model.DischargeTableValue; + +import gnu.trove.TDoubleArrayList; + +/** Documentation goes here. */ +public class DischargeTables +implements Serializable +{ + /** Private logger. */ + private static Logger log = Logger.getLogger(DischargeTables.class); + + public static final double DEFAULT_SCALE = 100.0; + + public static final int MASTER = 0; + + protected List<String> gaugeNames; + + protected String riverName; + + protected double scale; + + protected int kind; + + protected Map<String, double [][]> values; + + public DischargeTables() { + } + + public DischargeTables(String riverName, String gaugeName) { + this(riverName, gaugeName, MASTER); + } + + public DischargeTables(String riverName, String gaugeName, int kind) { + this(riverName, new String [] { gaugeName }, kind); + } + + public DischargeTables(String riverName, String [] gaugeNames) { + this(riverName, gaugeNames, MASTER); + } + + public DischargeTables(String riverName, String [] gaugeNames, int kind) { + this(riverName, Arrays.asList(gaugeNames), kind); + } + + public DischargeTables( + String riverName, + List<String> gaugeNames, + int kind + ) { + scale = Double.NaN; + this.kind = kind; + this.riverName = riverName; + this.gaugeNames = gaugeNames; + } + + public double [][] getFirstTable() { + return getFirstTable(DEFAULT_SCALE); + } + + public double [][] getFirstTable(double scale) { + Map<String, double [][]> values = getValues(scale); + for (double [][] table: values.values()) { + return table; + } + return null; + } + + public Map<String, double [][]> getValues() { + return getValues(DEFAULT_SCALE); + } + + public Map<String, double [][]> getValues(double scale) { + if (values == null || scale != this.scale) { + values = loadValues(scale); + this.scale = scale; + } + return values; + } + + /** + * Returns mapping of gauge name to values. + */ + protected Map<String, double [][]> loadValues(double scale) { + Map<String, double [][]> values = new HashMap<String, double [][]>(); + + Session session = SessionHolder.HOLDER.get(); + + Query gaugeQuery = session.createQuery( + "from Gauge where name=:gauge and river.name=:river"); + gaugeQuery.setParameter("river", riverName); + + for (String gaugeName: gaugeNames) { + gaugeQuery.setParameter("gauge", gaugeName); + List<Gauge> gauges = gaugeQuery.list(); + if (gauges.isEmpty()) { + log.warn( + "no gauge '"+gaugeName+"' at river '"+riverName+"'"); + continue; + } + Gauge gauge = gauges.get(0); + + List<DischargeTable> tables = gauge.getDischargeTables(); + + if (tables.isEmpty()) { + log.warn( + "no discharge table for gauge '" + gaugeName + "'"); + continue; + } + + // TODO: Filter by time interval + DischargeTable table = tables.get(0); + + double [][] vs = loadDischargeTableValues(table, scale); + + values.put(gaugeName, vs); + } + + return values; + } + + + /** + * @param table The discharge table + * @param scale The scale factor to adjust W and Q values. + * + * @return the values of a discharge table. + */ + public static double[][] loadDischargeTableValues( + DischargeTable table, + double scale + ) { + List<DischargeTableValue> dtvs = table.getDischargeTableValues(); + + final double [][] vs = new double[2][dtvs.size()]; + + int idx = 0; + for (DischargeTableValue dtv: dtvs) { + double q = dtv.getQ().doubleValue(); + vs[0][idx] = q * scale; + vs[1][idx] = dtv.getW().doubleValue() * scale; + ++idx; + } + + return vs; + } + + private static final double EPSILON = 1e-5; + + private static final boolean epsEquals(double a, double b) { + return Math.abs(a - b) < EPSILON; + } + + private static final boolean between(double a, double b, double x) { + if (a > b) { double t = a; a = b; b = t; } + return x > a && x < b; + } + + public static double [] getQsForW(double [][] values, double w) { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("getQsForW: W = " + w); + } + + double [] qs = values[0]; + double [] ws = values[1]; + + int N = Math.min(qs.length, ws.length); + + if (N == 0) { + if (debug) { + log.debug("Q(" + w + ") = []"); + } + return new double [0]; + } + + TDoubleArrayList outQs = new TDoubleArrayList(); + + if (epsEquals(ws[0], w)) { + outQs.add(qs[0]); + } + + for (int i = 1; i < N; ++i) { + if (epsEquals(ws[i], w)) { + outQs.add(qs[i]); + } + else if (between(ws[i-1], ws[i], w)) { + double w1 = ws[i-1]; + double w2 = ws[i]; + double q1 = qs[i-1]; + double q2 = qs[i]; + + // q1 = m*w1 + b + // q2 = m*w2 + b + // q2 - q1 = m*(w2 - w1) + // m = (q2 - q1)/(w2 - w1) # w2 != w1 + // b = q1 - m*w1 + // w1 != w2 + + double m = (q2 - q1)/(w2 - w1); + double b = q1 - m*w1; + double q = w*m + b; + + outQs.add(q); + } + } + + double [] result = outQs.toNativeArray(); + + if (debug) { + log.debug("Q(" + w + ") = " + Arrays.toString(result)); + } + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :