mschaefer@9176: /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde mschaefer@9176: * Software engineering by mschaefer@9176: * Björnsen Beratende Ingenieure GmbH mschaefer@9176: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt mschaefer@9176: * mschaefer@9176: * This file is Free Software under the GNU AGPL (>=v3) mschaefer@9176: * and comes with ABSOLUTELY NO WARRANTY! Check out the mschaefer@9176: * documentation coming with Dive4Elements River for details. mschaefer@9176: */ mschaefer@9176: package org.dive4elements.river.artifacts.sinfo.common; mschaefer@9176: mschaefer@9176: import org.apache.commons.lang.math.DoubleRange; mschaefer@9176: import org.apache.commons.math.FunctionEvaluationException; mschaefer@9176: import org.apache.commons.math.analysis.UnivariateRealFunction; mschaefer@9176: import org.apache.commons.math.analysis.interpolation.LinearInterpolator; mschaefer@9176: import org.dive4elements.river.artifacts.model.Calculation; mschaefer@9176: import org.dive4elements.river.model.DischargeTable; mschaefer@9176: import org.dive4elements.river.model.DischargeTableValue; mschaefer@9176: import org.dive4elements.river.model.Gauge; mschaefer@9176: mschaefer@9176: import gnu.trove.TDoubleArrayList; mschaefer@9176: mschaefer@9176: /** mschaefer@9176: * Loading and search/interpolation of a gauge's discharge table (.at) mschaefer@9176: * mschaefer@9176: * @author Matthias Schäfer mschaefer@9176: * mschaefer@9176: */ mschaefer@9176: public final class GaugeDischargeValuesFinder { mschaefer@9176: mschaefer@9176: /***** FIELDS *****/ mschaefer@9176: mschaefer@9176: // private static Logger log = Logger.getLogger(GaugeDischargeValuesFinder.class); mschaefer@9176: mschaefer@9176: private final Gauge gauge; mschaefer@9176: mschaefer@9176: private Calculation problems; mschaefer@9176: mschaefer@9176: private final UnivariateRealFunction wInterpolator; mschaefer@9176: mschaefer@9176: private final DoubleRange wRange; mschaefer@9176: mschaefer@9176: mschaefer@9176: /***** CONSTRUCTORS *****/ mschaefer@9176: mschaefer@9176: private GaugeDischargeValuesFinder(final Gauge gauge, final Calculation problems, final DischargeTable dischargeTable) { mschaefer@9176: this.gauge = gauge; mschaefer@9176: this.problems = problems; mschaefer@9176: final TDoubleArrayList ws = new TDoubleArrayList(); mschaefer@9176: final TDoubleArrayList qs = new TDoubleArrayList(); mschaefer@9176: for (final DischargeTableValue v : DischargeTable.getValuesSortedByW(dischargeTable)) { mschaefer@9176: ws.add(v.getW().doubleValue()); mschaefer@9176: qs.add(v.getQ().doubleValue()); mschaefer@9176: } mschaefer@9176: if (ws.size() >= 2) { mschaefer@9176: this.wInterpolator = new LinearInterpolator().interpolate(ws.toNativeArray(), qs.toNativeArray()); mschaefer@9176: this.wRange = new DoubleRange(ws.get(0), ws.get(ws.size() - 1)); mschaefer@9176: } mschaefer@9176: else { mschaefer@9176: this.wInterpolator = null; mschaefer@9176: this.wRange = null; mschaefer@9176: } mschaefer@9176: if ((this.wInterpolator == null) && (this.problems != null)) { mschaefer@9176: this.problems.addProblem("gauge_discharge_table.missing", gauge.getName()); mschaefer@9176: // Report only once mschaefer@9176: this.problems = null; mschaefer@9176: } mschaefer@9176: } mschaefer@9176: mschaefer@9176: mschaefer@9176: /***** METHODS *****/ mschaefer@9176: mschaefer@9176: /** mschaefer@9176: * Loads the the main discharge table of a gauge (GAUGE.at) mschaefer@9176: * mschaefer@9176: * @return The discharge table values finder of the gauge, or null mschaefer@9176: */ mschaefer@9176: public static GaugeDischargeValuesFinder loadValues(final Gauge gauge, final Calculation problems) { mschaefer@9176: final DischargeTable table = DischargeTable.getGaugeMainDischargeTable(gauge); mschaefer@9176: if ((table == null) || (table.getDischargeTableValues().size() == 0)) { mschaefer@9176: problems.addProblem("gauge_discharge_table.missing", gauge.getName()); mschaefer@9176: return null; mschaefer@9176: } mschaefer@9176: else mschaefer@9176: return new GaugeDischargeValuesFinder(gauge, problems, table); mschaefer@9176: } mschaefer@9176: mschaefer@9176: /** mschaefer@9176: * If this provider may return valid data at all. mschaefer@9176: */ mschaefer@9176: public boolean isValid() { mschaefer@9176: return (this.wInterpolator != null); mschaefer@9176: } mschaefer@9176: mschaefer@9176: /** mschaefer@9176: * Discharge for a W mschaefer@9176: * mschaefer@9176: * @param w mschaefer@9176: * W in cm above gauge datum mschaefer@9176: * @return Q, or NegInf for w less than all, or PosInf for w greater then all, or NaN in case of exception mschaefer@9176: */ mschaefer@9176: public double getDischarge(final double w) { mschaefer@9176: try { mschaefer@9176: if (this.wInterpolator == null) mschaefer@9176: return Double.NaN; mschaefer@9176: else if (w < this.wRange.getMinimumDouble()) mschaefer@9176: return Double.NEGATIVE_INFINITY; mschaefer@9176: else if (w > this.wRange.getMaximumDouble()) mschaefer@9176: return Double.POSITIVE_INFINITY; mschaefer@9176: else mschaefer@9176: return this.wInterpolator.value(w); mschaefer@9176: } mschaefer@9176: catch (@SuppressWarnings("unused") final FunctionEvaluationException e) { mschaefer@9176: // ignore exception because this can/will happen regularly mschaefer@9176: return Double.NaN; mschaefer@9176: } mschaefer@9176: } mschaefer@9176: }