view flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Parameters.java @ 4241:49cb65d5932d

Improved the historical discharge calculation. The calculation now creates new HistoricalWQKms (new subclass of WQKms). Those WQKms are used to create new facets from (new) type 'HistoricalDischargeCurveFacet'. The chart generator is improved to support those facets.
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Wed, 24 Oct 2012 14:34:35 +0200
parents 1df6984628c3
children bcf25d8c183e
line wrap: on
line source
package de.intevation.flys.artifacts.model;

import de.intevation.flys.artifacts.math.Linear;

import gnu.trove.TDoubleArrayList;

import java.io.Serializable;

import org.apache.log4j.Logger;

public class Parameters
implements   Serializable
{
    private static Logger log = Logger.getLogger(Parameters.class);

    public interface Visitor {

        void visit(double [] row);

    } // interface Visitor

    public static final double EPSILON = 1e-4;

    protected String []           columnNames;
    protected TDoubleArrayList [] columns;

    public Parameters() {
    }

    public Parameters(String [] columnNames) {
        if (columnNames == null || columnNames.length < 1) {
            throw new IllegalArgumentException("columnNames too short.");
        }
        this.columnNames = columnNames;
        columns = new TDoubleArrayList[columnNames.length];
        for (int i = 0; i < columns.length; ++i) {
            columns[i] = new TDoubleArrayList();
        }
    }

    public int columnIndex(String name) {
        for (int i = 0; i < columnNames.length; ++i) {
            if (columnNames[i].equals(name)) {
                return i;
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("columnIndex: " + name + " not found in columnNames");
        }
        return -1;
    }

    public int newRow() {

        int N = columns[0].size();

        for (int i = 0; i < columns.length; ++i) {
            columns[i].add(Double.NaN);
        }

        return N;
    }

    public double get(int row, int index) {
        return columns[index].getQuick(row);
    }

    public double get(int i, String columnName) {
        int index = columnIndex(columnName);
        return index >= 0
            ? columns[index].getQuick(i)
            : Double.NaN;
    }

    public void set(int row, int index, double value) {
        columns[index].setQuick(row, value);
    }

    public void set(int i, String columnName, double value) {
        int idx = columnIndex(columnName);
        if (idx >= 0) {
            columns[idx].setQuick(i, value);
        }
    }

    public boolean set(int row, int [] indices, double [] values) {
        boolean invalid = false;
        for (int i = 0; i < indices.length; ++i) {
            double v = values[i];
            if (Double.isNaN(v)) {
                invalid = true;
            }
            else {
                columns[indices[i]].setQuick(row, v);
            }
        }
        return invalid;
    }

    public boolean set(int row, String [] names, double [] values) {
        boolean success = true;
        for (int i = 0; i < names.length; ++i) {
            int idx = columnIndex(names[i]);
            if (idx >= 0) {
                columns[idx].setQuick(row, values[i]);
            }
            else {
                success = false;
            }
        }
        return success;
    }

    public int size() {
        return columns[0].size();
    }

    public int getNumberColumns() {
        return columnNames.length;
    }

    public String [] getColumnNames() {
        return columnNames;
    }

    public void removeNaNs() {
        W.removeNaNs(columns);
    }

    public int [] columnIndices(String [] columns) {
        int [] indices = new int[columns.length];
        for (int i = 0; i < columns.length; ++i) {
            indices[i] = columnIndex(columns[i]);
        }
        return indices;
    }

    public double getValue(int row, String column) {
        int idx = columnIndex(column);
        return idx >= 0
            ? columns[idx].getQuick(row)
            : Double.NaN;
    }

    public double [] get(int row, String [] columns) {
        return get(row, columns, new double[columns.length]);
    }

    public double [] get(int row, String [] columns, double [] values) {
        for (int i = 0; i < columns.length; ++i) {
            int idx = columnIndex(columns[i]);
            values[i] = idx < 0
                ? Double.NaN
                : this.columns[idx].getQuick(row);
        }

        return values;
    }

    public void get(int row, int [] columnIndices, double [] values) {
        for (int i = 0; i < columnIndices.length; ++i) {
            int index = columnIndices[i];
            values[i] = index >= 0 && index < columns.length
                ? columns[index].getQuick(row)
                : Double.NaN;
        }
    }

    public int binarySearch(String columnName, double value) {
        return binarySearch(columnIndex(columnName), value);
    }

    /**
     * Performes a binary search in the column identified by its
     * index.
     * @return Index of found element or negative insertion point (shifted by one)
     */
    public int binarySearch(int columnIndex, double value) {
        TDoubleArrayList column = columns[columnIndex];
        return column.binarySearch(value);
    }

    public int binarySearch(String columnName, double value, double epsilon) {
        return binarySearch(columnIndex(columnName), value, epsilon);
    }

    public int binarySearch(int columnIndex, double value, double epsilon) {
        if (epsilon < 0d) epsilon = -epsilon;
        double vl = value - epsilon;
        double vh = value + epsilon;

        TDoubleArrayList column = columns[columnIndex];
        int lo = 0, hi = column.size()-1;
        while (hi >= lo) {
            int mid = (lo + hi) >> 1;
            double v = column.getQuick(mid);
            if      (v < vl) lo = mid + 1;
            else if (v > vh) hi = mid - 1;
            else             return mid;
        }

        return -(lo + 1);
    }

    public double [] interpolate(int columnIndex, double key) {
        return interpolate(columnIndex, key, new double[columns.length]);
    }

    public double [] interpolate(String columnName, double key) {
        return interpolate(
            columnIndex(columnName), key, new double[columns.length]);
    }

    public double [] interpolate(
        String    columnName,
        double    key,
        double [] values
    ) {
        return interpolate(columnIndex(columnName), key, values);
    }

    public double [] interpolate(
        int       columnIndex,
        double    key,
        double [] values
    ) {
        int row = binarySearch(columnIndex, key, EPSILON);

        if (row >= 0) { // direct hit
            for (int i = 0; i < values.length; ++i) {
                values[i] = columns[i].getQuick(row);
            }
        }
        else {
            row = -row - 1;
            if (row < 1 || row >= size()) {
                return null;
            }
            double v1 = columns[columnIndex].getQuick(row-1);
            double v2 = columns[columnIndex].getQuick(row);
            double factor = Linear.factor(key, v1, v2);
            for (int i = 0; i < values.length; ++i) {
                values[i] = Linear.weight(
                    factor,
                    columns[i].getQuick(row-1),
                    columns[i].getQuick(row));
            }
        }
        return values;
    }


    public double [] interpolate(
        String    keyName,
        double    key,
        String [] columnNames
    ) {
        int keyIndex = columnIndex(keyName);
        return keyIndex < 0
            ? null
            : interpolate(keyIndex, key, columnNames);
    }

    public double [] interpolate(
        int       keyIndex,
        double    key,
        String [] columnNames
    ) {
        int row = binarySearch(keyIndex, key, EPSILON);

        if (row >= 0) { // direct match
            double [] values = new double[columnNames.length];
            for (int i = 0; i < values.length; ++i) {
                int ci = columnIndex(columnNames[i]);
                values[i] = ci < 0
                    ? Double.NaN
                    : columns[ci].getQuick(row);
            }
            return values;
        }

        row = -row - 1;
        if (row < 1 || row >= size()) {
            log.debug("interpolate: row is out of bounds");
            return null;
        }

        double v1 = columns[keyIndex].getQuick(row-1);
        double v2 = columns[keyIndex].getQuick(row);
        double factor = Linear.factor(key, v1, v2);

        double [] values = new double[columnNames.length];

        for (int i = 0; i < values.length; ++i) {
            int ci = columnIndex(columnNames[i]);
            values[i] = ci < 0
                ? Double.NaN
                : Linear.weight(
                    factor,
                    columns[ci].getQuick(row-1),
                    columns[ci].getQuick(row));
        }

        return values;
    }

    public boolean isSorted(String columnName) {
        return isSorted(columnIndex(columnName));
    }

    public boolean isSorted(int columnIndex) {
        TDoubleArrayList column = columns[columnIndex];
        for (int i = 1, N = column.size(); i < N; ++i) {
            if (column.getQuick(i-1) > column.getQuick(i)) {
                return false;
            }
        }
        return true;
    }

    public void visit(Visitor visitor) {
        visit(visitor, new double[columns.length]);
    }

    public void visit(Visitor visitor, double [] data) {
        for (int i = 0, R = size(); i < R; ++i) {
            for (int j = 0; j < data.length; ++j) {
                data[j] = columns[j].getQuick(i);
            }
            visitor.visit(data);
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org