sascha@146: package de.intevation.flys.artifacts.model; sascha@146: sascha@146: import java.util.List; sascha@146: import java.util.Map; sascha@146: import java.util.HashMap; sascha@146: import java.util.Arrays; sascha@329: import java.util.Comparator; sascha@146: sascha@146: import java.io.Serializable; sascha@146: sascha@146: import org.hibernate.Session; sascha@146: import org.hibernate.Query; sascha@146: sascha@146: import org.apache.log4j.Logger; sascha@146: ingo@315: import de.intevation.flys.backend.SessionHolder; sascha@146: import de.intevation.flys.model.Gauge; sascha@146: import de.intevation.flys.model.DischargeTable; sascha@146: import de.intevation.flys.model.DischargeTableValue; sascha@146: sascha@146: public class DischargeTables sascha@146: implements Serializable sascha@146: { sascha@329: private static Logger log = Logger.getLogger(DischargeTables.class); sascha@329: sascha@328: public static final double DEFAULT_SCALE = 100.0; sascha@328: sascha@328: public static final int MASTER = 0; sascha@328: sascha@329: public static final double EPSILON = 1e-5; sascha@329: sascha@329: public static Comparator Q_COMPARATOR = sascha@329: new Comparator() { sascha@329: public int compare(double [] a, double [] b) { sascha@329: double d = a[0] - b[0]; sascha@329: if (d < -EPSILON) return -1; sascha@329: if (d > +EPSILON) return +1; sascha@329: return 0; sascha@329: } sascha@329: }; sascha@146: sascha@146: protected List gaugeNames; sascha@146: sascha@146: protected String riverName; sascha@146: sascha@154: protected double scale; sascha@154: sascha@328: protected int kind; sascha@328: sascha@150: protected Map values; sascha@146: sascha@146: public DischargeTables() { sascha@146: } sascha@146: sascha@328: public DischargeTables(String riverName, String gaugeName) { sascha@328: this(riverName, gaugeName, MASTER); sascha@146: } sascha@146: sascha@328: public DischargeTables(String riverName, String gaugeName, int kind) { sascha@328: this(riverName, new String [] { gaugeName }, kind); sascha@328: } sascha@328: sascha@328: public DischargeTables(String riverName, String [] gaugeNames) { sascha@328: this(riverName, gaugeNames, MASTER); sascha@328: } sascha@328: sascha@328: public DischargeTables(String riverName, String [] gaugeNames, int kind) { sascha@328: this(riverName, Arrays.asList(gaugeNames), kind); sascha@328: } sascha@328: sascha@328: public DischargeTables( sascha@328: String riverName, sascha@328: List gaugeNames, sascha@328: int kind sascha@328: ) { sascha@154: scale = Double.NaN; sascha@328: this.kind = kind; sascha@146: this.riverName = riverName; sascha@146: this.gaugeNames = gaugeNames; sascha@146: } sascha@146: sascha@328: public double [][] getFirstTable() { sascha@328: return getFirstTable(DEFAULT_SCALE); sascha@328: } sascha@328: sascha@328: public double [][] getFirstTable(double scale) { sascha@328: Map values = getValues(scale); sascha@328: for (double [][] table: values.values()) { sascha@328: return table; sascha@328: } sascha@328: return null; sascha@328: } sascha@328: sascha@328: public Map getValues() { sascha@328: return getValues(DEFAULT_SCALE); sascha@328: } sascha@328: ingo@153: public Map getValues(double scale) { sascha@154: if (values == null || scale != this.scale) { ingo@153: values = loadValues(scale); sascha@154: this.scale = scale; sascha@146: } sascha@146: return values; sascha@146: } sascha@146: ingo@153: protected Map loadValues(double scale) { sascha@150: Map values = new HashMap(); sascha@146: sascha@311: Session session = SessionHolder.HOLDER.get(); sascha@146: sascha@311: Query gaugeQuery = session.createQuery( sascha@328: "from Gauge where name=:gauge and river.name=:river and kind=:kind"); sascha@311: gaugeQuery.setParameter("river", riverName); sascha@328: gaugeQuery.setInteger("kind", kind); sascha@146: sascha@311: for (String gaugeName: gaugeNames) { sascha@311: gaugeQuery.setParameter("gauge", gaugeName); sascha@311: List gauges = gaugeQuery.list(); sascha@311: if (gauges.isEmpty()) { sascha@311: log.warn( sascha@311: "no gauge '"+gaugeName+"' at river '"+riverName+"'"); sascha@311: continue; sascha@311: } sascha@311: Gauge gauge = gauges.get(0); sascha@146: sascha@311: List tables = gauge.getDischargeTables(); sascha@146: sascha@311: if (tables.isEmpty()) { sascha@311: log.warn( sascha@311: "no discharge table for gauge '" + gaugeName + "'"); sascha@311: continue; sascha@146: } sascha@146: sascha@311: // TODO: Filter by time interval sascha@311: DischargeTable table = tables.get(0); sascha@311: sascha@311: List dtvs = sascha@311: table.getDischargeTableValues(); sascha@311: sascha@311: double [][] vs = new double[2][dtvs.size()]; sascha@311: sascha@311: int idx = 0; sascha@311: for (DischargeTableValue dtv: dtvs) { sascha@311: vs[0][idx] = dtv.getQ().doubleValue() * scale; sascha@311: vs[1][idx] = dtv.getW().doubleValue() * scale; sascha@311: ++idx; sascha@311: } sascha@311: sascha@329: // TODO: Do this db level. sascha@329: Arrays.sort(vs, Q_COMPARATOR); sascha@329: sascha@311: values.put(gaugeName, vs); sascha@146: } sascha@311: sascha@311: return values; sascha@146: } sascha@329: sascha@329: public static boolean getWForQ( sascha@329: double [][] values, sascha@329: double q, sascha@329: double [] result sascha@329: ) { sascha@329: int index = Arrays.binarySearch(values, new double [] { q }, Q_COMPARATOR); sascha@329: if (index >= 0) { sascha@329: result[0] = values[1][index]; sascha@329: return true; sascha@329: } sascha@329: sascha@329: index = -index - 1; // insert position sascha@329: sascha@329: if (index == 0 || index+1 >= values.length) { sascha@329: // do not extraploate sascha@329: return false; sascha@329: } sascha@329: sascha@329: double q1 = values[index ][0]; sascha@329: double q2 = values[index+1][0]; sascha@329: double w1 = values[index ][1]; sascha@329: double w2 = values[index+1][1]; sascha@329: sascha@329: // w1 = m*q1 + b sascha@329: // w2 = m*q2 + b sascha@329: // w2 - w1 = m*(q2 - q1) sascha@329: // m = (w2 - w1)/(q2 - q1) # q2 != q1 sascha@329: // b = w1 - m*q1 sascha@329: sascha@329: if (q1 == q2) { sascha@329: result[0] = 0.5*(w1 + w2); sascha@329: } sascha@329: else { sascha@329: double m = (w2 - w1)/(q2 - q1); sascha@329: double b = w1 - m*q1; sascha@329: result[0] = q*m + b; sascha@329: } sascha@329: sascha@329: return true; sascha@329: } sascha@146: } sascha@146: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :