Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 430:7ab81ff32111 2.3
merged flys-artifacts/2.3
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:10 +0200 |
parents | eb22ffe4d74c |
children | 5d65fe4c08d5 |
comparison
equal
deleted
inserted
replaced
290:a6f56ed9238b | 430:7ab81ff32111 |
---|---|
1 package de.intevation.flys.artifacts; | |
2 | |
3 import java.util.List; | |
4 import java.util.Vector; | |
5 | |
6 import org.w3c.dom.Document; | |
7 import org.w3c.dom.Element; | |
8 import org.w3c.dom.Node; | |
9 | |
10 import org.apache.log4j.Logger; | |
11 | |
12 import de.intevation.artifacts.ArtifactNamespaceContext; | |
13 import de.intevation.artifacts.CallContext; | |
14 | |
15 import de.intevation.artifactdatabase.ProtocolUtils; | |
16 import de.intevation.artifactdatabase.state.Output; | |
17 import de.intevation.artifactdatabase.state.State; | |
18 import de.intevation.artifactdatabase.state.StateEngine; | |
19 import de.intevation.artifactdatabase.transition.TransitionEngine; | |
20 | |
21 import de.intevation.artifacts.common.utils.XMLUtils; | |
22 | |
23 import de.intevation.flys.model.Gauge; | |
24 import de.intevation.flys.model.River; | |
25 | |
26 import de.intevation.flys.artifacts.states.DefaultState; | |
27 import de.intevation.flys.artifacts.context.FLYSContext; | |
28 import de.intevation.flys.artifacts.math.BackJumpCorrector; | |
29 import de.intevation.flys.artifacts.model.MainValuesFactory; | |
30 import de.intevation.flys.artifacts.model.WQCKms; | |
31 import de.intevation.flys.artifacts.model.WQDay; | |
32 import de.intevation.flys.artifacts.model.WQKms; | |
33 import de.intevation.flys.artifacts.model.WstValueTable; | |
34 | |
35 | |
36 /** | |
37 * The default WINFO artifact. | |
38 * | |
39 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
40 */ | |
41 public class WINFOArtifact extends FLYSArtifact { | |
42 | |
43 /** The logger for this class */ | |
44 private static Logger logger = Logger.getLogger(WINFOArtifact.class); | |
45 | |
46 | |
47 /** The name of the artifact.*/ | |
48 public static final String ARTIFACT_NAME = "winfo"; | |
49 | |
50 /** XPath */ | |
51 public static final String XPATH_STATIC_UI ="/art:result/art:ui/art:static"; | |
52 | |
53 | |
54 /** | |
55 * The default constructor. | |
56 */ | |
57 public WINFOArtifact() { | |
58 } | |
59 | |
60 | |
61 /** | |
62 * This method returns a description of this artifact. | |
63 * | |
64 * @param data Some data. | |
65 * @param context The CallContext. | |
66 * | |
67 * @return the description of this artifact. | |
68 */ | |
69 public Document describe(Document data, CallContext context) { | |
70 logger.debug("Describe: the current state is: " + getCurrentStateId()); | |
71 | |
72 FLYSContext flysContext = null; | |
73 if (context instanceof FLYSContext) { | |
74 flysContext = (FLYSContext) context; | |
75 } | |
76 else { | |
77 flysContext = (FLYSContext) context.globalContext(); | |
78 } | |
79 | |
80 StateEngine stateEngine = (StateEngine) flysContext.get( | |
81 FLYSContext.STATE_ENGINE_KEY); | |
82 | |
83 TransitionEngine transitionEngine = (TransitionEngine) flysContext.get( | |
84 FLYSContext.TRANSITION_ENGINE_KEY); | |
85 | |
86 List<State> reachable = transitionEngine.getReachableStates( | |
87 this, getCurrentState(context), stateEngine); | |
88 | |
89 Document description = XMLUtils.newDocument(); | |
90 XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( | |
91 description, | |
92 ArtifactNamespaceContext.NAMESPACE_URI, | |
93 ArtifactNamespaceContext.NAMESPACE_PREFIX); | |
94 | |
95 Element root = ProtocolUtils.createRootNode(creator); | |
96 description.appendChild(root); | |
97 | |
98 State current = getCurrentState(context); | |
99 | |
100 ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash()); | |
101 ProtocolUtils.appendState(creator, root, current); | |
102 ProtocolUtils.appendReachableStates(creator, root, reachable); | |
103 | |
104 Element name = ProtocolUtils.createArtNode( | |
105 creator, "name", | |
106 new String[] { "value" }, | |
107 new String[] { getName() }); | |
108 | |
109 Element ui = ProtocolUtils.createArtNode( | |
110 creator, "ui", null, null); | |
111 | |
112 Element staticUI = ProtocolUtils.createArtNode( | |
113 creator, "static", null, null); | |
114 | |
115 Element outs = ProtocolUtils.createArtNode( | |
116 creator, "outputmodes", null, null); | |
117 appendOutputModes(description, outs, context, identifier()); | |
118 | |
119 appendStaticUI(description, staticUI, context, identifier()); | |
120 | |
121 Element dynamic = current.describe( | |
122 this, | |
123 description, | |
124 root, | |
125 context, | |
126 identifier()); | |
127 | |
128 if (dynamic != null) { | |
129 ui.appendChild(dynamic); | |
130 } | |
131 | |
132 ui.appendChild(staticUI); | |
133 | |
134 root.appendChild(name); | |
135 root.appendChild(ui); | |
136 root.appendChild(outs); | |
137 | |
138 return description; | |
139 } | |
140 | |
141 | |
142 /** | |
143 * Returns the name of the concrete artifact. | |
144 * | |
145 * @return the name of the concrete artifact. | |
146 */ | |
147 public String getName() { | |
148 return ARTIFACT_NAME; | |
149 } | |
150 | |
151 | |
152 protected void appendOutputModes( | |
153 Document doc, | |
154 Element outs, | |
155 CallContext context, | |
156 String uuid) | |
157 { | |
158 Vector<String> stateIds = getPreviousStateIds(); | |
159 | |
160 XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( | |
161 doc, | |
162 ArtifactNamespaceContext.NAMESPACE_URI, | |
163 ArtifactNamespaceContext.NAMESPACE_PREFIX); | |
164 | |
165 FLYSContext flysContext = getFlysContext(context); | |
166 StateEngine engine = (StateEngine) flysContext.get( | |
167 FLYSContext.STATE_ENGINE_KEY); | |
168 | |
169 for (String stateId: stateIds) { | |
170 logger.debug("Append output modes for state: " + stateId); | |
171 State state = engine.getState(stateId); | |
172 | |
173 List<Output> list = state.getOutputs(); | |
174 if (list == null || list.size() == 0) { | |
175 continue; | |
176 } | |
177 | |
178 ProtocolUtils.appendOutputModes(creator, outs, list); | |
179 } | |
180 | |
181 try { | |
182 DefaultState cur = (DefaultState) getCurrentState(context); | |
183 if (cur.validate(this, context)) { | |
184 List<Output> list = cur.getOutputs(); | |
185 if (list != null && list.size() > 0) { | |
186 logger.debug( | |
187 "Append output modes for state: " + cur.getID()); | |
188 | |
189 ProtocolUtils.appendOutputModes(creator, outs, list); | |
190 } | |
191 } | |
192 } | |
193 catch (IllegalArgumentException iae) { | |
194 // state is not valid, so we do not append its outputs. | |
195 } | |
196 } | |
197 | |
198 | |
199 /** | |
200 * This method appends the static data - that has already been inserted by | |
201 * the user - to the static node of the DESCRIBE document. | |
202 * | |
203 * @param doc The document. | |
204 * @param ui The root node. | |
205 * @param context The CallContext. | |
206 * @param uuid The identifier of the artifact. | |
207 */ | |
208 protected void appendStaticUI( | |
209 Document doc, | |
210 Node ui, | |
211 CallContext context, | |
212 String uuid) | |
213 { | |
214 Vector<String> stateIds = getPreviousStateIds(); | |
215 | |
216 FLYSContext flysContext = getFlysContext(context); | |
217 StateEngine engine = (StateEngine) flysContext.get( | |
218 FLYSContext.STATE_ENGINE_KEY); | |
219 | |
220 for (String stateId: stateIds) { | |
221 logger.debug("Append static data for state: " + stateId); | |
222 DefaultState state = (DefaultState) engine.getState(stateId); | |
223 state = (DefaultState) fillState(state); | |
224 | |
225 ui.appendChild(state.describeStatic(doc, ui, context, uuid)); | |
226 } | |
227 } | |
228 | |
229 | |
230 // | |
231 // METHODS FOR RETRIEVING COMPUTED DATA FOR DIFFERENT CHART TYPES | |
232 // | |
233 | |
234 /** | |
235 * Returns the data that is computed by a waterlevel computation. | |
236 * | |
237 * @return an array of data triples that consist of W, Q and Kms. | |
238 */ | |
239 public WQKms[] getWaterlevelData() | |
240 throws NullPointerException | |
241 { | |
242 logger.debug("WINFOArtifact.getWaterlevelData"); | |
243 | |
244 River river = getRiver(); | |
245 if (river == null) { | |
246 throw new NullPointerException("No river selected."); | |
247 } | |
248 | |
249 double[] kms = getKms(); | |
250 if (kms == null) { | |
251 throw new NullPointerException("No Kms selected."); | |
252 } | |
253 | |
254 double[] qs = getQs(); | |
255 if (qs == null) { | |
256 logger.debug("Determine Q values based on a set of W values."); | |
257 | |
258 double[] ws = getWs(); | |
259 qs = getQsForWs(ws); | |
260 } | |
261 | |
262 WstValueTable wst = WstValueTable.getTable(river); | |
263 if (wst == null) { | |
264 throw new NullPointerException("No Wst found for selected river."); | |
265 } | |
266 | |
267 // TODO Introduce a caching mechanism here! | |
268 | |
269 return computeWaterlevelData(kms, qs, wst); | |
270 } | |
271 | |
272 | |
273 /** | |
274 * Computes the data of a waterlevel computation based on the interpolation | |
275 * in WstValueTable. | |
276 * | |
277 * @param kms The kilometer values. | |
278 * @param qa The discharge values. | |
279 * @param wst The WstValueTable used for the interpolation. | |
280 * | |
281 * @return an array of data triples that consist of W, Q and Kms. | |
282 */ | |
283 public static WQKms[] computeWaterlevelData( | |
284 double[] kms, | |
285 double[] qs, | |
286 WstValueTable wst) | |
287 { | |
288 logger.info("WINFOArtifact.computeWaterlevelData"); | |
289 | |
290 WQKms[] wqkms = new WQKms[qs.length]; | |
291 for (int i = 0; i < wqkms.length; i++) { | |
292 wqkms[i] = new WQKms(kms.length); | |
293 } | |
294 | |
295 double [] interpolatedW = new double[qs.length]; | |
296 | |
297 for (double km: kms) { | |
298 wst.interpolateW(km, qs, interpolatedW); | |
299 | |
300 // TODO Modify the interpolation to return a better formed data | |
301 // structure. | |
302 for (int i = 0; i < interpolatedW.length; i++) { | |
303 wqkms[i].add(interpolatedW[i], qs[i], km); | |
304 } | |
305 } | |
306 | |
307 return wqkms; | |
308 } | |
309 | |
310 | |
311 /** | |
312 * Returns the data that is computed by a duration curve computation. | |
313 * | |
314 * @return the data computed by a duration curve computation. | |
315 */ | |
316 public WQDay getDurationCurveData() | |
317 throws NullPointerException | |
318 { | |
319 logger.debug("WINFOArtifact.getDurationCurveData"); | |
320 | |
321 River r = getRiver(); | |
322 | |
323 if (r == null) { | |
324 throw new NullPointerException("Cannot determine river."); | |
325 } | |
326 | |
327 Gauge g = getGauge(); | |
328 | |
329 if (g == null) { | |
330 throw new NullPointerException("Cannot determine gauge."); | |
331 } | |
332 | |
333 double[] locations = getLocations(); | |
334 | |
335 if (locations == null) { | |
336 throw new NullPointerException("Cannot determine location."); | |
337 } | |
338 | |
339 WstValueTable wst = WstValueTable.getTable(r); | |
340 if (wst == null) { | |
341 throw new NullPointerException("No Wst found for selected river."); | |
342 } | |
343 | |
344 // TODO Introduce a caching mechanism here! | |
345 | |
346 return computeDurationCurveData(g, wst, locations[0]); | |
347 } | |
348 | |
349 | |
350 /** | |
351 * Computes the data used to create duration curves. | |
352 * | |
353 * @param gauge The selected gauge. | |
354 * @param location The selected location. | |
355 * | |
356 * @return the computed data. | |
357 */ | |
358 public static WQDay computeDurationCurveData( | |
359 Gauge gauge, | |
360 WstValueTable wst, | |
361 double location) | |
362 { | |
363 logger.info("WINFOArtifact.computeDurationCurveData"); | |
364 | |
365 Object[] obj = MainValuesFactory.getDurationCurveData(gauge); | |
366 | |
367 int[] days = (int[]) obj[0]; | |
368 double[] qs = (double[]) obj[1]; | |
369 | |
370 double[] interpolatedW = new double[qs.length]; | |
371 interpolatedW = wst.interpolateW(location, qs, interpolatedW); | |
372 | |
373 WQDay wqday = new WQDay(qs.length); | |
374 | |
375 for (int i = 0; i < days.length; i++) { | |
376 wqday.add(days[i], interpolatedW[i], qs[i]); | |
377 } | |
378 | |
379 return wqday; | |
380 } | |
381 | |
382 | |
383 /** | |
384 * Returns the data that is computed by a discharge curve computation. | |
385 * | |
386 * @return the data computed by a discharge curve computation. | |
387 */ | |
388 public WQKms getComputedDischargeCurveData() | |
389 throws NullPointerException | |
390 { | |
391 logger.debug("WINFOArtifact.getComputedDischargeCurveData"); | |
392 | |
393 River r = getRiver(); | |
394 | |
395 if (r == null) { | |
396 throw new NullPointerException("Cannot determine river."); | |
397 } | |
398 | |
399 double[] locations = getLocations(); | |
400 | |
401 if (locations == null) { | |
402 throw new NullPointerException("Cannot determine location."); | |
403 } | |
404 | |
405 WstValueTable wst = WstValueTable.getTable(r); | |
406 if (wst == null) { | |
407 throw new NullPointerException("No Wst found for selected river."); | |
408 } | |
409 | |
410 // TODO Introduce a caching mechanism here! | |
411 | |
412 return computeDischargeCurveData(wst, locations[0]); | |
413 } | |
414 | |
415 | |
416 /** | |
417 * Computes the data used to create computed discharge curves. | |
418 * | |
419 * @param wst The WstValueTable that is used for the interpolation. | |
420 * @param location The location where the computation should be based on. | |
421 * | |
422 * @return an object that contains tuples of W/Q values at the specified | |
423 * location. | |
424 */ | |
425 public static WQKms computeDischargeCurveData( | |
426 WstValueTable wst, | |
427 double location) | |
428 { | |
429 logger.info("WINFOArtifact.computeDischargeCurveData"); | |
430 | |
431 double[][] wqs = wst.interpolateWQ(location); | |
432 | |
433 if (wqs == null) { | |
434 logger.error("Cannot compute discharge curve data."); | |
435 return null; | |
436 } | |
437 | |
438 double[] ws = wqs[0]; | |
439 double[] qs = wqs[1]; | |
440 | |
441 WQKms wqkms = new WQKms(ws.length); | |
442 | |
443 for (int i = 0; i < ws.length; i++) { | |
444 wqkms.add(ws[i], qs[i], location); | |
445 } | |
446 | |
447 return wqkms; | |
448 } | |
449 | |
450 | |
451 /** | |
452 * Returns the data computed by the discharge longitudinal section | |
453 * computation. | |
454 * | |
455 * @return an array of WQKms object - one object for each given Q value. | |
456 */ | |
457 public WQKms[] getDischargeLongitudinalSectionData() { | |
458 logger.debug("WINFOArtifact.getDischargeLongitudinalSectionData"); | |
459 | |
460 River river = getRiver(); | |
461 if (river == null) { | |
462 logger.error("No river selected."); | |
463 } | |
464 | |
465 WstValueTable wst = WstValueTable.getTable(river); | |
466 if (wst == null) { | |
467 logger.error("No Wst found for selected river."); | |
468 } | |
469 | |
470 double[][] dist = getSplittedDistance(); | |
471 int num = dist != null ? dist.length : 0; | |
472 | |
473 WQKms[][] wqkms = new WQKms[num][]; | |
474 | |
475 for (int i = 0; i < num; i++) { | |
476 double[] kms = getKms(dist[i]); | |
477 if (kms == null) { | |
478 // XXX maybe we should cancel this operation here. | |
479 continue; | |
480 } | |
481 | |
482 double[] qs = getQs(dist[i]); | |
483 if (qs == null) { | |
484 logger.debug("Determine Q values based on a set of W values."); | |
485 | |
486 double[] ws = getWs(dist[i]); | |
487 qs = getQsForWs(ws); | |
488 } | |
489 | |
490 wqkms[i] = computeWaterlevelData(kms, qs, wst); | |
491 } | |
492 | |
493 WQKms[] merged = WQKms.merge(wqkms); | |
494 int numMerged = merged.length; | |
495 WQKms[] computed = new WQKms[numMerged]; | |
496 | |
497 for (int i = 0; i < numMerged; i++) { | |
498 computed[i] = computeDischargeLongitudinalSectionData(merged[i]); | |
499 } | |
500 | |
501 // TODO Introduce a caching mechanism here! | |
502 | |
503 return computed; | |
504 } | |
505 | |
506 | |
507 /** | |
508 * Computes the data used for a discharge longitudinal section based on a | |
509 * given WQKms object. If there are backjumps while computing the data, a | |
510 * WQCKms object is returned, otherwise the incoming wqkms object. | |
511 * | |
512 * @param wqkms The WQKms object that contains W, Q and Kms. | |
513 * | |
514 * @return an instance of WQKms or WQCKms. | |
515 */ | |
516 public static WQKms computeDischargeLongitudinalSectionData(WQKms wqkms) { | |
517 logger.info("WINFOArtifact.computeDischargeLongitudinalSectionData"); | |
518 | |
519 BackJumpCorrector bjc = new BackJumpCorrector(); | |
520 | |
521 bjc.doCorrection(wqkms.getKms(), wqkms.getWs()); | |
522 | |
523 if (bjc.hasBackJumps()) { | |
524 logger.info("Discharge longitudinal section has backjumps."); | |
525 return new WQCKms( | |
526 wqkms.getKms(), | |
527 wqkms.getQs(), | |
528 wqkms.getWs(), | |
529 bjc.getCorrected()); | |
530 } | |
531 else { | |
532 logger.info("Discharge longitudinal section has no backjumps."); | |
533 return wqkms; | |
534 } | |
535 } | |
536 } | |
537 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |