view flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation6.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 b3aa91e45010
children 7b6c31390427
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;


/**
 * @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;
    }

    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[1], values[0],
            String.valueOf(km), dt.getTimeInterval());
    }

    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()]);
    }

    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()]);
    }

    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