# HG changeset patch # User mschaefer # Date 1532366406 -7200 # Node ID bcbae86ce7b3d36ae5684210bf7337b9f8e4d1db # Parent 9b16f58c62a78a496d4d346fc3522d7d0535aaf6 Improved flood duration curve calculation as specified by BfG diff -r 9b16f58c62a7 -r bcbae86ce7b3 artifacts/src/main/java/org/dive4elements/river/artifacts/model/WstValueTable.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WstValueTable.java Mon Jul 23 19:18:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WstValueTable.java Mon Jul 23 19:20:06 2018 +0200 @@ -8,31 +8,25 @@ package org.dive4elements.river.artifacts.model; -import java.io.Serializable; +import static org.dive4elements.river.backend.utils.EpsilonComparator.CMP; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.math.ArgumentOutsideDomainException; +import org.apache.commons.math.analysis.interpolation.SplineInterpolator; +import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; +import org.apache.commons.math.exception.MathIllegalArgumentException; +import org.apache.log4j.Logger; +import org.dive4elements.river.artifacts.math.Function; import org.dive4elements.river.artifacts.math.Linear; -import org.dive4elements.river.artifacts.math.Function; import org.dive4elements.river.utils.DoubleUtil; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.List; -import java.util.Collections; - -import org.apache.log4j.Logger; - -import org.apache.commons.math.analysis.interpolation.SplineInterpolator; - -import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; - -import org.apache.commons.math.ArgumentOutsideDomainException; - -import org.apache.commons.math.exception.MathIllegalArgumentException; - import gnu.trove.TDoubleArrayList; -import static org.dive4elements.river.backend.utils.EpsilonComparator.CMP; - /** * W, Q and km data from database 'wsts' spiced with interpolation algorithms. */ @@ -60,23 +54,23 @@ public Column() { } - public Column(String name) { + public Column(final String name) { this.name = name; } public String getName() { - return name; + return this.name; } - public void setName(String name) { + public void setName(final String name) { this.name = name; } public QRangeTree getQRangeTree() { - return qRangeTree; + return this.qRangeTree; } - public void setQRangeTree(QRangeTree qRangeTree) { + public void setQRangeTree(final QRangeTree qRangeTree) { this.qRangeTree = qRangeTree; } } // class Column @@ -92,12 +86,12 @@ public QPosition() { } - public QPosition(int index, double weight) { + public QPosition(final int index, final double weight) { this.index = index; this.weight = weight; } - public QPosition set(int index, double weight) { + public QPosition set(final int index, final double weight) { this.index = index; this.weight = weight; return this; @@ -112,38 +106,38 @@ public double [] splineWs; public SplineFunction( - PolynomialSplineFunction spline, - double [] splineQs, - double [] splineWs - ) { + final PolynomialSplineFunction spline, + final double [] splineQs, + final double [] splineWs + ) { this.spline = spline; this.splineQs = splineQs; this.splineWs = splineWs; } public double [][] sample( - int numSamples, - double km, - Calculation errors - ) { - double minQ = getQMin(); - double maxQ = getQMax(); + final int numSamples, + final double km, + final Calculation errors + ) { + final double minQ = getQMin(); + final double maxQ = getQMax(); - double [] outWs = new double[numSamples]; - double [] outQs = new double[numSamples]; + final double [] outWs = new double[numSamples]; + final double [] outQs = new double[numSamples]; Arrays.fill(outWs, Double.NaN); Arrays.fill(outQs, Double.NaN); - double stepWidth = (maxQ - minQ)/numSamples; + final double stepWidth = (maxQ - minQ)/numSamples; try { double q = minQ; for (int i = 0; i < outWs.length; ++i, q += stepWidth) { - outWs[i] = spline.value(outQs[i] = q); + outWs[i] = this.spline.value(outQs[i] = q); } } - catch (ArgumentOutsideDomainException aode) { + catch (final ArgumentOutsideDomainException aode) { if (errors != null) { errors.addProblem(km, "spline.interpolation.failed"); } @@ -154,26 +148,26 @@ } public double getQMin() { - return Math.min(splineQs[0], splineQs[splineQs.length-1]); + return Math.min(this.splineQs[0], this.splineQs[this.splineQs.length-1]); } public double getQMax() { - return Math.max(splineQs[0], splineQs[splineQs.length-1]); + return Math.max(this.splineQs[0], this.splineQs[this.splineQs.length-1]); } /** Constructs a continues index between the columns to Qs. */ public PolynomialSplineFunction createIndexQRelation() { - double [] indices = new double[splineQs.length]; + final double [] indices = new double[this.splineQs.length]; for (int i = 0; i < indices.length; ++i) { indices[i] = i; } try { - SplineInterpolator interpolator = new SplineInterpolator(); - return interpolator.interpolate(indices, splineQs); + final SplineInterpolator interpolator = new SplineInterpolator(); + return interpolator.interpolate(indices, this.splineQs); } - catch (MathIllegalArgumentException miae) { + catch (final MathIllegalArgumentException miae) { // Ignore me! } return null; @@ -192,11 +186,11 @@ public Row() { } - public Row(double km) { + public Row(final double km) { this.km = km; } - public Row(double km, double [] ws) { + public Row(final double km, final double [] ws) { this(km); this.ws = ws; } @@ -205,26 +199,26 @@ * Sort Qs and Ws for this Row over Q. */ private double[][] getSortedWQ( - WstValueTable table, - Calculation errors - ) { - int W = ws.length; + final WstValueTable table, + final Calculation errors + ) { + final int W = this.ws.length; if (W < 1) { if (errors != null) { - errors.addProblem(km, "no.ws.found"); + errors.addProblem(this.km, "no.ws.found"); } return new double[][] {{Double.NaN}, {Double.NaN}}; } - double [] sortedWs = ws; - double [] sortedQs = new double[W]; + final double [] sortedWs = this.ws; + final double [] sortedQs = new double[W]; for (int i=0; i < W; ++i) { - double q = table.getQIndex(i, km); + final double q = table.getQIndex(i, this.km); if (Double.isNaN(q) && errors != null) { errors.addProblem( - km, "no.q.found.in.column", i+1); + this.km, "no.q.found.in.column", i+1); } sortedQs[i] = q; } @@ -239,12 +233,12 @@ * this Row and another, sorted over Q. */ private double[][] getSortedWQ( - Row other, - double km, - WstValueTable table, - Calculation errors - ) { - int W = Math.min(ws.length, other.ws.length); + final Row other, + final double km, + final WstValueTable table, + final Calculation errors + ) { + final int W = Math.min(this.ws.length, other.ws.length); if (W < 1) { if (errors != null) { @@ -253,14 +247,14 @@ return new double[][] {{Double.NaN}, {Double.NaN}}; } - double factor = Linear.factor(km, this.km, other.km); + final double factor = Linear.factor(km, this.km, other.km); - double [] sortedQs = new double[W]; - double [] sortedWs = new double[W]; + final double [] sortedQs = new double[W]; + final double [] sortedWs = new double[W]; for (int i = 0; i < W; ++i) { - double wws = Linear.weight(factor, ws[i], other.ws[i]); - double wqs = table.getQIndex(i, km); + final double wws = Linear.weight(factor, this.ws[i], other.ws[i]); + final double wqs = table.getQIndex(i, km); if (Double.isNaN(wws) || Double.isNaN(wqs)) { if (errors != null) { @@ -280,34 +274,34 @@ /** * Find Qs matching w in an array of Qs and Ws sorted over Q. */ - private double[] findQsForW(double w, double[][] sortedWQ) { - int W = sortedWQ[0].length; + private double[] findQsForW(final double w, final double[][] sortedWQ) { + final int W = sortedWQ[0].length; - double[] sortedQs = sortedWQ[1]; - double[] sortedWs = sortedWQ[0]; + final double[] sortedQs = sortedWQ[1]; + final double[] sortedWs = sortedWQ[0]; - TDoubleArrayList qs = new TDoubleArrayList(); + final TDoubleArrayList qs = new TDoubleArrayList(); if (W > 0 && Math.abs(sortedWs[0]-w) < W_EPSILON) { - double q = sortedQs[0]; + final double q = sortedQs[0]; if (!Double.isNaN(q)) { qs.add(q); } } for (int i = 1; i < W; ++i) { - double w2 = sortedWs[i]; + final double w2 = sortedWs[i]; if (Double.isNaN(w2)) { continue; } if (Math.abs(w2-w) < W_EPSILON) { - double q = sortedQs[i]; + final double q = sortedQs[i]; if (!Double.isNaN(q)) { qs.add(q); } continue; } - double w1 = sortedWs[i-1]; + final double w1 = sortedWs[i-1]; if (Double.isNaN(w1)) { continue; } @@ -316,13 +310,13 @@ continue; } - double q1 = sortedQs[i-1]; - double q2 = sortedQs[i]; + final double q1 = sortedQs[i-1]; + final double q2 = sortedQs[i]; if (Double.isNaN(q1) || Double.isNaN(q2)) { continue; } - double q = Linear.linear(w, w1, w2, q1, q2); + final double q = Linear.linear(w, w1, w2, q1, q2); qs.add(q); } @@ -332,8 +326,9 @@ /** * Compare according to place of measurement (km). */ - public int compareTo(Row other) { - return CMP.compare(km, other.km); + @Override + public int compareTo(final Row other) { + return CMP.compare(this.km, other.km); } /** @@ -344,25 +339,25 @@ * @param table Table of which to use data for interpolation. */ public void interpolateW( - Row other, - double km, - double [] iqs, - double [] ows, - WstValueTable table, - Calculation errors - ) { - double kmWeight = Linear.factor(km, this.km, other.km); + final Row other, + final double km, + final double [] iqs, + final double [] ows, + final WstValueTable table, + final Calculation errors + ) { + final double kmWeight = Linear.factor(km, this.km, other.km); - QPosition qPosition = new QPosition(); + final QPosition qPosition = new QPosition(); for (int i = 0; i < iqs.length; ++i) { if (table.getQPosition(km, iqs[i], qPosition) != null) { - double wt = getW(qPosition); - double wo = other.getW(qPosition); + final double wt = getW(qPosition); + final double wo = other.getW(qPosition); if (Double.isNaN(wt) || Double.isNaN(wo)) { if (errors != null) { errors.addProblem( - km, "cannot.find.w.for.q", iqs[i]); + km, "cannot.find.w.for.q", iqs[i]); } ows[i] = Double.NaN; } @@ -381,21 +376,21 @@ public SplineFunction createSpline( - WstValueTable table, - Calculation errors - ) { - double[][] sortedWQ = getSortedWQ(table, errors); + final WstValueTable table, + final Calculation errors + ) { + final double[][] sortedWQ = getSortedWQ(table, errors); try { - SplineInterpolator interpolator = new SplineInterpolator(); - PolynomialSplineFunction spline = - interpolator.interpolate(sortedWQ[1], sortedWQ[0]); + final SplineInterpolator interpolator = new SplineInterpolator(); + final PolynomialSplineFunction spline = + interpolator.interpolate(sortedWQ[1], sortedWQ[0]); - return new SplineFunction(spline, sortedWQ[1], ws); + return new SplineFunction(spline, sortedWQ[1], this.ws); } - catch (MathIllegalArgumentException miae) { + catch (final MathIllegalArgumentException miae) { if (errors != null) { - errors.addProblem(km, "spline.creation.failed"); + errors.addProblem(this.km, "spline.creation.failed"); } log.error("spline creation failed", miae); } @@ -403,22 +398,22 @@ } public SplineFunction createSpline( - Row other, - double km, - WstValueTable table, - Calculation errors - ) { - double[][] sortedWQ = getSortedWQ(other, km, table, errors); + final Row other, + final double km, + final WstValueTable table, + final Calculation errors + ) { + final double[][] sortedWQ = getSortedWQ(other, km, table, errors); - SplineInterpolator interpolator = new SplineInterpolator(); + final SplineInterpolator interpolator = new SplineInterpolator(); try { - PolynomialSplineFunction spline = - interpolator.interpolate(sortedWQ[1], sortedWQ[0]); + final PolynomialSplineFunction spline = + interpolator.interpolate(sortedWQ[1], sortedWQ[0]); return new SplineFunction(spline, sortedWQ[1], sortedWQ[0]); } - catch (MathIllegalArgumentException miae) { + catch (final MathIllegalArgumentException miae) { if (errors != null) { errors.addProblem(km, "spline.creation.failed"); } @@ -429,60 +424,60 @@ } public double [][] interpolateWQ( - Row other, - double km, - int steps, - WstValueTable table, - Calculation errors - ) { - SplineFunction sf = createSpline(other, km, table, errors); + final Row other, + final double km, + final int steps, + final WstValueTable table, + final Calculation errors + ) { + final SplineFunction sf = createSpline(other, km, table, errors); return sf != null - ? sf.sample(steps, km, errors) - : new double[2][0]; + ? sf.sample(steps, km, errors) + : new double[2][0]; } public double [][] interpolateWQ( - int steps, - WstValueTable table, - Calculation errors - ) { - SplineFunction sf = createSpline(table, errors); + final int steps, + final WstValueTable table, + final Calculation errors + ) { + final SplineFunction sf = createSpline(table, errors); return sf != null - ? sf.sample(steps, km, errors) - : new double[2][0]; + ? sf.sample(steps, this.km, errors) + : new double[2][0]; } - public double getW(QPosition qPosition) { - int index = qPosition.index; - double weight = qPosition.weight; + public double getW(final QPosition qPosition) { + final int index = qPosition.index; + final double weight = qPosition.weight; return weight == 1.0 - ? ws[index] - : Linear.weight(weight, ws[index-1], ws[index]); + ? this.ws[index] + : Linear.weight(weight, this.ws[index-1], this.ws[index]); } public double getW( - Row other, - double km, - QPosition qPosition - ) { - double kmWeight = Linear.factor(km, this.km, other.km); + final Row other, + final double km, + final QPosition qPosition + ) { + final double kmWeight = Linear.factor(km, this.km, other.km); - int index = qPosition.index; - double weight = qPosition.weight; + final int index = qPosition.index; + final double weight = qPosition.weight; double tw, ow; if (weight == 1.0) { - tw = ws[index]; + tw = this.ws[index]; ow = other.ws[index]; } else { - tw = Linear.weight(weight, ws[index-1], ws[index]); + tw = Linear.weight(weight, this.ws[index-1], this.ws[index]); ow = Linear.weight(weight, other.ws[index-1], other.ws[index]); } @@ -490,30 +485,30 @@ } public double [] findQsForW( - double w, - WstValueTable table, - Calculation errors - ) { - log.debug("Find Qs for given W at tabulated km " + km); + final double w, + final WstValueTable table, + final Calculation errors + ) { + log.debug("Find Qs for given W at tabulated km " + this.km); return findQsForW(w, getSortedWQ(table, errors)); } public double [] findQsForW( - Row other, - double w, - double km, - WstValueTable table, - Calculation errors - ) { + final Row other, + final double w, + final double km, + final WstValueTable table, + final Calculation errors + ) { log.debug("Find Qs for given W at non-tabulated km " + km); return findQsForW(w, getSortedWQ(other, km, table, errors)); } - public double [] getMinMaxW(double [] result) { + public double [] getMinMaxW(final double [] result) { double minW = Double.MAX_VALUE; double maxW = -Double.MAX_VALUE; - for (int i = 0; i < ws.length; ++i) { - double w = ws[i]; + for (int i = 0; i < this.ws.length; ++i) { + final double w = this.ws[i]; if (w < minW) minW = w; if (w > maxW) maxW = w; } @@ -522,10 +517,10 @@ return result; } - public double [] getMinMaxW(Row other, double km, double [] result) { - double [] m1 = this .getMinMaxW(new double [2]); - double [] m2 = other.getMinMaxW(new double [2]); - double factor = Linear.factor(km, this.km, other.km); + public double [] getMinMaxW(final Row other, final double km, final double [] result) { + final double [] m1 = this .getMinMaxW(new double [2]); + final double [] m2 = other.getMinMaxW(new double [2]); + final double factor = Linear.factor(km, this.km, other.km); result[0] = Linear.weight(factor, m1[0], m2[0]); result[1] = Linear.weight(factor, m1[1], m2[1]); return result; @@ -539,10 +534,10 @@ protected Column [] columns; public WstValueTable() { - rows = new ArrayList(); + this.rows = new ArrayList<>(); } - public WstValueTable(Column [] columns) { + public WstValueTable(final Column [] columns) { this(); this.columns = columns; } @@ -551,13 +546,13 @@ * @param columns The WST-columns. * @param rows A list of Rows that must be sorted by km. */ - public WstValueTable(Column [] columns, List rows) { + public WstValueTable(final Column [] columns, final List rows) { this.columns = columns; this.rows = rows; } public Column [] getColumns() { - return columns; + return this.columns; } /** @@ -565,7 +560,7 @@ * @param qs Given Q values. * @param ws output parameter. */ - public double [] interpolateW(double km, double [] qs, double [] ws) { + public double [] interpolateW(final double km, final double [] qs, final double [] ws) { return interpolateW(km, qs, ws, null); } @@ -575,17 +570,17 @@ * @return output parameter ws. */ public double [] interpolateW( - double km, - double [] qs, - double [] ws, - Calculation errors - ) { - int rowIndex = Collections.binarySearch(rows, new Row(km)); + final double km, + final double [] qs, + final double [] ws, + final Calculation errors + ) { + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); - QPosition qPosition = new QPosition(); + final QPosition qPosition = new QPosition(); if (rowIndex >= 0) { // direct row match - Row row = rows.get(rowIndex); + final Row row = this.rows.get(rowIndex); for (int i = 0; i < qs.length; ++i) { if (getQPosition(km, qs[i], qPosition) == null) { if (errors != null) { @@ -595,9 +590,9 @@ } else { if (Double.isNaN(ws[i] = row.getW(qPosition)) - && errors != null) { + && errors != null) { errors.addProblem( - km, "cannot.find.w.for.q", qs[i]); + km, "cannot.find.w.for.q", qs[i]); } } } @@ -605,7 +600,7 @@ else { // needs bilinear interpolation rowIndex = -rowIndex -1; - if (rowIndex < 1 || rowIndex >= rows.size()) { + if (rowIndex < 1 || rowIndex >= this.rows.size()) { // do not extrapolate Arrays.fill(ws, Double.NaN); if (errors != null) { @@ -613,8 +608,8 @@ } } else { - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); r1.interpolateW(r2, km, qs, ws, this, errors); } } @@ -622,16 +617,46 @@ return ws; } - public double [] getMinMaxQ(double km) { + /** + * Interpolates a W for a km using a Q column position + */ + public double interpolateW(final double km, final QPosition qPosition, final Calculation errors) { + + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); + + if (rowIndex >= 0) { // direct row match + final Row row = this.rows.get(rowIndex); + return row.getW(qPosition); + } + else { // needs bilinear interpolation + rowIndex = -rowIndex - 1; + if ((rowIndex <= 0) || (rowIndex >= this.rows.size())) + return Double.NaN; + else { + final Row r1 = this.rows.get(rowIndex - 1); + final Row r2 = this.rows.get(rowIndex); + final double w1 = r1.getW(qPosition); + final double w2 = r2.getW(qPosition); + if (Double.isNaN(w1) || Double.isNaN(w2)) + return Double.NaN; + else { + final double kmWeight = Linear.factor(km, r1.km, r2.km); + return Linear.weight(kmWeight, w1, w2); + } + } + } + } + + public double [] getMinMaxQ(final double km) { return getMinMaxQ(km, new double [2]); } - public double [] getMinMaxQ(double km, double [] result) { + public double [] getMinMaxQ(final double km, final double [] result) { double minQ = Double.MAX_VALUE; double maxQ = -Double.MAX_VALUE; - for (int i = 0; i < columns.length; ++i) { - double q = columns[i].getQRangeTree().findQ(km); + for (int i = 0; i < this.columns.length; ++i) { + final double q = this.columns[i].getQRangeTree().findQ(km); if (!Double.isNaN(q)) { if (q < minQ) minQ = q; if (q > maxQ) maxQ = q; @@ -648,13 +673,13 @@ } public double [] getMinMaxQ(double from, double to, double step) { - double [] result = new double[2]; + final double [] result = new double[2]; double minQ = Double.MAX_VALUE; double maxQ = -Double.MAX_VALUE; if (from > to) { - double tmp = from; + final double tmp = from; from = to; to = tmp; } @@ -677,42 +702,42 @@ } return minQ < Double.MAX_VALUE - ? new double [] { minQ, maxQ } - : null; + ? new double [] { minQ, maxQ } + : null; } - public double [] getMinMaxW(double km) { + public double [] getMinMaxW(final double km) { return getMinMaxW(km, new double [2]); } - public double [] getMinMaxW(double km, double [] result) { - int rowIndex = Collections.binarySearch(rows, new Row(km)); + public double [] getMinMaxW(final double km, final double [] result) { + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex >= 0) { - return rows.get(rowIndex).getMinMaxW(result); + return this.rows.get(rowIndex).getMinMaxW(result); } rowIndex = -rowIndex -1; - if (rowIndex < 1 || rowIndex >= rows.size()) { + if (rowIndex < 1 || rowIndex >= this.rows.size()) { // do not extrapolate return null; } - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); return r1.getMinMaxW(r2, km, result); } public double [] getMinMaxW(double from, double to, double step) { - double [] result = new double[2]; + final double [] result = new double[2]; double minW = Double.MAX_VALUE; double maxW = -Double.MAX_VALUE; if (from > to) { - double tmp = from; + final double tmp = from; from = to; to = tmp; } @@ -735,14 +760,14 @@ } return minW < Double.MAX_VALUE - ? new double [] { minW, maxW } - : null; + ? new double [] { minW, maxW } + : null; } /** * Interpolate W and Q values at a given km. */ - public double [][] interpolateWQ(double km) { + public double [][] interpolateWQ(final double km) { return interpolateWQ(km, null); } @@ -753,7 +778,7 @@ * * @return double double array, first index Ws, second Qs. */ - public double [][] interpolateWQ(double km, Calculation errors) { + public double [][] interpolateWQ(final double km, final Calculation errors) { return interpolateWQ(km, DEFAULT_Q_STEPS, errors); } @@ -762,20 +787,20 @@ * Interpolate W and Q values at a given km. */ public double [][] interpolateWQ( - double km, - int steps, - Calculation errors - ) { - int rowIndex = Collections.binarySearch(rows, new Row(km)); + final double km, + final int steps, + final Calculation errors + ) { + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex >= 0) { // direct row match - Row row = rows.get(rowIndex); + final Row row = this.rows.get(rowIndex); return row.interpolateWQ(steps, this, errors); } rowIndex = -rowIndex -1; - if (rowIndex < 1 || rowIndex >= rows.size()) { + if (rowIndex < 1 || rowIndex >= this.rows.size()) { // do not extrapolate if (errors != null) { errors.addProblem(km, "km.not.found"); @@ -783,19 +808,19 @@ return new double[2][0]; } - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); return r1.interpolateWQ(r2, km, steps, this, errors); } public boolean interpolate( - double km, - double [] out, - QPosition qPosition, - Function qFunction - ) { - int R1 = rows.size()-1; + final double km, + final double [] out, + final QPosition qPosition, + final Function qFunction + ) { + final int R1 = this.rows.size()-1; out[1] = qFunction.value(getQ(qPosition, km)); @@ -803,16 +828,16 @@ return false; } - QPosition nPosition = new QPosition(); + final QPosition nPosition = new QPosition(); if (getQPosition(km, out[1], nPosition) == null) { return false; } - int rowIndex = Collections.binarySearch(rows, new Row(km)); + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex >= 0) { // direct row match - out[0] = rows.get(rowIndex).getW(nPosition); + out[0] = this.rows.get(rowIndex).getW(nPosition); return !Double.isNaN(out[0]); } @@ -823,8 +848,8 @@ return false; } - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); out[0] = r1.getW(r2, km, nPosition); return !Double.isNaN(out[0]); @@ -842,15 +867,15 @@ * @param errors calculation object to store errors. */ public QPosition interpolate( - double q, - double referenceKm, - double [] kms, - double [] ws, - double [] qs, - Calculation errors - ) { + final double q, + final double referenceKm, + final double [] kms, + final double [] ws, + final double [] qs, + final Calculation errors + ) { return interpolate( - q, referenceKm, kms, ws, qs, 0, kms.length, errors); + q, referenceKm, kms, ws, qs, 0, kms.length, errors); } /** @@ -860,16 +885,16 @@ * @param qs [out] looked up qs for kms. */ public QPosition interpolate( - double q, - double referenceKm, - double [] kms, - double [] ws, - double [] qs, - int startIndex, - int length, - Calculation errors - ) { - QPosition qPosition = getQPosition(referenceKm, q); + final double q, + final double referenceKm, + final double [] kms, + final double [] ws, + final double [] qs, + final int startIndex, + final int length, + final Calculation errors + ) { + final QPosition qPosition = getQPosition(referenceKm, q); if (qPosition == null) { // we cannot locate q at km @@ -881,9 +906,9 @@ return null; } - Row kmKey = new Row(); + final Row kmKey = new Row(); - int R1 = rows.size()-1; + final int R1 = this.rows.size()-1; for (int i = startIndex, end = startIndex+length; i < end; ++i) { @@ -896,12 +921,12 @@ } kmKey.km = kms[i]; - int rowIndex = Collections.binarySearch(rows, kmKey); + int rowIndex = Collections.binarySearch(this.rows, kmKey); if (rowIndex >= 0) { // direct row match - if (Double.isNaN(ws[i] = rows.get(rowIndex).getW(qPosition)) - && errors != null) { + if (Double.isNaN(ws[i] = this.rows.get(rowIndex).getW(qPosition)) + && errors != null) { errors.addProblem(kms[i], "cannot.find.w.for.q", q); } continue; @@ -917,11 +942,11 @@ ws[i] = Double.NaN; continue; } - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); if (Double.isNaN(ws[i] = r1.getW(r2, kms[i], qPosition)) - && errors != null) { + && errors != null) { errors.addProblem(kms[i], "cannot.find.w.for.q", q); } } @@ -939,14 +964,14 @@ * * @return Linearly interpolated w, NaN if one of the given rows was null. */ - public static double linearW(double km, Row row1, Row row2, int col) { + public static double linearW(final double km, final Row row1, final Row row2, final int col) { if (row1 == null || row2 == null) { return Double.NaN; } return Linear.linear(km, - row1.km, row2.km, - row1.ws[col], row2.ws[col]); + row1.km, row2.km, + row1.ws[col], row2.ws[col]); } /** @@ -955,27 +980,27 @@ * @param km position (km) at which to interpolate/lookup. * @return [[q0, q1, .. qx] , [w0, w1, .. wx]] (can contain NaNs) */ - public double [][] interpolateWQColumnwise(double km) { + public double [][] interpolateWQColumnwise(final double km) { log.debug("WstValueTable.interpolateWQColumnwise"); - double [] qs = new double[columns.length]; - double [] ws = new double[columns.length]; + final double [] qs = new double[this.columns.length]; + final double [] ws = new double[this.columns.length]; // Find out row from where we will start searching. - int rowIndex = Collections.binarySearch(rows, new Row(km)); + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex < 0) { rowIndex = -rowIndex -1; } // TODO Beyond definition, we could stop more clever. - if (rowIndex >= rows.size()) { - rowIndex = rows.size() -1; + if (rowIndex >= this.rows.size()) { + rowIndex = this.rows.size() -1; } - Row startRow = rows.get(rowIndex); + final Row startRow = this.rows.get(rowIndex); - for (int col = 0; col < columns.length; col++) { - qs[col] = columns[col].getQRangeTree().findQ(km); + for (int col = 0; col < this.columns.length; col++) { + qs[col] = this.columns[col].getQRangeTree().findQ(km); if (startRow.km == km && !Double.isNaN(startRow.ws[col])) { // Great. W is defined at km. ws[col] = startRow.ws[col]; @@ -986,18 +1011,18 @@ Row rowBefore = null; Row rowAfter = null; for (int before = rowIndex -1; before >= 0; before--) { - if (!Double.isNaN(rows.get(before).ws[col])) { - rowBefore = rows.get(before); + if (!Double.isNaN(this.rows.get(before).ws[col])) { + rowBefore = this.rows.get(before); break; } } if (rowBefore != null) { - for (int after = rowIndex, R = rows.size(); - after < R; - after++ - ) { - if (!Double.isNaN(rows.get(after).ws[col])) { - rowAfter = rows.get(after); + for (int after = rowIndex, R = this.rows.size(); + after < R; + after++ + ) { + if (!Double.isNaN(this.rows.get(after).ws[col])) { + rowAfter = this.rows.get(after); break; } } @@ -1009,34 +1034,34 @@ return new double [][] {qs, ws}; } - public double [] findQsForW(double km, double w, Calculation errors) { + public double [] findQsForW(final double km, final double w, final Calculation errors) { - int rowIndex = Collections.binarySearch(rows, new Row(km)); + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex >= 0) { - return rows.get(rowIndex).findQsForW(w, this, errors); + return this.rows.get(rowIndex).findQsForW(w, this, errors); } rowIndex = -rowIndex - 1; - if (rowIndex < 1 || rowIndex >= rows.size()) { + if (rowIndex < 1 || rowIndex >= this.rows.size()) { // Do not extrapolate. return new double[0]; } // Needs bilinear interpolation. - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); return r1.findQsForW(r2, w, km, this, errors); } - protected SplineFunction createSpline(double km, Calculation errors) { + protected SplineFunction createSpline(final double km, final Calculation errors) { - int rowIndex = Collections.binarySearch(rows, new Row(km)); + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex >= 0) { - SplineFunction sf = rows.get(rowIndex).createSpline(this, errors); + final SplineFunction sf = this.rows.get(rowIndex).createSpline(this, errors); if (sf == null && errors != null) { errors.addProblem(km, "cannot.create.wq.relation"); } @@ -1045,7 +1070,7 @@ rowIndex = -rowIndex - 1; - if (rowIndex < 1 || rowIndex >= rows.size()) { + if (rowIndex < 1 || rowIndex >= this.rows.size()) { // Do not extrapolate. if (errors != null) { errors.addProblem(km, "km.not.found"); @@ -1054,10 +1079,10 @@ } // Needs bilinear interpolation. - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); - SplineFunction sf = r1.createSpline(r2, km, this, errors); + final SplineFunction sf = r1.createSpline(r2, km, this, errors); if (sf == null && errors != null) { errors.addProblem(km, "cannot.create.wq.relation"); } @@ -1067,10 +1092,10 @@ /** 'Bezugslinienverfahren' */ public double [][] relateWs( - double km1, - double km2, - Calculation errors - ) { + final double km1, + final double km2, + final Calculation errors + ) { return relateWs(km1, km2, RELATE_WS_SAMPLES, errors); } @@ -1079,14 +1104,14 @@ boolean hasErrors; Calculation errors; - ErrorHandler(Calculation errors) { + ErrorHandler(final Calculation errors) { this.errors = errors; } - void error(double km, String key, Object ... args) { - if (errors != null && !hasErrors) { - hasErrors = true; - errors.addProblem(km, key, args); + void error(final double km, final String key, final Object ... args) { + if (this.errors != null && !this.hasErrors) { + this.hasErrors = true; + this.errors.addProblem(km, key, args); } } } // class ErrorHandler @@ -1097,22 +1122,22 @@ * the start km is always the same. */ public double [][] relateWs( - double km1, - double km2, - int numSamples, - Calculation errors - ) { - SplineFunction sf1 = createSpline(km1, errors); + final double km1, + final double km2, + final int numSamples, + final Calculation errors + ) { + final SplineFunction sf1 = createSpline(km1, errors); if (sf1 == null) { return new double[2][0]; } - SplineFunction sf2 = createSpline(km2, errors); + final SplineFunction sf2 = createSpline(km2, errors); if (sf2 == null) { return new double[2][0]; } - PolynomialSplineFunction iQ1 = sf1.createIndexQRelation(); + final PolynomialSplineFunction iQ1 = sf1.createIndexQRelation(); if (iQ1 == null) { if (errors != null) { errors.addProblem(km1, "cannot.create.index.q.relation"); @@ -1120,7 +1145,7 @@ return new double[2][0]; } - PolynomialSplineFunction iQ2 = sf2.createIndexQRelation(); + final PolynomialSplineFunction iQ2 = sf2.createIndexQRelation(); if (iQ2 == null) { if (errors != null) { errors.addProblem(km2, "cannot.create.index.q.relation"); @@ -1128,18 +1153,18 @@ return new double[2][0]; } - int N = Math.min(sf1.splineQs.length, sf2.splineQs.length); - double stepWidth = N/(double)numSamples; - - PolynomialSplineFunction qW1 = sf1.spline; - PolynomialSplineFunction qW2 = sf2.spline; + final int N = Math.min(sf1.splineQs.length, sf2.splineQs.length); + final double stepWidth = N/(double)numSamples; - TDoubleArrayList ws1 = new TDoubleArrayList(numSamples); - TDoubleArrayList ws2 = new TDoubleArrayList(numSamples); - TDoubleArrayList qs1 = new TDoubleArrayList(numSamples); - TDoubleArrayList qs2 = new TDoubleArrayList(numSamples); + final PolynomialSplineFunction qW1 = sf1.spline; + final PolynomialSplineFunction qW2 = sf2.spline; - ErrorHandler err = new ErrorHandler(errors); + final TDoubleArrayList ws1 = new TDoubleArrayList(numSamples); + final TDoubleArrayList ws2 = new TDoubleArrayList(numSamples); + final TDoubleArrayList qs1 = new TDoubleArrayList(numSamples); + final TDoubleArrayList qs2 = new TDoubleArrayList(numSamples); + + final ErrorHandler err = new ErrorHandler(errors); int i = 0; for (double p = 0d; p <= N-1; p += stepWidth, ++i) { @@ -1148,7 +1173,7 @@ try { q1 = iQ1.value(p); } - catch (ArgumentOutsideDomainException aode) { + catch (final ArgumentOutsideDomainException aode) { err.error(km1, "w.w.qkm1.failed", p); continue; } @@ -1157,7 +1182,7 @@ try { w1 = qW1.value(q1); } - catch (ArgumentOutsideDomainException aode) { + catch (final ArgumentOutsideDomainException aode) { err.error(km1, "w.w.wkm1.failed", q1, p); continue; } @@ -1166,7 +1191,7 @@ try { q2 = iQ2.value(p); } - catch (ArgumentOutsideDomainException aode) { + catch (final ArgumentOutsideDomainException aode) { err.error(km2, "w.w.qkm2.failed", p); continue; } @@ -1175,7 +1200,7 @@ try { w2 = qW2.value(q2); } - catch (ArgumentOutsideDomainException aode) { + catch (final ArgumentOutsideDomainException aode) { err.error(km2, "w.w.wkm2.failed", q2, p); continue; } @@ -1193,24 +1218,24 @@ qs2.toNativeArray() }; } - public QPosition getQPosition(double km, double q) { + public QPosition getQPosition(final double km, final double q) { return getQPosition(km, q, new QPosition()); } - public QPosition getQPosition(double km, double q, QPosition qPosition) { + public QPosition getQPosition(final double km, final double q, final QPosition qPosition) { - if (columns.length == 0) { + if (this.columns.length == 0) { return null; } - double qLast = columns[0].getQRangeTree().findQ(km); + double qLast = this.columns[0].getQRangeTree().findQ(km); if (Math.abs(qLast - q) < 0.00001) { return qPosition.set(0, 1d); } - for (int i = 1; i < columns.length; ++i) { - double qCurrent = columns[i].getQRangeTree().findQ(km); + for (int i = 1; i < this.columns.length; ++i) { + final double qCurrent = this.columns[i].getQRangeTree().findQ(km); if (Math.abs(qCurrent - q) < 0.00001) { return qPosition.set(i, 1d); } @@ -1220,7 +1245,7 @@ else { qMin = qCurrent; qMax = qLast; } if (q > qMin && q < qMax) { - double weight = Linear.factor(q, qLast, qCurrent); + final double weight = Linear.factor(q, qLast, qCurrent); return qPosition.set(i, weight); } qLast = qCurrent; @@ -1229,53 +1254,53 @@ return null; } - public double getQIndex(int index, double km) { - return columns[index].getQRangeTree().findQ(km); + public double getQIndex(final int index, final double km) { + return this.columns[index].getQRangeTree().findQ(km); } - public double getQ(QPosition qPosition, double km) { - int index = qPosition.index; - double weight = qPosition.weight; + public double getQ(final QPosition qPosition, final double km) { + final int index = qPosition.index; + final double weight = qPosition.weight; if (weight == 1d) { - return columns[index].getQRangeTree().findQ(km); + return this.columns[index].getQRangeTree().findQ(km); } - double q1 = columns[index-1].getQRangeTree().findQ(km); - double q2 = columns[index ].getQRangeTree().findQ(km); + final double q1 = this.columns[index-1].getQRangeTree().findQ(km); + final double q2 = this.columns[index ].getQRangeTree().findQ(km); return Linear.weight(weight, q1, q2); } - public double [][] interpolateTabulated(double km) { - return interpolateTabulated(km, new double[2][columns.length]); + public double [][] interpolateTabulated(final double km) { + return interpolateTabulated(km, new double[2][this.columns.length]); } - public double [][] interpolateTabulated(double km, double [][] result) { + public double [][] interpolateTabulated(final double km, final double [][] result) { - int rowIndex = Collections.binarySearch(rows, new Row(km)); + int rowIndex = Collections.binarySearch(this.rows, new Row(km)); if (rowIndex >= 0) { // Direct hit -> copy ws. - Row row = rows.get(rowIndex); + final Row row = this.rows.get(rowIndex); System.arraycopy( - row.ws, 0, result[0], 0, - Math.min(row.ws.length, result[0].length)); + row.ws, 0, result[0], 0, + Math.min(row.ws.length, result[0].length)); } else { rowIndex = -rowIndex -1; - if (rowIndex < 1 || rowIndex >= rows.size()) { + if (rowIndex < 1 || rowIndex >= this.rows.size()) { // Out of bounds. return null; } // Interpolate ws. - Row r1 = rows.get(rowIndex-1); - Row r2 = rows.get(rowIndex); - double factor = Linear.factor(km, r1.km, r2.km); + final Row r1 = this.rows.get(rowIndex-1); + final Row r2 = this.rows.get(rowIndex); + final double factor = Linear.factor(km, r1.km, r2.km); Linear.weight(factor, r1.ws, r2.ws, result[0]); } - double [] qs = result[1]; - for (int i = Math.min(qs.length, columns.length)-1; i >= 0; --i) { - qs[i] = columns[i].getQRangeTree().findQ(km); + final double [] qs = result[1]; + for (int i = Math.min(qs.length, this.columns.length)-1; i >= 0; --i) { + qs[i] = this.columns[i].getQRangeTree().findQ(km); } return result; } @@ -1283,7 +1308,7 @@ /** True if no QRange is given or Q equals zero. */ public boolean hasEmptyQ() { - for (Column column: columns) { + for (final Column column: this.columns) { if (column.getQRangeTree() == null) { return true; } @@ -1294,7 +1319,7 @@ } } - if (columns.length == 0) { + if (this.columns.length == 0) { log.warn("No columns in WstValueTable."); } @@ -1303,10 +1328,10 @@ /** Find ranges that are between km1 and km2 (inclusive?) */ - public List findSegments(double km1, double km2) { - return columns.length != 0 - ? columns[columns.length-1].getQRangeTree().findSegments(km1, km2) - : Collections.emptyList(); + public List findSegments(final double km1, final double km2) { + return this.columns.length != 0 + ? this.columns[this.columns.length-1].getQRangeTree().findSegments(km1, km2) + : Collections.emptyList(); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 9b16f58c62a7 -r bcbae86ce7b3 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java Mon Jul 23 19:18:11 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java Mon Jul 23 19:20:06 2018 +0200 @@ -66,8 +66,8 @@ /** * Calculate the infrastructures flood duration result rows */ - public void execute(final Calculation problems, final String label, final DoubleRange calcRange, - final RiversideChoiceKey riverside, final WINFOArtifact winfo, final FloodDurationCalculationResults results) { + public void execute(final Calculation problems, final String label, final DoubleRange calcRange, final RiversideChoiceKey riverside, + final WINFOArtifact winfo, final FloodDurationCalculationResults results) { // Find all gauges of the calc range, and create the duration finders final Map durFinders = new HashMap<>(); @@ -91,20 +91,23 @@ addInfrastructures(allStations, secondBank, infras); final double[] stationsSorted = sortStations(allStations.keySet()); - // Calculate W and Q for all stations and the selected discharge states - // TODO Geht das schneller, wenn man WstValueTable statt WINFOArtifact.computeWaterlevelData nutzt? - final WQKms[] wqkmsArray = calculateWaterlevels(winfo, stationsSorted, problems); + // Calculate W and Q for all stations and the selected discharge states/waterlevels + final WQKms[] wqkmsArray = calculateWsts(winfo, stationsSorted, problems); - // Determine discharge state labels of the main values - updateMainValueLabels(wqkmsArray, winfo, problems); + // Determine discharge state labels of the waterlevels + updateWstLabels(wqkmsArray, winfo, problems); - // Load base wst table (river).wst - first run takes long time, then it's cached + final Map> gaugeWstDurations = new HashMap<>(); + calcGaugeWstDurations(winfo, new ArrayList<>(durFinders.keySet()), gaugeWstDurations, durFinders); + + // Load base wst table (river).wst + // (should be in cache since already used in calculateWaterlevels (winfo.computeWaterlevelData) final WstValueTable wst = WstValueTableFactory.getTable(this.riverInfoProvider.getRiver()); - // Calculate the durations and create the result rows + // Create the result rows, and calculate and add the flood durations etc. for (int i = 0; i <= stationsSorted.length - 1; i++) { final Gauge gauge = this.riverInfoProvider.getGauge(stationsSorted[i], true); - final ResultRow row = createRow(stationsSorted[i], gauge, firstGauge, wqkmsArray, durFinders.get(gauge), i); + final ResultRow row = createRow(stationsSorted[i], gauge, firstGauge, wqkmsArray, gaugeWstDurations.get(gauge), i); if (allStations.containsKey(stationsSorted[i]) && (allStations.get(stationsSorted[i]) != null)) calculateInfrastructure(row, gauge, allStations.get(stationsSorted[i]), wst, durFinders); this.rows.add(row); @@ -115,50 +118,39 @@ } } - //// Create a finder for Q in the {river}.wst km-w-q table - // final WQBaseTableFinder wqFinder = WQBaseTableFinder.loadValues(this.riverInfoProvider.getRiver(), - //// calcRange.getMinimumDouble(), - // calcRange.getMaximumDouble(), problems); - // - //// Calculate the durations and create the result rows - // for (int i = 0; i <= stationsSorted.length - 1; i++) { - // final Gauge gauge = this.riverInfoProvider.getGauge(stationsSorted[i], true); - // final ResultRow row = createRow(stationsSorted[i], gauge, firstGauge, wqkmsArray, durFinders.get(gauge), i); - // if (allStations.containsKey(stationsSorted[i]) && (allStations.get(stationsSorted[i]) != null)) - // calculateInfrastructure(row, gauge, allStations.get(stationsSorted[i]), wqFinder, durFinders); - // this.rows.add(row); - // if (secondBank.containsKey(stationsSorted[i])) { - // final ResultRow row2 = ResultRow.create(row); - // calculateInfrastructure(row2, gauge, secondBank.get(stationsSorted[i]), wqFinder, durFinders); - // this.rows.add(row2); - // } - // } + // Get the labels of the selected waterlevels + final String[] wstLabels = new String[wqkmsArray.length]; + for (int i = 0; i <= wqkmsArray.length - 1; i++) + wstLabels[i] = wqkmsArray[i].getName(); - final String[] mainValueLabels = new String[wqkmsArray.length]; - for (int i = 0; i <= wqkmsArray.length - 1; i++) - mainValueLabels[i] = wqkmsArray[i].getName(); - results.addResult(new FloodDurationCalculationResult(label, mainValueLabels, this.rows), problems); + results.addResult(new FloodDurationCalculationResult(label, wstLabels, this.rows), problems); } /** * Calculates the duration curve for a station + * (other than the version 3.2.1 W-Info Dauerlinie the wst column positions + * are taken from the Q values of the gauge's Q-D-table) */ public WQDay calcWQDays(final Calculation problems, final double station, final WINFOArtifact winfo) { - // Same processing as in W-Info DurationCurveState - winfo.addStringData("ld_locations", Double.toString(station)); - final CalculationResult res = winfo.getDurationCurveData(); - final WQDay underflow = (WQDay) res.getData(); - // Transform underflow days into overflow days and re-sort - final int[] days = new int[underflow.getWs().length]; - final double[] ws = new double[days.length]; - final double[] qs = new double[days.length]; - for (int i = 0, j = days.length - 1; i <= days.length - 1; i++, j--) { - days[j] = 365 - underflow.getDay(i); - ws[j] = underflow.getW(i); - qs[j] = underflow.getQ(i); + final WstValueTable wst = WstValueTableFactory.getTable(this.riverInfoProvider.getRiver()); + final Gauge gauge = this.riverInfoProvider.getRiver().determineGaugeByPosition(station); + final Object[] obj = gauge.fetchDurationCurveData(); + final int[] udays = (int[]) obj[0]; + final double[] qs = (double[]) obj[1]; + final int[] odays = new int[udays.length]; + final double[] oqs = new double[udays.length]; + final double[] ows = new double[udays.length]; + for (int i = 0, j = udays.length - 1; i <= udays.length - 1; i++, j--) { + odays[j] = 365 - udays[i]; + oqs[j] = qs[i]; + final QPosition qpos = wst.getQPosition(gauge.getStation().doubleValue(), qs[i]); + if (qpos != null) + ows[j] = wst.interpolateW(station, qpos, problems); + else + ows[j] = Double.NaN; } - return new WQDay(days, ws, qs); + return new WQDay(odays, ows, oqs); } /** @@ -341,9 +333,8 @@ /** * Calculates an array of w-q-longitudinal sections for all artifact W/Q options */ - private WQKms[] calculateWaterlevels(final WINFOArtifact winfo, final double[] stations, final Calculation problems) { - // REMARK aus TkhCalculation - move to WinfoArtifactWrapper? - // TODO das ist ziemlich langsam - durch den WQBaseTableFinder ersetzen? (vorher W-Optionen in Q umrechnen) + private WQKms[] calculateWsts(final WINFOArtifact winfo, final double[] stations, final Calculation problems) { + // First run may take long, further runs are faster since WstValueTable is in cache then // (So funktioniert computeWaterlevelData wohl: // Es sucht die Spalte(n) zum Bezugspegel-Q in der W-Q-Tabelle ({river}.wst in Wst etc.), // interpoliert die horizontale Tabellenposition (Q) und dann die vertikale Tabellenposition der station; @@ -352,36 +343,35 @@ // interpoliert; // bei Vorgabe eines W auf freier Strecke wird wohl vorher noch die .wst-Interpolation eingesetzt, um das Q zu bekommen. - final CalculationResult waterlevelData = winfo.computeWaterlevelData(stations); + final CalculationResult wstsData = winfo.computeWaterlevelData(stations); /* copy all problems */ - final Calculation winfoProblems = waterlevelData.getReport(); + final Calculation winfoProblems = wstsData.getReport(); final List problems2 = winfoProblems.getProblems(); if (problems2 != null) { for (final Problem problem : problems2) { problems.addProblem(problem); } } - return (WQKms[]) waterlevelData.getData(); + return (WQKms[]) wstsData.getData(); } /** * Determines the waterlevel/discharge state labels for the selected Q or W values and sets them in the WQKms array */ - private void updateMainValueLabels(final WQKms[] wqkmsArray, final WINFOArtifact winfo, final Calculation problems) { + private void updateWstLabels(final WQKms[] wqkmsArray, final WINFOArtifact winfo, final Calculation problems) { for (int i = 0; i <= wqkmsArray.length - 1; i++) wqkmsArray[i].setName(buildWQDescription(wqkmsArray[i], winfo)); } /** - * - * @param wqkms - * @param descBuilder - * @return + * Builds the description label of a waterlevel */ private String buildWQDescription(final WQKms wqkms, final WINFOArtifact winfo) { + final WaterlevelDescriptionBuilder descBuilder = new WaterlevelDescriptionBuilder(winfo, this.context); + // TODO Zwischen numerischem Q-Wert und Dauerzahl-Hauptwert (0..364) unterscheiden final String description = descBuilder.getDesc(wqkms); if (!description.isEmpty() && Character.isDigit(description.charAt(0))) { if (winfo.isQ()) @@ -394,10 +384,32 @@ } /** + * Calculates the flood durations of the Qs of the waterlevels/discharge states for a map of gauges + */ + private void calcGaugeWstDurations(final WINFOArtifact winfo, final List gauges, final Map> gaugeWstDurations, + final Map durFinders) { + + final double[] gaugeKms = new double[gauges.size()]; + for (int i = 0; i <= gauges.size() - 1; i++) { + gaugeKms[i] = gauges.get(i).getStation().doubleValue(); + gaugeWstDurations.put(gauges.get(i), new ArrayList()); + } + final CalculationResult wstsData = winfo.computeWaterlevelData(gaugeKms); + final WQKms[] wsts = (WQKms[]) wstsData.getData(); + for (int i = 0; i <= gauges.size() - 1; i++) { + final GaugeDurationValuesFinder durFinder = durFinders.get(gauges.get(i)); + for (int j = 0; j <= wsts.length - 1; j++) { + final double d = durFinder.getDuration(wsts[j].getQ(i)); + gaugeWstDurations.get(gauges.get(i)).add(Double.valueOf(underflowDaysToOverflowDays(d))); + } + } + } + + /** * Create a result row for a station and its gauge, and add w-q-values as selected */ private ResultRow createRow(final Double station, final Gauge gauge, final Gauge firstGauge, final WQKms[] wqkmsArray, - final GaugeDurationValuesFinder durationFinder, final int kmIndex) { + final List gaugeDurations, final int kmIndex) { final ResultRow row = ResultRow.create(); row.putValue(GeneralResultType.station, station); @@ -410,39 +422,22 @@ final String location = this.riverInfoProvider.getLocation(station); row.putValue(SInfoResultType.location, location); - final List waterlevels = new ArrayList<>(wqkmsArray.length); - - for (final WQKms wqKms : wqkmsArray) { - assert (wqKms.getKm(kmIndex) == station.doubleValue()); + final List wsts = new ArrayList<>(wqkmsArray.length); - final int overflowDays = (int) Math.round(underflowDaysToOverflowDays(durationFinder.getDuration(wqKms.getQ(kmIndex)))); + for (int i = 0; i <= wqkmsArray.length - 1; i++) { + assert (wqkmsArray[i].getKm(kmIndex) == station.doubleValue()); - final DurationWaterlevel dw = new DurationWaterlevel(wqKms.getW(kmIndex), overflowDays, wqKms.getQ(kmIndex), wqKms.getName()); - waterlevels.add(dw); + final int overflowDays = (int) Math.round(gaugeDurations.get(i)); + + final DurationWaterlevel dw = new DurationWaterlevel(wqkmsArray[i].getW(kmIndex), overflowDays, wqkmsArray[i].getQ(kmIndex), + wqkmsArray[i].getName()); + wsts.add(dw); } - row.putValue(SInfoResultType.customMultiRowColWaterlevel, waterlevels); + row.putValue(SInfoResultType.customMultiRowColWaterlevel, wsts); return row; } - /// ** - // * Calculate the result row fields for one infrastructure - gives wrong duration numbers where Q changes within the - /// gauge range - // */ - // private void calculateInfrastructure(final ResultRow row, final Gauge gauge, final InfrastructureValue - /// infrastructure, final WQBaseTableFinder wqFinder, - // final Map durFinders) { - // - // final double q = wqFinder.getDischarge(infrastructure.getStation(), infrastructure.getHeight()); - // final double qOut = Double.isInfinite(q) ? Double.NaN : q; - // final double dur = underflowDaysToOverflowDays(durFinders.get(gauge).getDuration(q)); - // row.putValue(SInfoResultType.riverside, infrastructure.getAttributeKey()); - // row.putValue(SInfoResultType.floodDuration, dur); - // row.putValue(SInfoResultType.floodDischarge, qOut); - // row.putValue(SInfoResultType.infrastructureHeight, infrastructure.getHeight()); - // row.putValue(SInfoResultType.infrastructuretype, infrastructure.getInfrastructure().getType().getName()); - // } - /** * Calculate the result row fields for one infrastructure */ @@ -454,17 +449,16 @@ final double[] qs = wst.findQsForW(infrastructure.getStation().doubleValue(), infrastructure.getHeight().doubleValue(), problems); // TODO Fehlerbehandlung (kein Q gefunden) final double q = (qs.length >= 1) ? qs[0] : Double.NaN; - final double qOut = Double.isInfinite(q) ? Double.NaN : q; - // Determine the relative column position of the Q + // Determine the relative column position of the Q of the infrastructure height final QPosition qPos = wst.getQPosition(infrastructure.getStation().doubleValue(), q); // Get the Q for the found column position for the station of the gauge final double qGauge = wst.getQ(qPos, gauge.getStation().doubleValue()); // Interpolate the Q-D-table of the gauge final double dur = underflowDaysToOverflowDays(durFinders.get(gauge).getDuration(qGauge)); - // Set result row + // Set the result row row.putValue(SInfoResultType.riverside, infrastructure.getAttributeKey()); row.putValue(SInfoResultType.floodDuration, dur); - row.putValue(SInfoResultType.floodDischarge, qOut); + row.putValue(SInfoResultType.floodDischarge, q); row.putValue(SInfoResultType.infrastructureHeight, infrastructure.getHeight()); row.putValue(SInfoResultType.infrastructuretype, infrastructure.getInfrastructure().getType().getName()); }