andre@8587: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde andre@8587: * Software engineering by Intevation GmbH andre@8587: * andre@8587: * This file is Free Software under the GNU AGPL (>=v3) andre@8587: * and comes with ABSOLUTELY NO WARRANTY! Check out the andre@8587: * documentation coming with Dive4Elements River for details. andre@8587: */ andre@8587: andre@8587: package org.dive4elements.river.artifacts.model.minfo; andre@8587: andre@8587: import org.dive4elements.river.utils.DoubleUtil; andre@8587: andre@8587: import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; andre@8587: import org.apache.commons.math.ArgumentOutsideDomainException; andre@8587: andre@8587: import java.util.Arrays; andre@8587: import java.util.Set; andre@8587: import java.util.HashSet; andre@8587: andre@8587: import java.io.Serializable; andre@8587: andre@8587: /** Holder of a specific result from the bed quality calculation. andre@8587: * andre@8587: * Data is always a map of km to value. The type "bedload" andre@8587: * translates to german "Geschiebe" other results are either andre@8587: * specific to the top or the sublayer of the riverbed. andre@8587: * andre@8587: * The name can be the diameter of this result for bed and bedload andre@8587: * data. andre@8587: **/ andre@8587: public class BedQualityResultValue implements Serializable { andre@8587: public static final String[] DIAMETER_NAMES = new String[] { andre@8587: "D90", andre@8587: "D84", andre@8587: "D80", andre@8587: "D75", andre@8587: "D70", andre@8587: "D60", andre@8587: "D50", andre@8587: "D40", andre@8587: "D30", andre@8587: "D25", andre@8587: "D20", andre@8587: "D16", andre@8587: "D10", andre@8587: "DM", andre@8587: "DMIN", andre@8587: "DMAX" andre@8587: }; andre@8587: andre@8587: /* For ease of access */ andre@8587: public static final Set DIAMETER_NAME_SET = new HashSet( andre@8587: Arrays.asList(DIAMETER_NAMES)); andre@8587: andre@8587: private String name; andre@8587: private String type; andre@8587: private double [][] data; andre@8587: private transient PolynomialSplineFunction interpolFunc; andre@8653: private boolean isInterpolatableData; andre@8587: andre@8587: public BedQualityResultValue() { andre@8653: isInterpolatableData = false; andre@8587: } andre@8587: andre@8587: public BedQualityResultValue(String name, double [][] data, String type) { andre@8587: this.name = name; andre@8653: isInterpolatableData = false; andre@8587: setData(data); andre@8587: this.type = type; andre@8587: } andre@8587: andre@8587: public String getName() { andre@8587: return name; andre@8587: } andre@8587: andre@8638: public boolean isEmpty() { andre@8638: return data == null || data.length < 2 || data[0].length == 0; andre@8638: } andre@8638: andre@8653: public boolean isInterpolateable() { andre@8653: return isInterpolatableData; andre@8653: } andre@8653: andre@8587: public void setName(String name) { andre@8587: this.name = name; andre@8587: } andre@8587: andre@8587: public double [][] getData() { andre@8587: return data; andre@8587: } andre@8587: andre@8587: public double getData(double x) { andre@8587: int idx = Arrays.binarySearch(data[0], x); andre@8587: if (idx < 0) { andre@8587: return Double.NaN; andre@8587: } else { andre@8587: return data[1][idx]; andre@8587: } andre@8587: } andre@8587: andre@8587: public double getDataInterpolated(double x) { andre@8587: if (interpolFunc == null) { andre@8587: interpolFunc = DoubleUtil.getLinearInterpolator(data[0], data[1]); andre@8587: } andre@8587: try { andre@8587: return interpolFunc.value(x); andre@8587: } catch (ArgumentOutsideDomainException e) { andre@8587: return getData(x); andre@8587: } andre@8587: } andre@8587: andre@8587: public double [][] getDataInterpolated(double[] x) { andre@8587: double y[] = new double[x.length]; andre@8587: int i = 0; andre@8587: for (double point: x) { andre@8587: y[i++] = getDataInterpolated(point); andre@8587: } andre@8587: return new double[][] {x, y}; andre@8587: } andre@8587: andre@8587: public void setData(double [][] data) { andre@8587: this.data = data; andre@8653: andre@8653: if (!isEmpty() && data[0].length > 1 && data[0].length == data[1].length) { andre@8653: int usable_points = 0; andre@8653: for (double val :data[1]) { andre@8653: if (!Double.isNaN(val)) { andre@8653: usable_points++; andre@8653: } andre@8653: if (usable_points == 2) { andre@8653: isInterpolatableData = true; andre@8653: return; andre@8653: } andre@8653: } andre@8653: } andre@8587: } andre@8587: andre@8587: public void setType(String type) { andre@8587: this.type = type; andre@8587: } andre@8587: andre@8587: public String getType() { andre@8587: return type; andre@8587: } andre@8587: andre@8587: /** Checks wether or not the name matches that of a diameter */ andre@8587: public boolean isDiameterResult() { andre@8587: return DIAMETER_NAME_SET.contains(name.toUpperCase()); andre@8587: } andre@8587: }