Mercurial > dive4elements > river
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 : |