view artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java @ 8980:b194fa64506a

SINFO - show results themes according to spec, either raw data or floating mean values. Some improvements to error handling and handling of empty results.
author gernotbelger
date Thu, 05 Apr 2018 18:30:34 +0200
parents 45f1ad66560e
children 16df9f7a9815
line wrap: on
line source
/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
 * Software engineering by
 *  Björnsen Beratende Ingenieure GmbH
 *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */
package org.dive4elements.river.artifacts.sinfo.tkhcalculation;

import org.apache.commons.lang.math.DoubleRange;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.dive4elements.river.artifacts.model.QKms;
import org.dive4elements.river.artifacts.model.WKms;
import org.dive4elements.river.artifacts.model.WQKms;
import org.dive4elements.river.utils.DoubleUtil;

import gnu.trove.TDoubleDoubleHashMap;

/**
 * @author Gernot Belger
 */
public final class DischargeValuesFinder {

    private final UnivariateRealFunction qInterpolator;

    private final TDoubleDoubleHashMap exactValues;

    private final QKms qKms;

    /**
     * Create an instance from a {@link WKms} object. If the given {@link WKms} is not a {@link WQKms}, a finder that always
     * returns {@link Double#NaN} is returned.
     */
    public static DischargeValuesFinder fromKms(final WKms wstKms) {
        if (!(wstKms instanceof QKms)) {
            return new DischargeValuesFinder(null);
        }

        final QKms qKms = (QKms) wstKms;

        return new DischargeValuesFinder(qKms);
    }

    public DischargeValuesFinder(final QKms qKms) {
        this.qKms = qKms;

        if (qKms == null) {
            this.qInterpolator = null;
            this.exactValues = null;
        } else {
            this.qInterpolator = DoubleUtil.getLinearInterpolator(qKms.allKms(), qKms.allQs());

            this.exactValues = new TDoubleDoubleHashMap(qKms.size());

            for (int i = 0; i < qKms.size(); i++) {
                final double station = qKms.getKm(i);
                final double discharge = qKms.getQ(i);
                this.exactValues.put(station, discharge);
            }
        }
    }

    /**
     * If this provider may return valid data at all.
     */
    public boolean isValid() {
        return this.qInterpolator != null;
    }

    public DoubleRange getRange() {
        return new DoubleRange(this.qKms.allQs().min(), this.qKms.allQs().max());
    }

    public double getDischarge(final double station) {

        try {
            // FIXME: check: ich dachte wir interpolieren den abfluss nicht linear?

            // IMPORTANT: we first try to retrieve the exact value if it is present, to avoid rounding changes due to interpolation.
            // This is important because in the WaterlevelExporter code, these values are double-compared (with '==' ...) in order
            // to find the corresponding main-value.
            if (this.exactValues != null && this.exactValues.contains(station))
                return this.exactValues.get(station);

            if (this.qInterpolator == null)
                return Double.NaN;

            return this.qInterpolator.value(station);
        }
        catch (final FunctionEvaluationException e) {
            e.printStackTrace();
            return Double.NaN;
        }
    }
}

http://dive4elements.wald.intevation.org