Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8894:a66f2a7c4f84
SINFO FlowDepth - slight code cleanup
author | gernotbelger |
---|---|
date | Thu, 15 Feb 2018 18:40:40 +0100 |
parents | f431aec10d2c |
children | b6f7961e4cc5 |
comparison
equal
deleted
inserted
replaced
8893:ffebc94cf679 | 8894:a66f2a7c4f84 |
---|---|
14 import java.util.Collection; | 14 import java.util.Collection; |
15 import java.util.Collections; | 15 import java.util.Collections; |
16 import java.util.Date; | 16 import java.util.Date; |
17 import java.util.List; | 17 import java.util.List; |
18 | 18 |
19 import org.apache.commons.lang.math.DoubleRange; | |
19 import org.apache.commons.math.FunctionEvaluationException; | 20 import org.apache.commons.math.FunctionEvaluationException; |
20 import org.apache.commons.math.analysis.UnivariateRealFunction; | 21 import org.apache.commons.math.analysis.UnivariateRealFunction; |
21 import org.dive4elements.artifacts.ArtifactDatabase; | 22 import org.dive4elements.artifacts.ArtifactDatabase; |
22 import org.dive4elements.artifacts.CallContext; | 23 import org.dive4elements.artifacts.CallContext; |
23 import org.dive4elements.river.artifacts.BedHeightsArtifact; | 24 import org.dive4elements.river.artifacts.BedHeightsArtifact; |
29 import org.dive4elements.river.artifacts.model.minfo.QualityMeasurementFactory; | 30 import org.dive4elements.river.artifacts.model.minfo.QualityMeasurementFactory; |
30 import org.dive4elements.river.artifacts.model.minfo.QualityMeasurements; | 31 import org.dive4elements.river.artifacts.model.minfo.QualityMeasurements; |
31 import org.dive4elements.river.artifacts.resources.Resources; | 32 import org.dive4elements.river.artifacts.resources.Resources; |
32 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; | 33 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; |
33 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; | 34 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; |
35 import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; | |
36 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; | |
37 import org.dive4elements.river.artifacts.sinfo.util.WstInfo; | |
34 import org.dive4elements.river.artifacts.states.WaterlevelData; | 38 import org.dive4elements.river.artifacts.states.WaterlevelData; |
35 import org.dive4elements.river.artifacts.states.WaterlevelFetcher; | 39 import org.dive4elements.river.artifacts.states.WaterlevelFetcher; |
36 import org.dive4elements.river.model.BedHeight; | 40 import org.dive4elements.river.model.BedHeight; |
37 import org.dive4elements.river.model.BedHeightValue; | 41 import org.dive4elements.river.model.BedHeightValue; |
38 import org.dive4elements.river.model.Gauge; | 42 import org.dive4elements.river.model.Gauge; |
63 final String user = database.findArtifactUser(sinfo.identifier()); | 67 final String user = database.findArtifactUser(sinfo.identifier()); |
64 | 68 |
65 /* access input data */ | 69 /* access input data */ |
66 final FlowDepthAccess access = new FlowDepthAccess(sinfo); | 70 final FlowDepthAccess access = new FlowDepthAccess(sinfo); |
67 final River river = access.getRiver(); | 71 final River river = access.getRiver(); |
72 final RiverInfo riverInfo = new RiverInfo(river); | |
68 | 73 |
69 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); | 74 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); |
70 | 75 |
71 final double from = access.getFrom(); | 76 final double from = access.getFrom(); |
72 final double to = access.getTo(); | 77 final double to = access.getTo(); |
78 final DoubleRange calcRange = new DoubleRange(from, to); | |
73 | 79 |
74 final boolean useTkh = access.isUseTransportBodies(); | 80 final boolean useTkh = access.isUseTransportBodies(); |
75 | 81 |
76 /* calculate results for each diff pair */ | 82 /* calculate results for each diff pair */ |
77 final Calculation problems = new Calculation(); | 83 final Calculation problems = new Calculation(); |
79 final List<Gauge> gauges = river.determineGauges(from, to); | 85 final List<Gauge> gauges = river.determineGauges(from, to); |
80 final GaugeIndex gaugeIndex = new GaugeIndex(gauges); | 86 final GaugeIndex gaugeIndex = new GaugeIndex(gauges); |
81 | 87 |
82 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); | 88 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); |
83 | 89 |
84 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from, to, useTkh); | 90 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); |
85 | 91 |
86 for (final DifferencesPair diffPair : diffPairs) { | 92 for (final DifferencesPair diffPair : diffPairs) { |
87 final FlowDepthCalculationResult result = calculateResult(river, from, to, diffPair, problems, gaugeIndex); | 93 final FlowDepthCalculationResult result = calculateResult(river, calcRange, diffPair, problems, gaugeIndex); |
88 if (result != null) | 94 if (result != null) |
89 results.addResult(result); | 95 results.addResult(result); |
90 } | 96 } |
91 | 97 |
92 return new CalculationResult(results, problems); | 98 return new CalculationResult(results, problems); |
93 } | 99 } |
94 | 100 |
95 private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair, | 101 private FlowDepthCalculationResult calculateResult(final River river, final DoubleRange calcRange, final DifferencesPair diffPair, |
96 final Calculation problems, final GaugeIndex gaugeIndex) { | 102 final Calculation problems, final GaugeIndex gaugeIndex) { |
97 | 103 |
98 /* access real input data from database */ | 104 /* access real input data from database */ |
99 final String soundingId = diffPair.getSoundingId(); | 105 final String soundingId = diffPair.getSoundingId(); |
100 final String wstId = diffPair.getWstId(); | 106 final String wstId = diffPair.getWstId(); |
101 | 107 |
102 final BedHeight bedHeight = loadBedHeight(soundingId, from, to); | 108 final BedHeight bedHeight = loadBedHeight(soundingId); |
103 if (bedHeight == null) { | 109 if (bedHeight == null) { |
104 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); | 110 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); |
105 problems.addProblem(message); | 111 problems.addProblem(message); |
106 return null; | 112 return null; |
107 } | 113 } |
118 final String wspLabel = wstKms.getName(); | 124 final String wspLabel = wstKms.getName(); |
119 final String soundingLabel = bedHeight.getDescription(); | 125 final String soundingLabel = bedHeight.getDescription(); |
120 final String label = String.format("%s - %s", wspLabel, soundingLabel); | 126 final String label = String.format("%s - %s", wspLabel, soundingLabel); |
121 | 127 |
122 checkYearDifference(label, waterlevel, bedHeight, problems); | 128 checkYearDifference(label, waterlevel, bedHeight, problems); |
123 checkWaterlevelDiscretisation(wstKms, problems); | 129 checkWaterlevelDiscretisation(wstKms, calcRange, problems); |
130 // TODO: prüfen, ob sohlhöen die calcRange abdecken/überschneiden | |
124 | 131 |
125 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ | 132 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ |
126 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); | 133 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); |
127 | 134 |
128 final Gauge refGauge = waterlevel.findReferenceGauge(river); | 135 final Gauge refGauge = waterlevel.findReferenceGauge(river); |
140 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); | 147 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); |
141 problems.addProblem(message); | 148 problems.addProblem(message); |
142 // TODO: keine Berechnung TKH | 149 // TODO: keine Berechnung TKH |
143 } | 150 } |
144 | 151 |
145 final QualityMeasurements bedMeasurements = getBedMeasurements(river, from, to, sounding.getYear()); | 152 final QualityMeasurements bedMeasurements = getBedMeasurements(river, calcRange, sounding.getYear()); |
146 // FIXME: prüfung ob (genug) werte vorhanden sind? was sind genau die kriterien? falls nein, problemhinzufügen und keine | 153 // FIXME: prüfung ob (genug) werte vorhanden sind? was sind genau die kriterien? falls nein, problemhinzufügen und keine |
147 // berechnung tkh | 154 // berechnung tkh |
148 // FIXME: wie wird ggf. interpoliert? --> absprache? | 155 // FIXME: wie wird ggf. interpoliert? --> absprache? |
149 // FIXME: mir direkt aufgefallen, die Beispieldatenbank liefert Werte zum gleichen km und zeitpunkt, die messwerte sind | 156 // FIXME: mir direkt aufgefallen, die Beispieldatenbank liefert Werte zum gleichen km und zeitpunkt, die messwerte sind |
150 // aber unterschiedlich....??? | 157 // aber unterschiedlich....??? |
163 final List<BedHeightValue> values = bedHeight.getValues(); | 170 final List<BedHeightValue> values = bedHeight.getValues(); |
164 | 171 |
165 final List<BedHeightValue> sortedValues = new ArrayList<>(values); | 172 final List<BedHeightValue> sortedValues = new ArrayList<>(values); |
166 Collections.sort(sortedValues, new BedHeightStationComparator()); | 173 Collections.sort(sortedValues, new BedHeightStationComparator()); |
167 | 174 |
168 SoilKind lastKind = SoilKind.mobil; | 175 SoilKind lastKind = SoilKind.starr; |
169 | 176 |
170 for (final BedHeightValue bedHeightValue : sortedValues) { | 177 for (final BedHeightValue bedHeightValue : sortedValues) { |
171 | 178 |
172 final Double station = bedHeightValue.getStation(); | 179 final Double station = bedHeightValue.getStation(); |
173 if (station == null || station.isNaN()) | 180 if (station == null || station.isNaN()) |
178 continue; | 185 continue; |
179 | 186 |
180 final double km = station; | 187 final double km = station; |
181 final double meanBedHeight = meanBedHeightDbl; | 188 final double meanBedHeight = meanBedHeightDbl; |
182 | 189 |
190 if (!calcRange.containsDouble(km)) | |
191 continue; | |
192 | |
183 try { | 193 try { |
184 // FIXME: check out of range | 194 // FIXME: check out of range |
185 final double wst = wstInterpolator.value(km); | 195 final double wst = wstInterpolator.value(km); |
186 | 196 |
187 final double flowDepth = wst - meanBedHeight; | 197 final double flowDepth = wst - meanBedHeight; |
191 final double discharge = Double.NaN; | 201 final double discharge = Double.NaN; |
192 | 202 |
193 // FIXME: calculate tkh | 203 // FIXME: calculate tkh |
194 | 204 |
195 // REMARK: bissl spielerei zum testen damit die sohlart nicht zu schnell wechselt | 205 // REMARK: bissl spielerei zum testen damit die sohlart nicht zu schnell wechselt |
196 final boolean changeKind = Math.random() > 0.95; | 206 final boolean changeKind = false; // Math.random() > 0.95; |
197 SoilKind kind; | 207 SoilKind kind; |
198 if (changeKind) { | 208 if (changeKind) { |
199 switch (lastKind) { | 209 switch (lastKind) { |
200 case starr: | 210 case starr: |
201 kind = SoilKind.mobil; | 211 kind = SoilKind.mobil; |
229 tkhUp = tkh / 2; | 239 tkhUp = tkh / 2; |
230 tkhDown = -tkh / 2; | 240 tkhDown = -tkh / 2; |
231 break; | 241 break; |
232 } | 242 } |
233 | 243 |
234 | |
235 // REMARK: access the location once only during calculation | 244 // REMARK: access the location once only during calculation |
236 final String location = LocationProvider.getLocation(river.getName(), km); | 245 final String location = LocationProvider.getLocation(river.getName(), km); |
237 | 246 |
238 // REMARK: access the gauge once only during calculation | 247 // REMARK: access the gauge once only during calculation |
239 final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km); | 248 final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km); |
256 | 265 |
257 /** | 266 /** |
258 * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb) | 267 * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb) |
259 * Abhängig von Peiljahr | 268 * Abhängig von Peiljahr |
260 */ | 269 */ |
261 private QualityMeasurements getBedMeasurements(final River river, final double from, final double to, final int soundingYear) { | 270 private QualityMeasurements getBedMeasurements(final River river, final DoubleRange calcRange, final Integer soundingYear) { |
262 | 271 |
263 /* construct valid measurement time range */ | 272 /* construct valid measurement time range */ |
264 final Calendar cal = Calendar.getInstance(); | 273 final Calendar cal = Calendar.getInstance(); |
265 cal.clear(); | 274 cal.clear(); |
266 | 275 |
268 final Date startTime = cal.getTime(); | 277 final Date startTime = cal.getTime(); |
269 | 278 |
270 cal.set(soundingYear + VALID_BED_MEASUREMENT_YEARS, 11, 31); | 279 cal.set(soundingYear + VALID_BED_MEASUREMENT_YEARS, 11, 31); |
271 final Date endTime = cal.getTime(); | 280 final Date endTime = cal.getTime(); |
272 | 281 |
273 return QualityMeasurementFactory.getBedMeasurements(river.getName(), from, to, startTime, endTime); | 282 return QualityMeasurementFactory.getBedMeasurements(river.getName(), calcRange.getMinimumDouble(), calcRange.getMaximumDouble(), startTime, endTime); |
274 } | 283 } |
275 | 284 |
276 /** | 285 /** |
277 * Checks the year difference between waterlevels and sounding, and issues a warning if too big. | 286 * Checks the year difference between waterlevels and sounding, and issues a warning if too big. |
278 * | 287 * |
294 | 303 |
295 final int maxDifference = getMaxDifferenceYears(soundingYear); | 304 final int maxDifference = getMaxDifferenceYears(soundingYear); |
296 | 305 |
297 final int difference = Math.abs(soundingYear - wstYear); | 306 final int difference = Math.abs(soundingYear - wstYear); |
298 if (difference > maxDifference) { | 307 if (difference > maxDifference) { |
299 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.year_difference", null, label, difference); | 308 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.year_difference", null, label, wstYear, |
309 soundingYear); | |
300 problems.addProblem(message); | 310 problems.addProblem(message); |
301 } | 311 } |
302 } | 312 } |
303 | 313 |
304 private int getMaxDifferenceYears(final int year) { | 314 private int getMaxDifferenceYears(final int year) { |
330 | 340 |
331 return null; | 341 return null; |
332 } | 342 } |
333 | 343 |
334 /* Checks if the discretisation of the waterlevel exceeds 1000m */ | 344 /* Checks if the discretisation of the waterlevel exceeds 1000m */ |
335 // FIXME: vermutlich sollten wir diesen check auf den gültigkeitsbereich einschränken | 345 |
336 private void checkWaterlevelDiscretisation(final WKms wstKms, final Calculation problems) { | 346 private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { |
347 | |
337 final int size = wstKms.size(); | 348 final int size = wstKms.size(); |
338 for (int i = 0; i < size - 2; i++) { | 349 for (int i = 0; i < size - 2; i++) { |
339 final double kmPrev = wstKms.getKm(i); | 350 final double kmPrev = wstKms.getKm(i); |
340 final double kmNext = wstKms.getKm(i + 1); | 351 final double kmNext = wstKms.getKm(i + 1); |
341 | 352 |
342 if (Math.abs(kmPrev - kmNext) > 1) { | 353 /* only check if we are within the calculation range */ |
343 final String label = wstKms.getName(); | 354 if (calcRange.overlapsRange(new DoubleRange(kmPrev, kmNext))) { |
344 | 355 if (Math.abs(kmPrev - kmNext) > 1) { |
345 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label); | 356 final String label = wstKms.getName(); |
346 problems.addProblem(kmPrev, message); | 357 |
358 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label); | |
359 problems.addProblem(kmPrev, message); | |
360 } | |
347 } | 361 } |
348 } | 362 } |
349 } | 363 } |
350 | 364 |
351 private BedHeight loadBedHeight(final String soundingId, final double from, final double to) { | 365 private BedHeight loadBedHeight(final String soundingId) { |
352 | 366 |
353 // REMARK: absolutely unbelievable.... | 367 // REMARK: absolutely unbelievable.... |
354 // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type | 368 // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type |
355 // throughout flys. | 369 // throughout flys. |
356 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... | 370 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... |