Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/SoilKindKmValueFinder.java @ 8964:45f1ad66560e
Code cleanup concerning calculations: improved error handling; improved interpolation; bed heights are now always used for spatial discretisation
author | gernotbelger |
---|---|
date | Thu, 29 Mar 2018 15:48:17 +0200 |
parents | 1a8f19f3b776 |
children | b194fa64506a |
comparison
equal
deleted
inserted
replaced
8963:b98fbd91f64a | 8964:45f1ad66560e |
---|---|
14 import java.util.Map.Entry; | 14 import java.util.Map.Entry; |
15 import java.util.NavigableMap; | 15 import java.util.NavigableMap; |
16 import java.util.TreeMap; | 16 import java.util.TreeMap; |
17 | 17 |
18 import org.apache.commons.lang.math.DoubleRange; | 18 import org.apache.commons.lang.math.DoubleRange; |
19 import org.apache.commons.math.ArgumentOutsideDomainException; | 19 import org.dive4elements.river.artifacts.model.Calculation; |
20 import org.dive4elements.river.backend.SessionHolder; | 20 import org.dive4elements.river.backend.SessionHolder; |
21 import org.dive4elements.river.model.River; | 21 import org.dive4elements.river.model.River; |
22 import org.hibernate.SQLQuery; | 22 import org.hibernate.SQLQuery; |
23 import org.hibernate.Session; | 23 import org.hibernate.Session; |
24 import org.hibernate.type.StandardBasicTypes; | 24 import org.hibernate.type.StandardBasicTypes; |
25 | |
26 | 25 |
27 /** | 26 /** |
28 * @author Matthias Schäfer | 27 * @author Matthias Schäfer |
29 */ | 28 */ |
30 final class SoilKindKmValueFinder { | 29 final class SoilKindKmValueFinder { |
36 /** | 35 /** |
37 * Query selecting the bed mobility attribute for a range of stations of a river | 36 * Query selecting the bed mobility attribute for a range of stations of a river |
38 */ | 37 */ |
39 private static final String SQL_BED_MOBILITY = "SELECT bmv.station, bmv.moving" | 38 private static final String SQL_BED_MOBILITY = "SELECT bmv.station, bmv.moving" |
40 + " FROM bed_mobility bm INNER JOIN bed_mobility_values bmv ON bm.id = bmv.bed_mobility_id" | 39 + " FROM bed_mobility bm INNER JOIN bed_mobility_values bmv ON bm.id = bmv.bed_mobility_id" |
41 + " WHERE (bm.river_id=:river_id) AND (bmv.station BETWEEN (:fromkm-0.0001) AND (:tokm+0.0001))" | 40 + " WHERE (bm.river_id=:river_id) AND (bmv.station BETWEEN (:fromkm-0.0001) AND (:tokm+0.0001))" + " ORDER BY bmv.station ASC"; |
42 + " ORDER BY bmv.station ASC"; | |
43 | 41 |
44 private final NavigableMap<Double, SoilKind> kmMobility; | 42 private final NavigableMap<Double, SoilKind> kmMobility = new TreeMap<>(); |
45 | 43 |
44 private Calculation problems; | |
46 | 45 |
47 /***** CONSTRUCTORS *****/ | 46 /***** CONSTRUCTORS *****/ |
48 | 47 |
49 private SoilKindKmValueFinder() { | 48 private SoilKindKmValueFinder(final Calculation problems, final List<Object[]> queryRows) { |
50 /* only instantiate me via static constructor */ | 49 this.problems = problems; |
51 this.kmMobility = null; | |
52 } | |
53 | 50 |
54 private SoilKindKmValueFinder(final List<Object[]> queryRows) { | |
55 this.kmMobility = new TreeMap<>(); | |
56 for (int i = 0; i <= queryRows.size() - 1; i++) { | 51 for (int i = 0; i <= queryRows.size() - 1; i++) { |
57 this.kmMobility.put(Double.valueOf((double) queryRows.get(i)[0]), (((int) queryRows.get(i)[1]) == 1) ? SoilKind.mobil : SoilKind.starr); | 52 this.kmMobility.put(Double.valueOf((double) queryRows.get(i)[0]), (((int) queryRows.get(i)[1]) == 1) ? SoilKind.mobil : SoilKind.starr); |
58 } | 53 } |
59 } | 54 } |
60 | 55 |
63 /** | 58 /** |
64 * Loads the range of the river's kms with their soil kind. | 59 * Loads the range of the river's kms with their soil kind. |
65 * | 60 * |
66 * @return Whether the load has been successful | 61 * @return Whether the load has been successful |
67 */ | 62 */ |
68 public static SoilKindKmValueFinder loadValues(final River river, final DoubleRange kmRange) { | 63 public static SoilKindKmValueFinder loadValues(final Calculation problems, final River river, final DoubleRange kmRange) { |
69 final Session session = SessionHolder.HOLDER.get(); | 64 final Session session = SessionHolder.HOLDER.get(); |
70 final SQLQuery sqlQuery = session.createSQLQuery(SQL_BED_MOBILITY).addScalar("station", StandardBasicTypes.DOUBLE) | 65 final SQLQuery sqlQuery = session.createSQLQuery(SQL_BED_MOBILITY).addScalar("station", StandardBasicTypes.DOUBLE).addScalar("moving", |
71 .addScalar("moving", StandardBasicTypes.INTEGER); | 66 StandardBasicTypes.INTEGER); |
72 sqlQuery.setInteger("river_id", river.getId().intValue()); | 67 sqlQuery.setInteger("river_id", river.getId().intValue()); |
73 sqlQuery.setDouble("fromkm", kmRange.getMinimumDouble()); | 68 sqlQuery.setDouble("fromkm", kmRange.getMinimumDouble()); |
74 sqlQuery.setDouble("tokm", kmRange.getMaximumDouble()); | 69 sqlQuery.setDouble("tokm", kmRange.getMaximumDouble()); |
75 final List<Object[]> rows = sqlQuery.list(); | 70 final List<Object[]> rows = sqlQuery.list(); |
76 if (rows.size() >= 1) | 71 if (rows.size() >= 1) |
77 return new SoilKindKmValueFinder(rows); | 72 return new SoilKindKmValueFinder(problems, rows); |
78 else | 73 |
79 return null; | 74 problems.addProblem("soilkindkmvaluefinder.empty"); |
75 return null; | |
80 } | 76 } |
81 | 77 |
82 /***** METHODS *****/ | 78 /***** METHODS *****/ |
83 | 79 |
84 /** | 80 /** |
85 * Searches a km with its soil kind | 81 * Searches a km with its soil kind |
86 */ | 82 */ |
87 public SoilKind findSoilKind(final double km) throws ArgumentOutsideDomainException { | 83 public SoilKind findSoilKind(final double km) { |
88 if ((this.kmMobility == null) || this.kmMobility.isEmpty()) | 84 |
89 throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN); | 85 if (this.kmMobility.containsKey(Double.valueOf(km))) |
90 else if (this.kmMobility.containsKey(Double.valueOf(km))) | |
91 return this.kmMobility.get(Double.valueOf(km)); | 86 return this.kmMobility.get(Double.valueOf(km)); |
92 else { | 87 |
93 // FIXME: Assert minimum distance between neighbouring stations and candidate km? | 88 final Entry<Double, SoilKind> streamUp = this.kmMobility.floorEntry(Double.valueOf(km)); |
94 final Entry<Double, SoilKind> streamUp = this.kmMobility.floorEntry(Double.valueOf(km)); | 89 if (streamUp == null) |
95 if (streamUp == null) | 90 { |
96 throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN); | 91 reportProblem(km); |
97 else { | 92 return null; |
98 // Return the soil kind of the neighbouring station with the shorter distance to the candidate. | |
99 final Entry<Double, SoilKind> streamDown = this.kmMobility.ceilingEntry(Double.valueOf(km)); | |
100 if (streamDown == null) | |
101 return streamUp.getValue(); | |
102 else if ((streamUp.getKey().doubleValue() + streamDown.getKey().doubleValue()) / 2 <= km) | |
103 return streamUp.getValue(); | |
104 else | |
105 return streamDown.getValue(); | |
106 } | |
107 } | 93 } |
94 | |
95 // FIXME: Assert minimum distance between neighbouring stations and candidate km? | |
96 | |
97 // Return the soil kind of the neighbouring station with the shorter distance to the candidate. | |
98 final Entry<Double, SoilKind> streamDown = this.kmMobility.ceilingEntry(Double.valueOf(km)); | |
99 if (streamDown == null) | |
100 return streamUp.getValue(); | |
101 | |
102 final double streamUpValue = streamUp.getKey().doubleValue(); | |
103 final double streamDownValue = streamDown.getKey().doubleValue(); | |
104 | |
105 if ((streamUpValue + streamDownValue) / 2 <= km) | |
106 return streamUp.getValue(); | |
107 | |
108 return streamDown.getValue(); | |
109 } | |
110 | |
111 private void reportProblem(final double km) { | |
112 if (this.problems == null) | |
113 return; | |
114 | |
115 this.problems.addProblem(km, "soilkindkmvaluefinder.missing"); | |
116 | |
117 // report problem only once | |
118 this.problems = null; | |
108 } | 119 } |
109 } | 120 } |