ingo@2215: package de.intevation.flys.artifacts.model;
ingo@2215:
ingo@2228: import java.util.ArrayList;
ingo@4241: import java.util.Arrays;
ingo@2228: import java.util.Date;
ingo@2228: import java.util.List;
ingo@2228:
ingo@2215: import org.apache.log4j.Logger;
ingo@2215:
ingo@2228: import de.intevation.flys.model.DischargeTable;
ingo@2219: import de.intevation.flys.model.Gauge;
ingo@2228: import de.intevation.flys.model.TimeInterval;
ingo@2219:
ingo@2215:
ingo@2215: /**
felix@5339: * Historical Discharge Calculation.
ingo@2215: * @author Ingo Weinzierl
ingo@2215: */
ingo@2215: public class Calculation6 extends Calculation {
ingo@2215:
ingo@2215: private static final Logger logger = Logger.getLogger(Calculation6.class);
ingo@2215:
ingo@4232: private int mode;
ingo@4232: private long[] timerange;
ingo@2219: private double[] values;
ingo@2215:
ingo@2219: public static final int MODE_W = 0;
ingo@2219: public static final int MODE_Q = 1;
ingo@2219:
ingo@4136: public static final double SCALE = 1d;
ingo@2230:
ingo@2228: public Calculation6(int mode, long[] timerange, double[] values) {
ingo@4232: this.mode = mode;
ingo@2219: this.timerange = timerange;
ingo@4232: this.values = values;
ingo@2215: }
ingo@2215:
ingo@2219: public CalculationResult calculate(Gauge gauge) {
ingo@2219: if (!checkParameters() || gauge == null) {
ingo@2219: logger.warn("Parameters not valid for calculation.");
ingo@2219:
ingo@2219: return null;
ingo@2219: }
ingo@2219:
ingo@2219: if (logger.isDebugEnabled()) {
ingo@2219: debug();
ingo@2219: }
ingo@2219:
ingo@4232: DischargeTable refTable = fetchReferenceTable(gauge);
ingo@2228: List dts = fetchDischargeTables(gauge);
ingo@2219:
ingo@2304: int numTables = dts.size();
ingo@2304:
ingo@2304: logger.debug("Take " + numTables + " into account.");
ingo@2304:
ingo@2304: if (numTables == 0) {
ingo@2304: addProblem("cannot.find.hist.q.tables");
ingo@2304: }
ingo@2228:
ingo@4241: WQTimerange[] wqt = prepareTimerangeData(refTable, dts);
ingo@4241: WQKms[] wqs = prepareWQData(dts);
ingo@2228:
ingo@2250: logger.debug("Number of calculation results: " + wqt.length);
ingo@2250:
ingo@4241: return new CalculationResult(new HistoricalDischargeData(wqt, wqs),
ingo@4241: this);
ingo@2215: }
ingo@2219:
ingo@2219: protected boolean checkParameters() {
ingo@2219: if (!(mode == MODE_W || mode == MODE_Q)) {
ingo@2219: logger.warn("Invalid mode '" + mode + "' for calculation.");
ingo@2219: return false;
ingo@2219: }
ingo@2219:
ingo@2219: if (timerange == null || timerange.length < 2) {
ingo@2219: logger.warn("Invalid timerange for calculation.");
ingo@2219: return false;
ingo@2219: }
ingo@2219:
ingo@2219: if (values == null || values.length == 0) {
ingo@2219: logger.warn("No values for W or Q specified.");
ingo@2219: return false;
ingo@2219: }
ingo@2219:
ingo@2219: return true;
ingo@2219: }
ingo@2219:
ingo@2311: protected DischargeTable fetchReferenceTable(Gauge gauge) {
ingo@2311: return gauge.fetchMasterDischargeTable();
ingo@2311: }
ingo@2311:
ingo@2228: protected List fetchDischargeTables(Gauge gauge) {
ingo@2228: List relevant = new ArrayList();
ingo@4232: List all = gauge.getDischargeTables();
ingo@2228:
ingo@4232: for (DischargeTable dt : all) {
ingo@2228: if (isDischargeTableRelevant(dt)) {
ingo@2228: relevant.add(dt);
ingo@2228: }
ingo@2228: }
ingo@2228:
ingo@2228: return relevant;
ingo@2228: }
ingo@2228:
felix@5339: /** True if timerange of given discharge table overlaps with timerange. */
ingo@2228: protected boolean isDischargeTableRelevant(DischargeTable dt) {
ingo@2228: TimeInterval ti = dt.getTimeInterval();
ingo@2228:
ingo@2598: if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE || ti == null) {
ingo@2315: return false;
ingo@2315: }
ingo@2315:
ingo@4232: Date start = ti.getStartTime();
ingo@2228: long startTime = start.getTime();
ingo@2228:
ingo@2228: if (startTime >= timerange[0] && startTime <= timerange[1]) {
ingo@2228: return true;
ingo@2228: }
ingo@2228:
ingo@4232: Date stop = ti.getStopTime();
ingo@2228: long stopTime = stop != null ? stop.getTime() : -1l;
ingo@2228:
ingo@2228: if (stopTime >= timerange[0] && stopTime <= timerange[1]) {
ingo@2228: return true;
ingo@2228: }
ingo@2228:
ingo@2228: logger.debug("DischargeTable not in range: " + start + " -> " + stop);
ingo@2228:
ingo@2228: return false;
ingo@2228: }
ingo@2228:
ingo@4241: protected WQTimerange[] prepareTimerangeData(DischargeTable refTable,
ingo@4232: List dts) {
ingo@2311: if (refTable == null) {
ingo@2311: addProblem("cannot.find.hist.q.reftable");
ingo@2311: return prepareSimpleData(dts);
ingo@2311: }
ingo@2311: else {
ingo@2311: return prepareData(refTable, dts);
ingo@2311: }
ingo@2311: }
ingo@2311:
ingo@4241: protected WQKms[] prepareWQData(List dts) {
ingo@4241: WQKms[] wqs = new WQKms[dts.size()];
ingo@4241:
ingo@4241: int idx = 0;
ingo@4241:
ingo@4241: for (DischargeTable dt : dts) {
ingo@4241: double[][] values = null;
ingo@4241:
ingo@4241: if (dt.getKind() == DischargeTables.MASTER) {
ingo@4241: values = DischargeTables.loadDischargeTableValues(dt,
ingo@4241: DischargeTables.MASTER_SCALE);
ingo@4241:
ingo@4241: }
ingo@4241: else {
ingo@4241: values = DischargeTables.loadDischargeTableValues(dt,
ingo@4241: DischargeTables.HISTORICAL_SCALE);
ingo@4241:
ingo@4241: }
ingo@4241:
ingo@4241: wqs[idx++] = prepareWQ(dt, values);
ingo@4241: }
ingo@4241:
ingo@4241: return wqs;
ingo@4241: }
ingo@4241:
ingo@4241: protected WQKms prepareWQ(DischargeTable dt, double[][] values) {
ingo@4241: double km = dt.getGauge().getStation().doubleValue();
ingo@4241:
ingo@4241: double[] kms = new double[values[0].length];
ingo@4241: Arrays.fill(kms, km);
ingo@4241:
ingo@4281: return new HistoricalWQKms(kms, values[0], values[1],
ingo@4241: String.valueOf(km), dt.getTimeInterval());
ingo@4241: }
ingo@4241:
felix@5339: /** Without reference. */
ingo@2311: protected WQTimerange[] prepareSimpleData(List dts) {
ingo@4232: List wqts = new ArrayList(values.length);
ingo@2228:
ingo@4232: for (double value : values) {
ingo@2228: logger.debug("Prepare data for value: " + value);
ingo@2228:
ingo@4232: String name = mode == MODE_W ? "W=" + value : "Q=" + value;
ingo@4232: WQTimerange wqt = null;
ingo@2228:
ingo@4232: for (DischargeTable dt : dts) {
ingo@4232: Date[] ti = prepareTimeInterval(dt);
ingo@2315: Timerange t = new Timerange(ti[0], ti[1]);
ingo@4232: double w;
ingo@4232: double q;
ingo@2228:
ingo@2228: if (mode == MODE_W) {
ingo@2228: w = value;
ingo@4138: q = findValueForW(dt, w, DischargeTables.HISTORICAL_SCALE);
ingo@2244:
ingo@2244: if (Double.isNaN(q)) {
ingo@2244: logger.warn("Cannot find Q for W: " + w);
ingo@2315: addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
ingo@2244: continue;
ingo@2244: }
ingo@2228: }
ingo@2228: else {
ingo@2228: q = value;
ingo@4232: w = findValueForQ(dt, q, DischargeTables.HISTORICAL_SCALE);
ingo@2228: }
ingo@2228:
ingo@2315: logger.debug("Q=" + q + " | W=" + w);
ingo@2230:
ingo@2244: if (wqt == null) {
ingo@2244: wqt = new WQTimerange(name);
ingo@2244: }
ingo@2244:
ingo@2228: wqt.add(w, q, t);
ingo@2228: }
ingo@2228:
ingo@2244: if (wqt != null) {
ingo@2244: wqts.add(wqt);
ingo@2244: }
ingo@2228: }
ingo@2228:
sascha@3452: return wqts.toArray(new WQTimerange[wqts.size()]);
ingo@2228: }
ingo@2228:
felix@5339: /** With reference. */
ingo@4232: protected HistoricalWQTimerange[] prepareData(DischargeTable refTable,
ingo@4232: List dts) {
ingo@4232: List wqts = new ArrayList(
ingo@4232: values.length);
ingo@2228:
ingo@4232: for (double value : values) {
ingo@2311: logger.debug("Prepare data plus diff for value: " + value);
ingo@2311:
ingo@2311: String name = mode == MODE_W ? "W=" + value : "Q=" + value;
ingo@4232: HistoricalWQTimerange wqt = null;
ingo@2311:
ingo@2311: double ref;
ingo@2315: double diff;
ingo@2311:
ingo@2311: if (refTable != null && mode == MODE_W) {
ingo@4232: ref = findValueForW(refTable, value,
ingo@4232: DischargeTables.MASTER_SCALE);
ingo@2311: }
ingo@2311: else if (refTable != null) {
ingo@4232: ref = findValueForQ(refTable, value,
ingo@4232: DischargeTables.MASTER_SCALE);
ingo@2311: }
ingo@2311: else {
ingo@2311: ref = Double.NaN;
ingo@2311: }
ingo@2311:
ingo@4232: for (DischargeTable dt : dts) {
ingo@2315: Date[] ti = prepareTimeInterval(dt);
ingo@2311:
ingo@4232: Timerange t = new Timerange(ti[0], ti[1]);
ingo@4232: double w;
ingo@4232: double q;
ingo@2311:
ingo@2311: if (mode == MODE_W) {
ingo@4232: w = value;
ingo@4232: q = findValueForW(dt, w, DischargeTables.HISTORICAL_SCALE);
ingo@2311:
ingo@2311: if (Double.isNaN(q)) {
ingo@2311: logger.warn("Cannot find Q for W: " + w);
ingo@2315: addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
ingo@2311: continue;
ingo@2311: }
ingo@2315:
ingo@4232: diff = ref - q;
ingo@2311: }
ingo@2311: else {
ingo@4232: q = value;
ingo@4232: w = findValueForQ(dt, q, DischargeTables.HISTORICAL_SCALE);
ingo@4232:
ingo@4232: if (Double.isNaN(w)) {
ingo@4232: logger.warn("Cannot find W for Q: " + q);
ingo@4232: addProblem("cannot.find.hist.w.for.q", q, ti[0], ti[1]);
ingo@4232: continue;
ingo@4232: }
ingo@4232: diff = ref - w;
ingo@2311: }
ingo@2311:
ingo@2315: logger.debug("Q=" + q + " | W=" + w + " | Ref = " + ref);
ingo@2311:
ingo@2311: if (wqt == null) {
ingo@2311: wqt = new HistoricalWQTimerange(name);
ingo@2311: }
ingo@2311:
ingo@2315: wqt.add(w, q, diff, t);
ingo@2311: }
ingo@2311:
ingo@2311: if (wqt != null) {
ingo@2311: wqts.add(wqt);
ingo@2311: }
ingo@2311: }
ingo@2311:
ingo@4232: return (HistoricalWQTimerange[]) wqts
ingo@4232: .toArray(new HistoricalWQTimerange[wqts.size()]);
ingo@2311: }
ingo@2311:
felix@5339: /** Returns discharge table interval as Date[]. */
ingo@2315: protected Date[] prepareTimeInterval(DischargeTable dt) {
ingo@2315: TimeInterval ti = dt.getTimeInterval();
ingo@2315:
ingo@2315: Date start = ti.getStartTime();
ingo@4232: Date end = ti.getStopTime();
ingo@2315:
ingo@2315: if (end == null) {
ingo@2315: logger.warn("TimeInterval has no stop time set!");
ingo@2315:
ingo@2315: end = new Date();
ingo@2315: }
ingo@2315:
ingo@2315: return new Date[] { start, end };
ingo@2315: }
ingo@2315:
ingo@4138: protected double findValueForW(DischargeTable dt, double w, double scale) {
ingo@4138: double[][] vs = DischargeTables.loadDischargeTableValues(dt, scale);
ingo@4232: double[] qs = DischargeTables.getQsForW(vs, w);
sascha@2418: return qs.length == 0 ? Double.NaN : qs[0];
ingo@2228: }
ingo@2228:
ingo@4232: protected double findValueForQ(DischargeTable dt, double q, double scale) {
ingo@4232: double[][] vs = DischargeTables.loadDischargeTableValues(dt, scale);
ingo@4232: double[] ws = DischargeTables.getWsForQ(vs, q);
ingo@2228:
ingo@4232: return ws.length == 0 ? Double.NaN : ws[0];
ingo@2228: }
ingo@2228:
ingo@2219: /**
ingo@2219: * Writes the parameters used for this calculation to logger.
ingo@2219: */
ingo@2219: public void debug() {
ingo@2219: StringBuilder sb = new StringBuilder();
ingo@4232: for (double value : values) {
ingo@2219: sb.append(String.valueOf(value) + " ");
ingo@2219: }
ingo@2219:
ingo@2219: logger.debug("========== Calculation6 ==========");
ingo@2219: logger.debug(" Mode: " + mode);
ingo@2219: logger.debug(" Timerange: " + timerange[0] + " - " + timerange[1]);
ingo@2219: logger.debug(" Input values: " + sb.toString());
ingo@2219: logger.debug("==================================");
ingo@2219: }
ingo@2215: }
ingo@2215: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :