view artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/ChannelFinder.java @ 9432:d194c5b24bf8

Added bundu bzws w calculation and longitudinal sections of wspl and depth
author mschaefer
date Mon, 20 Aug 2018 09:46:02 +0200
parents
children ac41551a8e4d
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.bundu.bezugswst;

import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;

import org.dive4elements.river.artifacts.math.Linear;
import org.dive4elements.river.artifacts.model.Calculation;
import org.dive4elements.river.model.River;
import org.dive4elements.river.model.sinfo.Channel;
import org.dive4elements.river.model.sinfo.ChannelValue;

/**
 * Provides channel depth and height of a river
 *
 * @author Matthias Schäfer
 */
public final class ChannelFinder {

    /***** TYPES *****/

    public enum ChannelValueType {
        depth {
            @Override
            public Double getValue(final ChannelValue channelValue) {
                return channelValue.getDepth();
            }
        },
        width {
            @Override
            public Double getValue(final ChannelValue channelValue) {
                return channelValue.getWidth();
            }
        };

        public abstract Double getValue(final ChannelValue channelValue);
    }

    /***** FIELDS *****/

    // private static Logger log = Logger.getLogger(ChannelFinder.class);

    private static double MAX_DISTANCE_KM = 1;

    private final NavigableMap<Double, ChannelValue> values = new TreeMap<>();

    private Calculation problems;


    /***** CONSTRUCTORS *****/

    private ChannelFinder(final Calculation problems, final Channel channel) {

        this.problems = problems;

        for (final ChannelValue v : channel.getValues()) {
            this.values.put(v.getStation(), v);
        }
    }

    /***** METHODS *****/

    /**
     * Loads the channel values for a river and year
     *
     * @return Whether the load has been successful
     */
    public static ChannelFinder loadValues(final Calculation problems, final River river, final int year) {
        final Channel channel = Channel.getSeries(river, year);
        if (channel != null)
            return new ChannelFinder(problems, channel);

        problems.addProblem("channelfinder.empty");
        return null;
    }


    /***** METHODS *****/

    /**
     * Searches the channel depth of a station
     */
    public double getDepth(final double station) {
        final double value = interpolateChannel(station, ChannelValueType.depth);
        if (Double.isNaN(value))
            reportProblem(station);
        return value;
    }

    /**
     * Searches the channel width of a station
     */
    public double getWidth(final double station) {
        final double value = interpolateChannel(station, ChannelValueType.width);
        if (Double.isNaN(value))
            reportProblem(station);
        return value;
    }

    /**
     * Searches and interpolates a channel value for a km
     */
    private double interpolateChannel(final double km, final ChannelValueType type) {

        if (this.values.containsKey(km)) {
            final Double value = type.getValue(this.values.get(km));
            return (value == null) ? Double.NaN : value.doubleValue();
        }

        final Entry<Double, ChannelValue> floorEntry = this.values.floorEntry(km);
        final Entry<Double, ChannelValue> ceilingEntry = this.values.ceilingEntry(km);

        if ((floorEntry == null) || (ceilingEntry == null))
            return Double.NaN;

        final double floorKm = floorEntry.getKey().doubleValue();
        final double ceilKm = ceilingEntry.getKey().doubleValue();

        /* report once if the interpolation distance exceeds 1000m */
        if ((Math.abs(floorKm - ceilKm) > MAX_DISTANCE_KM) && (this.problems != null)) {
            this.problems.addProblem(km, "linearInterpolator.maxdistance", MAX_DISTANCE_KM * 1000);
            this.problems = null;
            return Double.NaN;
        }

        final Double floorHeight = type.getValue(floorEntry.getValue());
        final Double ceilingHeight = type.getValue(ceilingEntry.getValue());

        if (floorHeight == null || ceilingHeight == null)
            return Double.NaN;

        return Linear.linear(km, floorKm, ceilKm, floorHeight, ceilingHeight);
    }

    private void reportProblem(final double km) {

        if (this.problems == null)
            return;

        this.problems.addProblem(km, "channelfinder.missing");

        // report problem only once
        this.problems = null;
    }
}

http://dive4elements.wald.intevation.org