comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java @ 3814:8083f6384023

merged flys-artifacts/pre2.6-2012-01-04
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:56 +0200
parents 6b0ae0f2cae6
children 59af81364eb1
comparison
equal deleted inserted replaced
1491:2a00f4849738 3814:8083f6384023
1 package de.intevation.flys.artifacts.model;
2
3 import java.util.List;
4 import java.util.Map;
5 import java.util.HashMap;
6 import java.util.Arrays;
7 import java.util.Comparator;
8
9 import java.io.Serializable;
10
11 import org.hibernate.Session;
12 import org.hibernate.Query;
13
14 import org.apache.log4j.Logger;
15
16 import de.intevation.flys.backend.SessionHolder;
17 import de.intevation.flys.model.Gauge;
18 import de.intevation.flys.model.DischargeTable;
19 import de.intevation.flys.model.DischargeTableValue;
20
21 public class DischargeTables
22 implements Serializable
23 {
24 private static Logger log = Logger.getLogger(DischargeTables.class);
25
26 public static final double DEFAULT_SCALE = 100.0;
27
28 public static final int MASTER = 0;
29
30 protected List<String> gaugeNames;
31
32 protected String riverName;
33
34 protected double scale;
35
36 protected int kind;
37
38 protected Map<String, double [][]> values;
39
40 public DischargeTables() {
41 }
42
43 public DischargeTables(String riverName, String gaugeName) {
44 this(riverName, gaugeName, MASTER);
45 }
46
47 public DischargeTables(String riverName, String gaugeName, int kind) {
48 this(riverName, new String [] { gaugeName }, kind);
49 }
50
51 public DischargeTables(String riverName, String [] gaugeNames) {
52 this(riverName, gaugeNames, MASTER);
53 }
54
55 public DischargeTables(String riverName, String [] gaugeNames, int kind) {
56 this(riverName, Arrays.asList(gaugeNames), kind);
57 }
58
59 public DischargeTables(
60 String riverName,
61 List<String> gaugeNames,
62 int kind
63 ) {
64 scale = Double.NaN;
65 this.kind = kind;
66 this.riverName = riverName;
67 this.gaugeNames = gaugeNames;
68 }
69
70 public double [][] getFirstTable() {
71 return getFirstTable(DEFAULT_SCALE);
72 }
73
74 public double [][] getFirstTable(double scale) {
75 Map<String, double [][]> values = getValues(scale);
76 for (double [][] table: values.values()) {
77 return table;
78 }
79 return null;
80 }
81
82 public Map<String, double [][]> getValues() {
83 return getValues(DEFAULT_SCALE);
84 }
85
86 public Map<String, double [][]> getValues(double scale) {
87 if (values == null || scale != this.scale) {
88 values = loadValues(scale);
89 this.scale = scale;
90 }
91 return values;
92 }
93
94 /**
95 * Returns mapping of gauge name to values.
96 */
97 protected Map<String, double [][]> loadValues(double scale) {
98 Map<String, double [][]> values = new HashMap<String, double [][]>();
99
100 Session session = SessionHolder.HOLDER.get();
101
102 Query gaugeQuery = session.createQuery(
103 "from Gauge where name=:gauge and river.name=:river");
104 gaugeQuery.setParameter("river", riverName);
105
106 for (String gaugeName: gaugeNames) {
107 gaugeQuery.setParameter("gauge", gaugeName);
108 List<Gauge> gauges = gaugeQuery.list();
109 if (gauges.isEmpty()) {
110 log.warn(
111 "no gauge '"+gaugeName+"' at river '"+riverName+"'");
112 continue;
113 }
114 Gauge gauge = gauges.get(0);
115
116 List<DischargeTable> tables = gauge.getDischargeTables();
117
118 if (tables.isEmpty()) {
119 log.warn(
120 "no discharge table for gauge '" + gaugeName + "'");
121 continue;
122 }
123
124 // TODO: Filter by time interval
125 DischargeTable table = tables.get(0);
126
127 List<DischargeTableValue> dtvs =
128 table.getDischargeTableValues();
129
130 final double [][] vs = new double[2][dtvs.size()];
131
132 boolean qSorted = true;
133
134 double lastQ = -Double.MAX_VALUE;
135
136 int idx = 0;
137 for (DischargeTableValue dtv: dtvs) {
138 double q = dtv.getQ().doubleValue();
139 vs[0][idx] = q * scale;
140 vs[1][idx] = dtv.getW().doubleValue() * scale;
141 ++idx;
142
143 if (qSorted && lastQ > q) {
144 qSorted = false;
145 }
146 lastQ = q;
147 }
148
149 if (!qSorted) {
150 log.debug("need to sort by q values");
151 // TODO: Do this db level.
152 // XXX: This is so ugly :-(
153 Integer [] indices = new Integer[vs[0].length];
154 for (int i = 0; i < indices.length; ++i) {
155 indices[i] = i;
156 }
157
158 Arrays.sort(indices, new Comparator<Integer>() {
159 public int compare(Integer a, Integer b) {
160 double va = vs[1][a];
161 double vb = vs[1][b];
162 double d = va - vb;
163 if (d < 0.0) return -1;
164 if (d > 0.0) return +1;
165 return 0;
166 }
167 });
168
169 double [][] vs2 = new double[2][vs[0].length];
170 for (int i = 0; i < indices.length; ++i) {
171 vs2[0][i] = vs[0][indices[i]];
172 vs2[1][i] = vs[1][indices[i]];
173 }
174 values.put(gaugeName, vs2);
175 }
176 else {
177 values.put(gaugeName, vs);
178 }
179
180 }
181
182 return values;
183 }
184
185 public static double getQForW(double [][] values, double w) {
186
187 boolean debug = log.isDebugEnabled();
188
189 if (debug) {
190 log.debug("calculating getQForW(" + w + ")");
191 }
192
193 int index = Arrays.binarySearch(values[1], w);
194 if (index >= 0) {
195 return values[0][index];
196 }
197
198 index = -index - 1; // insert position
199
200 if (index < 1 || index >= values[0].length) {
201 // do not extraploate
202 if (debug) {
203 log.debug("we do not extrapolate: NaN");
204 }
205 return Double.NaN;
206 }
207
208 double w1 = values[1][index-1];
209 double w2 = values[1][index ];
210 double q1 = values[0][index-1];
211 double q2 = values[0][index ];
212
213 // q1 = m*w1 + b
214 // q2 = m*w2 + b
215 // q2 - q1 = m*(w2 - w1)
216 // m = (q2 - q1)/(w2 - w1) # w2 != w1
217 // b = q1 - m*w1
218
219 double q;
220 if (w1 == w2) {
221 q = 0.5*(q1 + q2);
222 if (debug) {
223 log.debug("same w1 and w2: " + w1);
224 }
225 }
226 else {
227 double m = (q2 - q1)/(w2 - w1);
228 double b = q1 - m*w1;
229 q = w*m + b;
230 }
231 if (debug) {
232 log.debug("Q(" + w + ") = " + q);
233 }
234 return q;
235 }
236 }
237 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org