comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java @ 3786:4adc35aa655c

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

http://dive4elements.wald.intevation.org