comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java @ 3318:dbe2f85bf160

merged flys-artifacts/2.8
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:35 +0200
parents b2ea89a665bc
children 1d9c9a3493ea
comparison
equal deleted inserted replaced
2987:98c7a46ec5ae 3318:dbe2f85bf160
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 :

http://dive4elements.wald.intevation.org