comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8915:d9dbf0b74bc2

Refaktoring of flow depth calculation, extracting tkh part. First implementation of tkh calculation.
author gernotbelger
date Wed, 28 Feb 2018 17:27:15 +0100
parents e3519c3e7a0a
children 5d5d482da3e9
comparison
equal deleted inserted replaced
8914:e3519c3e7a0a 8915:d9dbf0b74bc2
7 * and comes with ABSOLUTELY NO WARRANTY! Check out the 7 * and comes with ABSOLUTELY NO WARRANTY! Check out the
8 * documentation coming with Dive4Elements River for details. 8 * documentation coming with Dive4Elements River for details.
9 */ 9 */
10 package org.dive4elements.river.artifacts.sinfo.flowdepth; 10 package org.dive4elements.river.artifacts.sinfo.flowdepth;
11 11
12 import java.util.ArrayList;
13 import java.util.Calendar;
14 import java.util.Collection; 12 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.Date;
17 import java.util.List;
18 13
19 import org.apache.commons.lang.math.DoubleRange; 14 import org.apache.commons.lang.math.DoubleRange;
20 import org.apache.commons.math.FunctionEvaluationException;
21 import org.apache.commons.math.analysis.UnivariateRealFunction;
22 import org.dive4elements.artifacts.ArtifactDatabase;
23 import org.dive4elements.artifacts.CallContext; 15 import org.dive4elements.artifacts.CallContext;
24 import org.dive4elements.river.artifacts.BedHeightsArtifact; 16 import org.dive4elements.river.artifacts.BedHeightsArtifact;
25 import org.dive4elements.river.artifacts.model.Calculation; 17 import org.dive4elements.river.artifacts.model.Calculation;
26 import org.dive4elements.river.artifacts.model.CalculationResult; 18 import org.dive4elements.river.artifacts.model.CalculationResult;
27 import org.dive4elements.river.artifacts.model.DateRange;
28 import org.dive4elements.river.artifacts.model.LocationProvider;
29 import org.dive4elements.river.artifacts.model.QKms;
30 import org.dive4elements.river.artifacts.model.WKms; 19 import org.dive4elements.river.artifacts.model.WKms;
31 import org.dive4elements.river.artifacts.resources.Resources; 20 import org.dive4elements.river.artifacts.resources.Resources;
32 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; 21 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
22 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
33 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; 23 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair;
34 import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo; 24 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder;
25 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator;
26 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
27 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
35 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; 28 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
36 import org.dive4elements.river.artifacts.sinfo.util.WstInfo; 29 import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
37 import org.dive4elements.river.artifacts.states.WaterlevelData; 30 import org.dive4elements.river.artifacts.states.WaterlevelData;
38 import org.dive4elements.river.artifacts.states.WaterlevelFetcher; 31 import org.dive4elements.river.artifacts.states.WaterlevelFetcher;
39 import org.dive4elements.river.model.BedHeight;
40 import org.dive4elements.river.model.BedHeightValue;
41 import org.dive4elements.river.model.Gauge;
42 import org.dive4elements.river.model.River; 32 import org.dive4elements.river.model.River;
43 import org.dive4elements.river.utils.DoubleUtil;
44 import org.dive4elements.river.utils.GaugeIndex;
45 import org.dive4elements.river.utils.RiverUtils; 33 import org.dive4elements.river.utils.RiverUtils;
46 34
47 class FlowDepthCalculation { 35 class FlowDepthCalculation {
48 36
49 // private static Logger log = Logger.getLogger(FlowDepthCalculation.class); 37 // private static Logger log = Logger.getLogger(FlowDepthCalculation.class);
50
51 private static final int VALID_BED_MEASUREMENT_YEARS = 20;
52
53 private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range";
54 38
55 private final CallContext context; 39 private final CallContext context;
56 40
57 public FlowDepthCalculation(final CallContext context) { 41 public FlowDepthCalculation(final CallContext context) {
58 this.context = context; 42 this.context = context;
59 } 43 }
60 44
61 public CalculationResult calculate(final SINFOArtifact sinfo) { 45 public CalculationResult calculate(final SINFOArtifact sinfo) {
62 46
63 /* 47 final String user = CalculationUtils.findArtifactUser(this.context, sinfo);
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());
69 48
70 /* access input data */ 49 /* access input data */
71 final FlowDepthAccess access = new FlowDepthAccess(sinfo); 50 final FlowDepthAccess access = new FlowDepthAccess(sinfo);
72 final River river = access.getRiver(); 51 final River river = access.getRiver();
73 final RiverInfo riverInfo = new RiverInfo(river); 52 final RiverInfo riverInfo = new RiverInfo(river);
74 53
75 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); 54 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs();
76 55
77 final double from = access.getFrom(); 56 final DoubleRange calcRange = access.getRange();
78 final double to = access.getTo();
79 final DoubleRange calcRange = new DoubleRange(from, to);
80 57
81 final boolean useTkh = access.isUseTransportBodies(); 58 final boolean useTkh = access.isUseTransportBodies();
82 59
83 /* calculate results for each diff pair */ 60 /* calculate results for each diff pair */
84 final Calculation problems = new Calculation(); 61 final Calculation problems = new Calculation();
85 62
86 final List<Gauge> gauges = river.determineGauges(from, to); 63 final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange);
87 final GaugeIndex gaugeIndex = new GaugeIndex(gauges);
88 64
89 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); 65 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
90 66
91 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); 67 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh);
92 68
93 for (final DifferencesPair diffPair : diffPairs) { 69 for (final DifferencesPair diffPair : diffPairs) {
94 final FlowDepthCalculationResult result = calculateResult(river, calcRange, diffPair, problems, gaugeIndex, useTkh); 70 final FlowDepthCalculationResult result = calculateResult(calcRange, diffPair, problems, infoProvider, useTkh);
95 if (result != null) 71 if (result != null)
96 results.addResult(result); 72 results.addResult(result);
97 } 73 }
98 74
99 return new CalculationResult(results, problems); 75 return new CalculationResult(results, problems);
100 } 76 }
101 77
102 /** 78 /**
103 * Calculates one W-MSH differences pair. 79 * Calculates one W-MSH differences pair.
80 *
81 * @param infoProvider
104 */ 82 */
105 private FlowDepthCalculationResult calculateResult(final River river, final DoubleRange calcRange, final DifferencesPair diffPair, 83 private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final DifferencesPair diffPair,
106 final Calculation problems, final GaugeIndex gaugeIndex, final boolean useTkh) { 84 final Calculation problems, final RiverInfoProvider infoProvider, final boolean useTkh) {
107 85
108 /* access real input data from database */ 86 /* access real input data from database */
109 final String soundingId = diffPair.getSoundingId(); 87 final String soundingId = diffPair.getSoundingId();
110 final String wstId = diffPair.getWstId(); 88 final String wstId = diffPair.getWstId();
111 89
112 final BedHeight bedHeight = loadBedHeight(soundingId); 90 final BedHeightsFinder bedHeight = loadBedHeight(soundingId, calcRange);
113 if (bedHeight == null) { 91 if (bedHeight == null) {
114 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); 92 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId);
115 problems.addProblem(message); 93 problems.addProblem(message);
116 return null; 94 return null;
117 } 95 }
124 return null; 102 return null;
125 } 103 }
126 final WKms wstKms = waterlevel.getWkms(); 104 final WKms wstKms = waterlevel.getWkms();
127 105
128 final String wspLabel = wstKms.getName(); 106 final String wspLabel = wstKms.getName();
129 final String soundingLabel = bedHeight.getDescription(); 107 final String soundingLabel = bedHeight.getInfo().getDescription();
130 final String label = String.format("%s - %s", wspLabel, soundingLabel); 108 final String label = String.format("%s - %s", wspLabel, soundingLabel);
131 109
132 checkYearDifference(label, waterlevel, bedHeight, problems); 110 checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems);
133 checkWaterlevelDiscretisation(wstKms, calcRange, problems); 111 checkWaterlevelDiscretisation(wstKms, calcRange, problems);
134 // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden 112 // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden
135 113
136 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ 114 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */
137 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); 115 final RiverInfoProvider riverInfoProvider = infoProvider.forWaterlevel(waterlevel);
138 116
139 final Gauge refGauge = waterlevel.findReferenceGauge(river);
140 final String refGaugeName = refGauge == null ? notinrange : refGauge.getName();
141
142 final BedHeightInfo sounding = BedHeightInfo.from(bedHeight);
143 final int wspYear = waterlevel.getYear(); 117 final int wspYear = waterlevel.getYear();
144 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, refGaugeName); 118 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge());
145 119
146 final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding); 120 final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms);
147 121
148 boolean doCalcTkh = useTkh; 122 final River river = riverInfoProvider.getRiver();
149 if (doCalcTkh && !(wstKms instanceof QKms)) { 123 final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, dischargeProvider,
150 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); 124 bedHeight);
151 problems.addProblem(message); 125
152 doCalcTkh = false; 126 final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wstKms, dischargeProvider, bedHeight, tkhCalculator);
153 } 127 return calculator.execute(label, wstInfo, calcRange);
154 128 }
155 BedQualityD50KmValueFinder bedMeasurementsFinder = null; 129
156 if (doCalcTkh) {
157 bedMeasurementsFinder = loadBedMeasurements(river, calcRange, sounding.getYear().intValue());
158 if (bedMeasurementsFinder == null) {
159 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
160 problems.addProblem(message);
161 doCalcTkh = false;
162 }
163 }
164
165 final String bedHeightLabel = bedHeight.getDescription();
166 final String wstLabel = wstKms.getName();
167
168 final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs());
169 UnivariateRealFunction qInterpolator = null;
170 DoubleRange qRange = null;
171 if (doCalcTkh) {
172 qInterpolator = DoubleUtil.getLinearInterpolator(((QKms) wstKms).allKms(), ((QKms) wstKms).allQs());
173 if (qInterpolator != null)
174 qRange = new DoubleRange(((QKms) wstKms).allQs().min(), ((QKms) wstKms).allQs().max());
175 else {
176 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
177 problems.addProblem(message);
178 doCalcTkh = false;
179 }
180 }
181
182 // FIXME: sort by station first, but in what direction?
183 // FIXME: using river.getKmUp()?
184 final List<BedHeightValue> values = bedHeight.getValues();
185
186 final List<BedHeightValue> sortedValues = new ArrayList<>(values);
187 Collections.sort(sortedValues, new BedHeightStationComparator());
188
189 // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden?
190 /* SoilKind lastKind = SoilKind.mobil; */
191 SoilKindKmValueFinder soilKindFinder = null;
192 if (doCalcTkh) {
193 soilKindFinder = new SoilKindKmValueFinder();
194 if (!soilKindFinder.loadValues(river, calcRange)) {
195 doCalcTkh = false;
196 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
197 problems.addProblem(message);
198 }
199 }
200
201 FlowVelocityModelKmValueFinder flowVelocitiesFinder = null;
202 if (doCalcTkh) {
203 flowVelocitiesFinder = new FlowVelocityModelKmValueFinder();
204 if (!flowVelocitiesFinder.loadValues(river, calcRange, qRange)) {
205 doCalcTkh = false;
206 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingVelocity", null, label);
207 problems.addProblem(message);
208 }
209 }
210
211 for (final BedHeightValue bedHeightValue : sortedValues) {
212
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
224 if (!calcRange.containsDouble(km))
225 continue;
226
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;
235 double discharge;
236 if (qInterpolator != null)
237 discharge = qInterpolator.value(km);
238 else
239 discharge = Double.NaN;
240
241 // Calculate tkh
242 double tkh = 0;
243 if (doCalcTkh) {
244 double d50 = Double.NaN;
245 try {
246 d50 = bedMeasurementsFinder.findD50(km);
247 }
248 catch (final Exception e) {
249 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingD50", null, label);
250 problems.addProblem(km, message);
251 // FIXME: cumulate problems to one message?
252 }
253 if (!Double.isNaN(d50)) {
254 if (flowVelocitiesFinder.findKmQValues(km, discharge)) {
255 tkh = calculateTkh(wst - meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), d50, flowVelocitiesFinder.getFindTauFound());
256 if (!Double.isNaN(tkh) && (tkh < 0))
257 tkh = 0;
258 /*
259 * log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f",
260 * km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(),
261 * d50*1000, tkh));
262 */
263 } else {
264 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
265 problems.addProblem(km, message);
266 // FIXME: cumulate problems to one message?
267 }
268 } else
269 tkh = Double.NaN;
270 }
271
272 // Soil kind
273 SoilKind kind = SoilKind.mobil;
274 if (doCalcTkh) {
275 try {
276 kind = soilKindFinder.findSoilKind(km);
277 }
278 catch (final Exception e) {
279 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
280 problems.addProblem(km, message);
281 // FIXME: cumulate problems to one message?
282 }
283 }
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
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
311 resultData.addRow(km, flowDepth, flowDepthTkh, kind, tkh, tkhUp, tkhDown, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel,
312 location);
313 }
314 catch (final FunctionEvaluationException e) {
315 /* should only happen if out of range */
316 e.printStackTrace();
317 /* simply ignore */
318 }
319 }
320
321 return resultData;
322 }
323
324 /**
325 * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
326 * Abhängig von Peiljahr
327 */
328 private BedQualityD50KmValueFinder loadBedMeasurements(final River river, final DoubleRange kmRange, final int soundingYear) {
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
340 final BedQualityD50KmValueFinder finder = new BedQualityD50KmValueFinder();
341 if (finder.loadValues(river, kmRange, new DateRange(startTime, endTime)))
342 return finder;
343 else
344 return null;
345 }
346 130
347 /** 131 /**
348 * Checks the year difference between waterlevels and sounding, and issues a warning if too big. 132 * Checks the year difference between waterlevels and sounding, and issues a warning if too big.
349 * 133 *
350 * Zeitraum Zeitliche Differenz [a] 134 * Zeitraum Zeitliche Differenz [a]
351 * X ≥ 1998 ± 3 135 * X ≥ 1998 ± 3
352 * 1958 ≤ X < 1998 ± 6 136 * 1958 ≤ X < 1998 ± 6
353 * 1918 ≤ X < 1958 ± 12 137 * 1918 ≤ X < 1958 ± 12
354 * X < 1918 ± 25 138 * X < 1918 ± 25
355 */ 139 */
356 private void checkYearDifference(final String label, final WaterlevelData waterlevel, final BedHeight sounding, final Calculation problems) { 140 private void checkYearDifference(final String label, final WaterlevelData waterlevel, final Integer soundingYear, final Calculation problems) {
357
358 final Integer soundingYear = sounding.getYear();
359 if (soundingYear == null) 141 if (soundingYear == null)
360 return; 142 return;
361 143
362 final int wstYear = waterlevel.getYear(); 144 final int wstYear = waterlevel.getYear();
363 if (wstYear < 0) 145 if (wstYear < 0)
386 168
387 /* >= 1998 */ 169 /* >= 1998 */
388 return 3; 170 return 3;
389 } 171 }
390 172
391 private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex, final double km) {
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 */ 173 /* Checks if the discretisation of the waterlevel exceeds 1000m */
407 174
408 private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { 175 private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) {
409 176
410 final int size = wstKms.size(); 177 final int size = wstKms.size();
422 } 189 }
423 } 190 }
424 } 191 }
425 } 192 }
426 193
427 private BedHeight loadBedHeight(final String soundingId) { 194 private BedHeightsFinder loadBedHeight(final String soundingId, final DoubleRange calcRange) {
428 195
429 // REMARK: absolutely unbelievable.... 196 // REMARK: absolutely unbelievable....
430 // The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type 197 // The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type
431 // throughout flys. 198 // throughout flys.
432 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... 199 // The knowledge on how to parse the datacage-ids is spread through the complete code-base...
436 final String[] parts = soundingId.split(";"); 203 final String[] parts = soundingId.split(";");
437 204
438 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context); 205 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context);
439 206
440 final Integer bedheightId = artifact.getDataAsInteger("height_id"); 207 final Integer bedheightId = artifact.getDataAsInteger("height_id");
208 if (bedheightId == null) {
209 // FIXME: error message!
210 return null;
211 }
212
441 // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the 213 // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the
442 // other type means) 214 // other type means)
443 // Luckily, the requirement is to only access 'single' data here. 215 // Luckily, the requirement is to only access 'single' data here.
444 // final String bedheightType = artifact.getDataAsString("type"); 216 // final String bedheightType = artifact.getDataAsString("type");
445 217
447 // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via 219 // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via
448 // hibernate stuff 220 // hibernate stuff
449 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. 221 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes.
450 // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); 222 // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to);
451 223
452 return BedHeight.getBedHeightById(bedheightId); 224 return BedHeightsFinder.forId(bedheightId, calcRange);
453 }
454
455 /**
456 * Calculates a transport body height
457 *
458 * @param h
459 * flow depth in m
460 * @param vm
461 * flow velocity in m
462 * @param d50
463 * grain diameter D50 in m (!)
464 * @param tau
465 * shear stress in N/m^2
466 * @return transport body height in cm (!)
467 */
468 private double calculateTkh(final double h, final double vm, final double d50, final double tau) {
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;
476
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;
479 final double critShields = 0.22 * Math.pow(partReynolds, -0.6) + 0.06 * Math.pow(10, 7.7 * Math.pow(partReynolds, -0.6));
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 } 225 }
483 } 226 }

http://dive4elements.wald.intevation.org