view artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/DischargeValuesFinder.java @ 8946:5d5d482da3e9

Implementing SINFO - FlowDepthMinMax calculation
author gernotbelger
date Tue, 13 Mar 2018 18:49:33 +0100
parents b10f8415798c
children 45f1ad66560e
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 {
            // 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