Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/WINFOArtifact.java @ 9425:3f49835a00c3
Extended CrossSectionFacet so it may fetch different data from within the artifact result.
Also allows to have acces to the potentially already computed artifact result via its normal computation cache.
author | gernotbelger |
---|---|
date | Fri, 17 Aug 2018 15:31:02 +0200 |
parents | f61bc0c63188 |
children | 2b83d3a96703 |
comparison
equal
deleted
inserted
replaced
9424:da19f1f58d72 | 9425:3f49835a00c3 |
---|---|
6 * documentation coming with Dive4Elements River for details. | 6 * documentation coming with Dive4Elements River for details. |
7 */ | 7 */ |
8 | 8 |
9 package org.dive4elements.river.artifacts; | 9 package org.dive4elements.river.artifacts; |
10 | 10 |
11 import java.io.Serializable; | |
12 import java.util.Arrays; | |
13 import java.util.Map; | |
14 | |
15 import org.apache.log4j.Logger; | |
11 import org.dive4elements.artifactdatabase.data.StateData; | 16 import org.dive4elements.artifactdatabase.data.StateData; |
12 | |
13 import org.dive4elements.artifactdatabase.state.Facet; | 17 import org.dive4elements.artifactdatabase.state.Facet; |
14 import org.dive4elements.artifactdatabase.state.FacetActivity; | 18 import org.dive4elements.artifactdatabase.state.FacetActivity; |
15 | |
16 import org.dive4elements.artifacts.Artifact; | 19 import org.dive4elements.artifacts.Artifact; |
17 import org.dive4elements.artifacts.CallContext; | 20 import org.dive4elements.artifacts.CallContext; |
18 | |
19 import org.dive4elements.artifacts.common.utils.StringUtils; | 21 import org.dive4elements.artifacts.common.utils.StringUtils; |
20 | |
21 import org.dive4elements.river.artifacts.access.Calculation4Access; | 22 import org.dive4elements.river.artifacts.access.Calculation4Access; |
23 import org.dive4elements.river.artifacts.access.ComputationRangeAccess; | |
22 import org.dive4elements.river.artifacts.access.RangeAccess; | 24 import org.dive4elements.river.artifacts.access.RangeAccess; |
23 import org.dive4elements.river.artifacts.access.RiverAccess; | 25 import org.dive4elements.river.artifacts.access.RiverAccess; |
24 import org.dive4elements.river.artifacts.access.ComputationRangeAccess; | 26 import org.dive4elements.river.artifacts.model.Calculation; |
25 import org.dive4elements.river.artifacts.geom.Lines; | |
26 | |
27 import org.dive4elements.river.artifacts.model.Calculation1; | 27 import org.dive4elements.river.artifacts.model.Calculation1; |
28 import org.dive4elements.river.artifacts.model.Calculation2; | 28 import org.dive4elements.river.artifacts.model.Calculation2; |
29 import org.dive4elements.river.artifacts.model.Calculation3; | 29 import org.dive4elements.river.artifacts.model.Calculation3; |
30 import org.dive4elements.river.artifacts.model.Calculation4; | 30 import org.dive4elements.river.artifacts.model.Calculation4; |
31 import org.dive4elements.river.artifacts.model.Calculation5; | 31 import org.dive4elements.river.artifacts.model.Calculation5; |
32 import org.dive4elements.river.artifacts.model.Calculation; | |
33 import org.dive4elements.river.artifacts.model.CalculationResult; | 32 import org.dive4elements.river.artifacts.model.CalculationResult; |
34 import org.dive4elements.river.artifacts.model.DischargeTables; | 33 import org.dive4elements.river.artifacts.model.DischargeTables; |
35 import org.dive4elements.river.artifacts.model.FacetTypes; | 34 import org.dive4elements.river.artifacts.model.FacetTypes; |
36 import org.dive4elements.river.artifacts.model.WQCKms; | 35 import org.dive4elements.river.artifacts.model.WQCKms; |
37 import org.dive4elements.river.artifacts.model.WQKms; | 36 import org.dive4elements.river.artifacts.model.WQKms; |
38 import org.dive4elements.river.artifacts.model.WW; | 37 import org.dive4elements.river.artifacts.model.WW; |
39 import org.dive4elements.river.artifacts.model.WstValueTable; | 38 import org.dive4elements.river.artifacts.model.WstValueTable; |
40 import org.dive4elements.river.artifacts.model.WstValueTableFactory; | 39 import org.dive4elements.river.artifacts.model.WstValueTableFactory; |
41 | |
42 import org.dive4elements.river.artifacts.model.extreme.ExtremeResult; | 40 import org.dive4elements.river.artifacts.model.extreme.ExtremeResult; |
43 | |
44 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; | 41 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; |
45 | |
46 import org.dive4elements.river.model.DischargeTable; | 42 import org.dive4elements.river.model.DischargeTable; |
47 import org.dive4elements.river.model.FastCrossSectionLine; | |
48 import org.dive4elements.river.model.Gauge; | 43 import org.dive4elements.river.model.Gauge; |
49 import org.dive4elements.river.model.River; | 44 import org.dive4elements.river.model.River; |
50 | |
51 import org.dive4elements.river.utils.DoubleUtil; | 45 import org.dive4elements.river.utils.DoubleUtil; |
52 import org.dive4elements.river.utils.RiverUtils; | 46 import org.dive4elements.river.utils.RiverUtils; |
53 | 47 |
54 import gnu.trove.TDoubleArrayList; | 48 import gnu.trove.TDoubleArrayList; |
55 | |
56 import java.awt.geom.Point2D; | |
57 | |
58 import java.util.Arrays; | |
59 import java.util.List; | |
60 import java.util.Map; | |
61 | |
62 import org.apache.log4j.Logger; | |
63 | |
64 | 49 |
65 /** | 50 /** |
66 * The default WINFO artifact. | 51 * The default WINFO artifact. |
67 * | 52 * |
68 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | 53 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> |
69 */ | 54 */ |
70 public class WINFOArtifact | 55 public class WINFOArtifact extends D4EArtifact implements FacetTypes, WaterLineArtifact { |
71 extends D4EArtifact | |
72 implements FacetTypes, WaterLineArtifact { | |
73 | 56 |
74 /** The log for this class. */ | 57 /** The log for this class. */ |
75 private static Logger log = Logger.getLogger(WINFOArtifact.class); | 58 private static Logger log = Logger.getLogger(WINFOArtifact.class); |
76 | 59 |
77 /** The name of the artifact. */ | 60 /** The name of the artifact. */ |
78 public static final String ARTIFACT_NAME = "winfo"; | 61 public static final String ARTIFACT_NAME = "winfo"; |
79 | 62 |
80 /** XPath */ | 63 /** XPath */ |
81 public static final String XPATH_STATIC_UI = | 64 public static final String XPATH_STATIC_UI = "/art:result/art:ui/art:static"; |
82 "/art:result/art:ui/art:static"; | 65 |
83 | 66 /** |
84 /** The default number of steps between the start end end of a selected Q | 67 * The default number of steps between the start end end of a selected Q |
85 * range. */ | 68 * range. |
69 */ | |
86 public static final int DEFAULT_Q_STEPS = 30; | 70 public static final int DEFAULT_Q_STEPS = 30; |
87 | 71 |
88 private static final String [] INACTIVES = new String[] { | 72 private static final String[] INACTIVES = new String[] { LONGITUDINAL_Q, DURATION_Q, STATIC_WQKMS_Q }; |
89 LONGITUDINAL_Q, | |
90 DURATION_Q, | |
91 STATIC_WQKMS_Q | |
92 }; | |
93 | 73 |
94 static { | 74 static { |
95 // TODO: Move to configuration. | 75 // TODO: Move to configuration. |
96 FacetActivity.Registry.getInstance().register( | 76 FacetActivity.Registry.getInstance().register(ARTIFACT_NAME, new FacetActivity() { |
97 ARTIFACT_NAME, | 77 @Override |
98 new FacetActivity() { | 78 public Boolean isInitialActive(final Artifact artifact, final Facet facet, final String outputName) { |
99 @Override | 79 final String fname = facet.getName(); |
100 public Boolean isInitialActive( | 80 if ((fname.equals(MAINVALUES_Q) || fname.equals(MAINVALUES_W)) && outputName.equals("computed_discharge_curve")) { |
101 Artifact artifact, | 81 return Boolean.FALSE; |
102 Facet facet, | |
103 String outputName | |
104 ) { | |
105 String fname = facet.getName(); | |
106 if ((fname.equals(MAINVALUES_Q) | |
107 || fname.equals(MAINVALUES_W)) | |
108 && outputName.equals("computed_discharge_curve")) | |
109 { | |
110 return Boolean.FALSE; | |
111 } | |
112 return !StringUtils.contains(fname, INACTIVES); | |
113 } | 82 } |
114 }); | 83 return !StringUtils.contains(fname, INACTIVES); |
84 } | |
85 }); | |
115 } | 86 } |
116 | 87 |
117 /** | 88 /** |
118 * The default constructor. | 89 * The default constructor. |
119 */ | 90 */ |
120 public WINFOArtifact() { | 91 public WINFOArtifact() { |
121 } | 92 } |
122 | |
123 | |
124 | 93 |
125 /** | 94 /** |
126 * Returns the name of the concrete artifact. | 95 * Returns the name of the concrete artifact. |
127 * | 96 * |
128 * @return the name of the concrete artifact. | 97 * @return the name of the concrete artifact. |
130 @Override | 99 @Override |
131 public String getName() { | 100 public String getName() { |
132 return ARTIFACT_NAME; | 101 return ARTIFACT_NAME; |
133 } | 102 } |
134 | 103 |
135 protected static boolean reportGeneratedWs( | 104 protected static boolean reportGeneratedWs(final Calculation report, final double[] ws) { |
136 Calculation report, | |
137 double [] ws | |
138 ) { | |
139 if (ws == null || ws.length < 2) { | 105 if (ws == null || ws.length < 2) { |
140 return false; | 106 return false; |
141 } | 107 } |
142 | 108 |
143 double lastW = ws[0]; | 109 double lastW = ws[0]; |
144 boolean alreadyReported = false; | 110 boolean alreadyReported = false; |
145 | 111 |
146 for (int i = 1; i < ws.length; ++i) { | 112 for (int i = 1; i < ws.length; ++i) { |
147 if (Math.abs(lastW - ws[i]) < 1e-5) { | 113 if (Math.abs(lastW - ws[i]) < 1e-5) { |
148 if (!alreadyReported) { | 114 if (!alreadyReported) { |
149 alreadyReported = true; | 115 alreadyReported = true; |
150 report.addProblem("more.than.one.q.for.w", ws[i]); | 116 report.addProblem("more.than.one.q.for.w", ws[i]); |
151 } | 117 } |
152 } | 118 } else { |
153 else { | |
154 alreadyReported = false; | 119 alreadyReported = false; |
155 } | 120 } |
156 lastW = ws[i]; | 121 lastW = ws[i]; |
157 } | 122 } |
158 | 123 |
159 return true; | 124 return true; |
160 } | 125 } |
161 | |
162 | 126 |
163 // | 127 // |
164 // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES | 128 // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES |
165 // | 129 // |
166 // | 130 // |
181 /** | 145 /** |
182 * Returns the data that is computed by a waterlevel computation. | 146 * Returns the data that is computed by a waterlevel computation. |
183 * | 147 * |
184 * @return an array of data triples that consist of W, Q and Kms. | 148 * @return an array of data triples that consist of W, Q and Kms. |
185 */ | 149 */ |
186 public CalculationResult getWaterlevelData(CallContext context) | 150 public CalculationResult getWaterlevelData(final CallContext context) { |
187 { | |
188 log.debug("WINFOArtifact.getWaterlevelData"); | 151 log.debug("WINFOArtifact.getWaterlevelData"); |
189 | 152 |
190 String calculationMode = getDataAsString("calculation_mode"); | 153 final String calculationMode = getDataAsString("calculation_mode"); |
191 | 154 |
192 // If this WINFO-Artifact has a calculation trait. | 155 // If this WINFO-Artifact has a calculation trait. |
193 if (calculationMode != null) | 156 if (calculationMode != null) { |
194 { | |
195 if (calculationMode.equals("calc.discharge.longitudinal.section")) | 157 if (calculationMode.equals("calc.discharge.longitudinal.section")) |
196 return getDischargeLongitudinalSectionData(); | 158 return getDischargeLongitudinalSectionData(); |
197 | 159 |
198 if (calculationMode.equals("calc.extreme.curve")) | 160 if (calculationMode.equals("calc.extreme.curve")) |
199 return (CalculationResult)this.compute(context, ComputeType.ADVANCE, false); | 161 return (CalculationResult) this.compute(context, ComputeType.ADVANCE, false); |
200 | 162 |
201 if (calculationMode.equals("calc.w.differences")) | 163 if (calculationMode.equals("calc.w.differences")) |
202 return (CalculationResult)this.compute(context, ComputeType.ADVANCE, true); | 164 return (CalculationResult) this.compute(context, ComputeType.ADVANCE, true); |
203 | 165 |
204 log.warn("Unhandled calculation_mode " + calculationMode); | 166 log.warn("Unhandled calculation_mode " + calculationMode); |
205 } | 167 } |
206 | 168 |
207 // Otherwise get it from parameterization. | 169 // Otherwise get it from parameterization. |
208 // TODO: wrong comment: now always a waterlevle computation is executed; actually there is a calc_mode for that, why dont check? | 170 // TODO: wrong comment: now always a waterlevle computation is executed; actually there is a calc_mode for that, why |
171 // dont check? | |
209 return computeWaterlevelData(); | 172 return computeWaterlevelData(); |
210 } | 173 } |
211 | 174 |
212 /** Execu5tes the calculation of 'waterlevel', fetches all input data from this artifact */ | 175 /** Execu5tes the calculation of 'waterlevel', fetches all input data from this artifact */ |
213 private CalculationResult computeWaterlevelData() { | 176 private CalculationResult computeWaterlevelData() { |
214 final double[] kms = new ComputationRangeAccess(this).getKms(); | 177 final double[] kms = new ComputationRangeAccess(this).getKms(); |
215 if (kms == null) | 178 if (kms == null) |
216 return error(new WQKms[0], "no.kms.selected"); | 179 return error(new WQKms[0], "no.kms.selected"); |
217 | 180 |
218 return computeWaterlevelData(kms); | 181 return computeWaterlevelData(kms); |
219 } | 182 } |
220 | 183 |
221 /** | 184 /** |
222 * Execu5tes the calculation of 'waterlevel'. | 185 * Execu5tes the calculation of 'waterlevel'. |
223 * Allows to override the stations for which the calculation is done. All other inputs are fetched from this artifact. | 186 * Allows to override the stations for which the calculation is done. All other inputs are fetched from this artifact. |
224 */ | 187 */ |
225 public final CalculationResult computeWaterlevelData(final double kms[]) { | 188 public final CalculationResult computeWaterlevelData(final double kms[]) { |
226 | 189 |
227 final River river = new RiverAccess(this).getRiver(); | 190 final River river = new RiverAccess(this).getRiver(); |
228 if (river == null) | 191 if (river == null) |
229 return error(new WQKms[0], "no.river.selected"); | 192 return error(new WQKms[0], "no.river.selected"); |
230 | 193 |
231 double[] qs = getQs(); | 194 double[] qs = getQs(); |
232 double[] ws = null; | 195 double[] ws = null; |
233 | 196 |
234 Calculation report = new Calculation(); | 197 final Calculation report = new Calculation(); |
235 | 198 |
236 if (qs == null) { | 199 if (qs == null) { |
237 log.debug("Determine Q values based on a set of W values."); | 200 log.debug("Determine Q values based on a set of W values."); |
238 ws = getWs(); | 201 ws = getWs(); |
239 double [][] qws = getQsForWs(ws, report); | 202 final double[][] qws = getQsForWs(ws, report); |
240 if (qws == null || qws.length == 0) { | 203 if (qws == null || qws.length == 0) { |
241 return error(new WQKms[0], "converting.ws.to.qs.failed"); | 204 return error(new WQKms[0], "converting.ws.to.qs.failed"); |
242 } | 205 } |
243 qs = qws[0]; | 206 qs = qws[0]; |
244 | 207 |
245 if (reportGeneratedWs(report, qws[1])) { | 208 if (reportGeneratedWs(report, qws[1])) { |
246 ws = qws[1]; | 209 ws = qws[1]; |
247 } | 210 } |
248 } | 211 } |
249 | 212 |
250 WstValueTable wst = WstValueTableFactory.getTable(river); | 213 final WstValueTable wst = WstValueTableFactory.getTable(river); |
251 if (wst == null) { | 214 if (wst == null) { |
252 return error(new WQKms[0], "no.wst.for.selected.river"); | 215 return error(new WQKms[0], "no.wst.for.selected.river"); |
253 } | 216 } |
254 | 217 |
255 RangeAccess rangeAccess = new RangeAccess(this); | 218 final RangeAccess rangeAccess = new RangeAccess(this); |
256 double [] range = rangeAccess.getKmRange(); | 219 final double[] range = rangeAccess.getKmRange(); |
257 if (range == null) { | 220 if (range == null) { |
258 return error(new WQKms[0], "no.range.found"); | 221 return error(new WQKms[0], "no.range.found"); |
259 } | 222 } |
260 | 223 |
261 double refKm; | 224 double refKm; |
262 | 225 |
263 if (isFreeQ() || isFreeW()) { | 226 if (isFreeQ() || isFreeW()) { |
264 refKm = range[0]; | 227 refKm = range[0]; |
265 log.debug("'free' calculation (km " + refKm + ")"); | 228 log.debug("'free' calculation (km " + refKm + ")"); |
266 } | 229 } else { |
267 else { | 230 final Gauge gauge = river.determineRefGauge(range, rangeAccess.isRange()); |
268 Gauge gauge = river.determineRefGauge( | |
269 range, rangeAccess.isRange()); | |
270 | 231 |
271 if (gauge == null) { | 232 if (gauge == null) { |
272 return error( | 233 return error(new WQKms[0], "no.gauge.found.for.km", range[0]); |
273 new WQKms[0], "no.gauge.found.for.km", range[0]); | |
274 } | 234 } |
275 | 235 |
276 refKm = gauge.getStation().doubleValue(); | 236 refKm = gauge.getStation().doubleValue(); |
277 | 237 |
278 log.debug( | 238 log.debug("reference gauge: " + gauge.getName() + " (km " + refKm + ")"); |
279 "reference gauge: " + gauge.getName() + " (km " + refKm + ")"); | 239 } |
280 } | 240 |
281 | 241 return computeWaterlevelData(kms, qs, ws, wst, refKm, report); |
282 return computeWaterlevelData(kms, qs, ws, wst, refKm, report); | |
283 } | 242 } |
284 | 243 |
285 /** | 244 /** |
286 * Computes the data of a waterlevel computation based on the interpolation | 245 * Computes the data of a waterlevel computation based on the interpolation |
287 * in WstValueTable. | 246 * in WstValueTable. |
288 * | 247 * |
289 * @param kms The kilometer values. | 248 * @param kms |
290 * @param qs The discharge values. | 249 * The kilometer values. |
291 * @param wst The WstValueTable used for the interpolation. | 250 * @param qs |
251 * The discharge values. | |
252 * @param wst | |
253 * The WstValueTable used for the interpolation. | |
292 * | 254 * |
293 * @return an array of data triples that consist of W, Q and Kms. | 255 * @return an array of data triples that consist of W, Q and Kms. |
294 */ | 256 */ |
295 private static CalculationResult computeWaterlevelData( | 257 private static CalculationResult computeWaterlevelData(final double[] kms, final double[] qs, final double[] ws, final WstValueTable wst, |
296 double [] kms, | 258 final double refKm, final Calculation report) { |
297 double [] qs, | |
298 double [] ws, | |
299 WstValueTable wst, | |
300 double refKm, | |
301 Calculation report | |
302 ) { | |
303 log.info("WINFOArtifact.computeWaterlevelData"); | 259 log.info("WINFOArtifact.computeWaterlevelData"); |
304 | 260 |
305 Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm); | 261 final Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm); |
306 | 262 |
307 if (report != null) { | 263 if (report != null) { |
308 calc1.addProblems(report); | 264 calc1.addProblems(report); |
309 } | 265 } |
310 | 266 |
311 return calc1.calculate(wst); | 267 return calc1.calculate(wst); |
312 } | 268 } |
313 | 269 |
314 | |
315 /** | 270 /** |
316 * Returns the data that is computed by a duration curve computation. | 271 * Returns the data that is computed by a duration curve computation. |
317 * | 272 * |
318 * @return the data computed by a duration curve computation. | 273 * @return the data computed by a duration curve computation. |
319 */ | 274 */ |
320 public CalculationResult getDurationCurveData() { | 275 public CalculationResult getDurationCurveData() { |
321 log.debug("WINFOArtifact.getDurationCurveData"); | 276 log.debug("WINFOArtifact.getDurationCurveData"); |
322 | 277 |
323 RangeAccess rangeAccess = new RangeAccess(this); | 278 final RangeAccess rangeAccess = new RangeAccess(this); |
324 | 279 |
325 River r = rangeAccess.getRiver(); | 280 final River r = rangeAccess.getRiver(); |
326 if (r == null) { | 281 if (r == null) { |
327 return error(null, "no.river.selected"); | 282 return error(null, "no.river.selected"); |
328 } | 283 } |
329 | 284 |
330 double[] locations = rangeAccess.getLocations(); | 285 final double[] locations = rangeAccess.getLocations(); |
331 if (locations == null) { | 286 if (locations == null) { |
332 return error(null, "no.locations.selected"); | 287 return error(null, "no.locations.selected"); |
333 } | 288 } |
334 | 289 |
335 Gauge g = r.determineGaugeByPosition(locations[0]); | 290 final Gauge g = r.determineGaugeByPosition(locations[0]); |
336 if (g == null) { | 291 if (g == null) { |
337 return error(null, "no.gauge.selected"); | 292 return error(null, "no.gauge.selected"); |
338 } | 293 } |
339 | 294 |
340 WstValueTable wst = WstValueTableFactory.getTable(r); | 295 final WstValueTable wst = WstValueTableFactory.getTable(r); |
341 if (wst == null) { | 296 if (wst == null) { |
342 return error(null, "no.wst.for.river"); | 297 return error(null, "no.wst.for.river"); |
343 } | 298 } |
344 | 299 |
345 return computeDurationCurveData(g, wst, locations[0]); | 300 return computeDurationCurveData(g, wst, locations[0]); |
346 } | 301 } |
347 | 302 |
348 | |
349 /** | 303 /** |
350 * Computes the data used to create duration curves. | 304 * Computes the data used to create duration curves. |
351 * | 305 * |
352 * @param gauge The selected gauge. | 306 * @param gauge |
353 * @param location The selected location. | 307 * The selected gauge. |
308 * @param location | |
309 * The selected location. | |
354 * | 310 * |
355 * @return the computed data. | 311 * @return the computed data. |
356 */ | 312 */ |
357 private static CalculationResult computeDurationCurveData( | 313 private static CalculationResult computeDurationCurveData(final Gauge gauge, final WstValueTable wst, final double location) { |
358 Gauge gauge, | |
359 WstValueTable wst, | |
360 double location) | |
361 { | |
362 log.info("WINFOArtifact.computeDurationCurveData"); | 314 log.info("WINFOArtifact.computeDurationCurveData"); |
363 | 315 |
364 Object[] obj = gauge.fetchDurationCurveData(); | 316 final Object[] obj = gauge.fetchDurationCurveData(); |
365 | 317 |
366 int[] days = (int[]) obj[0]; | 318 final int[] days = (int[]) obj[0]; |
367 double[] qs = (double[]) obj[1]; | 319 final double[] qs = (double[]) obj[1]; |
368 | 320 |
369 Calculation3 calculation = new Calculation3(location, days, qs); | 321 final Calculation3 calculation = new Calculation3(location, days, qs); |
370 | 322 |
371 return calculation.calculate(wst); | 323 return calculation.calculate(wst); |
372 } | 324 } |
373 | 325 |
374 | |
375 /** | 326 /** |
376 * Returns the data that is computed by a discharge curve computation. | 327 * Returns the data that is computed by a discharge curve computation. |
377 * | 328 * |
378 * @return the data computed by a discharge curve computation. | 329 * @return the data computed by a discharge curve computation. |
379 */ | 330 */ |
380 public CalculationResult getComputedDischargeCurveData() | 331 public CalculationResult getComputedDischargeCurveData() throws NullPointerException { |
381 throws NullPointerException | |
382 { | |
383 log.debug("WINFOArtifact.getComputedDischargeCurveData"); | 332 log.debug("WINFOArtifact.getComputedDischargeCurveData"); |
384 | 333 |
385 River r = RiverUtils.getRiver(this); | 334 final River r = RiverUtils.getRiver(this); |
386 | 335 |
387 if (r == null) { | 336 if (r == null) { |
388 return error(new WQKms[0], "no.river.selected"); | 337 return error(new WQKms[0], "no.river.selected"); |
389 } | 338 } |
390 | 339 |
391 RangeAccess rangeAccess = new RangeAccess(this); | 340 final RangeAccess rangeAccess = new RangeAccess(this); |
392 double[] locations = rangeAccess.getLocations(); | 341 final double[] locations = rangeAccess.getLocations(); |
393 | 342 |
394 if (locations == null) { | 343 if (locations == null) { |
395 return error(new WQKms[0], "no.locations.selected"); | 344 return error(new WQKms[0], "no.locations.selected"); |
396 } | 345 } |
397 | 346 |
398 WstValueTable wst = WstValueTableFactory.getTable(r); | 347 final WstValueTable wst = WstValueTableFactory.getTable(r); |
399 if (wst == null) { | 348 if (wst == null) { |
400 return error(new WQKms[0], "no.wst.for.river"); | 349 return error(new WQKms[0], "no.wst.for.river"); |
401 } | 350 } |
402 | 351 |
403 return computeDischargeCurveData(wst, locations[0]); | 352 return computeDischargeCurveData(wst, locations[0]); |
404 } | 353 } |
405 | 354 |
406 | |
407 /** | 355 /** |
408 * Computes the data used to create computed discharge curves. | 356 * Computes the data used to create computed discharge curves. |
409 * | 357 * |
410 * @param wst The WstValueTable that is used for the interpolation (river- | 358 * @param wst |
359 * The WstValueTable that is used for the interpolation (river- | |
411 * bound). | 360 * bound). |
412 * @param location The location where the computation should be based on. | 361 * @param location |
362 * The location where the computation should be based on. | |
413 * | 363 * |
414 * @return an object that contains tuples of W/Q values at the specified | 364 * @return an object that contains tuples of W/Q values at the specified |
415 * location. | 365 * location. |
416 */ | 366 */ |
417 private static CalculationResult computeDischargeCurveData( | 367 private static CalculationResult computeDischargeCurveData(final WstValueTable wst, final double location) { |
418 WstValueTable wst, | |
419 double location) | |
420 { | |
421 log.info("WINFOArtifact.computeDischargeCurveData"); | 368 log.info("WINFOArtifact.computeDischargeCurveData"); |
422 | 369 |
423 Calculation2 calculation = new Calculation2(location); | 370 final Calculation2 calculation = new Calculation2(location); |
424 | 371 |
425 return calculation.calculate(wst); | 372 return calculation.calculate(wst); |
426 } | 373 } |
427 | 374 |
428 | |
429 /** Create CalculationResult with data and message. */ | 375 /** Create CalculationResult with data and message. */ |
430 protected static final CalculationResult error(Object data, String msg) { | 376 protected static final CalculationResult error(final Object data, final String msg) { |
431 return new CalculationResult(data, new Calculation(msg)); | 377 return new CalculationResult(data, new Calculation(msg)); |
432 } | 378 } |
433 | 379 |
434 /** Create CalculationResult with data and message with args. */ | 380 /** Create CalculationResult with data and message with args. */ |
435 protected static final CalculationResult error( | 381 protected static final CalculationResult error(final Object data, final String msg, final Object... args) { |
436 Object data, | |
437 String msg, | |
438 Object ... args | |
439 ) { | |
440 return new CalculationResult(data, new Calculation(msg, args)); | 382 return new CalculationResult(data, new Calculation(msg, args)); |
441 } | 383 } |
442 | 384 |
443 | |
444 /** | 385 /** |
445 * Returns the data that is computed by a reference curve computation. | 386 * Returns the data that is computed by a reference curve computation. |
446 * | 387 * |
447 * @return the data computed by a reference curve computation. | 388 * @return the data computed by a reference curve computation. |
448 */ | 389 */ |
449 public CalculationResult getReferenceCurveData(CallContext context) { | 390 public CalculationResult getReferenceCurveData(final CallContext context) { |
450 | 391 |
451 Double startKm = getReferenceStartKm(); | 392 final Double startKm = getReferenceStartKm(); |
452 | 393 |
453 if (startKm == null) { | 394 if (startKm == null) { |
454 return error(new WW[0], "no.reference.start.km"); | 395 return error(new WW[0], "no.reference.start.km"); |
455 } | 396 } |
456 | 397 |
457 double [] endKms = getReferenceEndKms(); | 398 final double[] endKms = getReferenceEndKms(); |
458 | 399 |
459 if (endKms == null || endKms.length == 0) { | 400 if (endKms == null || endKms.length == 0) { |
460 return error(new WW[0], "no.reference.end.kms"); | 401 return error(new WW[0], "no.reference.end.kms"); |
461 } | 402 } |
462 | 403 |
463 Calculation5 calc5 = new Calculation5(startKm, endKms); | 404 final Calculation5 calc5 = new Calculation5(startKm, endKms); |
464 | 405 |
465 River r = RiverUtils.getRiver(this); | 406 final River r = RiverUtils.getRiver(this); |
466 if (r == null) { | 407 if (r == null) { |
467 return error(new WW[0], "no.river.found"); | 408 return error(new WW[0], "no.river.found"); |
468 } | 409 } |
469 | 410 |
470 WstValueTable wst = WstValueTableFactory.getTable(r); | 411 final WstValueTable wst = WstValueTableFactory.getTable(r); |
471 if (wst == null) { | 412 if (wst == null) { |
472 return error(new WW[0], "no.wst.for.river"); | 413 return error(new WW[0], "no.wst.for.river"); |
473 } | 414 } |
474 | 415 |
475 Map<Double, Double> kms2gaugeDatums = r.queryGaugeDatumsKMs(); | 416 final Map<Double, Double> kms2gaugeDatums = r.queryGaugeDatumsKMs(); |
476 | 417 |
477 return calc5.calculate(wst, kms2gaugeDatums, context); | 418 return calc5.calculate(wst, kms2gaugeDatums, context); |
478 } | 419 } |
479 | |
480 | 420 |
481 /** Get reference (start) km. */ | 421 /** Get reference (start) km. */ |
482 public Double getReferenceStartKm() { | 422 public Double getReferenceStartKm() { |
483 StateData sd = getData("reference_startpoint"); | 423 final StateData sd = getData("reference_startpoint"); |
484 | 424 |
485 if (sd == null) { | 425 if (sd == null) { |
486 log.warn("no reference start given."); | 426 log.warn("no reference start given."); |
487 return null; | 427 return null; |
488 } | 428 } |
497 } | 437 } |
498 | 438 |
499 try { | 439 try { |
500 return Double.valueOf(input); | 440 return Double.valueOf(input); |
501 } | 441 } |
502 catch (NumberFormatException nfe) { | 442 catch (final NumberFormatException nfe) { |
503 log.warn("reference start string is not numeric."); | 443 log.warn("reference start string is not numeric."); |
504 } | 444 } |
505 | 445 |
506 return null; | 446 return null; |
507 } | 447 } |
508 | 448 |
509 | |
510 /** | 449 /** |
511 * Get end kms for reference curve (null if none). | 450 * Get end kms for reference curve (null if none). |
512 */ | 451 */ |
513 public double [] getReferenceEndKms() { | 452 public double[] getReferenceEndKms() { |
514 StateData sd = getData("reference_endpoint"); | 453 final StateData sd = getData("reference_endpoint"); |
515 | 454 |
516 if (sd == null) { | 455 if (sd == null) { |
517 log.warn("no reference end given."); | 456 log.warn("no reference end given."); |
518 return null; | 457 return null; |
519 } | 458 } else { |
520 else { | |
521 log.debug("Reference end km : " + sd.getValue()); | 459 log.debug("Reference end km : " + sd.getValue()); |
522 } | 460 } |
523 | 461 |
524 String input = (String) sd.getValue(); | 462 String input = (String) sd.getValue(); |
525 | 463 |
526 if (input == null || (input = input.trim()).length() == 0) { | 464 if (input == null || (input = input.trim()).length() == 0) { |
527 log.warn("reference end string is empty."); | 465 log.warn("reference end string is empty."); |
528 return null; | 466 return null; |
529 } | 467 } |
530 | 468 |
531 TDoubleArrayList endKms = new TDoubleArrayList(); | 469 final TDoubleArrayList endKms = new TDoubleArrayList(); |
532 | 470 |
533 for (String part: input.split("\\s+")) { | 471 for (final String part : input.split("\\s+")) { |
534 try { | 472 try { |
535 double km = Double.parseDouble(part); | 473 final double km = Double.parseDouble(part); |
536 if (!endKms.contains(km)) { | 474 if (!endKms.contains(km)) { |
537 endKms.add(km); | 475 endKms.add(km); |
538 } | 476 } |
539 } | 477 } |
540 catch (NumberFormatException nfe) { | 478 catch (final NumberFormatException nfe) { |
541 log.warn("reference end string is not numeric."); | 479 log.warn("reference end string is not numeric."); |
542 } | 480 } |
543 } | 481 } |
544 | 482 |
545 return endKms.toNativeArray(); | 483 return endKms.toNativeArray(); |
546 } | 484 } |
547 | 485 |
548 | |
549 /** | 486 /** |
550 * Get corrected waterline against surface/profile. | 487 * Get corrected waterline against surface/profile. |
551 */ | 488 */ |
552 private Lines.LineData waterLineC(int idx, FastCrossSectionLine csl) { | 489 private double waterLineC(final int idx, final double currentKm) { |
553 List<Point2D> points = csl.getPoints(); | 490 |
554 | 491 final WQKms[] wqckms = (WQKms[]) getDischargeLongitudinalSectionData().getData(); |
555 WQKms[] wqckms = (WQKms[]) | |
556 getDischargeLongitudinalSectionData().getData(); | |
557 | 492 |
558 // Find index of km. | 493 // Find index of km. |
559 double wishKM = csl.getKm(); | 494 final double wishKM = currentKm; |
560 | 495 |
561 // Find W/C at km, linear naive approach. | 496 // Find W/C at km, linear naive approach. |
562 WQCKms triple = (WQCKms) wqckms[idx-1]; | 497 final WQCKms triple = (WQCKms) wqckms[idx - 1]; |
563 | 498 |
564 if (triple.size() == 0) { | 499 if (triple.size() == 0) { |
565 log.warn("Calculation of c/waterline is empty."); | 500 log.warn("Calculation of c/waterline is empty."); |
566 return Lines.createWaterLines(points, 0.0f); | 501 return Double.NaN; |
567 } | 502 } |
568 | 503 |
569 // Linear seach in WQKms for closest km. | 504 // Linear seach in WQKms for closest km. |
570 double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); | 505 double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); |
571 double last_c = triple.getC(0); | 506 double last_c = triple.getC(0); |
572 | 507 |
573 for (int i = 0, T = triple.size(); i < T; i++) { | 508 for (int i = 0, T = triple.size(); i < T; i++) { |
574 double diff = Math.abs(wishKM - triple.getKm(i)); | 509 final double diff = Math.abs(wishKM - triple.getKm(i)); |
575 if (diff > old_dist_wish) { | 510 if (diff > old_dist_wish) { |
576 break; | 511 break; |
577 } | 512 } |
578 last_c = triple.getC(i); | 513 last_c = triple.getC(i); |
579 old_dist_wish = diff; | 514 old_dist_wish = diff; |
580 } | 515 } |
581 | 516 |
582 return Lines.createWaterLines(points, last_c); | 517 return last_c; |
583 } | 518 } |
584 | |
585 | 519 |
586 /** | 520 /** |
587 * Get points of line describing the surface of water at cross section. | 521 * Get points of line describing the surface of water at cross section. |
588 * | 522 * |
589 * @param idx Index for getWaterlevelData. | 523 * @param idx |
590 * @param csl The profile/surface to fill with water. | 524 * Index for getWaterlevelData. |
591 * @param nextIgnored Ignored in this implementation of WaterLineArtifact. | 525 * @param csl |
592 * @param prevIgnored Ignored in this implementation of WaterLineArtifact. | 526 * The profile/surface to fill with water. |
527 * @param nextIgnored | |
528 * Ignored in this implementation of WaterLineArtifact. | |
529 * @param prevIgnored | |
530 * Ignored in this implementation of WaterLineArtifact. | |
593 * | 531 * |
594 * @return an array holding coordinates of points of surface of water ( | 532 * @return an array holding coordinates of points of surface of water ( |
595 * in the form {{x1, x2} {y1, y2}} ). | 533 * in the form {{x1, x2} {y1, y2}} ). |
596 */ | 534 */ |
597 @Override | 535 @Override |
598 public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, | 536 public double getWaterLevel(final ComputeType type, final String hash, final String stateId, final double currentKm, final Serializable waterLineIndex, |
599 double nextIgnored, double prevIgnored, CallContext context) { | 537 final double nextKm, final double prevKm, final CallContext context) { |
600 log.debug("getWaterLines(" + idx + ")"); | 538 |
601 | 539 final int idx = (int) waterLineIndex; |
602 List<Point2D> points = csl.getPoints(); | |
603 | 540 |
604 // Need W at km | 541 // Need W at km |
605 Object waterlevelResult = getWaterlevelData(context).getData(); | 542 final Object waterlevelResult = getWaterlevelData(context).getData(); |
606 WQKms [] wqkms; | 543 WQKms[] wqkms; |
607 | 544 |
608 if (waterlevelResult instanceof ExtremeResult) { | 545 if (waterlevelResult instanceof ExtremeResult) { |
609 wqkms = ((ExtremeResult) waterlevelResult).getWQKms(); | 546 wqkms = ((ExtremeResult) waterlevelResult).getWQKms(); |
610 } | 547 } else { |
611 else { | |
612 wqkms = (WQKms[]) waterlevelResult; | 548 wqkms = (WQKms[]) waterlevelResult; |
613 } | 549 } |
614 | 550 |
615 if (wqkms.length == 0) { | 551 if (wqkms.length == 0) { |
616 log.error("No WQKms found."); | 552 log.error("No WQKms found."); |
617 return Lines.createWaterLines(points, 0.0f); | 553 return Double.NaN; |
618 } | 554 } |
619 | 555 |
620 if (wqkms.length <= idx) { | 556 if (wqkms.length <= idx) { |
621 log.error("getWaterLines() requested index (" | 557 log.error("getWaterLines() requested index (" + idx + " not found."); |
622 + idx + " not found."); | 558 return waterLineC(idx, currentKm); |
623 return waterLineC(idx, csl); | |
624 } | 559 } |
625 | 560 |
626 // Find W at km, linear naive approach. | 561 // Find W at km, linear naive approach. |
627 WQKms triple = wqkms[idx]; | 562 final WQKms triple = wqkms[idx]; |
628 | 563 |
629 // Find index of km. | 564 // Find index of km. |
630 double wishKM = csl.getKm(); | 565 final double wishKM = currentKm; |
631 | 566 |
632 if (triple.size() == 0) { | 567 if (triple.size() == 0) { |
633 log.warn("Calculation of waterline is empty."); | 568 log.warn("Calculation of waterline is empty."); |
634 return Lines.createWaterLines(points, 0.0f); | 569 return Double.NaN; |
635 } | 570 } |
636 | 571 |
637 // Early abort if we would need to extrapolate. | 572 // Early abort if we would need to extrapolate. |
638 int T = triple.size(); | 573 final int T = triple.size(); |
639 double max_km = triple.getKm(T-1), min_km = triple.getKm(0); | 574 final double max_km = triple.getKm(T - 1), min_km = triple.getKm(0); |
640 if (wishKM < min_km || wishKM > max_km) { | 575 if (wishKM < min_km || wishKM > max_km) { |
641 // TODO Does this have to be done in the other WaterlineArtifact | 576 // TODO Does this have to be done in the other WaterlineArtifact |
642 // implementations, too? | 577 // implementations, too? |
643 log.warn("Will not extrapolate waterlevels."); | 578 log.warn("Will not extrapolate waterlevels."); |
644 return Lines.createWaterLines(points, 0.0f); | 579 return Double.NaN; |
645 } | 580 } |
646 | |
647 int old_idx = 0; | |
648 | 581 |
649 // Linear seach in WQKms for closest km. | 582 // Linear seach in WQKms for closest km. |
650 double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); | 583 double old_dist_wish = Math.abs(wishKM - triple.getKm(0)); |
651 double last_w = triple.getW(0); | 584 double last_w = triple.getW(0); |
652 | 585 |
653 for (int i = 0; i < T; i++) { | 586 for (int i = 0; i < T; i++) { |
654 double diff = Math.abs(wishKM - triple.getKm(i)); | 587 final double diff = Math.abs(wishKM - triple.getKm(i)); |
655 if (diff > old_dist_wish) { | 588 if (diff > old_dist_wish) { |
656 break; | 589 break; |
657 } | 590 } |
658 last_w = triple.getW(i); | 591 last_w = triple.getW(i); |
659 old_dist_wish = diff; | 592 old_dist_wish = diff; |
660 } | 593 } |
661 | 594 |
662 return Lines.createWaterLines(points, last_w); | 595 return last_w; |
663 } | 596 } |
664 | |
665 | 597 |
666 /** | 598 /** |
667 * Returns the Qs for a number of Ws. | 599 * Returns the Qs for a number of Ws. |
668 * | 600 * |
669 * @param ws An array of W values. | 601 * @param ws |
602 * An array of W values. | |
670 * | 603 * |
671 * @return an array of Q values. | 604 * @return an array of Q values. |
672 */ | 605 */ |
673 private double [][] getQsForWs(double[] ws, Calculation report) { | 606 private double[][] getQsForWs(final double[] ws, final Calculation report) { |
674 | 607 |
675 if (ws == null) { | 608 if (ws == null) { |
676 log.error("getQsForWs: ws == null"); | 609 log.error("getQsForWs: ws == null"); |
677 return null; | 610 return null; |
678 } | 611 } |
679 | 612 |
680 boolean debug = log.isDebugEnabled(); | 613 final boolean debug = log.isDebugEnabled(); |
681 | 614 |
682 if (debug) { | 615 if (debug) { |
683 log.debug("D4EArtifact.getQsForWs"); | 616 log.debug("D4EArtifact.getQsForWs"); |
684 } | 617 } |
685 | 618 |
686 River r = RiverUtils.getRiver(this); | 619 final River r = RiverUtils.getRiver(this); |
687 if (r == null) { | 620 if (r == null) { |
688 log.warn("no river found"); | 621 log.warn("no river found"); |
689 return null; | 622 return null; |
690 } | 623 } |
691 | 624 |
692 RangeAccess rangeAccess = new RangeAccess(this); | 625 final RangeAccess rangeAccess = new RangeAccess(this); |
693 double [] range = rangeAccess.getKmRange(); | 626 final double[] range = rangeAccess.getKmRange(); |
694 if (range == null) { | 627 if (range == null) { |
695 log.warn("no ranges found"); | 628 log.warn("no ranges found"); |
696 return null; | 629 return null; |
697 } | 630 } |
698 | 631 |
699 if (isFreeW()) { | 632 if (isFreeW()) { |
700 log.debug("Bezugslinienverfahren I: W auf freier Strecke"); | 633 log.debug("Bezugslinienverfahren I: W auf freier Strecke"); |
701 // The simple case of the "Bezugslinienverfahren" | 634 // The simple case of the "Bezugslinienverfahren" |
702 // "W auf freier Strecke". | 635 // "W auf freier Strecke". |
703 WstValueTable wst = WstValueTableFactory.getTable(r); | 636 final WstValueTable wst = WstValueTableFactory.getTable(r); |
704 if (wst == null) { | 637 if (wst == null) { |
705 log.warn("no wst value table found"); | 638 log.warn("no wst value table found"); |
706 return null; | 639 return null; |
707 } | 640 } |
708 double km = range[0]; | 641 final double km = range[0]; |
709 | 642 |
710 TDoubleArrayList outQs = new TDoubleArrayList(ws.length); | 643 final TDoubleArrayList outQs = new TDoubleArrayList(ws.length); |
711 TDoubleArrayList outWs = new TDoubleArrayList(ws.length); | 644 final TDoubleArrayList outWs = new TDoubleArrayList(ws.length); |
712 | 645 |
713 boolean generatedWs = false; | 646 boolean generatedWs = false; |
714 | 647 |
715 for (int i = 0; i < ws.length; ++i) { | 648 for (int i = 0; i < ws.length; ++i) { |
716 double w = ws[i]; | 649 final double w = ws[i]; |
717 if (debug) { | 650 if (debug) { |
718 log.debug("getQsForWs: lookup Q for W: " + w); | 651 log.debug("getQsForWs: lookup Q for W: " + w); |
719 } | 652 } |
720 // There could be more than one Q per W. | 653 // There could be more than one Q per W. |
721 double [] qs = wst.findQsForW(km, w, report); | 654 final double[] qs = wst.findQsForW(km, w, report); |
722 for (int j = 0; j < qs.length; ++j) { | 655 for (int j = 0; j < qs.length; ++j) { |
723 outWs.add(ws[i]); | 656 outWs.add(ws[i]); |
724 outQs.add(qs[j]); | 657 outQs.add(qs[j]); |
725 } | 658 } |
726 generatedWs |= qs.length != 1; | 659 generatedWs |= qs.length != 1; |
728 | 661 |
729 if (debug) { | 662 if (debug) { |
730 log.debug("getQsForWs: number of Qs: " + outQs.size()); | 663 log.debug("getQsForWs: number of Qs: " + outQs.size()); |
731 } | 664 } |
732 | 665 |
733 return new double [][] { | 666 return new double[][] { outQs.toNativeArray(), generatedWs ? outWs.toNativeArray() : null }; |
734 outQs.toNativeArray(), | |
735 generatedWs ? outWs.toNativeArray() : null }; | |
736 } | 667 } |
737 | 668 |
738 if (debug) { | 669 if (debug) { |
739 log.debug("range: " + Arrays.toString(range)); | 670 log.debug("range: " + Arrays.toString(range)); |
740 } | 671 } |
741 | 672 |
742 Gauge g = rangeAccess.getRiver().determineRefGauge( | 673 final Gauge g = rangeAccess.getRiver().determineRefGauge(range, rangeAccess.isRange()); |
743 range, rangeAccess.isRange()); | |
744 if (g == null) { | 674 if (g == null) { |
745 log.warn("no gauge found for km: " + range[0]); | 675 log.warn("no gauge found for km: " + range[0]); |
746 return null; | 676 return null; |
747 } | 677 } |
748 | 678 |
749 if (debug) { | 679 if (debug) { |
750 log.debug("convert w->q with gauge '" + g.getName() + "'"); | 680 log.debug("convert w->q with gauge '" + g.getName() + "'"); |
751 } | 681 } |
752 | 682 |
753 DischargeTable dt = g.fetchMasterDischargeTable(); | 683 final DischargeTable dt = g.fetchMasterDischargeTable(); |
754 | 684 |
755 if (dt == null) { | 685 if (dt == null) { |
756 log.warn("No master discharge table found for gauge '" | 686 log.warn("No master discharge table found for gauge '" + g.getName() + "'"); |
757 + g.getName() + "'"); | 687 return null; |
758 return null; | 688 } |
759 } | 689 |
760 | 690 final double[][] values = DischargeTables.loadDischargeTableValues(dt); |
761 double [][] values = DischargeTables.loadDischargeTableValues(dt); | 691 |
762 | 692 final TDoubleArrayList wsOut = new TDoubleArrayList(ws.length); |
763 TDoubleArrayList wsOut = new TDoubleArrayList(ws.length); | 693 final TDoubleArrayList qsOut = new TDoubleArrayList(ws.length); |
764 TDoubleArrayList qsOut = new TDoubleArrayList(ws.length); | |
765 | 694 |
766 boolean generatedWs = false; | 695 boolean generatedWs = false; |
767 | 696 |
768 for (int i = 0; i < ws.length; i++) { | 697 for (int i = 0; i < ws.length; i++) { |
769 if (Double.isNaN(ws[i])) { | 698 if (Double.isNaN(ws[i])) { |
770 log.warn("W is NaN: ignored"); | 699 log.warn("W is NaN: ignored"); |
771 continue; | 700 continue; |
772 } | 701 } |
773 double [] qs = DischargeTables.getQsForW(values, ws[i]); | 702 final double[] qs = DischargeTables.getQsForW(values, ws[i]); |
774 | 703 |
775 if (qs.length == 0) { | 704 if (qs.length == 0) { |
776 log.warn("No Qs found for W = " + ws[i]); | 705 log.warn("No Qs found for W = " + ws[i]); |
777 } | 706 } else { |
778 else { | 707 for (final double q : qs) { |
779 for (double q: qs) { | |
780 wsOut.add(ws[i]); | 708 wsOut.add(ws[i]); |
781 qsOut.add(q); | 709 qsOut.add(q); |
782 } | 710 } |
783 } | 711 } |
784 generatedWs |= qs.length != 1; | 712 generatedWs |= qs.length != 1; |
785 } | 713 } |
786 | 714 |
787 return new double [][] { | 715 return new double[][] { qsOut.toNativeArray(), generatedWs ? wsOut.toNativeArray() : null }; |
788 qsOut.toNativeArray(), | 716 } |
789 generatedWs ? wsOut.toNativeArray() : null | |
790 }; | |
791 } | |
792 | |
793 | 717 |
794 /** | 718 /** |
795 * Returns the selected distance based on a given range (from, to). | 719 * Returns the selected distance based on a given range (from, to). |
796 * | 720 * |
797 * @param dFrom The StateData that contains the lower value. | 721 * @param dFrom |
798 * @param dTo The StateData that contains the upper value. | 722 * The StateData that contains the lower value. |
723 * @param dTo | |
724 * The StateData that contains the upper value. | |
799 * | 725 * |
800 * @return the selected distance. | 726 * @return the selected distance. |
801 */ | 727 */ |
802 protected double[] getDistanceByRange(StateData dFrom, StateData dTo) { | 728 protected double[] getDistanceByRange(final StateData dFrom, final StateData dTo) { |
803 double from = Double.parseDouble((String) dFrom.getValue()); | 729 final double from = Double.parseDouble((String) dFrom.getValue()); |
804 double to = Double.parseDouble((String) dTo.getValue()); | 730 final double to = Double.parseDouble((String) dTo.getValue()); |
805 | 731 |
806 return new double[] { from, to }; | 732 return new double[] { from, to }; |
807 } | 733 } |
808 | 734 |
809 | |
810 /** | 735 /** |
811 * This method returns the Q values. | 736 * This method returns the Q values. |
812 * | 737 * |
813 * @return the selected Q values or null, if no Q values are selected. | 738 * @return the selected Q values or null, if no Q values are selected. |
814 */ | 739 */ |
815 public double[] getQs() { | 740 public double[] getQs() { |
816 StateData dMode = getData("wq_isq"); | 741 final StateData dMode = getData("wq_isq"); |
817 StateData dSelection = getData("wq_isrange"); | 742 final StateData dSelection = getData("wq_isrange"); |
818 | 743 |
819 boolean isRange = dSelection != null | 744 final boolean isRange = dSelection != null ? Boolean.valueOf((String) dSelection.getValue()) : false; |
820 ? Boolean.valueOf((String)dSelection.getValue()) | |
821 : false; | |
822 | 745 |
823 if (isQ()) { | 746 if (isQ()) { |
824 if (!isRange) { | 747 if (!isRange) { |
825 return getSingleWQValues(); | 748 return getSingleWQValues(); |
826 } | 749 } else { |
827 else { | |
828 return getWQTriple(); | 750 return getWQTriple(); |
829 } | 751 } |
830 } | 752 } else { |
831 else { | |
832 log.warn("You try to get Qs, but W has been inserted."); | 753 log.warn("You try to get Qs, but W has been inserted."); |
833 return null; | 754 return null; |
834 } | 755 } |
835 } | 756 } |
836 | 757 |
837 | |
838 public boolean isQ() { | 758 public boolean isQ() { |
839 StateData mode = getData("wq_isq"); | 759 final StateData mode = getData("wq_isq"); |
840 String value = (mode != null) ? (String) mode.getValue() : null; | 760 final String value = (mode != null) ? (String) mode.getValue() : null; |
841 return value != null ? Boolean.valueOf(value) : false; | 761 return value != null ? Boolean.valueOf(value) : false; |
842 } | 762 } |
843 | 763 |
844 public boolean isW() { | 764 public boolean isW() { |
845 StateData mode = getData("wq_isq"); | 765 final StateData mode = getData("wq_isq"); |
846 String value = (mode != null) ? (String) mode.getValue() : null; | 766 final String value = (mode != null) ? (String) mode.getValue() : null; |
847 return value != null ? !Boolean.valueOf(value) : false; | 767 return value != null ? !Boolean.valueOf(value) : false; |
848 } | 768 } |
849 | 769 |
850 public boolean isFreeW() { | 770 public boolean isFreeW() { |
851 if(!isW()) { | 771 if (!isW()) { |
852 return false; | 772 return false; |
853 } | 773 } |
854 StateData mode = getData("wq_isfree"); | 774 final StateData mode = getData("wq_isfree"); |
855 String value = (mode != null) ? (String) mode.getValue() : null; | 775 final String value = (mode != null) ? (String) mode.getValue() : null; |
856 | 776 |
857 return value != null ? Boolean.valueOf(value) : false; | 777 return value != null ? Boolean.valueOf(value) : false; |
858 } | 778 } |
859 | |
860 | 779 |
861 /** | 780 /** |
862 * Returns true, if the parameter is set to compute data on a free range. | 781 * Returns true, if the parameter is set to compute data on a free range. |
863 * Otherwise it returns false, which tells the calculation that it is bound | 782 * Otherwise it returns false, which tells the calculation that it is bound |
864 * to a gauge. | 783 * to a gauge. |
865 * | 784 * |
866 * @return true, if the calculation should compute on a free range otherwise | 785 * @return true, if the calculation should compute on a free range otherwise |
867 * false and the calculation is bound to a gauge. | 786 * false and the calculation is bound to a gauge. |
868 */ | 787 */ |
869 public boolean isFreeQ() { | 788 public boolean isFreeQ() { |
870 if(!isQ()) { | 789 if (!isQ()) { |
871 return false; | 790 return false; |
872 } | 791 } |
873 StateData mode = getData("wq_isfree"); | 792 final StateData mode = getData("wq_isfree"); |
874 String value = (mode != null) ? (String) mode.getValue() : null; | 793 final String value = (mode != null) ? (String) mode.getValue() : null; |
875 | 794 |
876 log.debug("isFreeQ: " + value); | 795 log.debug("isFreeQ: " + value); |
877 | 796 |
878 return value != null && Boolean.valueOf(value); | 797 return value != null && Boolean.valueOf(value); |
879 } | 798 } |
880 | 799 |
881 | |
882 /** | 800 /** |
883 * Returns the Q values based on a specified kilometer range. | 801 * Returns the Q values based on a specified kilometer range. |
884 * | 802 * |
885 * @param range A 2dim array with lower and upper kilometer range. | 803 * @param range |
804 * A 2dim array with lower and upper kilometer range. | |
886 * | 805 * |
887 * @return an array of Q values. | 806 * @return an array of Q values. |
888 */ | 807 */ |
889 public double[] getQs(double[] range) { | 808 public double[] getQs(final double[] range) { |
890 StateData dMode = getData("wq_isq"); | 809 final StateData dMode = getData("wq_isq"); |
891 | 810 |
892 if (isQ()) { | 811 if (isQ()) { |
893 return getWQForDist(range); | 812 return getWQForDist(range); |
894 } | 813 } |
895 | 814 |
896 log.warn("You try to get Qs, but Ws has been inserted."); | 815 log.warn("You try to get Qs, but Ws has been inserted."); |
897 return null; | 816 return null; |
898 } | 817 } |
899 | 818 |
900 | |
901 /** | 819 /** |
902 * Returns the W values based on a specified kilometer range. | 820 * Returns the W values based on a specified kilometer range. |
903 * | 821 * |
904 * @param range A 2dim array with lower and upper kilometer range. | 822 * @param range |
823 * A 2dim array with lower and upper kilometer range. | |
905 * | 824 * |
906 * @return an array of W values. | 825 * @return an array of W values. |
907 */ | 826 */ |
908 public double[] getWs(double[] range) { | 827 public double[] getWs(final double[] range) { |
909 if (isW()) { | 828 if (isW()) { |
910 return getWQForDist(range); | 829 return getWQForDist(range); |
911 } | 830 } |
912 | 831 |
913 log.warn("You try to get Ws, but Qs has been inserted."); | 832 log.warn("You try to get Ws, but Qs has been inserted."); |
914 return null; | 833 return null; |
915 } | 834 } |
916 | 835 |
917 | |
918 /** | 836 /** |
919 * This method returns the W values. | 837 * This method returns the W values. |
920 * | 838 * |
921 * @return the selected W values or null, if no W values are selected. | 839 * @return the selected W values or null, if no W values are selected. |
922 */ | 840 */ |
923 public double[] getWs() { | 841 public double[] getWs() { |
924 if (isW()) { | 842 if (isW()) { |
925 StateData dSingle = getData("wq_single"); | 843 final StateData dSingle = getData("wq_single"); |
926 if (dSingle != null) { | 844 if (dSingle != null) { |
927 return getSingleWQValues(); | 845 return getSingleWQValues(); |
928 } | 846 } else { |
929 else { | |
930 return getWQTriple(); | 847 return getWQTriple(); |
931 } | 848 } |
932 } | 849 } else { |
933 else { | |
934 log.warn("You try to get Ws, but Q has been inserted."); | 850 log.warn("You try to get Ws, but Q has been inserted."); |
935 return null; | 851 return null; |
936 } | 852 } |
937 } | 853 } |
938 | 854 |
939 /** | 855 /** |
940 * This method returns the given W or Q values for a specific range | 856 * This method returns the given W or Q values for a specific range |
941 * (inserted in the WQ input panel for discharge longitudinal sections). | 857 * (inserted in the WQ input panel for discharge longitudinal sections). |
942 * | 858 * |
943 * @param dist A 2dim array with lower und upper kilometer values. | 859 * @param dist |
860 * A 2dim array with lower und upper kilometer values. | |
944 * | 861 * |
945 * @return an array of W or Q values. | 862 * @return an array of W or Q values. |
946 */ | 863 */ |
947 protected double[] getWQForDist(double[] dist) { | 864 protected double[] getWQForDist(final double[] dist) { |
948 log.debug("Search wq values for range: " + dist[0] + " - " + dist[1]); | 865 log.debug("Search wq values for range: " + dist[0] + " - " + dist[1]); |
949 StateData data = getData("wq_values"); | 866 final StateData data = getData("wq_values"); |
950 | 867 |
951 if (data == null) { | 868 if (data == null) { |
952 log.warn("Missing wq values!"); | 869 log.warn("Missing wq values!"); |
953 return null; | 870 return null; |
954 } | 871 } |
955 | 872 |
956 String dataString = (String) data.getValue(); | 873 final String dataString = (String) data.getValue(); |
957 String[] ranges = dataString.split(":"); | 874 final String[] ranges = dataString.split(":"); |
958 | 875 |
959 for (String range: ranges) { | 876 for (final String range : ranges) { |
960 String[] parts = range.split(";"); | 877 final String[] parts = range.split(";"); |
961 | 878 |
962 double lower = Double.parseDouble(parts[0]); | 879 final double lower = Double.parseDouble(parts[0]); |
963 double upper = Double.parseDouble(parts[1]); | 880 final double upper = Double.parseDouble(parts[1]); |
964 | 881 |
965 if (lower <= dist[0] && upper >= dist[1]) { | 882 if (lower <= dist[0] && upper >= dist[1]) { |
966 String[] values = parts[2].split(","); | 883 final String[] values = parts[2].split(","); |
967 | 884 |
968 int num = values.length; | 885 final int num = values.length; |
969 double[] res = new double[num]; | 886 final double[] res = new double[num]; |
970 | 887 |
971 for (int i = 0; i < num; i++) { | 888 for (int i = 0; i < num; i++) { |
972 try { | 889 try { |
973 res[i] = Double.parseDouble(values[i]); | 890 res[i] = Double.parseDouble(values[i]); |
974 } | 891 } |
975 catch (NumberFormatException nfe) { | 892 catch (final NumberFormatException nfe) { |
976 log.warn(nfe, nfe); | 893 log.warn(nfe, nfe); |
977 } | 894 } |
978 } | 895 } |
979 | 896 |
980 return res; | 897 return res; |
984 log.warn("Specified range for WQ not found!"); | 901 log.warn("Specified range for WQ not found!"); |
985 | 902 |
986 return null; | 903 return null; |
987 } | 904 } |
988 | 905 |
989 | |
990 /** | 906 /** |
991 * This method returns an array of inserted WQ triples that consist of from, | 907 * This method returns an array of inserted WQ triples that consist of from, |
992 * to and the step width. | 908 * to and the step width. |
993 * | 909 * |
994 * @return an array of from, to and step width. | 910 * @return an array of from, to and step width. |
995 */ | 911 */ |
996 protected double[] getWQTriple() { | 912 protected double[] getWQTriple() { |
997 StateData dFrom = getData("wq_from"); | 913 final StateData dFrom = getData("wq_from"); |
998 StateData dTo = getData("wq_to"); | 914 final StateData dTo = getData("wq_to"); |
999 | 915 |
1000 if (dFrom == null || dTo == null) { | 916 if (dFrom == null || dTo == null) { |
1001 log.warn("Missing start or end value for range."); | 917 log.warn("Missing start or end value for range."); |
1002 return null; | 918 return null; |
1003 } | 919 } |
1004 | 920 |
1005 double from = Double.parseDouble((String) dFrom.getValue()); | 921 final double from = Double.parseDouble((String) dFrom.getValue()); |
1006 double to = Double.parseDouble((String) dTo.getValue()); | 922 final double to = Double.parseDouble((String) dTo.getValue()); |
1007 | 923 |
1008 StateData dStep = getData("wq_step"); | 924 final StateData dStep = getData("wq_step"); |
1009 | 925 |
1010 if (dStep == null) { | 926 if (dStep == null) { |
1011 log.warn("No step width given. Cannot compute Qs."); | 927 log.warn("No step width given. Cannot compute Qs."); |
1012 return null; | 928 return null; |
1013 } | 929 } |
1014 | 930 |
1015 double step = Double.parseDouble((String) dStep.getValue()); | 931 double step = Double.parseDouble((String) dStep.getValue()); |
1016 | 932 |
1017 // if no width is given, the DEFAULT_Q_STEPS is used to compute the step | 933 // if no width is given, the DEFAULT_Q_STEPS is used to compute the step |
1018 // width. Maybe, we should round the value to a number of digits. | 934 // width. Maybe, we should round the value to a number of digits. |
1019 if (step == 0d) { | 935 if (step == 0d) { |
1020 double diff = to - from; | 936 final double diff = to - from; |
1021 step = diff / DEFAULT_Q_STEPS; | 937 step = diff / DEFAULT_Q_STEPS; |
1022 } | 938 } |
1023 | 939 |
1024 return DoubleUtil.explode(from, to, step); | 940 return DoubleUtil.explode(from, to, step); |
1025 } | 941 } |
1026 | |
1027 | 942 |
1028 /** | 943 /** |
1029 * Returns an array of inserted WQ double values stored as whitespace | 944 * Returns an array of inserted WQ double values stored as whitespace |
1030 * separated list. | 945 * separated list. |
1031 * | 946 * |
1032 * @return an array of W or Q values. | 947 * @return an array of W or Q values. |
1033 */ | 948 */ |
1034 protected double[] getSingleWQValues() { | 949 protected double[] getSingleWQValues() { |
1035 StateData dSingle = getData("wq_single"); | 950 final StateData dSingle = getData("wq_single"); |
1036 | 951 |
1037 if (dSingle == null) { | 952 if (dSingle == null) { |
1038 log.warn("Cannot determine single WQ values. No data given."); | 953 log.warn("Cannot determine single WQ values. No data given."); |
1039 return null; | 954 return null; |
1040 } | 955 } |
1041 | 956 |
1042 String tmp = (String) dSingle.getValue(); | 957 final String tmp = (String) dSingle.getValue(); |
1043 String[] strValues = tmp.split(" "); | 958 final String[] strValues = tmp.split(" "); |
1044 | 959 |
1045 TDoubleArrayList values = new TDoubleArrayList(); | 960 final TDoubleArrayList values = new TDoubleArrayList(); |
1046 | 961 |
1047 for (String strValue: strValues) { | 962 for (final String strValue : strValues) { |
1048 try { | 963 try { |
1049 values.add(Double.parseDouble(strValue)); | 964 values.add(Double.parseDouble(strValue)); |
1050 } | 965 } |
1051 catch (NumberFormatException nfe) { | 966 catch (final NumberFormatException nfe) { |
1052 log.warn(nfe, nfe); | 967 log.warn(nfe, nfe); |
1053 } | 968 } |
1054 } | 969 } |
1055 | 970 |
1056 values.sort(); | 971 values.sort(); |