comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java @ 1055:61c051e53f9b

Moved WINFO specific stuff from FLYS into WINFO artifact. flys-artifacts/trunk@2525 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 22 Aug 2011 15:25:48 +0000
parents eccf966fb677
children bd1b751deab3
comparison
equal deleted inserted replaced
1054:1f3e944a805c 1055:61c051e53f9b
1 package de.intevation.flys.artifacts; 1 package de.intevation.flys.artifacts;
2 2
3 import java.util.Arrays; 3 import de.intevation.artifactdatabase.ArtifactDatabaseImpl;
4 import java.util.ArrayList; 4 import de.intevation.artifactdatabase.DefaultArtifact;
5 import java.util.Collection; 5
6 import java.util.Collections; 6 import de.intevation.artifactdatabase.data.DefaultStateData;
7 import java.util.HashMap; 7 import de.intevation.artifactdatabase.data.StateData;
8 import java.util.HashSet; 8
9 import java.util.TreeMap; 9 import de.intevation.artifactdatabase.state.DefaultOutput;
10 import java.util.List; 10 import de.intevation.artifactdatabase.state.Facet;
11 import java.util.Map; 11 import de.intevation.artifactdatabase.state.Output;
12 import java.util.Set; 12 import de.intevation.artifactdatabase.state.State;
13 13 import de.intevation.artifactdatabase.state.StateEngine;
14 import javax.xml.xpath.XPathConstants; 14
15 15 import de.intevation.artifactdatabase.transition.TransitionEngine;
16 import gnu.trove.TDoubleArrayList;
17
18 import net.sf.ehcache.Cache;
19
20 import org.apache.log4j.Logger;
21
22 import org.w3c.dom.Document;
23 import org.w3c.dom.Element;
24 import org.w3c.dom.NodeList;
25 16
26 import de.intevation.artifacts.Artifact; 17 import de.intevation.artifacts.Artifact;
27 import de.intevation.artifacts.ArtifactDatabase; 18 import de.intevation.artifacts.ArtifactDatabase;
28 import de.intevation.artifacts.ArtifactDatabaseException; 19 import de.intevation.artifacts.ArtifactDatabaseException;
29 import de.intevation.artifacts.ArtifactFactory; 20 import de.intevation.artifacts.ArtifactFactory;
30 import de.intevation.artifacts.CallContext; 21 import de.intevation.artifacts.CallContext;
31 import de.intevation.artifacts.CallMeta; 22 import de.intevation.artifacts.CallMeta;
32 23
33 import de.intevation.artifacts.common.ArtifactNamespaceContext; 24 import de.intevation.artifacts.common.ArtifactNamespaceContext;
25
34 import de.intevation.artifacts.common.utils.XMLUtils; 26 import de.intevation.artifacts.common.utils.XMLUtils;
35 27
36 import de.intevation.artifactdatabase.ArtifactDatabaseImpl; 28 import de.intevation.flys.artifacts.cache.CacheFactory;
37 import de.intevation.artifactdatabase.DefaultArtifact;
38 import de.intevation.artifactdatabase.data.DefaultStateData;
39 import de.intevation.artifactdatabase.data.StateData;
40 import de.intevation.artifactdatabase.state.DefaultOutput;
41 import de.intevation.artifactdatabase.state.Facet;
42 import de.intevation.artifactdatabase.state.Output;
43 import de.intevation.artifactdatabase.state.State;
44 import de.intevation.artifactdatabase.state.StateEngine;
45 import de.intevation.artifactdatabase.transition.TransitionEngine;
46
47 import de.intevation.flys.utils.DoubleUtil;
48
49 import de.intevation.flys.model.Gauge;
50 import de.intevation.flys.model.River;
51 29
52 import de.intevation.flys.artifacts.context.FLYSContext; 30 import de.intevation.flys.artifacts.context.FLYSContext;
53 31
54 import de.intevation.flys.artifacts.cache.CacheFactory; 32 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
55
56 import de.intevation.flys.artifacts.model.DischargeTables;
57 import de.intevation.flys.artifacts.model.RiverFactory;
58 import de.intevation.flys.artifacts.model.Segment;
59 33
60 import de.intevation.flys.artifacts.states.DefaultState; 34 import de.intevation.flys.artifacts.states.DefaultState;
61 import de.intevation.flys.artifacts.states.DefaultState.ComputeType; 35
62 import de.intevation.flys.artifacts.states.LocationDistanceSelect; 36 import java.util.ArrayList;
63 37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.TreeMap;
44
45 import javax.xml.xpath.XPathConstants;
46
47 import net.sf.ehcache.Cache;
48
49 import org.apache.log4j.Logger;
50
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53 import org.w3c.dom.NodeList;
64 54
65 /** 55 /**
66 * The defaul FLYS artifact. 56 * The defaul FLYS artifact.
67 * 57 *
68 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> 58 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
89 /** The constant string that shows that an operation was successful.*/ 79 /** The constant string that shows that an operation was successful.*/
90 public static final String OPERATION_SUCCESSFUL = "SUCCESS"; 80 public static final String OPERATION_SUCCESSFUL = "SUCCESS";
91 81
92 /** The constant string that shows that an operation failed.*/ 82 /** The constant string that shows that an operation failed.*/
93 public static final String OPERATION_FAILED = "FAILURE"; 83 public static final String OPERATION_FAILED = "FAILURE";
94
95 /** The default number of steps between the start end end of a selected Q
96 * range.*/
97 public static final int DEFAULT_Q_STEPS = 30;
98
99 /** The default step width between the start end end kilometer.*/
100 public static final double DEFAULT_KM_STEPS = 0.1;
101 84
102 85
103 /** The identifier of the current state. */ 86 /** The identifier of the current state. */
104 protected String currentStateId; 87 protected String currentStateId;
105 88
516 if (prevs.contains(stateId)) { 499 if (prevs.contains(stateId)) {
517 return true; 500 return true;
518 } 501 }
519 502
520 return false; 503 return false;
521 }
522
523
524 /**
525 * Returns the selected River object based on the 'river' data that might
526 * have been inserted by the user.
527 *
528 * @return the selected River or null if no river has been chosen yet.
529 */
530 public River getRiver() {
531 StateData dRiver = getData("river");
532
533 return dRiver != null
534 ? RiverFactory.getRiver((String) dRiver.getValue())
535 : null;
536 }
537
538
539 /**
540 * Returns the selected distance of points.
541 *
542 * @return the selected distance or points.
543 */
544 public double[] getDistance() {
545 StateData dMode = getData("ld_mode");
546 StateData dFrom = getData("ld_from");
547 StateData dTo = getData("ld_to");
548 StateData dLocations = getData("ld_locations");
549
550 if (dMode != null) {
551 String mode = (String)dMode.getValue();
552 if ("location".equals(mode)) {
553 double[] locations = getLocations();
554 return new double[] { locations[0], locations[locations.length-1] };
555 }
556 if (dFrom != null && dTo != null) {
557 return getDistanceByRange(dFrom, dTo);
558 }
559 }
560
561 if (dLocations != null) {
562 double[] locations = getLocations();
563 return new double[] { locations[0], locations[locations.length-1] };
564 }
565
566 if (dFrom != null && dTo != null) {
567 return getDistanceByRange(dFrom, dTo);
568 }
569
570 logger.warn("No data found for distance determination!");
571
572 return null;
573 }
574
575
576 /**
577 * Determines the selected mode of distance/range input.
578 *
579 * @return true, if the range mode is selected otherwise false.
580 */
581 public boolean isRange() {
582 StateData mode = getData("ld_mode");
583
584 if (mode == null) {
585 logger.warn("No mode location/range chosen. Defaults to range.");
586 return true;
587 }
588
589 String value = (String) mode.getValue();
590
591 return value.equals("distance");
592 }
593
594
595 /**
596 * Returns the selected locations based on a given array of locations.
597 *
598 * @param locations The StateData that contains the locations.
599 *
600 * @return the selected locations.
601 */
602 public double[] getLocations() {
603 StateData dLocations = getData("ld_locations");
604 String locationStr = dLocations != null
605 ? (String) dLocations.getValue()
606 : "";
607
608 if (locationStr == null || locationStr.length() == 0) {
609 logger.warn("No valid location string found!");
610 return null;
611 }
612
613 String[] tmp = locationStr.split(" ");
614 TDoubleArrayList locations = new TDoubleArrayList();
615
616 for (String l: tmp) {
617 try {
618 locations.add(Double.parseDouble(l));
619 }
620 catch (NumberFormatException nfe) {
621 logger.warn(nfe, nfe);
622 }
623 }
624
625 locations.sort();
626
627 return locations.toNativeArray();
628 }
629
630
631 /**
632 * Returns the selected distance based on a given range (from, to).
633 *
634 * @param dFrom The StateData that contains the lower value.
635 * @param dTo The StateData that contains the upper value.
636 *
637 * @return the selected distance.
638 */
639 protected double[] getDistanceByRange(StateData dFrom, StateData dTo) {
640 double from = Double.parseDouble((String) dFrom.getValue());
641 double to = Double.parseDouble((String) dTo.getValue());
642
643 return new double[] { from, to };
644 }
645
646
647 /**
648 * Returns the selected Kms.
649 *
650 * @param distance An 2dim array with [lower, upper] values.
651 *
652 * @return the selected Kms.
653 */
654 public double[] getKms(double[] distance) {
655 StateData dStep = getData("ld_step");
656
657 if (dStep == null) {
658 logger.warn("No step width given. Cannot compute Kms.");
659 return null;
660 }
661
662 double step = Double.parseDouble((String) dStep.getValue());
663
664 // transform step from 'm' into 'km'
665 step = step / 1000;
666
667 if (step == 0d) {
668 step = DEFAULT_KM_STEPS;
669 }
670
671 return DoubleUtil.explode(distance[0], distance[1], step);
672 }
673
674
675 /**
676 * Returns the selected Kms.
677 *
678 * @return the selected kms.
679 */
680 public double[] getKms() {
681 if (isRange()) {
682 double[] distance = getDistance();
683 return getKms(distance);
684
685 }
686 else {
687 return LocationDistanceSelect.getLocations(this);
688 }
689 }
690
691 public double [] getFromToStep() {
692 if (!isRange()) {
693 return null;
694 }
695 double [] fromTo = getDistance();
696
697 if (fromTo == null) {
698 return null;
699 }
700
701 StateData dStep = getData("ld_step");
702 if (dStep == null) {
703 return null;
704 }
705
706 double [] result = new double[3];
707 result[0] = fromTo[0];
708 result[1] = fromTo[1];
709
710 try {
711 String step = (String)dStep.getValue();
712 result[2] = DoubleUtil.round(Double.parseDouble(step) / 1000d);
713 }
714 catch (NumberFormatException nfe) {
715 return null;
716 }
717
718 return result;
719 }
720
721
722 /**
723 * Returns the gauge based on the current distance and river.
724 *
725 * @return the gauge.
726 */
727 public Gauge getGauge() {
728 River river = getRiver();
729
730 if (river == null) {
731 logger.debug("no river found");
732 return null;
733 }
734
735 double[] dist = getDistance();
736
737 if (dist == null) {
738 logger.debug("no range found");
739 return null;
740 }
741
742 if (logger.isDebugEnabled()) {
743 logger.debug("Determine gauge for:");
744 logger.debug("... river: " + river.getName());
745 logger.debug("... distance: " + dist[0] + " - " + dist[1]);
746 }
747
748 Gauge gauge = river.determineGauge(dist[0], dist[1]);
749
750 String name = gauge != null ? gauge.getName() : "'n/a";
751 logger.debug("Found gauge: " + name);
752
753 return gauge;
754 }
755
756
757 /**
758 * Returns the gauges that match the selected kilometer range.
759 *
760 * @return the gauges based on the selected kilometer range.
761 */
762 public List<Gauge> getGauges() {
763
764 River river = getRiver();
765 if (river == null) {
766 return null;
767 }
768
769 double [] dist = getDistance();
770 if (dist == null) {
771 return null;
772 }
773
774 return river.determineGauges(dist[0], dist[1]);
775 }
776
777
778 /**
779 * This method returns the Q values.
780 *
781 * @return the selected Q values or null, if no Q values are selected.
782 */
783 public double[] getQs() {
784 StateData dMode = getData("wq_mode");
785 StateData dSelection = getData("wq_selection");
786
787 String mode = dMode != null ? (String) dMode.getValue() : "";
788 String sel = dSelection != null ? (String)dSelection.getValue() : null;
789
790 if (mode.equals("Q")) {
791 if (sel != null && sel.equals("single")) {
792 return getSingleWQValues();
793 }
794 else {
795 return getWQTriple();
796 }
797 }
798 else {
799 logger.warn("You try to get Qs, but W has been inserted.");
800 return null;
801 }
802 }
803
804
805 public boolean isQ() {
806 StateData mode = getData("wq_mode");
807 return mode != null && mode.getValue().equals("Q");
808 }
809
810
811 /**
812 * Returns true, if the parameter is set to compute data on a free range.
813 * Otherwise it returns false, which tells the calculation that it is bound
814 * to a gauge.
815 *
816 * @return true, if the calculation should compute on a free range otherwise
817 * false and the calculation is bound to a gauge.
818 */
819 public boolean isFreeQ() {
820 StateData mode = getData("wq_free");
821 String value = mode != null ? (String) mode.getValue() : null;
822
823 logger.debug("isFreeQ: " + value);
824
825 if (value == null) {
826 return false;
827 }
828
829 return Boolean.valueOf(value);
830 }
831
832
833 /**
834 * Returns the Q values based on a specified kilometer range.
835 *
836 * @param range A 2dim array with lower and upper kilometer range.
837 *
838 * @return an array of Q values.
839 */
840 public double[] getQs(double[] range) {
841 StateData dMode = getData("wq_mode");
842 StateData dValues = getData("wq_values");
843
844 String mode = dMode != null ? (String) dMode.getValue() : "";
845
846 if (mode.equals("Q")) {
847 return getWQForDist(range);
848 }
849
850 logger.warn("You try to get Qs, but Ws has been inserted.");
851 return null;
852 }
853
854
855 /**
856 * Returns the W values based on a specified kilometer range.
857 *
858 * @param range A 2dim array with lower and upper kilometer range.
859 *
860 * @return an array of W values.
861 */
862 public double[] getWs(double[] range) {
863 StateData dMode = getData("wq_mode");
864 StateData dValues = getData("wq_values");
865
866 String mode = dMode != null ? (String) dMode.getValue() : "";
867
868 if (mode.equals("W")) {
869 return getWQForDist(range);
870 }
871
872 logger.warn("You try to get Ws, but Qs has been inserted.");
873 return null;
874 }
875
876
877 /**
878 * This method returns the W values.
879 *
880 * @return the selected W values or null, if no W values are selected.
881 */
882 public double[] getWs() {
883 StateData dMode = getData("wq_mode");
884 StateData dSingle = getData("wq_single");
885
886 String mode = dMode != null ? (String) dMode.getValue() : "";
887
888 if (mode.equals("W")) {
889 if (dSingle != null) {
890 return getSingleWQValues();
891 }
892 else {
893 return getWQTriple();
894 }
895 }
896 else {
897 logger.warn("You try to get Qs, but W has been inserted.");
898 return null;
899 }
900 }
901
902 public List<Segment> getSegments() {
903 StateData wqValues = getData("wq_values");
904 if (wqValues == null) {
905 logger.warn("no wq_values given");
906 return Collections.emptyList();
907 }
908 String input = (String)wqValues.getValue();
909 if (input == null || (input = input.trim()).length() == 0) {
910 logger.warn("wq_values are empty");
911 return Collections.emptyList();
912 }
913 return Segment.parseSegments(input);
914 }
915
916
917 /**
918 * Returns the Qs for a number of Ws. This method makes use of
919 * DischargeTables.getQForW().
920 *
921 * @param ws An array of W values.
922 *
923 * @return an array of Q values.
924 */
925 public double[] getQsForWs(double[] ws) {
926
927 boolean debug = logger.isDebugEnabled();
928
929 if (debug) {
930 logger.debug("FLYSArtifact.getQsForWs");
931 }
932
933 River r = getRiver();
934 if (r == null) {
935 logger.warn("no river found");
936 return null;
937
938 }
939
940 double [] range = getDistance();
941 if (range == null) {
942 logger.warn("no ranges found");
943 return null;
944 }
945
946 if (debug) {
947 logger.debug("range: " + Arrays.toString(range));
948 }
949
950 Gauge g = r.determineGaugeByPosition(range[0]);
951 if (g == null) {
952 logger.warn("no gauge found for km: " + range[0]);
953 return null;
954 }
955
956 if (debug) {
957 logger.debug("convert w->q with gauge '" + g.getName() + "'");
958 }
959
960 DischargeTables dt = new DischargeTables(r.getName(), g.getName());
961 Map<String, double [][]> tmp = dt.getValues();
962
963 double[][] values = tmp.get(g.getName());
964 double[] qs = new double[ws.length];
965
966 for (int i = 0; i < ws.length; i++) {
967 qs[i] = dt.getQForW(values, ws[i]);
968 if (debug) {
969 logger.debug("w: " + ws[i] + " -> q: " + qs[i]);
970 }
971 }
972
973 return qs;
974 }
975
976 /**
977 * This method returns the given W or Q values for a specific range
978 * (inserted in the WQ input panel for discharge longitudinal sections).
979 *
980 * @param dist A 2dim array with lower und upper kilometer values.
981 *
982 * @return an array of W or Q values.
983 */
984 protected double[] getWQForDist(double[] dist) {
985 logger.debug("Search wq values for range: " + dist[0] + " - " + dist[1]);
986 StateData data = getData("wq_values");
987
988 if (data == null) {
989 logger.warn("Missing wq values!");
990 return null;
991 }
992
993 String dataString = (String) data.getValue();
994 String[] ranges = dataString.split(":");
995
996 for (String range: ranges) {
997 String[] parts = range.split(";");
998
999 double lower = Double.parseDouble(parts[0]);
1000 double upper = Double.parseDouble(parts[1]);
1001
1002 if (lower <= dist[0] && upper >= dist[1]) {
1003 String[] values = parts[2].split(",");
1004
1005 int num = values.length;
1006 double[] res = new double[num];
1007
1008 for (int i = 0; i < num; i++) {
1009 try {
1010 res[i] = Double.parseDouble(values[i]);
1011 }
1012 catch (NumberFormatException nfe) {
1013 logger.warn(nfe, nfe);
1014 }
1015 }
1016
1017 return res;
1018 }
1019 }
1020
1021 logger.warn("Specified range for WQ not found!");
1022
1023 return null;
1024 }
1025
1026
1027 /**
1028 * This method returns an array of inserted WQ triples that consist of from,
1029 * to and the step width.
1030 *
1031 * @return an array of from, to and step width.
1032 */
1033 protected double[] getWQTriple() {
1034 StateData dFrom = getData("wq_from");
1035 StateData dTo = getData("wq_to");
1036
1037 if (dFrom == null || dTo == null) {
1038 logger.warn("Missing start or end value for range.");
1039 return null;
1040 }
1041
1042 double from = Double.parseDouble((String) dFrom.getValue());
1043 double to = Double.parseDouble((String) dTo.getValue());
1044
1045 StateData dStep = getData("wq_step");
1046
1047 if (dStep == null) {
1048 logger.warn("No step width given. Cannot compute Qs.");
1049 return null;
1050 }
1051
1052 double step = Double.parseDouble((String) dStep.getValue());
1053
1054 // if no width is given, the DEFAULT_Q_STEPS is used to compute the step
1055 // width. Maybe, we should round the value to a number of digits.
1056 if (step == 0d) {
1057 double diff = to - from;
1058 step = diff / DEFAULT_Q_STEPS;
1059 }
1060
1061 return DoubleUtil.explode(from, to, step);
1062 }
1063
1064
1065 /**
1066 * Returns an array of inserted WQ double values stored as whitespace
1067 * separated list.
1068 *
1069 * @return an array of W or Q values.
1070 */
1071 protected double[] getSingleWQValues() {
1072 StateData dSingle = getData("wq_single");
1073
1074 if (dSingle == null) {
1075 logger.warn("Cannot determine single WQ values. No data given.");
1076 return null;
1077 }
1078
1079 String tmp = (String) dSingle.getValue();
1080 String[] strValues = tmp.split(" ");
1081
1082 TDoubleArrayList values = new TDoubleArrayList();
1083
1084 for (String strValue: strValues) {
1085 try {
1086 values.add(Double.parseDouble(strValue));
1087 }
1088 catch (NumberFormatException nfe) {
1089 logger.warn(nfe, nfe);
1090 }
1091 }
1092
1093 values.sort();
1094
1095 return values.toNativeArray();
1096 } 504 }
1097 505
1098 506
1099 /** 507 /**
1100 * Computes the hash code of the entered values. 508 * Computes the hash code of the entered values.

http://dive4elements.wald.intevation.org