Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java @ 3468:f37e7e8907cb
merged flys-artifacts/2.8.1
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:39 +0200 |
parents | b2ea89a665bc |
children | 1d9c9a3493ea |
comparison
equal
deleted
inserted
replaced
3387:5ffad8bde8ad | 3468:f37e7e8907cb |
---|---|
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 | |
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 de.intevation.flys.backend.SessionHolder; | |
16 import de.intevation.flys.model.Gauge; | |
17 import de.intevation.flys.model.DischargeTable; | |
18 import de.intevation.flys.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 public static final double DEFAULT_SCALE = 100.0; | |
30 | |
31 public static final int MASTER = 0; | |
32 | |
33 protected List<String> gaugeNames; | |
34 | |
35 protected String riverName; | |
36 | |
37 protected double scale; | |
38 | |
39 protected int kind; | |
40 | |
41 protected Map<String, double [][]> values; | |
42 | |
43 public DischargeTables() { | |
44 } | |
45 | |
46 public DischargeTables(String riverName, String gaugeName) { | |
47 this(riverName, gaugeName, MASTER); | |
48 } | |
49 | |
50 public DischargeTables(String riverName, String gaugeName, int kind) { | |
51 this(riverName, new String [] { gaugeName }, kind); | |
52 } | |
53 | |
54 public DischargeTables(String riverName, String [] gaugeNames) { | |
55 this(riverName, gaugeNames, MASTER); | |
56 } | |
57 | |
58 public DischargeTables(String riverName, String [] gaugeNames, int kind) { | |
59 this(riverName, Arrays.asList(gaugeNames), kind); | |
60 } | |
61 | |
62 public DischargeTables( | |
63 String riverName, | |
64 List<String> gaugeNames, | |
65 int kind | |
66 ) { | |
67 scale = Double.NaN; | |
68 this.kind = kind; | |
69 this.riverName = riverName; | |
70 this.gaugeNames = gaugeNames; | |
71 } | |
72 | |
73 public double [][] getFirstTable() { | |
74 return getFirstTable(DEFAULT_SCALE); | |
75 } | |
76 | |
77 public double [][] getFirstTable(double scale) { | |
78 Map<String, double [][]> values = getValues(scale); | |
79 for (double [][] table: values.values()) { | |
80 return table; | |
81 } | |
82 return null; | |
83 } | |
84 | |
85 public Map<String, double [][]> getValues() { | |
86 return getValues(DEFAULT_SCALE); | |
87 } | |
88 | |
89 public Map<String, double [][]> getValues(double scale) { | |
90 if (values == null || scale != this.scale) { | |
91 values = loadValues(scale); | |
92 this.scale = scale; | |
93 } | |
94 return values; | |
95 } | |
96 | |
97 /** | |
98 * Returns mapping of gauge name to values. | |
99 */ | |
100 protected Map<String, double [][]> loadValues(double scale) { | |
101 Map<String, double [][]> values = new HashMap<String, double [][]>(); | |
102 | |
103 Session session = SessionHolder.HOLDER.get(); | |
104 | |
105 Query gaugeQuery = session.createQuery( | |
106 "from Gauge where name=:gauge and river.name=:river"); | |
107 gaugeQuery.setParameter("river", riverName); | |
108 | |
109 for (String gaugeName: gaugeNames) { | |
110 gaugeQuery.setParameter("gauge", gaugeName); | |
111 List<Gauge> gauges = gaugeQuery.list(); | |
112 if (gauges.isEmpty()) { | |
113 log.warn( | |
114 "no gauge '"+gaugeName+"' at river '"+riverName+"'"); | |
115 continue; | |
116 } | |
117 Gauge gauge = gauges.get(0); | |
118 | |
119 List<DischargeTable> tables = gauge.getDischargeTables(); | |
120 | |
121 if (tables.isEmpty()) { | |
122 log.warn( | |
123 "no discharge table for gauge '" + gaugeName + "'"); | |
124 continue; | |
125 } | |
126 | |
127 // TODO: Filter by time interval | |
128 DischargeTable table = tables.get(0); | |
129 | |
130 double [][] vs = loadDischargeTableValues(table, scale); | |
131 | |
132 values.put(gaugeName, vs); | |
133 } | |
134 | |
135 return values; | |
136 } | |
137 | |
138 | |
139 /** | |
140 * @param table The discharge table | |
141 * @param scale The scale factor to adjust W and Q values. | |
142 * | |
143 * @return the values of a discharge table. | |
144 */ | |
145 public static double[][] loadDischargeTableValues( | |
146 DischargeTable table, | |
147 double scale | |
148 ) { | |
149 List<DischargeTableValue> dtvs = table.getDischargeTableValues(); | |
150 | |
151 final double [][] vs = new double[2][dtvs.size()]; | |
152 | |
153 int idx = 0; | |
154 for (DischargeTableValue dtv: dtvs) { | |
155 double q = dtv.getQ().doubleValue(); | |
156 vs[0][idx] = q * scale; | |
157 vs[1][idx] = dtv.getW().doubleValue() * scale; | |
158 ++idx; | |
159 } | |
160 | |
161 return vs; | |
162 } | |
163 | |
164 private static final double EPSILON = 1e-5; | |
165 | |
166 private static final boolean epsEquals(double a, double b) { | |
167 return Math.abs(a - b) < EPSILON; | |
168 } | |
169 | |
170 private static final boolean between(double a, double b, double x) { | |
171 if (a > b) { double t = a; a = b; b = t; } | |
172 return x > a && x < b; | |
173 } | |
174 | |
175 public static double [] getQsForW(double [][] values, double w) { | |
176 | |
177 boolean debug = log.isDebugEnabled(); | |
178 | |
179 if (debug) { | |
180 log.debug("getQsForW: W = " + w); | |
181 } | |
182 | |
183 double [] qs = values[0]; | |
184 double [] ws = values[1]; | |
185 | |
186 int N = Math.min(qs.length, ws.length); | |
187 | |
188 if (N == 0) { | |
189 if (debug) { | |
190 log.debug("Q(" + w + ") = []"); | |
191 } | |
192 return new double [0]; | |
193 } | |
194 | |
195 TDoubleArrayList outQs = new TDoubleArrayList(); | |
196 | |
197 if (epsEquals(ws[0], w)) { | |
198 outQs.add(qs[0]); | |
199 } | |
200 | |
201 for (int i = 1; i < N; ++i) { | |
202 if (epsEquals(ws[i], w)) { | |
203 outQs.add(qs[i]); | |
204 } | |
205 else if (between(ws[i-1], ws[i], w)) { | |
206 double w1 = ws[i-1]; | |
207 double w2 = ws[i]; | |
208 double q1 = qs[i-1]; | |
209 double q2 = qs[i]; | |
210 | |
211 // q1 = m*w1 + b | |
212 // q2 = m*w2 + b | |
213 // q2 - q1 = m*(w2 - w1) | |
214 // m = (q2 - q1)/(w2 - w1) # w2 != w1 | |
215 // b = q1 - m*w1 | |
216 // w1 != w2 | |
217 | |
218 double m = (q2 - q1)/(w2 - w1); | |
219 double b = q1 - m*w1; | |
220 double q = w*m + b; | |
221 | |
222 outQs.add(q); | |
223 } | |
224 } | |
225 | |
226 double [] result = outQs.toNativeArray(); | |
227 | |
228 if (debug) { | |
229 log.debug("Q(" + w + ") = " + Arrays.toString(result)); | |
230 } | |
231 | |
232 return result; | |
233 } | |
234 } | |
235 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |