[PATCH 5 of 5] 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
Wald Commits
scm-commit at wald.intevation.org
Tue Feb 5 15:52:20 CET 2019
# 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<ResultRow> 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<Double> areas = new ArrayList<>();
final List<Double> 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<Double> volumes, final List<Double> areas, final int current, final int first, final int last,
- final int field) {
+ private double computeMissingVolume(final List<Double> volumes, final List<Double> 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<Double>) 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<Double>) 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<Double> 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));
More information about the Dive4Elements-commits
mailing list