comparison flys-artifacts/src/main/java/org/dive4elements/river/artifacts/model/DischargeTables.java @ 5831:bd047b71ab37

Repaired internal references
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 12:06:39 +0200
parents flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java@5f38d1c39ebd
children
comparison
equal deleted inserted replaced
5830:160f53ee0870 5831:bd047b71ab37
1 package org.dive4elements.river.artifacts.model;
2
3 import java.util.List;
4 import java.util.Map;
5 import java.util.HashMap;
6 import java.util.Arrays;
7
8 import java.io.Serializable;
9
10 import org.hibernate.Session;
11 import org.hibernate.Query;
12
13 import org.apache.log4j.Logger;
14
15 import org.dive4elements.river.backend.SessionHolder;
16 import org.dive4elements.river.model.Gauge;
17 import org.dive4elements.river.model.DischargeTable;
18 import org.dive4elements.river.model.DischargeTableValue;
19
20 import gnu.trove.TDoubleArrayList;
21
22 /** Documentation goes here. */
23 public class DischargeTables
24 implements Serializable
25 {
26 /** Private logger. */
27 private static Logger log = Logger.getLogger(DischargeTables.class);
28
29 /** Scale to convert discharge table values of master table into [cm]. */
30 public static final double MASTER_SCALE = 100d;
31
32 /** Scale to convert discharge table values of historical tables into [cm]. */
33 public static final double HISTORICAL_SCALE = 1d;
34
35 public static final int MASTER = 0;
36
37 protected List<String> gaugeNames;
38
39 protected String riverName;
40
41 protected double scale;
42
43 protected int kind;
44
45 protected Map<String, double [][]> values;
46
47 public DischargeTables() {
48 }
49
50 public DischargeTables(String riverName, String gaugeName) {
51 this(riverName, gaugeName, MASTER);
52 }
53
54 public DischargeTables(String riverName, String gaugeName, int kind) {
55 this(riverName, new String [] { gaugeName }, kind);
56 }
57
58 public DischargeTables(String riverName, String [] gaugeNames) {
59 this(riverName, gaugeNames, MASTER);
60 }
61
62 public DischargeTables(String riverName, String [] gaugeNames, int kind) {
63 this(riverName, Arrays.asList(gaugeNames), kind);
64 }
65
66 public DischargeTables(
67 String riverName,
68 List<String> gaugeNames,
69 int kind
70 ) {
71 scale = Double.NaN;
72 this.kind = kind;
73 this.riverName = riverName;
74 this.gaugeNames = gaugeNames;
75 }
76
77 public double [][] getFirstTable() {
78 return getFirstTable(MASTER_SCALE);
79 }
80
81 public double [][] getFirstTable(double scale) {
82 Map<String, double [][]> values = getValues(scale);
83 for (double [][] table: values.values()) {
84 return table;
85 }
86 return null;
87 }
88
89 public Map<String, double [][]> getValues() {
90 return getValues(MASTER_SCALE);
91 }
92
93 public Map<String, double [][]> getValues(double scale) {
94 if (values == null || scale != this.scale) {
95 values = loadValues(scale);
96 this.scale = scale;
97 }
98 return values;
99 }
100
101 /**
102 * Returns mapping of gauge name to values.
103 */
104 protected Map<String, double [][]> loadValues(double scale) {
105 Map<String, double [][]> values = new HashMap<String, double [][]>();
106
107 Session session = SessionHolder.HOLDER.get();
108
109 Query gaugeQuery = session.createQuery(
110 "from Gauge where name=:gauge and river.name=:river");
111 gaugeQuery.setParameter("river", riverName);
112
113 for (String gaugeName: gaugeNames) {
114 gaugeQuery.setParameter("gauge", gaugeName);
115 List<Gauge> gauges = gaugeQuery.list();
116 if (gauges.isEmpty()) {
117 log.warn(
118 "no gauge '"+gaugeName+"' at river '"+riverName+"'");
119 continue;
120 }
121 Gauge gauge = gauges.get(0);
122
123 List<DischargeTable> tables = gauge.getDischargeTables();
124
125 if (tables.isEmpty()) {
126 log.warn(
127 "no discharge table for gauge '" + gaugeName + "'");
128 continue;
129 }
130
131 // TODO: Filter by time interval
132 DischargeTable table = null;
133 for (DischargeTable dt : tables) {
134 if (dt.getKind() == 0) {
135 table = dt;
136 break;
137 }
138 }
139 if (table == null) {
140 table = tables.get(0);
141 }
142 double [][] vs = loadDischargeTableValues(table, scale);
143
144 values.put(gaugeName, vs);
145 }
146
147 return values;
148 }
149
150
151 /**
152 * @param table The discharge table
153 * @param scale The scale factor to adjust W and Q values.
154 *
155 * @return the values of a discharge table.
156 */
157 public static double[][] loadDischargeTableValues(
158 DischargeTable table,
159 double scale
160 ) {
161 List<DischargeTableValue> dtvs = table.getDischargeTableValues();
162
163 final double [][] vs = new double[2][dtvs.size()];
164
165 int idx = 0;
166 for (DischargeTableValue dtv: dtvs) {
167 double q = dtv.getQ().doubleValue();
168 vs[0][idx] = q * scale;
169 vs[1][idx] = dtv.getW().doubleValue() * scale;
170 ++idx;
171 }
172
173 return vs;
174 }
175
176 private static final double EPSILON = 1e-5;
177
178 private static final boolean epsEquals(double a, double b) {
179 return Math.abs(a - b) < EPSILON;
180 }
181
182 private static final boolean between(double a, double b, double x) {
183 if (a > b) { double t = a; a = b; b = t; }
184 return x > a && x < b;
185 }
186
187 /**
188 * Find or interpolate Qs from q/w array.
189 * @param values [[q0,q1,q2],[w0,w1,w2]]
190 * @param w W value to look for in values.
191 */
192 public static double [] getQsForW(double [][] values, double w) {
193
194 boolean debug = log.isDebugEnabled();
195
196 if (debug) {
197 log.debug("getQsForW: W = " + w);
198 }
199
200 double [] qs = values[0];
201 double [] ws = values[1];
202
203 int N = Math.min(qs.length, ws.length);
204
205 if (N == 0) {
206 if (debug) {
207 log.debug("Q(" + w + ") = []");
208 }
209 return new double [0];
210 }
211
212 TDoubleArrayList outQs = new TDoubleArrayList();
213
214 if (epsEquals(ws[0], w)) {
215 outQs.add(qs[0]);
216 }
217
218 for (int i = 1; i < N; ++i) {
219 if (epsEquals(ws[i], w)) {
220 outQs.add(qs[i]);
221 }
222 else if (between(ws[i-1], ws[i], w)) {
223 double w1 = ws[i-1];
224 double w2 = ws[i];
225 double q1 = qs[i-1];
226 double q2 = qs[i];
227
228 // q1 = m*w1 + b
229 // q2 = m*w2 + b
230 // q2 - q1 = m*(w2 - w1)
231 // m = (q2 - q1)/(w2 - w1) # w2 != w1
232 // b = q1 - m*w1
233 // w1 != w2
234
235 double m = (q2 - q1)/(w2 - w1);
236 double b = q1 - m*w1;
237 double q = w*m + b;
238
239 outQs.add(q);
240 }
241 }
242
243 double [] result = outQs.toNativeArray();
244
245 if (debug) {
246 log.debug("Q(" + w + ") = " + Arrays.toString(result));
247 }
248
249 return result;
250 }
251
252 public static double [] getWsForQ(double [][] values, double q) {
253
254 boolean debug = log.isDebugEnabled();
255
256 if (debug) {
257 log.debug("getWsForQ: W = " + q);
258 }
259
260 double [] qs = values[0];
261 double [] ws = values[1];
262
263 int N = Math.min(qs.length, ws.length);
264
265 if (N == 0) {
266 if (debug) {
267 log.debug("W(" + q + ") = []");
268 }
269 return new double [0];
270 }
271
272 TDoubleArrayList outWs = new TDoubleArrayList();
273
274 if (epsEquals(qs[0], q)) {
275 outWs.add(ws[0]);
276 }
277
278 for (int i = 1; i < N; ++i) {
279 if (epsEquals(qs[i], q)) {
280 outWs.add(ws[i]);
281 }
282 else if (between(qs[i-1], qs[i], q)) {
283 double w1 = ws[i-1];
284 double w2 = ws[i];
285 double q1 = qs[i-1];
286 double q2 = qs[i];
287
288 // w1 = m*q1 + b
289 // w2 = m*q2 + b
290 // w2 - w1 = m*(q2 - q1)
291 // m = (w2 - w1)/(q2 - q1) # q2 != q1
292 // b = w1 - m*q1
293 // q1 != q2
294
295 double m = (w2 - w1)/(q2 - q1);
296 double b = w1 - m*q1;
297 double w = q*m + b;
298
299 outWs.add(w);
300 }
301 }
302
303 double [] result = outWs.toNativeArray();
304
305 if (debug) {
306 log.debug("W(" + q + ") = " + Arrays.toString(result));
307 }
308
309 return result;
310 }
311 }
312 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org