Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/artifacts/model/Calculation4.java @ 9479:2b83d3a96703
i18n TODO "benutzerdefiniert" = "custom" fixed
author | gernotbelger |
---|---|
date | Mon, 10 Sep 2018 15:31:55 +0200 |
parents | 5e38e2924c07 |
children | 33ce8eba9806 |
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde * Software engineering by Intevation GmbH * * 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.model; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.access.Calculation4Access; import org.dive4elements.river.artifacts.math.BackJumpCorrector; import org.dive4elements.river.artifacts.math.Function; import org.dive4elements.river.artifacts.math.Identity; import org.dive4elements.river.artifacts.math.Linear; import org.dive4elements.river.artifacts.model.WstValueTable.QPosition; import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.model.River; import org.dive4elements.river.utils.DoubleUtil; public class Calculation4 extends Calculation { private static Logger log = Logger.getLogger(Calculation4.class); public static final double MINIMAL_STEP_WIDTH = 1e-5; protected List<Segment> segments; protected boolean isQ; protected double from; protected double to; protected double step; protected String river; public Calculation4() { } public Calculation4(final Calculation4Access access) { log.debug("Calculation4Access.cnst"); final String river = access.getRiverName(); final List<Segment> segments = access.getSegments(); final double[] range = access.getFromToStep(); final boolean isQ = access.isQ(); if (river == null) { addProblem("no.river.selected"); } if (range == null) { addProblem("no.range.found"); } if (segments == null || segments.isEmpty()) { addProblem("cannot.create.segments"); } if (!hasProblems()) { this.river = river; this.segments = segments; this.from = range[0]; this.to = range[1]; this.step = range[2]; this.isQ = isQ; } } public CalculationResult calculate(final CallMeta meta) { if (hasProblems()) { return new CalculationResult(new WQKms[0], this); } WstValueTable table = null; final River r = RiverFactory.getRiver(this.river); if (r == null) { addProblem("no.river.found"); } else { table = WstValueTableFactory.getTable(r); if (table == null) { addProblem("no.wst.for.river"); } else { Segment.setReferencePointConvertQ(this.segments, r, this.isQ, this); } } return hasProblems() ? new CalculationResult(new WQKms[0], this) : innerCalculate(table, meta); } protected CalculationResult innerCalculate(final WstValueTable table, final CallMeta meta) { final boolean debug = log.isDebugEnabled(); if (debug) { log.debug("calculate from " + this.from + " to " + this.to + " step " + this.step); log.debug("# segments: " + this.segments.size()); for (final Segment segment : this.segments) { log.debug(" " + segment); } } final int numResults = this.segments.get(0).values.length; if (numResults < 1) { log.debug("no values given"); addProblem("no.values.given"); return new CalculationResult(new WQKms[0], this); } final WQKms[] results = new WQKms[numResults]; for (int i = 0; i < results.length; ++i) { results[i] = new WQKms(); } if (Math.abs(this.step) < MINIMAL_STEP_WIDTH) { this.step = MINIMAL_STEP_WIDTH; } if (this.from > this.to) { this.step = -this.step; } final QPosition[] qPositions = new QPosition[numResults]; final Function[] functions = new Function[numResults]; final double[] out = new double[2]; final Segment sentinel = new Segment(Double.MAX_VALUE); Segment s1 = sentinel, s2 = sentinel; for (double pos = this.from; this.from < this.to ? pos <= this.to : pos >= this.to; pos = DoubleUtil.round(pos + this.step)) { if (pos < s1.referencePoint || pos > s2.referencePoint) { if (debug) { log.debug("need to find new interval for " + pos); } // find new interval if (pos <= this.segments.get(0).referencePoint) { // before first segment -> "gleichwertig" if (debug) { log.debug("before first segment -> gleichwertig"); } final Segment first = this.segments.get(0); final double[] values = first.values; final double refPos = first.referencePoint; for (int i = 0; i < qPositions.length; ++i) { qPositions[i] = table.getQPosition(refPos, values[i]); } sentinel.setReferencePoint(-Double.MAX_VALUE); s1 = sentinel; s2 = this.segments.get(0); Arrays.fill(functions, Identity.IDENTITY); } else if (pos >= this.segments.get(this.segments.size() - 1).referencePoint) { // after last segment -> "gleichwertig" if (debug) { log.debug("after last segment -> gleichwertig"); } final Segment last = this.segments.get(this.segments.size() - 1); final double[] values = last.values; final double refPos = last.referencePoint; for (int i = 0; i < qPositions.length; ++i) { qPositions[i] = table.getQPosition(refPos, values[i]); } sentinel.setReferencePoint(Double.MAX_VALUE); s1 = last; s2 = sentinel; Arrays.fill(functions, Identity.IDENTITY); } else { // "ungleichwertig" // find matching interval if (debug) { log.debug("in segments -> ungleichwertig"); } s1 = s2 = null; for (int i = 1, N = this.segments.size(); i < N; ++i) { final Segment si1 = this.segments.get(i - 1); final Segment si = this.segments.get(i); if (debug) { log.debug("check " + pos + " in " + si1.referencePoint + " - " + si.referencePoint); } if (pos >= si1.referencePoint && pos <= si.referencePoint) { s1 = si1; s2 = si; break; } } if (s1 == null) { throw new IllegalStateException("no interval found"); } Segment anchor, free; if (this.from > this.to) { anchor = s1; free = s2; } else { anchor = s2; free = s1; } // build transforms based on "gleichwertiger" phase for (int i = 0; i < qPositions.length; ++i) { final QPosition qi = table.getQPosition(anchor.referencePoint, anchor.values[i]); if ((qPositions[i] = qi) == null) { addProblem(pos, "cannot.find.q", anchor.values[i]); functions[i] = Identity.IDENTITY; } else { final double qA = table.getQ(qi, anchor.referencePoint); final double qF = table.getQ(qi, free.referencePoint); functions[i] = Double.isNaN(qA) || Double.isNaN(qF) ? Identity.IDENTITY : new Linear(qA, qF, anchor.values[i], free.values[i]); if (debug) { log.debug(anchor.referencePoint + ": " + qA + " -> " + functions[i].value(qA) + " / " + free.referencePoint + ": " + qF + " -> " + functions[i].value(qF)); } } } // build transforms } // "ungleichwertiges" interval } // find matching interval for (int i = 0; i < qPositions.length; ++i) { final QPosition qPosition = qPositions[i]; if (qPosition == null) { continue; } if (table.interpolate(pos, out, qPosition, functions[i])) { results[i].add(out[0], out[1], pos); } else { addProblem(pos, "cannot.interpolate.w.q"); } } } final String custom = Resources.format(meta, "common.custom"); // Backjump correction for (int i = 0; i < results.length; ++i) { final BackJumpCorrector bjc = new BackJumpCorrector(); final double[] ws = results[i].getWs(); final double[] kms = results[i].getKms(); if (bjc.doCorrection(kms, ws, this)) { results[i] = new WQCKms(results[i], bjc.getCorrected()); } } // Name the curves. for (int i = 0; i < results.length; ++i) { results[i].setName(createName(i, custom)); } // Generate the "Umhuellende". final ConstantWQKms[] infoldings = generateInfolding(table, results, this.from, this.to, this.step); // TODO: Use qkms in a new result type. final WQKms[] newResults = new WQKms[results.length + infoldings.length]; System.arraycopy(results, 0, newResults, 0, results.length); System.arraycopy(infoldings, 0, newResults, results.length, infoldings.length); return new CalculationResult(newResults, this); } protected ConstantWQKms[] generateInfolding(final WstValueTable wst, final WQKms[] results, final double from, final double to, final double step) { final WstValueTable.Column[] columns = wst.getColumns(); final InfoldingColumns ic = new InfoldingColumns(columns); ic.markInfoldingColumns(results); final List<ConstantWQKms> infoldings = new ArrayList<>(); final boolean[] infoldingColumns = ic.getInfoldingColumns(); double[] kms = null; double[] ws = null; for (int i = 0; i < infoldingColumns.length; ++i) { if (!infoldingColumns[i]) { continue; } if (kms == null) { kms = DoubleUtil.explode(from, to, step); ws = new double[kms.length]; } final QRangeTree.QuickQFinder qf = columns[i].getQRangeTree().new QuickQFinder(); final int numProblemsBefore = numProblems(); final double[] qs = qf.findQs(kms, this); final String name = columns[i].getName(); final ConstantWQKms infolding = new ConstantWQKms(kms, qs, ws, name); if (numProblems() > numProblemsBefore) { infolding.removeNaNs(); } infoldings.add(infolding); } for (int i = 0, I = infoldings.size(); i < I; i++) { final ConstantWQKms infolding = infoldings.get(i); final String name = infolding.getName(); // TODO: i18n if (i == 0) { infolding.setName("untere Umh\u00fcllende " + name); } else if (i == I - 1) { infolding.setName("obere Umh\u00fcllende " + name); } else { infolding.setName("geschnitten " + name); } } return infoldings.toArray(new ConstantWQKms[infoldings.size()]); } // TODO: issue1109/2, merge with FixRealizingCalculation protected String createName(final int index, final String custom) { final StringBuilder sb = new StringBuilder(this.isQ ? "Q" : "W"); sb.append(" ").append(custom).append(" ("); for (int i = 0, N = this.segments.size(); i < N; ++i) { if (i > 0) { sb.append("; "); } final Segment segment = this.segments.get(i); sb.append((segment.backup != null ? segment.backup : segment.values)[index]); } sb.append(')'); return sb.toString(); } }