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 :

http://dive4elements.wald.intevation.org