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 :

http://dive4elements.wald.intevation.org