view flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation6.java @ 5665:3b12c890b0b2

Fix RangeAccess.getLocations for Reference Curves.
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Thu, 11 Apr 2013 17:24:19 +0200
parents 1b73b731f7bd
children
line wrap: on
line source
package de.intevation.flys.artifacts.model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import de.intevation.flys.model.DischargeTable;
import de.intevation.flys.model.Gauge;
import de.intevation.flys.model.TimeInterval;


/**
 * Historical Discharge Calculation.
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class Calculation6 extends Calculation {

    private static final Logger logger = Logger.getLogger(Calculation6.class);

    private int mode;
    private long[] timerange;
    private double[] values;

    public static final int MODE_W = 0;
    public static final int MODE_Q = 1;

    public static final double SCALE = 1d;

    public Calculation6(int mode, long[] timerange, double[] values) {
        this.mode = mode;
        this.timerange = timerange;
        this.values = values;
    }

    public CalculationResult calculate(Gauge gauge) {
        if (!checkParameters() || gauge == null) {
            logger.warn("Parameters not valid for calculation.");

            return null;
        }

        if (logger.isDebugEnabled()) {
            debug();
        }

        DischargeTable refTable = fetchReferenceTable(gauge);
        List<DischargeTable> dts = fetchDischargeTables(gauge);

        int numTables = dts.size();

        logger.debug("Take " + numTables + " into account.");

        if (numTables == 0) {
            addProblem("cannot.find.hist.q.tables");
        }

        WQTimerange[] wqt = prepareTimerangeData(refTable, dts);
        WQKms[] wqs = prepareWQData(dts);

        logger.debug("Number of calculation results: " + wqt.length);

        return new CalculationResult(new HistoricalDischargeData(wqt, wqs),
            this);
    }

    protected boolean checkParameters() {
        if (!(mode == MODE_W || mode == MODE_Q)) {
            logger.warn("Invalid mode '" + mode + "' for calculation.");
            return false;
        }

        if (timerange == null || timerange.length < 2) {
            logger.warn("Invalid timerange for calculation.");
            return false;
        }

        if (values == null || values.length == 0) {
            logger.warn("No values for W or Q specified.");
            return false;
        }

        return true;
    }

    protected DischargeTable fetchReferenceTable(Gauge gauge) {
        return gauge.fetchMasterDischargeTable();
    }

    protected List<DischargeTable> fetchDischargeTables(Gauge gauge) {
        List<DischargeTable> relevant = new ArrayList<DischargeTable>();
        List<DischargeTable> all = gauge.getDischargeTables();

        for (DischargeTable dt : all) {
            if (isDischargeTableRelevant(dt)) {
                relevant.add(dt);
            }
        }

        return relevant;
    }

    /** True if timerange of given discharge table overlaps with timerange. */
    protected boolean isDischargeTableRelevant(DischargeTable dt) {
        TimeInterval ti = dt.getTimeInterval();

        if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE || ti == null) {
            return false;
        }

        Date start = ti.getStartTime();
        long startTime = start.getTime();

        if (startTime >= timerange[0] && startTime <= timerange[1]) {
            return true;
        }

        Date stop = ti.getStopTime();
        long stopTime = stop != null ? stop.getTime() : -1l;

        if (stopTime >= timerange[0] && stopTime <= timerange[1]) {
            return true;
        }

        logger.debug("DischargeTable not in range: " + start + " -> " + stop);

        return false;
    }

    protected WQTimerange[] prepareTimerangeData(DischargeTable refTable,
        List<DischargeTable> dts) {
        if (refTable == null) {
            addProblem("cannot.find.hist.q.reftable");
            return prepareSimpleData(dts);
        }
        else {
            return prepareData(refTable, dts);
        }
    }

    protected WQKms[] prepareWQData(List<DischargeTable> dts) {
        WQKms[] wqs = new WQKms[dts.size()];

        int idx = 0;

        for (DischargeTable dt : dts) {
            double[][] values = null;

            if (dt.getKind() == DischargeTables.MASTER) {
                values = DischargeTables.loadDischargeTableValues(dt,
                    DischargeTables.MASTER_SCALE);

            }
            else {
                values = DischargeTables.loadDischargeTableValues(dt,
                    DischargeTables.HISTORICAL_SCALE);

            }

            wqs[idx++] = prepareWQ(dt, values);
        }

        return wqs;
    }

    protected WQKms prepareWQ(DischargeTable dt, double[][] values) {
        double km = dt.getGauge().getStation().doubleValue();

        double[] kms = new double[values[0].length];
        Arrays.fill(kms, km);

        return new HistoricalWQKms(kms, values[0], values[1],
            String.valueOf(km), dt.getTimeInterval());
    }

    /** Without reference. */
    protected WQTimerange[] prepareSimpleData(List<DischargeTable> dts) {
        List<WQTimerange> wqts = new ArrayList<WQTimerange>(values.length);

        for (double value : values) {
            logger.debug("Prepare data for value: " + value);

            String name = mode == MODE_W ? "W=" + value : "Q=" + value;
            WQTimerange wqt = null;

            for (DischargeTable dt : dts) {
                Date[] ti = prepareTimeInterval(dt);
                Timerange t = new Timerange(ti[0], ti[1]);
                double w;
                double q;

                if (mode == MODE_W) {
                    w = value;
                    q = findValueForW(dt, w, DischargeTables.HISTORICAL_SCALE);

                    if (Double.isNaN(q)) {
                        logger.warn("Cannot find Q for W: " + w);
                        addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
                        continue;
                    }
                }
                else {
                    q = value;
                    w = findValueForQ(dt, q, DischargeTables.HISTORICAL_SCALE);
                }

                logger.debug("Q=" + q + " | W=" + w);

                if (wqt == null) {
                    wqt = new WQTimerange(name);
                }

                wqt.add(w, q, t);
            }

            if (wqt != null) {
                wqts.add(wqt);
            }
        }

        return wqts.toArray(new WQTimerange[wqts.size()]);
    }

    /** With reference. */
    protected HistoricalWQTimerange[] prepareData(DischargeTable refTable,
        List<DischargeTable> dts) {
        List<HistoricalWQTimerange> wqts = new ArrayList<HistoricalWQTimerange>(
            values.length);

        for (double value : values) {
            logger.debug("Prepare data plus diff for value: " + value);

            String name = mode == MODE_W ? "W=" + value : "Q=" + value;
            HistoricalWQTimerange wqt = null;

            double ref;
            double diff;

            if (refTable != null && mode == MODE_W) {
                ref = findValueForW(refTable, value,
                    DischargeTables.MASTER_SCALE);
            }
            else if (refTable != null) {
                ref = findValueForQ(refTable, value,
                    DischargeTables.MASTER_SCALE);
            }
            else {
                ref = Double.NaN;
            }

            for (DischargeTable dt : dts) {
                Date[] ti = prepareTimeInterval(dt);

                Timerange t = new Timerange(ti[0], ti[1]);
                double w;
                double q;

                if (mode == MODE_W) {
                    w = value;
                    q = findValueForW(dt, w, DischargeTables.HISTORICAL_SCALE);

                    if (Double.isNaN(q)) {
                        logger.warn("Cannot find Q for W: " + w);
                        addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
                        continue;
                    }

                    diff = ref - q;
                }
                else {
                    q = value;
                    w = findValueForQ(dt, q, DischargeTables.HISTORICAL_SCALE);

                    if (Double.isNaN(w)) {
                        logger.warn("Cannot find W for Q: " + q);
                        addProblem("cannot.find.hist.w.for.q", q, ti[0], ti[1]);
                        continue;
                    }
                    diff = ref - w;
                }

                logger.debug("Q=" + q + " | W=" + w + " | Ref = " + ref);

                if (wqt == null) {
                    wqt = new HistoricalWQTimerange(name);
                }

                wqt.add(w, q, diff, t);
            }

            if (wqt != null) {
                wqts.add(wqt);
            }
        }

        return (HistoricalWQTimerange[]) wqts
            .toArray(new HistoricalWQTimerange[wqts.size()]);
    }

    /** Returns discharge table interval as Date[]. */
    protected Date[] prepareTimeInterval(DischargeTable dt) {
        TimeInterval ti = dt.getTimeInterval();

        Date start = ti.getStartTime();
        Date end = ti.getStopTime();

        if (end == null) {
            logger.warn("TimeInterval has no stop time set!");

            end = new Date();
        }

        return new Date[] { start, end };
    }

    protected double findValueForW(DischargeTable dt, double w, double scale) {
        double[][] vs = DischargeTables.loadDischargeTableValues(dt, scale);
        double[] qs = DischargeTables.getQsForW(vs, w);
        return qs.length == 0 ? Double.NaN : qs[0];
    }

    protected double findValueForQ(DischargeTable dt, double q, double scale) {
        double[][] vs = DischargeTables.loadDischargeTableValues(dt, scale);
        double[] ws = DischargeTables.getWsForQ(vs, q);

        return ws.length == 0 ? Double.NaN : ws[0];
    }

    /**
     * Writes the parameters used for this calculation to logger.
     */
    public void debug() {
        StringBuilder sb = new StringBuilder();
        for (double value : values) {
            sb.append(String.valueOf(value) + " ");
        }

        logger.debug("========== Calculation6 ==========");
        logger.debug("   Mode:         " + mode);
        logger.debug("   Timerange:    " + timerange[0] + " - " + timerange[1]);
        logger.debug("   Input values: " + sb.toString());
        logger.debug("==================================");
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org