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 }

http://dive4elements.wald.intevation.org