Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java @ 1190:f514894ec2fd
merged flys-artifacts/2.5
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:17 +0200 |
parents | db68806e6563 |
children | 6b0ae0f2cae6 |
comparison
equal
deleted
inserted
replaced
917:b48c36076e17 | 1190:f514894ec2fd |
---|---|
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 protected Map<String, double [][]> loadValues(double scale) { | |
95 Map<String, double [][]> values = new HashMap<String, double [][]>(); | |
96 | |
97 Session session = SessionHolder.HOLDER.get(); | |
98 | |
99 Query gaugeQuery = session.createQuery( | |
100 "from Gauge where name=:gauge and river.name=:river"); | |
101 gaugeQuery.setParameter("river", riverName); | |
102 | |
103 for (String gaugeName: gaugeNames) { | |
104 gaugeQuery.setParameter("gauge", gaugeName); | |
105 List<Gauge> gauges = gaugeQuery.list(); | |
106 if (gauges.isEmpty()) { | |
107 log.warn( | |
108 "no gauge '"+gaugeName+"' at river '"+riverName+"'"); | |
109 continue; | |
110 } | |
111 Gauge gauge = gauges.get(0); | |
112 | |
113 List<DischargeTable> tables = gauge.getDischargeTables(); | |
114 | |
115 if (tables.isEmpty()) { | |
116 log.warn( | |
117 "no discharge table for gauge '" + gaugeName + "'"); | |
118 continue; | |
119 } | |
120 | |
121 // TODO: Filter by time interval | |
122 DischargeTable table = tables.get(0); | |
123 | |
124 List<DischargeTableValue> dtvs = | |
125 table.getDischargeTableValues(); | |
126 | |
127 final double [][] vs = new double[2][dtvs.size()]; | |
128 | |
129 boolean qSorted = true; | |
130 | |
131 double lastQ = -Double.MAX_VALUE; | |
132 | |
133 int idx = 0; | |
134 for (DischargeTableValue dtv: dtvs) { | |
135 double q = dtv.getQ().doubleValue(); | |
136 vs[0][idx] = q * scale; | |
137 vs[1][idx] = dtv.getW().doubleValue() * scale; | |
138 ++idx; | |
139 | |
140 if (qSorted && lastQ > q) { | |
141 qSorted = false; | |
142 } | |
143 lastQ = q; | |
144 } | |
145 | |
146 if (!qSorted) { | |
147 log.debug("need to sort by q values"); | |
148 // TODO: Do this db level. | |
149 // XXX: This is so ugly :-( | |
150 Integer [] indices = new Integer[vs[0].length]; | |
151 for (int i = 0; i < indices.length; ++i) { | |
152 indices[i] = i; | |
153 } | |
154 | |
155 Arrays.sort(indices, new Comparator<Integer>() { | |
156 public int compare(Integer a, Integer b) { | |
157 double va = vs[1][a]; | |
158 double vb = vs[1][b]; | |
159 double d = va - vb; | |
160 if (d < 0.0) return -1; | |
161 if (d > 0.0) return +1; | |
162 return 0; | |
163 } | |
164 }); | |
165 | |
166 double [][] vs2 = new double[2][vs[0].length]; | |
167 for (int i = 0; i < indices.length; ++i) { | |
168 vs2[0][i] = vs[0][indices[i]]; | |
169 vs2[1][i] = vs[1][indices[i]]; | |
170 } | |
171 values.put(gaugeName, vs2); | |
172 } | |
173 else { | |
174 values.put(gaugeName, vs); | |
175 } | |
176 | |
177 } | |
178 | |
179 return values; | |
180 } | |
181 | |
182 public static double getQForW(double [][] values, double w) { | |
183 | |
184 boolean debug = log.isDebugEnabled(); | |
185 | |
186 if (debug) { | |
187 log.debug("calculating getQForW(" + w + ")"); | |
188 } | |
189 | |
190 int index = Arrays.binarySearch(values[1], w); | |
191 if (index >= 0) { | |
192 return values[0][index]; | |
193 } | |
194 | |
195 index = -index - 1; // insert position | |
196 | |
197 if (index < 1 || index >= values[0].length) { | |
198 // do not extraploate | |
199 if (debug) { | |
200 log.debug("we do not extrapolate: NaN"); | |
201 } | |
202 return Double.NaN; | |
203 } | |
204 | |
205 double w1 = values[1][index-1]; | |
206 double w2 = values[1][index ]; | |
207 double q1 = values[0][index-1]; | |
208 double q2 = values[0][index ]; | |
209 | |
210 // q1 = m*w1 + b | |
211 // q2 = m*w2 + b | |
212 // q2 - q1 = m*(w2 - w1) | |
213 // m = (q2 - q1)/(w2 - w1) # w2 != w1 | |
214 // b = q1 - m*w1 | |
215 | |
216 double q; | |
217 if (w1 == w2) { | |
218 q = 0.5*(q1 + q2); | |
219 if (debug) { | |
220 log.debug("same w1 and w1: " + w1); | |
221 } | |
222 } | |
223 else { | |
224 double m = (q2 - q1)/(w2 - w1); | |
225 double b = q1 - m*w1; | |
226 q = w*m + b; | |
227 } | |
228 if (debug) { | |
229 log.debug("Q(" + w + ") = " + q); | |
230 } | |
231 return q; | |
232 } | |
233 } | |
234 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |