Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java @ 9446:e60584f2a531
Added bundu bzws calculation for missing volumes (masses still not yet ready) and results1/2/3
author | mschaefer |
---|---|
date | Tue, 21 Aug 2018 18:19:35 +0200 |
parents | ecadc9ed0ba0 |
children | d32b11d585cd |
comparison
equal
deleted
inserted
replaced
9445:ff0e5386de70 | 9446:e60584f2a531 |
---|---|
15 | 15 |
16 import org.dive4elements.artifacts.CallContext; | 16 import org.dive4elements.artifacts.CallContext; |
17 import org.dive4elements.river.artifacts.access.FixRealizingAccess; | 17 import org.dive4elements.river.artifacts.access.FixRealizingAccess; |
18 import org.dive4elements.river.artifacts.bundu.BUNDUArtifact; | 18 import org.dive4elements.river.artifacts.bundu.BUNDUArtifact; |
19 import org.dive4elements.river.artifacts.bundu.BunduResultType; | 19 import org.dive4elements.river.artifacts.bundu.BunduResultType; |
20 import org.dive4elements.river.artifacts.common.AbstractResultType; | |
20 import org.dive4elements.river.artifacts.common.GeneralResultType; | 21 import org.dive4elements.river.artifacts.common.GeneralResultType; |
21 import org.dive4elements.river.artifacts.common.ResultRow; | 22 import org.dive4elements.river.artifacts.common.ResultRow; |
22 import org.dive4elements.river.artifacts.model.Calculation; | 23 import org.dive4elements.river.artifacts.model.Calculation; |
23 import org.dive4elements.river.artifacts.model.Calculation.Problem; | 24 import org.dive4elements.river.artifacts.model.Calculation.Problem; |
24 import org.dive4elements.river.artifacts.model.CalculationResult; | 25 import org.dive4elements.river.artifacts.model.CalculationResult; |
40 | 41 |
41 class BezugswstCalculation { | 42 class BezugswstCalculation { |
42 | 43 |
43 // private static Logger log = Logger.getLogger(BezugswstCalculation.class); | 44 // private static Logger log = Logger.getLogger(BezugswstCalculation.class); |
44 | 45 |
46 /** | |
47 * Additional depth (m) to compute the excavation volume | |
48 */ | |
49 private final static double EXCAVATION_DEPTH = 0.2; // REMARK Sollte von außen einstellbar sein | |
50 | |
51 /** | |
52 * Excavation costs (euro) per cubic meter | |
53 */ | |
54 private final static double EXPENSE_PER_CBM = 12.0; // REMARK Sollte von außen einstellbar sein | |
55 | |
45 private final CallContext context; | 56 private final CallContext context; |
57 | |
58 private final List<ResultRow> rows; | |
46 | 59 |
47 | 60 |
48 public BezugswstCalculation(final CallContext context) { | 61 public BezugswstCalculation(final CallContext context) { |
49 this.context = context; | 62 this.context = context; |
63 this.rows = new ArrayList<>(); | |
50 } | 64 } |
51 | 65 |
52 | 66 |
53 /** | 67 /** |
54 * Calculates the result rows of a bundu bzws workflow | 68 * Calculates the result rows of a bundu bzws workflow |
92 // Fetch the river channel data | 106 // Fetch the river channel data |
93 final ChannelFinder channelFinder = ChannelFinder.loadValues(problems, river, access.getBezugsJahr()); | 107 final ChannelFinder channelFinder = ChannelFinder.loadValues(problems, river, access.getBezugsJahr()); |
94 if (channelFinder == null) | 108 if (channelFinder == null) |
95 return new CalculationResult(results, problems); | 109 return new CalculationResult(results, problems); |
96 | 110 |
97 // Calculate the result rows | 111 // Compute the result rows |
98 final List<ResultRow> rows = new ArrayList<>(); | |
99 for (int i = 0; i <= wqkms.size() - 1; i++) { | 112 for (int i = 0; i <= wqkms.size() - 1; i++) { |
100 rows.add(createRow(wqkms.getKm(i), wqkms.getW(i), wqkms.getQ(i), bedHeightsFinder, channelFinder, riverInfoProvider, wstInfo)); | 113 this.rows.add(createRow(wqkms.getKm(i), wqkms.getW(i), wqkms.getQ(i), bedHeightsFinder, channelFinder, riverInfoProvider, wstInfo)); |
114 } | |
115 | |
116 // Compute the missing volumes | |
117 if (access.isCalculateMissingValue()) { | |
118 computeMissingVolumes(access.getMissingVolFrom().doubleValue(), access.getMissingVolTo().doubleValue(), problems); | |
119 // TODO Lagerungsdichte holen/berechnen (density) und Massen berechnen | |
101 } | 120 } |
102 | 121 |
103 // Add the result to the results collection | 122 // Add the result to the results collection |
104 final WaterlevelDescriptionBuilder descBuilder = new WaterlevelDescriptionBuilder(winfo, this.context); | 123 final WaterlevelDescriptionBuilder descBuilder = new WaterlevelDescriptionBuilder(winfo, this.context); |
105 final String qtext = descBuilder.getMetadataQ(); | 124 final String qtext = descBuilder.getMetadataQ(); |
106 final BezugswstMainCalculationResult result = new BezugswstMainCalculationResult("bundu-bzws", rows, bedHeightsFinder.getInfo(), wstInfo, | 125 final BezugswstMainCalculationResult result = new BezugswstMainCalculationResult("bundu-bzws", this.rows, bedHeightsFinder.getInfo(), wstInfo, |
107 access.getFunction(), preprocessing, startYear, endYear, ud, qtext, wqkms, missingVolFrom, missingVolTo); | 126 access.getFunction(), preprocessing, startYear, endYear, ud, qtext, wqkms, missingVolFrom, missingVolTo); |
108 results.addResult(result, problems); | 127 results.addResult(result, problems); |
109 | 128 |
110 // // missing volume calculation | 129 // Create the missing volume results |
111 // if (access.getMissingVolFrom() != null) { | 130 if (access.getMissingVolFrom() != null) { |
112 // /// FIRST RESULT | 131 final String title1 = Resources.getMsg(this.context.getMeta(), "bundu.export.csv.title.bezugswst.result1"); |
113 // final List<ResultRow> listResult1 = new ArrayList<>(); | 132 final BezugswstMissVolCalculationResult1 r1 = new BezugswstMissVolCalculationResult1(title1, this.rows); |
114 // final ResultRow rowResult1 = ResultRow.create(); | 133 results.addResult(r1, null); |
115 // rowResult1.putValue(BunduResultType.bezugswst, 45.15); | 134 |
116 // rowResult1.putValue(GeneralResultType.dischargeQwithUnit, 890); | 135 final String title2 = Resources.getMsg(this.context.getMeta(), "bundu.export.csv.title.bezugswst.result2"); |
117 // rowResult1.putValue(GeneralResultType.waterlevelLabel, "GLQ"); | 136 final BezugswstMissVolCalculationResult2 r2 = new BezugswstMissVolCalculationResult2(title2, this.rows); |
118 // rowResult1.putValue(GeneralResultType.gaugeLabel, "Bonn"); | 137 results.addResult(r2, null); |
119 // | 138 |
120 // rowResult1.putValue(BunduResultType.sounding, "NIEDERRHEIN_QP-2002"); | 139 final String title3 = Resources.getMsg(this.context.getMeta(), "bundu.export.csv.title.bezugswst.result3"); |
121 // rowResult1.putValue(BunduResultType.channelLowerEdge, 42.65); | 140 final List<ResultRow> totalRows = new ArrayList<>(); |
122 // rowResult1.putValue(BunduResultType.channelMinDepth, 2.5); | 141 totalRows.add(createTotalsRow(missingVolFrom.doubleValue(), missingVolTo.doubleValue(), problems)); |
123 // rowResult1.putValue(BunduResultType.hasMissingDepth, Resources.getMsg(meta, "true")); | 142 final BezugswstMissVolCalculationResult3 r3 = new BezugswstMissVolCalculationResult3(title3, totalRows); |
124 // rowResult1.putValue(BunduResultType.missVolume, 2250); | 143 results.addResult(r3, null); |
125 // rowResult1.putValue(BunduResultType.missMass, 3897); | 144 } |
126 // rowResult1.putValue(BunduResultType.excavationVolume, 2475); | |
127 // rowResult1.putValue(BunduResultType.excavationCosts, 999.99); | |
128 // rowResult1.putValue(BunduResultType.channelWidth, 150); | |
129 // rowResult1.putValue(BunduResultType.density, 1732); | |
130 // | |
131 // rowResult1.putValue(GeneralResultType.location, "Spitzenlage"); | |
132 // listResult1.add(rowResult1); | |
133 // | |
134 // final BezugswstMissVolCalculationResult1 r1 = new BezugswstMissVolCalculationResult1( | |
135 // Resources.getMsg(meta, "bundu.export.csv.title.bezugswst.result1"), listResult1); | |
136 // results.addResult(r1, null); | |
137 // | |
138 // // SECOND RESULT | |
139 // final List<ResultRow> listResult2 = new ArrayList<>(); | |
140 // final ResultRow rowResult2 = ResultRow.create(); | |
141 // | |
142 // rowResult2.putValue(GeneralResultType.station, 890); | |
143 // final List<String> fieldValues = new ArrayList<>(); | |
144 // fieldValues.add("444 [m³] / 765 [t]"); | |
145 // fieldValues.add("4.444 [m³] / 1.765 [t]"); | |
146 // fieldValues.add("444 [m³] / 765 [t]"); | |
147 // fieldValues.add(""); | |
148 // fieldValues.add(""); | |
149 // fieldValues.add(""); | |
150 // fieldValues.add(""); | |
151 // fieldValues.add(""); | |
152 // fieldValues.add(""); | |
153 // fieldValues.add("444 [m³] / 765 [t]"); | |
154 // rowResult2.putValue(BunduResultType.fields, fieldValues); | |
155 // rowResult2.putValue(BunduResultType.meanBedheight, "9.444 [m³] / 8.765 [t]"); | |
156 // | |
157 // listResult2.add(rowResult2); | |
158 // | |
159 // final BezugswstMissVolCalculationResult2 r2 = new BezugswstMissVolCalculationResult2( | |
160 // Resources.getMsg(meta, "bundu.export.csv.title.bezugswst.result2"), listResult2); | |
161 // results.addResult(r2, null); | |
162 // | |
163 // // Third RESULT | |
164 // final List<ResultRow> listResult3 = new ArrayList<>(); | |
165 // final ResultRow rowResult3 = ResultRow.create(); | |
166 // | |
167 // rowResult3.putValue(BunduResultType.stationForMiss, "650 - 651"); | |
168 // rowResult3.putValue(BunduResultType.missVolume, 52950); | |
169 // rowResult3.putValue(BunduResultType.missMass, 91491); | |
170 // | |
171 // listResult3.add(rowResult3); | |
172 // | |
173 // final BezugswstMissVolCalculationResult3 r3 = new BezugswstMissVolCalculationResult3( | |
174 // Resources.getMsg(meta, "bundu.export.csv.title.bezugswst.result3"), listResult3); | |
175 // results.addResult(r3, null); | |
176 // | |
177 // } | |
178 | 145 |
179 return new CalculationResult(results, problems); | 146 return new CalculationResult(results, problems); |
180 } | 147 } |
181 | 148 |
182 /** | 149 /** |
204 * Create a result row for a station | 171 * Create a result row for a station |
205 */ | 172 */ |
206 private ResultRow createRow(final double station, final double w, final double q, final BedHeightsFinder bedHeightsFinder, | 173 private ResultRow createRow(final double station, final double w, final double q, final BedHeightsFinder bedHeightsFinder, |
207 final ChannelFinder channelFinder, final RiverInfoProvider riverInfoProv, final WstInfo wstInfo) { | 174 final ChannelFinder channelFinder, final RiverInfoProvider riverInfoProv, final WstInfo wstInfo) { |
208 | 175 |
176 // Set W and Q | |
209 final ResultRow row = ResultRow.create(); | 177 final ResultRow row = ResultRow.create(); |
210 row.putValue(GeneralResultType.station, station); | 178 row.putValue(GeneralResultType.station, station); |
211 row.putValue(BunduResultType.bezugswst, w); | 179 row.putValue(BunduResultType.bezugswst, w); |
212 row.putValue(GeneralResultType.dischargeQwithUnit, q); | 180 row.putValue(GeneralResultType.dischargeQwithUnit, q); |
213 row.putValue(GeneralResultType.waterlevelLabel, wstInfo.getLabel()); | 181 row.putValue(GeneralResultType.waterlevelLabel, wstInfo.getLabel()); |
214 row.putValue(GeneralResultType.gaugeLabel, riverInfoProv.findGauge(station)); | 182 row.putValue(GeneralResultType.gaugeLabel, riverInfoProv.findGauge(station)); |
215 row.putValue(GeneralResultType.location, riverInfoProv.getLocation(station)); | 183 row.putValue(GeneralResultType.location, riverInfoProv.getLocation(station)); |
184 | |
185 // Set bed and channel bottom height | |
216 final double msh = bedHeightsFinder.getMeanBedHeight(station); | 186 final double msh = bedHeightsFinder.getMeanBedHeight(station); |
217 row.putValue(SInfoResultType.meanBedHeight, msh); | 187 row.putValue(SInfoResultType.meanBedHeight, msh); |
218 if (!Double.isNaN(w) && !Double.isNaN(msh)) | 188 if (!Double.isNaN(w) && !Double.isNaN(msh)) |
219 row.putValue(SInfoResultType.flowdepth, Formatter.roundFlowDepth(w).subtract(Formatter.roundFlowDepth(msh)).doubleValue()); | 189 row.putValue(SInfoResultType.flowdepth, Formatter.roundFlowDepth(w).subtract(Formatter.roundFlowDepth(msh)).doubleValue()); |
220 else | 190 else |
221 row.putValue(SInfoResultType.flowdepth, Double.NaN); | 191 row.putValue(SInfoResultType.flowdepth, Double.NaN); |
222 final double channelDepth = channelFinder.getDepth(station); | 192 final double channelDepth = channelFinder.getDepth(station); |
223 row.putValue(BunduResultType.channelDepth, channelDepth); | 193 row.putValue(BunduResultType.channelDepth, channelDepth); |
194 double channelHeight; | |
224 if (!Double.isNaN(w) && !Double.isNaN(channelDepth)) | 195 if (!Double.isNaN(w) && !Double.isNaN(channelDepth)) |
225 row.putValue(BunduResultType.channelLowerEdge, Formatter.roundFlowDepth(w).subtract(Formatter.roundFlowDepth(channelDepth)).doubleValue()); | 196 channelHeight = Formatter.roundFlowDepth(w).subtract(Formatter.roundFlowDepth(channelDepth)).doubleValue(); |
226 else | 197 else |
227 row.putValue(BunduResultType.channelLowerEdge, Double.NaN); | 198 channelHeight = Double.NaN; |
199 row.putValue(BunduResultType.channelLowerEdge, channelHeight); | |
200 final double channelWidth = channelFinder.getWidth(station); | |
201 row.putValue(BunduResultType.channelWidth, channelWidth); | |
202 | |
203 // Set field heights and missing heights | |
228 final List<Double> fieldHeights = new ArrayList<>(); | 204 final List<Double> fieldHeights = new ArrayList<>(); |
229 final List<Double> fieldDepths = new ArrayList<>(); | 205 final List<Double> fieldDepths = new ArrayList<>(); |
206 final List<Double> fieldMissDepths = new ArrayList<>(); | |
207 final List<Double> fieldMissWidths = new ArrayList<>(); | |
208 int missFieldCnt = 0; | |
230 for (int i = BedHeightValueType.FIELD_FIRST_INDEX; i <= BedHeightValueType.FIELD_LAST_INDEX; i++) { | 209 for (int i = BedHeightValueType.FIELD_FIRST_INDEX; i <= BedHeightValueType.FIELD_LAST_INDEX; i++) { |
231 final double h = bedHeightsFinder.getFieldHeight(station, i); | 210 final double h = bedHeightsFinder.getFieldHeight(station, i); |
232 fieldHeights.add(Double.valueOf(h)); | 211 fieldHeights.add(Double.valueOf(h)); |
233 fieldDepths.add(w - h); | 212 fieldDepths.add(Double.valueOf(w - h)); |
234 } | 213 if (h > channelHeight + 0.001) { |
214 missFieldCnt++; | |
215 fieldMissDepths.add(Double.valueOf(h - channelHeight)); | |
216 fieldMissWidths.add(Double.valueOf(channelWidth / BedHeightValueType.FIELD_LAST_INDEX)); | |
217 } | |
218 else { | |
219 fieldMissDepths.add(Double.valueOf(0.0)); | |
220 fieldMissWidths.add(Double.valueOf(0.0)); | |
221 } | |
222 } | |
223 row.putValue(BunduResultType.missDepthFields, fieldMissDepths); | |
224 row.putValue(BunduResultType.missWidthFields, fieldMissWidths); | |
225 row.putValue(BunduResultType.hasMissingDepth, (missFieldCnt >= 1)); | |
235 row.putValue(BunduResultType.bedHeightFields, fieldHeights); | 226 row.putValue(BunduResultType.bedHeightFields, fieldHeights); |
236 row.putValue(BunduResultType.depthFields, fieldDepths); | 227 row.putValue(BunduResultType.depthFields, fieldDepths); |
228 | |
229 // Preset the missing volume fields with NaN | |
230 row.putValue(BunduResultType.excavationCosts, Double.NaN); | |
231 row.putValue(BunduResultType.excavationVolume, Double.NaN); | |
232 row.putValue(BunduResultType.missVolumeMeanBed, Double.NaN); | |
233 row.putValue(BunduResultType.missMassMeanBed, Double.NaN); | |
234 row.putValue(BunduResultType.missVolumeTotal, Double.NaN); | |
235 row.putValue(BunduResultType.missMassTotal, Double.NaN); | |
236 row.putValue(BunduResultType.density, Double.NaN); | |
237 row.putValue(BunduResultType.missStationRangeFrom, Double.NaN); | |
238 row.putValue(BunduResultType.missStationRangeTo, Double.NaN); | |
239 | |
237 return row; | 240 return row; |
238 } | 241 } |
242 | |
243 /** | |
244 * Computes the missing volumes in a km range | |
245 */ | |
246 private void computeMissingVolumes(final double kmFrom, final double kmTo, final Calculation problems) { | |
247 // Search start km | |
248 int first = -1; | |
249 for (int j = 0; j <= this.rows.size() - 1; j++) { | |
250 if (this.rows.get(j).getDoubleValue(GeneralResultType.station) > kmFrom - 0.0001) { | |
251 first = j; | |
252 break; | |
253 } | |
254 } | |
255 if (first < 0) | |
256 return; | |
257 int last = this.rows.size() - 1; | |
258 int i = first; | |
259 while (i <= this.rows.size() - 1) { | |
260 if (this.rows.get(i).getDoubleValue(GeneralResultType.station) > kmTo + 0.0001) | |
261 break; | |
262 if (this.rows.get(i).getDoubleValue(GeneralResultType.station) > kmTo - 0.0001) | |
263 last = i; | |
264 final List<Double> areas = new ArrayList<>(); | |
265 final List<Double> volumes = new ArrayList<>(); | |
266 double vTotal = 0.0; | |
267 double vExcav = 0.0; | |
268 double expenses = 0.0; | |
269 for (int j = BedHeightValueType.FIELD_FIRST_INDEX; j <= BedHeightValueType.FIELD_LAST_INDEX; j++) { | |
270 if (getFieldValue(i, BunduResultType.missDepthFields, j) > 0.0001) { | |
271 computeMissingVolume(volumes, areas, i, first, last, j); | |
272 vTotal += volumes.get(j - 1); | |
273 vExcav += volumes.get(j - 1) + areas.get(j - 1) * EXCAVATION_DEPTH; | |
274 expenses += vExcav * EXPENSE_PER_CBM; | |
275 } | |
276 else { | |
277 volumes.add(Double.valueOf(0.0)); | |
278 areas.add(Double.valueOf(0.0)); | |
279 } | |
280 } | |
281 this.rows.get(i).putValue(BunduResultType.missVolumeFields, volumes); | |
282 this.rows.get(i).putValue(BunduResultType.missAreaFields, areas); | |
283 this.rows.get(i).putValue(BunduResultType.missVolumeTotal, vTotal); | |
284 this.rows.get(i).putValue(BunduResultType.excavationVolume, vExcav); | |
285 this.rows.get(i).putValue(BunduResultType.excavationCosts, expenses); | |
286 i++; | |
287 } | |
288 } | |
289 | |
290 /** | |
291 * Computes the missing volume of a field of a km row | |
292 */ | |
293 private void computeMissingVolume(final List<Double> volumes, final List<Double> areas, final int current, final int first, final int last, | |
294 final int field) { | |
295 final double areaCurr = missingArea(current, first, last, field); | |
296 final double areaPrev = missingArea(current - 1, first, last, field); | |
297 final double areaNext = missingArea(current + 1, first, last, field); | |
298 final double kmCurr = missingKm(current); | |
299 final double kmPrev = missingKm(current - 1); | |
300 final double kmNext = missingKm(current + 1); | |
301 if (Double.isNaN(kmPrev) || Double.isNaN(kmNext)) { | |
302 volumes.add(Double.valueOf(0.0)); | |
303 areas.add(Double.valueOf(0.0)); | |
304 } | |
305 else { | |
306 final double area1 = 0.5 * (areaCurr + areaPrev); | |
307 final double area2 = 0.5 * (areaCurr + areaNext); | |
308 volumes.add(Double.valueOf((Math.abs(kmCurr - kmPrev) * 0.5 * area1) + (Math.abs(kmNext - kmCurr) * 0.5 * area2))); | |
309 areas.add(Double.valueOf(area1 + area2)); | |
310 } | |
311 } | |
312 | |
313 /** | |
314 * Gets the missing area of a field and a row if in range, otherwise 0.0 | |
315 */ | |
316 private double missingArea(final int rowIndex, final int first, final int last, final int fieldIndex) { | |
317 if ((first <= rowIndex) && (rowIndex <= last)) | |
318 return getFieldValue(rowIndex, BunduResultType.missDepthFields, fieldIndex) | |
319 * getFieldValue(rowIndex, BunduResultType.missWidthFields, fieldIndex); | |
320 else | |
321 return 0.0; | |
322 } | |
323 | |
324 /** | |
325 * Gets the km of a row if within range, otherwise NaN | |
326 */ | |
327 private double missingKm(final int rowIndex) { | |
328 if ((0 <= rowIndex) && (rowIndex <= this.rows.size() - 1)) | |
329 return this.rows.get(rowIndex).getDoubleValue(GeneralResultType.station); | |
330 else | |
331 return Double.NaN; | |
332 } | |
333 | |
334 /** | |
335 * Gets a value of one of the field list types of a row | |
336 * | |
337 * @param rowIndex | |
338 * @param type | |
339 * @param fieldIndex | |
340 * 1-based field index | |
341 */ | |
342 private double getFieldValue(final int rowIndex, final AbstractResultType type, final int fieldIndex) { | |
343 @SuppressWarnings("unchecked") | |
344 final List<Double> values = (List<Double>) this.rows.get(rowIndex).getValue(type); | |
345 return values.get(fieldIndex - 1); | |
346 } | |
347 | |
348 /** | |
349 * Computes the volume and mass total of all rows with missing volumes | |
350 */ | |
351 private ResultRow createTotalsRow(final double kmFrom, final double kmTo, final Calculation problems) { | |
352 // Search start km | |
353 double vTotal = 0.0; | |
354 double mTotal = 0.0; | |
355 for (final ResultRow row : this.rows) { | |
356 final double volume = row.getDoubleValue(BunduResultType.missVolumeMeanBed); | |
357 final double mass = row.getDoubleValue(BunduResultType.missMassMeanBed); | |
358 if (!Double.isNaN(volume) && !Double.isNaN(mass)) { | |
359 vTotal += volume; | |
360 mTotal += mass; | |
361 } | |
362 } | |
363 final ResultRow sumRow = ResultRow.create(); | |
364 sumRow.putValue(BunduResultType.missStationRangeFrom, Double.valueOf(kmFrom)); | |
365 sumRow.putValue(BunduResultType.missStationRangeTo, Double.valueOf(kmTo)); | |
366 sumRow.putValue(BunduResultType.missVolumeTotal, vTotal); | |
367 sumRow.putValue(BunduResultType.missMassTotal, mTotal); | |
368 return sumRow; | |
369 } | |
239 } | 370 } |