# HG changeset patch # User mschaefer # Date 1549378295 -3600 # Node ID 17414e70746e5d09a12370a963c4b46abcaaae82 # Parent 5395c6d4ca509ee935e1389971d9a9979ace2302 Softwaretests...20181219 10.1/10.2/10.5/10.9: corrected computation of missing volume and excavation volume, date range for density queries as in Sinfo/Tkh, empty values instead of 0 if computation not possible diff -r 5395c6d4ca50 -r 17414e70746e artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java Tue Feb 05 15:47:58 2019 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BezugswstCalculation.java Tue Feb 05 15:51:35 2019 +0100 @@ -11,7 +11,6 @@ package org.dive4elements.river.artifacts.bundu.bezugswst; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; import org.dive4elements.artifacts.CallContext; @@ -24,6 +23,7 @@ import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.model.Calculation.Problem; import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.DateRange; import org.dive4elements.river.artifacts.model.WQKms; import org.dive4elements.river.artifacts.model.fixings.FixRealizingCalculation; import org.dive4elements.river.artifacts.model.fixings.FixRealizingResult; @@ -32,6 +32,7 @@ import org.dive4elements.river.artifacts.services.DynamicMainValuesTimeRangeDeterminationService; import org.dive4elements.river.artifacts.services.DynamicMainValuesTimeRangeDeterminationService.GaugeInfoResult; import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; +import org.dive4elements.river.artifacts.sinfo.tkhstate.BedQualityD50TimeRangeConfig; import org.dive4elements.river.artifacts.sinfo.tkhstate.WinfoArtifactWrapper; import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; @@ -56,6 +57,8 @@ */ private final static double EXPENSE_PER_CBM = 12.0; // REMARK Sollte von außen einstellbar sein + private final static double KM_TO_M = 1000.0; + private final CallContext context; private final List rows; @@ -116,7 +119,7 @@ // Fetch the bed levels of the selected sounding final Integer bedHeightId = access.getBedHeightID(); - final BedHeightsFinder bedHeightsFinder = (bedHeightId != null) ? BedHeightsFinder.forId(problems, bedHeightId, access.getRange()) + final BedHeightsFinder bedHeightsFinder = (bedHeightId != null) ? BedHeightsFinder.forId(problems, bedHeightId, access.getRange(), false) : BedHeightsFinder.NullFinder(); // Fetch the river channel data @@ -135,7 +138,8 @@ return new CalculationResult(results, problems); computeMissingVolumes(problems); final BedQualityCalculator bqCalculator = computeDensities(problems, bunduartifact, access, river); - computeMissingMasses(problems, bqCalculator); + if (bqCalculator != null) + computeMissingMasses(problems, bqCalculator); } // Add the result to the results collection @@ -225,7 +229,9 @@ final double channelWidth = channelFinder.getWidth(station); row.putValue(BunduResultType.channelWidth, channelWidth); if (!Double.isNaN(channelHeight)) { - if (msh > channelHeight + 0.001) + if (Double.isNaN(msh)) + row.putValue(BunduResultType.missDepthMeanBed, Double.NaN); + else if (msh > channelHeight + 0.001) row.putValue(BunduResultType.missDepthMeanBed, msh - channelHeight); else row.putValue(BunduResultType.missDepthMeanBed, 0.0); @@ -242,7 +248,11 @@ final double h = bedHeightsFinder.getFieldHeight(station, i); fieldHeights.add(Double.valueOf(h)); fieldDepths.add(Double.valueOf(w - h)); - if (h > channelHeight + 0.001) { + if (Double.isNaN(h)) { + fieldMissDepths.add(Double.NaN); + fieldMissWidths.add(Double.NaN); + } + else if (h > channelHeight + 0.001) { missFieldCnt++; fieldMissDepths.add(Double.valueOf(h - channelHeight)); fieldMissWidths.add(Double.valueOf(channelWidth / BedHeightValueType.FIELD_LAST_INDEX)); @@ -252,7 +262,7 @@ } fieldNulls.add(Double.NaN); } - if (isKmInMissingVolumeRange(station)) { + if (!Double.isNaN(msh) && isKmInMissingVolumeRange(station)) { row.putValue(BunduResultType.missDepthFields, fieldMissDepths); row.putValue(BunduResultType.missWidthFields, fieldMissWidths); row.putValue(BunduResultType.hasMissingDepth, (missFieldCnt >= 1)); @@ -303,19 +313,24 @@ break; if (km > this.missKmTo.doubleValue() - 0.0001) last = i; + if (this.rows.get(i).getValue(BunduResultType.hasMissingDepth) == null) + continue; + final double chDepth = this.rows.get(i).getDoubleValue(BunduResultType.channelDepth) + EXCAVATION_DEPTH; final List areas = new ArrayList<>(); final List volumes = new ArrayList<>(); double vTotal = 0.0; double vExcav = 0.0; for (int j = BedHeightValueType.FIELD_FIRST_INDEX; j <= BedHeightValueType.FIELD_LAST_INDEX; j++) { if (getFieldValue(i, BunduResultType.missDepthFields, j) > 0.0001) { - computeMissingVolume(volumes, areas, i, first, last, j); + computeMissingVolume(volumes, areas, i, first, last, j, ActualMissingHeightComputer.Instance); vTotal += volumes.get(j - 1); - vExcav += volumes.get(j - 1) + areas.get(j - 1) * EXCAVATION_DEPTH; } else { volumes.add(Double.valueOf(0.0)); areas.add(Double.valueOf(0.0)); } + if (chDepth - getFieldValue(i, BunduResultType.depthFields, j) > 0.0001) { + vExcav += computeMissingVolume(null, null, i, first, last, j, ExcavationMissingAreaComputer.Instance); + } } final double[] meanBedVolumeArea = computeMeanBedMissingAreaAndVolume(i, first, last); this.rows.get(i).putValue(BunduResultType.missVolumeMeanBed, meanBedVolumeArea[0]); @@ -331,33 +346,80 @@ /** * Computes the missing volume of a field of a km row */ - private void computeMissingVolume(final List volumes, final List areas, final int current, final int first, final int last, - final int field) { + private double computeMissingVolume(final List volumes, final List areas, final int current, final int first, final int last, + final int field, final MissingHeightComputer heightcomputer) { - final double areaCurr = missingArea(current, first, last, field); - final double areaPrev = missingArea(current - 1, first, last, field); - final double areaNext = missingArea(current + 1, first, last, field); + final double dhCurr = heightcomputer.missingHeight(this.rows.get(current), current, first, last, field); + final double dhPrev = heightcomputer.missingHeight(this.rows.get(current - 1), current - 1, first, last, field); + final double dhNext = heightcomputer.missingHeight(this.rows.get(current + 1), current + 1, first, last, field); final double kmCurr = missingKm(current); final double kmPrev = missingKm(current - 1); final double kmNext = missingKm(current + 1); - final double area1 = Double.isNaN(kmPrev) ? 0.0 : 0.5 * (areaCurr + areaPrev); - final double area2 = Double.isNaN(kmNext) ? 0.0 : 0.5 * (areaCurr + areaNext); - final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * 500 * area1) + (Math.abs(kmNext - kmCurr) * 500 * area2)); - volumes.add(volume); - if (!Double.isNaN(volume)) - areas.add(Double.valueOf(area1 + area2)); - else - areas.add(Double.NaN); + final double width = getFieldValue(current, BunduResultType.missWidthFields, field); + final double area1 = Double.isNaN(kmPrev) ? 0.0 : (0.25 * dhPrev + 0.75 * dhCurr) * width; + final double area2 = Double.isNaN(kmNext) ? 0.0 : (0.75 * dhCurr + 0.25 * dhNext) * width; + final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * KM_TO_M / 2 * area1) + (Math.abs(kmNext - kmCurr) * KM_TO_M / 2 * area2)); + if (volumes != null) + volumes.add(volume); + if (areas != null) { + if (!Double.isNaN(volume)) + areas.add(Double.valueOf(area1 + area2)); + else + areas.add(Double.NaN); + } + return volume; } /** - * Gets the missing area of a field and a row if in range, otherwise 0.0 + * Interface for the function that computes the missing height of a field */ - private double missingArea(final int rowIndex, final int first, final int last, final int fieldIndex) { - if ((first <= rowIndex) && (rowIndex <= last)) - return getFieldValue(rowIndex, BunduResultType.missDepthFields, fieldIndex) * getFieldValue(rowIndex, BunduResultType.missWidthFields, fieldIndex); - else - return 0.0; + private interface MissingHeightComputer { + /** + * Gets the missing area of a field and a row if in range, otherwise 0.0 + */ + double missingHeight(final ResultRow row, final int rowIndex, final int first, final int last, final int fieldIndex); + } + + /** + * Computation of the actual missing height of a field + */ + private static class ActualMissingHeightComputer implements MissingHeightComputer { + public static MissingHeightComputer Instance = new ActualMissingHeightComputer(); + + /** + * Gets the missing height of a field and a row if in range, otherwise 0.0 + */ + @SuppressWarnings("unchecked") + @Override + public double missingHeight(final ResultRow row, final int rowIndex, final int first, final int last, final int fieldIndex) { + if ((first <= rowIndex) && (rowIndex <= last)) { + return ((List) row.getValue(BunduResultType.missDepthFields)).get(fieldIndex - 1).doubleValue(); + } + else + return 0.0; + } + } + + /** + * Computation of the excavation height of a field + */ + private static class ExcavationMissingAreaComputer implements MissingHeightComputer { + public static MissingHeightComputer Instance = new ExcavationMissingAreaComputer(); + + /** + * Gets the excavation height of a field and a row if in range, otherwise 0.0 + */ + @SuppressWarnings("unchecked") + @Override + public double missingHeight(final ResultRow row, final int rowIndex, final int first, final int last, final int fieldIndex) { + if ((first <= rowIndex) && (rowIndex <= last)) { + final double channeldepth = row.getDoubleValue(BunduResultType.channelDepth) + EXCAVATION_DEPTH; + final double fielddepth = ((List) row.getValue(BunduResultType.depthFields)).get(fieldIndex - 1).doubleValue(); + return (channeldepth - fielddepth); + } + else + return 0.0; + } } /** @@ -365,30 +427,31 @@ */ private double[] computeMeanBedMissingAreaAndVolume(final int current, final int first, final int last) { - final double areaCurr = meanBedMissingArea(current, first, last); - if (areaCurr < 0.0001) + final double dhCurr = meanBedMissingHeight(current, first, last); + if (dhCurr < 0.0001) return new double[] { 0.0, 0.0 }; - final double areaPrev = meanBedMissingArea(current - 1, first, last); - final double areaNext = meanBedMissingArea(current + 1, first, last); + final double dhPrev = meanBedMissingHeight(current - 1, first, last); + final double dhNext = meanBedMissingHeight(current + 1, first, last); final double kmCurr = missingKm(current); final double kmPrev = missingKm(current - 1); final double kmNext = missingKm(current + 1); - final double area1 = Double.isNaN(kmPrev) ? 0.0 : 0.5 * (areaCurr + areaPrev); - final double area2 = Double.isNaN(kmNext) ? 0.0 : 0.5 * (areaCurr + areaNext); - final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * 500 * area1) + (Math.abs(kmNext - kmCurr) * 500 * area2)); + final double width = this.rows.get(current).getDoubleValue(BunduResultType.channelWidth); + final double area1 = Double.isNaN(kmPrev) ? 0.0 : (0.25 * dhPrev + 0.75 * dhCurr) * width; + final double area2 = Double.isNaN(kmNext) ? 0.0 : (0.75 * dhCurr + 0.25 * dhNext) * width; + final double volume = Double.valueOf((Math.abs(kmCurr - kmPrev) * KM_TO_M / 2 * area1) + (Math.abs(kmNext - kmCurr) * KM_TO_M / 2 * area2)); final double area = Double.isNaN(volume) ? Double.NaN : Double.valueOf(area1 + area2); return new double[] { volume, area }; } /** - * Gets the missing area of the mean bed level and a row if in range, otherwise 0.0 + * Gets the missing height of the mean bed level and a row if in range, otherwise 0.0 */ - private double meanBedMissingArea(final int rowIndex, final int first, final int last) { + private double meanBedMissingHeight(final int rowIndex, final int first, final int last) { if ((first <= rowIndex) && (rowIndex <= last)) { final double dh = this.rows.get(rowIndex).getDoubleValue(BunduResultType.channelDepth) - this.rows.get(rowIndex).getDoubleValue(BunduResultType.flowdepthMeanBed); if (dh > 0.0) - return dh * this.rows.get(rowIndex).getDoubleValue(BunduResultType.channelWidth); + return dh; return 0.0; } return 0.0; @@ -398,7 +461,7 @@ * Gets the km of a row if within range, otherwise NaN */ private double missingKm(final int rowIndex) { - if ((0 <= rowIndex) && (rowIndex <= this.rows.size() - 1)) + if ((0 <= rowIndex) && (rowIndex <= this.rows.size() - 1) && (this.rows.get(rowIndex).getValue(BunduResultType.hasMissingDepth) != null)) return this.rows.get(rowIndex).getDoubleValue(GeneralResultType.station); return Double.NaN; } @@ -412,12 +475,10 @@ // REMARK 10km tolerance at start and end to enable interpolation there final double[] kms = DoubleUtil.explode(access.getMissingVolFrom().doubleValue() - 10.0, access.getMissingVolTo().doubleValue() + 10.0, access.getStep().doubleValue() / 1000); - final Calendar endDay = Calendar.getInstance(); - endDay.set(access.getBezugsJahr().intValue(), 11, 31); - final Calendar startDay = Calendar.getInstance(); - // TODO Spezialregelung für den Rhein (bis 1999, 2000 bis 2009, ab 2010) - startDay.set(endDay.get(Calendar.YEAR) - 20, 0, 1); - bqCalculator.execute(problems, river, kms, startDay.getTime(), endDay.getTime()); + final DateRange dateRange = BedQualityD50TimeRangeConfig.getDefaults(river, access.getBezugsJahr().intValue(), problems); + if (dateRange == null) + return null; + bqCalculator.execute(problems, river, kms, dateRange.getFrom(), dateRange.getTo()); return bqCalculator; } @@ -433,12 +494,17 @@ final double density = getDensity(row.getDoubleValue(GeneralResultType.station), densityFinder); final List masses = new ArrayList<>(); double kmTotal = 0.0; + int mcnt = 0; for (int j = BedHeightValueType.FIELD_FIRST_INDEX; j <= BedHeightValueType.FIELD_LAST_INDEX; j++) { final double m = volumes.get(j - 1) * density; masses.add(m); - if (!Double.isNaN(m)) + if (!Double.isNaN(m)) { kmTotal += m; + mcnt += 1; + } } + if (mcnt == 0) + kmTotal = Double.NaN; row.putValue(BunduResultType.density, density); row.putValue(BunduResultType.missMassFields, masses); row.putValue(BunduResultType.missMassTotal, kmTotal); @@ -469,18 +535,36 @@ double mTotal = 0.0; double eTotal = 0.0; double cTotal = 0.0; + int vcnt = 0; + int mcnt = 0; + int ecnt = 0; for (final ResultRow row : this.rows) { final double volume = row.getDoubleValue(BunduResultType.missVolumeTotal); final double mass = row.getDoubleValue(BunduResultType.missMassTotal); + if (!Double.isNaN(volume)) { + vTotal += volume; + vcnt++; + if (!Double.isNaN(mass)) { + mTotal += mass; + mcnt++; + } + } final double excavation = row.getDoubleValue(BunduResultType.excavationVolume); final double costs = row.getDoubleValue(BunduResultType.excavationCosts); - if (!Double.isNaN(volume) && !Double.isNaN(mass)) { - vTotal += volume; - mTotal += mass; + if (!Double.isNaN(excavation)) { eTotal += excavation; cTotal += costs; + ecnt++; } } + if (vcnt == 0) + vTotal = Double.NaN; + if (mcnt == 0) + mTotal = Double.NaN; + if (ecnt == 0) { + eTotal = Double.NaN; + cTotal = Double.NaN; + } final ResultRow sumRow = ResultRow.create(); sumRow.putValue(BunduResultType.missStationRangeFrom, Double.valueOf(this.missKmFrom)); sumRow.putValue(BunduResultType.missStationRangeTo, Double.valueOf(this.missKmTo));