Mercurial > dive4elements > river
annotate artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8914:e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
author | gernotbelger |
---|---|
date | Tue, 27 Feb 2018 18:06:52 +0100 |
parents | 37ff7f435912 |
children | d9dbf0b74bc2 |
rev | line source |
---|---|
8854 | 1 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde |
8877 | 2 * Software engineering by |
3 * Björnsen Beratende Ingenieure GmbH | |
8854 | 4 * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt |
5 * | |
6 * This file is Free Software under the GNU AGPL (>=v3) | |
7 * and comes with ABSOLUTELY NO WARRANTY! Check out the | |
8 * documentation coming with Dive4Elements River for details. | |
9 */ | |
10 package org.dive4elements.river.artifacts.sinfo.flowdepth; | |
11 | |
8883 | 12 import java.util.ArrayList; |
8891 | 13 import java.util.Calendar; |
8854 | 14 import java.util.Collection; |
8883 | 15 import java.util.Collections; |
8891 | 16 import java.util.Date; |
8854 | 17 import java.util.List; |
18 | |
8894 | 19 import org.apache.commons.lang.math.DoubleRange; |
8883 | 20 import org.apache.commons.math.FunctionEvaluationException; |
21 import org.apache.commons.math.analysis.UnivariateRealFunction; | |
8879 | 22 import org.dive4elements.artifacts.ArtifactDatabase; |
8854 | 23 import org.dive4elements.artifacts.CallContext; |
24 import org.dive4elements.river.artifacts.BedHeightsArtifact; | |
25 import org.dive4elements.river.artifacts.model.Calculation; | |
26 import org.dive4elements.river.artifacts.model.CalculationResult; | |
8898 | 27 import org.dive4elements.river.artifacts.model.DateRange; |
8854 | 28 import org.dive4elements.river.artifacts.model.LocationProvider; |
8901 | 29 import org.dive4elements.river.artifacts.model.QKms; |
8854 | 30 import org.dive4elements.river.artifacts.model.WKms; |
31 import org.dive4elements.river.artifacts.resources.Resources; | |
32 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; | |
33 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; | |
8894 | 34 import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; |
35 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; | |
36 import org.dive4elements.river.artifacts.sinfo.util.WstInfo; | |
8882 | 37 import org.dive4elements.river.artifacts.states.WaterlevelData; |
38 import org.dive4elements.river.artifacts.states.WaterlevelFetcher; | |
8854 | 39 import org.dive4elements.river.model.BedHeight; |
8883 | 40 import org.dive4elements.river.model.BedHeightValue; |
8854 | 41 import org.dive4elements.river.model.Gauge; |
42 import org.dive4elements.river.model.River; | |
8883 | 43 import org.dive4elements.river.utils.DoubleUtil; |
8854 | 44 import org.dive4elements.river.utils.GaugeIndex; |
45 import org.dive4elements.river.utils.RiverUtils; | |
46 | |
47 class FlowDepthCalculation { | |
48 | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
49 // private static Logger log = Logger.getLogger(FlowDepthCalculation.class); |
8898 | 50 |
8891 | 51 private static final int VALID_BED_MEASUREMENT_YEARS = 20; |
52 | |
8854 | 53 private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range"; |
54 | |
8877 | 55 private final CallContext context; |
8854 | 56 |
8882 | 57 public FlowDepthCalculation(final CallContext context) { |
8877 | 58 this.context = context; |
8854 | 59 } |
60 | |
8877 | 61 public CalculationResult calculate(final SINFOArtifact sinfo) { |
8854 | 62 |
8879 | 63 /* |
64 * find the user of this artifact, sadly this is not part of the calling context, so instead we determine the | |
65 * owner oft the artifact | |
66 */ | |
67 final ArtifactDatabase database = this.context.getDatabase(); | |
68 final String user = database.findArtifactUser(sinfo.identifier()); | |
8854 | 69 |
8877 | 70 /* access input data */ |
71 final FlowDepthAccess access = new FlowDepthAccess(sinfo); | |
72 final River river = access.getRiver(); | |
8894 | 73 final RiverInfo riverInfo = new RiverInfo(river); |
8854 | 74 |
8877 | 75 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); |
76 | |
77 final double from = access.getFrom(); | |
78 final double to = access.getTo(); | |
8894 | 79 final DoubleRange calcRange = new DoubleRange(from, to); |
8877 | 80 |
81 final boolean useTkh = access.isUseTransportBodies(); | |
82 | |
83 /* calculate results for each diff pair */ | |
84 final Calculation problems = new Calculation(); | |
85 | |
86 final List<Gauge> gauges = river.determineGauges(from, to); | |
87 final GaugeIndex gaugeIndex = new GaugeIndex(gauges); | |
88 | |
8882 | 89 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); |
8877 | 90 |
8894 | 91 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); |
8877 | 92 |
93 for (final DifferencesPair diffPair : diffPairs) { | |
8898 | 94 final FlowDepthCalculationResult result = calculateResult(river, calcRange, diffPair, problems, gaugeIndex, useTkh); |
8882 | 95 if (result != null) |
8877 | 96 results.addResult(result); |
97 } | |
98 | |
8882 | 99 return new CalculationResult(results, problems); |
8877 | 100 } |
101 | |
8898 | 102 /** |
103 * Calculates one W-MSH differences pair. | |
104 */ | |
8894 | 105 private FlowDepthCalculationResult calculateResult(final River river, final DoubleRange calcRange, final DifferencesPair diffPair, |
8898 | 106 final Calculation problems, final GaugeIndex gaugeIndex, final boolean useTkh) { |
8877 | 107 |
108 /* access real input data from database */ | |
109 final String soundingId = diffPair.getSoundingId(); | |
110 final String wstId = diffPair.getWstId(); | |
111 | |
8894 | 112 final BedHeight bedHeight = loadBedHeight(soundingId); |
8882 | 113 if (bedHeight == null) { |
8884 | 114 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); |
8877 | 115 problems.addProblem(message); |
116 return null; | |
117 } | |
118 | |
8882 | 119 /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */ |
8884 | 120 final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN); |
8882 | 121 if (waterlevel == null) { |
8884 | 122 final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'", wstId); |
8877 | 123 problems.addProblem(message); |
124 return null; | |
125 } | |
8882 | 126 final WKms wstKms = waterlevel.getWkms(); |
127 | |
8883 | 128 final String wspLabel = wstKms.getName(); |
129 final String soundingLabel = bedHeight.getDescription(); | |
130 final String label = String.format("%s - %s", wspLabel, soundingLabel); | |
8877 | 131 |
8883 | 132 checkYearDifference(label, waterlevel, bedHeight, problems); |
8894 | 133 checkWaterlevelDiscretisation(wstKms, calcRange, problems); |
8901 | 134 // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden |
8882 | 135 |
136 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ | |
8884 | 137 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); |
8882 | 138 |
139 final Gauge refGauge = waterlevel.findReferenceGauge(river); | |
140 final String refGaugeName = refGauge == null ? notinrange : refGauge.getName(); | |
8877 | 141 |
142 final BedHeightInfo sounding = BedHeightInfo.from(bedHeight); | |
8883 | 143 final int wspYear = waterlevel.getYear(); |
8882 | 144 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, refGaugeName); |
8877 | 145 |
146 final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding); | |
147 | |
8901 | 148 boolean doCalcTkh = useTkh; |
149 if (doCalcTkh && !(wstKms instanceof QKms)) { | |
8884 | 150 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); |
8877 | 151 problems.addProblem(message); |
8901 | 152 doCalcTkh = false; |
8877 | 153 } |
154 | |
8898 | 155 BedQualityD50KmValueFinder bedMeasurementsFinder = null; |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
156 if (doCalcTkh) { |
8901 | 157 bedMeasurementsFinder = loadBedMeasurements(river, calcRange, sounding.getYear().intValue()); |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
158 if (bedMeasurementsFinder == null) { |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
159 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
160 problems.addProblem(message); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
161 doCalcTkh = false; |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
162 } |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
163 } |
8877 | 164 |
165 final String bedHeightLabel = bedHeight.getDescription(); | |
166 final String wstLabel = wstKms.getName(); | |
167 | |
8884 | 168 final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs()); |
8898 | 169 UnivariateRealFunction qInterpolator = null; |
170 DoubleRange qRange = null; | |
8901 | 171 if (doCalcTkh) { |
172 qInterpolator = DoubleUtil.getLinearInterpolator(((QKms) wstKms).allKms(), ((QKms) wstKms).allQs()); | |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
173 if (qInterpolator != null) |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
174 qRange = new DoubleRange(((QKms) wstKms).allQs().min(), ((QKms) wstKms).allQs().max()); |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
175 else { |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
176 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
177 problems.addProblem(message); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
178 doCalcTkh = false; |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
179 } |
8898 | 180 } |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
181 |
8883 | 182 // FIXME: sort by station first, but in what direction? |
8898 | 183 // FIXME: using river.getKmUp()? |
8883 | 184 final List<BedHeightValue> values = bedHeight.getValues(); |
8877 | 185 |
8883 | 186 final List<BedHeightValue> sortedValues = new ArrayList<>(values); |
187 Collections.sort(sortedValues, new BedHeightStationComparator()); | |
8882 | 188 |
8898 | 189 // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden? |
190 /* SoilKind lastKind = SoilKind.mobil; */ | |
191 SoilKindKmValueFinder soilKindFinder = null; | |
8901 | 192 if (doCalcTkh) { |
8898 | 193 soilKindFinder = new SoilKindKmValueFinder(); |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
194 if (!soilKindFinder.loadValues(river, calcRange)) { |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
195 doCalcTkh = false; |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
196 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
197 problems.addProblem(message); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
198 } |
8898 | 199 } |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
200 |
8898 | 201 FlowVelocityModelKmValueFinder flowVelocitiesFinder = null; |
8901 | 202 if (doCalcTkh) { |
8898 | 203 flowVelocitiesFinder = new FlowVelocityModelKmValueFinder(); |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
204 if (!flowVelocitiesFinder.loadValues(river, calcRange, qRange)) { |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
205 doCalcTkh = false; |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
206 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingVelocity", null, label); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
207 problems.addProblem(message); |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
208 } |
8898 | 209 } |
8886 | 210 |
8883 | 211 for (final BedHeightValue bedHeightValue : sortedValues) { |
8877 | 212 |
8883 | 213 final Double station = bedHeightValue.getStation(); |
214 if (station == null || station.isNaN()) | |
215 continue; | |
216 | |
217 final Double meanBedHeightDbl = bedHeightValue.getHeight(); | |
218 if (meanBedHeightDbl == null || meanBedHeightDbl.isNaN()) | |
219 continue; | |
220 | |
221 final double km = station; | |
222 final double meanBedHeight = meanBedHeightDbl; | |
223 | |
8894 | 224 if (!calcRange.containsDouble(km)) |
225 continue; | |
226 | |
8883 | 227 try { |
228 // FIXME: check out of range | |
229 final double wst = wstInterpolator.value(km); | |
230 | |
231 final double flowDepth = wst - meanBedHeight; | |
232 | |
233 // FIXME: piecewise constant interpolation? | |
234 // final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN; | |
8898 | 235 double discharge; |
236 if (qInterpolator != null) | |
237 discharge = qInterpolator.value(km); | |
238 else | |
239 discharge = Double.NaN; | |
8883 | 240 |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
241 // Calculate tkh |
8898 | 242 double tkh = 0; |
8901 | 243 if (doCalcTkh) { |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
244 double d50 = Double.NaN; |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
245 try { |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
246 d50 = bedMeasurementsFinder.findD50(km); |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
247 } |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
248 catch (final Exception e) { |
8898 | 249 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingD50", null, label); |
250 problems.addProblem(km, message); | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
251 // FIXME: cumulate problems to one message? |
8898 | 252 } |
8901 | 253 if (!Double.isNaN(d50)) { |
254 if (flowVelocitiesFinder.findKmQValues(km, discharge)) { | |
255 tkh = calculateTkh(wst - meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), d50, flowVelocitiesFinder.getFindTauFound()); | |
8911
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
256 if (!Double.isNaN(tkh) && (tkh < 0)) |
37ff7f435912
SINFO Flowdepth: more error checks, d50 interpolation, avoid negative tkh
mschaefer
parents:
8901
diff
changeset
|
257 tkh = 0; |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
258 /* |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
259 * log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f", |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
260 * km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(), |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
261 * d50*1000, tkh)); |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
262 */ |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
263 } else { |
8901 | 264 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); |
265 problems.addProblem(km, message); | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
266 // FIXME: cumulate problems to one message? |
8901 | 267 } |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
268 } else |
8898 | 269 tkh = Double.NaN; |
270 } | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
271 |
8898 | 272 // Soil kind |
8901 | 273 SoilKind kind = SoilKind.mobil; |
274 if (doCalcTkh) { | |
8898 | 275 try { |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
276 kind = soilKindFinder.findSoilKind(km); |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
277 } |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
278 catch (final Exception e) { |
8898 | 279 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label); |
280 problems.addProblem(km, message); | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
281 // FIXME: cumulate problems to one message? |
8898 | 282 } |
283 } | |
8886 | 284 |
285 final double flowDepthTkh; | |
286 final double tkhUp; | |
287 final double tkhDown; | |
288 switch (kind) { | |
289 case starr: | |
290 flowDepthTkh = wst - (meanBedHeight + tkh / 100); | |
291 tkhUp = tkh; | |
292 tkhDown = 0; | |
293 break; | |
294 | |
295 case mobil: | |
296 default: | |
297 flowDepthTkh = wst - (meanBedHeight + tkh / 200); | |
298 tkhUp = tkh / 2; | |
299 tkhDown = -tkh / 2; | |
300 break; | |
301 } | |
302 | |
8883 | 303 // REMARK: access the location once only during calculation |
304 final String location = LocationProvider.getLocation(river.getName(), km); | |
305 | |
306 // REMARK: access the gauge once only during calculation | |
307 final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km); | |
308 | |
309 final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); | |
310 | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
311 resultData.addRow(km, flowDepth, flowDepthTkh, kind, tkh, tkhUp, tkhDown, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel, |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
312 location); |
8883 | 313 } |
314 catch (final FunctionEvaluationException e) { | |
315 /* should only happen if out of range */ | |
316 e.printStackTrace(); | |
317 /* simply ignore */ | |
318 } | |
8877 | 319 } |
320 | |
321 return resultData; | |
322 } | |
323 | |
8883 | 324 /** |
8891 | 325 * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb) |
326 * Abhängig von Peiljahr | |
327 */ | |
8898 | 328 private BedQualityD50KmValueFinder loadBedMeasurements(final River river, final DoubleRange kmRange, final int soundingYear) { |
8891 | 329 |
330 /* construct valid measurement time range */ | |
331 final Calendar cal = Calendar.getInstance(); | |
332 cal.clear(); | |
333 | |
334 cal.set(soundingYear - VALID_BED_MEASUREMENT_YEARS, 0, 1); | |
335 final Date startTime = cal.getTime(); | |
336 | |
337 cal.set(soundingYear + VALID_BED_MEASUREMENT_YEARS, 11, 31); | |
338 final Date endTime = cal.getTime(); | |
339 | |
8898 | 340 final BedQualityD50KmValueFinder finder = new BedQualityD50KmValueFinder(); |
341 if (finder.loadValues(river, kmRange, new DateRange(startTime, endTime))) | |
342 return finder; | |
343 else | |
344 return null; | |
8891 | 345 } |
346 | |
347 /** | |
8883 | 348 * Checks the year difference between waterlevels and sounding, and issues a warning if too big. |
349 * | |
350 * Zeitraum Zeitliche Differenz [a] | |
351 * X ≥ 1998 ± 3 | |
352 * 1958 ≤ X < 1998 ± 6 | |
353 * 1918 ≤ X < 1958 ± 12 | |
354 * X < 1918 ± 25 | |
355 */ | |
8884 | 356 private void checkYearDifference(final String label, final WaterlevelData waterlevel, final BedHeight sounding, final Calculation problems) { |
8883 | 357 |
358 final Integer soundingYear = sounding.getYear(); | |
359 if (soundingYear == null) | |
360 return; | |
361 | |
362 final int wstYear = waterlevel.getYear(); | |
363 if (wstYear < 0) | |
364 return; | |
365 | |
366 final int maxDifference = getMaxDifferenceYears(soundingYear); | |
367 | |
368 final int difference = Math.abs(soundingYear - wstYear); | |
369 if (difference > maxDifference) { | |
8894 | 370 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.year_difference", null, label, wstYear, |
371 soundingYear); | |
8883 | 372 problems.addProblem(message); |
373 } | |
374 } | |
375 | |
376 private int getMaxDifferenceYears(final int year) { | |
377 | |
378 if (year < 1918) | |
379 return 25; | |
380 | |
381 if (1918 <= year && year < 1958) | |
382 return 12; | |
383 | |
384 if (1958 <= year && year < 1998) | |
385 return 6; | |
386 | |
387 /* >= 1998 */ | |
388 return 3; | |
389 } | |
390 | |
8884 | 391 private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex, final double km) { |
8882 | 392 |
393 // REMARK: using same logic as in WaterlevelExporter here | |
394 | |
395 final boolean showAllGauges = waterlevel.isShowAllGauges(); | |
396 | |
397 if (showAllGauges) | |
398 return gaugeIndex.findGauge(km); | |
399 | |
400 if (refGauge.getRange().contains(km)) | |
401 return refGauge; | |
402 | |
403 return null; | |
404 } | |
405 | |
406 /* Checks if the discretisation of the waterlevel exceeds 1000m */ | |
8894 | 407 |
408 private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { | |
409 | |
8882 | 410 final int size = wstKms.size(); |
411 for (int i = 0; i < size - 2; i++) { | |
412 final double kmPrev = wstKms.getKm(i); | |
413 final double kmNext = wstKms.getKm(i + 1); | |
414 | |
8894 | 415 /* only check if we are within the calculation range */ |
416 if (calcRange.overlapsRange(new DoubleRange(kmPrev, kmNext))) { | |
417 if (Math.abs(kmPrev - kmNext) > 1) { | |
418 final String label = wstKms.getName(); | |
8882 | 419 |
8894 | 420 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label); |
421 problems.addProblem(kmPrev, message); | |
422 } | |
8882 | 423 } |
424 } | |
425 } | |
426 | |
8894 | 427 private BedHeight loadBedHeight(final String soundingId) { |
8877 | 428 |
8883 | 429 // REMARK: absolutely unbelievable.... |
8898 | 430 // The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type |
8882 | 431 // throughout flys. |
8877 | 432 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... |
433 | |
8882 | 434 // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but |
435 // this is plain random | |
8877 | 436 final String[] parts = soundingId.split(";"); |
437 | |
438 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context); | |
439 | |
440 final Integer bedheightId = artifact.getDataAsInteger("height_id"); | |
8883 | 441 // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the |
8882 | 442 // other type means) |
8877 | 443 // Luckily, the requirement is to only access 'single' data here. |
444 // final String bedheightType = artifact.getDataAsString("type"); | |
445 | |
8883 | 446 // REMARK: BedDifferences uses this, but we also need the metadata of the BedHeight |
447 // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via | |
8882 | 448 // hibernate stuff |
8877 | 449 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. |
8882 | 450 // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); |
8877 | 451 |
452 return BedHeight.getBedHeightById(bedheightId); | |
453 } | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
454 |
8898 | 455 /** |
456 * Calculates a transport body height | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
457 * |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
458 * @param h |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
459 * flow depth in m |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
460 * @param vm |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
461 * flow velocity in m |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
462 * @param d50 |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
463 * grain diameter D50 in m (!) |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
464 * @param tau |
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
465 * shear stress in N/m^2 |
8898 | 466 * @return transport body height in cm (!) |
467 */ | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
468 private double calculateTkh(final double h, final double vm, final double d50, final double tau) { |
8898 | 469 final double PHYS_G = 9.81; |
470 final double PHYS_SPECGRAV_S = 2.6; | |
471 final double PHYS_VELOCCOEFF_N = 6; | |
472 final double PHYS_FORMCOEFF_ALPHA = 0.7; | |
473 final double PHYS_VISCOSITY_NUE = 1.3e-6; | |
474 final double PHYS_GRAIN_DENSITY_RHOS = 2603; | |
475 final double PHYS_WATER_DENSITY_RHO = 999.97; | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
476 |
8898 | 477 final double froude = vm / Math.sqrt(PHYS_G * h); |
478 final double partReynolds = Math.sqrt((PHYS_SPECGRAV_S - 1) * PHYS_G * d50) / PHYS_VISCOSITY_NUE * d50; | |
8914
e3519c3e7a0a
Workflow for SINFO-Transport bodies heights inclduing winfo calculation
gernotbelger
parents:
8911
diff
changeset
|
479 final double critShields = 0.22 * Math.pow(partReynolds, -0.6) + 0.06 * Math.pow(10, 7.7 * Math.pow(partReynolds, -0.6)); |
8898 | 480 final double critTau = critShields * (PHYS_GRAIN_DENSITY_RHOS - PHYS_WATER_DENSITY_RHO) * PHYS_G * d50; |
481 return 100 * h * (1 - Math.pow(froude, 2)) / (2 * PHYS_VELOCCOEFF_N * PHYS_FORMCOEFF_ALPHA) * (1 - critTau / tau); | |
482 } | |
8884 | 483 } |