comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 3468:f37e7e8907cb

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

http://dive4elements.wald.intevation.org