sascha@3220: package de.intevation.flys.exports.fixings; sascha@3220: sascha@3220: import de.intevation.artifacts.CallMeta; sascha@3220: sascha@3220: import de.intevation.flys.artifacts.math.fitting.Function; sascha@3220: sascha@3220: import de.intevation.flys.artifacts.model.Parameters; sascha@3220: sascha@3220: import de.intevation.flys.artifacts.resources.Resources; sascha@3220: sascha@3220: import de.intevation.flys.exports.ATWriter; sascha@3220: sascha@3220: import java.io.IOException; sascha@3220: import java.io.PrintWriter; sascha@3220: import java.io.Writer; sascha@3220: sascha@3220: import java.util.ArrayDeque; sascha@3220: import java.util.Collection; sascha@3220: import java.util.Locale; sascha@3220: sascha@3220: import org.apache.log4j.Logger; sascha@3220: sascha@3220: public class FixATWriter sascha@3220: { sascha@3220: private static Logger log = Logger.getLogger(FixATWriter.class); sascha@3220: sascha@3220: public static final String I18N_HEADER_KEY = sascha@3220: "fix.export.at.header"; sascha@3220: sascha@3220: public static final String I18N_HEADER_DEFAULT = sascha@3220: "Exported fixings discharge curve for {0} {0}-km: {1}"; sascha@3220: sascha@3220: public static final String [] Q_MAX_COLUMN = new String [] { "max_q" }; sascha@3220: sascha@3220: public static class WQ { sascha@3220: sascha@3220: protected double w; sascha@3220: protected double q; sascha@3220: sascha@3220: public WQ() { sascha@3220: } sascha@3220: sascha@3220: public WQ(double w, double q) { sascha@3220: this.w = w; sascha@3220: this.q = q; sascha@3220: } sascha@3220: } // class WQ sascha@3220: sascha@3220: protected Function function; sascha@3220: protected Parameters parameters; sascha@3220: sascha@3220: public FixATWriter() { sascha@3220: } sascha@3220: sascha@3220: public FixATWriter(Function function, Parameters parameters) { sascha@3220: this.function = function; sascha@3220: this.parameters = parameters; sascha@3220: } sascha@3220: sascha@3220: public void write( sascha@3220: Writer writer, sascha@3220: CallMeta meta, sascha@3220: String river, sascha@3220: double km sascha@3220: ) sascha@3220: throws IOException { sascha@3220: PrintWriter out = new PrintWriter(writer); sascha@3220: printHeader(out, meta, river, km); sascha@3220: sascha@3220: double [] coeffs = parameters.interpolate( sascha@3220: "km", km, function.getParameterNames()); sascha@3220: sascha@3220: double [] qMax = parameters.interpolate( sascha@3220: "km", km, Q_MAX_COLUMN); sascha@3220: sascha@3220: if (coeffs == null || qMax == null) { sascha@3220: log.debug("No data found at km " + km + "."); sascha@3220: return; sascha@3220: } sascha@3220: sascha@3220: de.intevation.flys.artifacts.math.Function funcInst = sascha@3220: function.instantiate(coeffs); sascha@3220: sascha@3220: double wMax = funcInst.value(qMax[0]); sascha@3220: sascha@3220: if (Double.isNaN(wMax) || wMax < 0d) { sascha@3220: log.debug("function '" + function.getName() + sascha@3220: "' eval failed at " + wMax); sascha@3220: return; sascha@3220: } sascha@3220: sascha@3220: Function inverse = function.getInverse(); sascha@3220: sascha@3220: de.intevation.flys.artifacts.math.Function invInst = sascha@3220: inverse.instantiate(coeffs); sascha@3220: sascha@3220: /* TODO: Do some fancy root finding stuff with the sascha@3220: * first derivative of the inverse function to find sascha@3220: * the minimum of function and directly export sascha@3220: * the longest strict monotonous ascending run of sascha@3220: * ws of the inverse in range [0, wMax]. sascha@3220: * sascha@3220: * To simplify the situation we iterate in steps sascha@3220: * of 10cm over the range and export the longest sascha@3220: * run. sascha@3220: */ sascha@3220: sascha@3220: ArrayDeque longest = new ArrayDeque(); sascha@3220: ArrayDeque current = new ArrayDeque(); sascha@3220: sascha@3220: for (double w = 0d; w <= wMax; w += 0.1d) { sascha@3220: double q = invInst.value(w); sascha@3220: sascha@3220: if (Double.isNaN(q)) { sascha@3220: log.debug("Eval of inverse for " + w + " failed."); sascha@3220: continue; sascha@3220: } sascha@3220: sascha@3220: WQ wq = new WQ(w, q); sascha@3220: sascha@3220: if (current.isEmpty() || current.getLast().q < q) { sascha@3220: current.add(wq); sascha@3220: } sascha@3220: else { sascha@3220: if (current.size() >= longest.size()) { sascha@3220: longest = current; sascha@3220: } sascha@3220: current = new ArrayDeque(); sascha@3220: current.add(wq); sascha@3220: } sascha@3220: } sascha@3220: sascha@3220: if (current.size() >= longest.size()) { sascha@3220: longest = current; sascha@3220: } sascha@3220: sascha@3220: printWQs(out, longest); sascha@3220: out.flush(); sascha@3220: } sascha@3220: sascha@3220: protected void printWQs(PrintWriter out, Collection wqs) { sascha@3220: int lastColumn = 10; sascha@3220: for (WQ wq: wqs) { sascha@3220: int column = (int)(wq.w * 10d) % 10; sascha@3220: sascha@3220: if (lastColumn > column) { sascha@3220: for (; lastColumn < 10; ++lastColumn) { sascha@3220: out.print(ATWriter.EMPTY); sascha@3220: } sascha@3220: out.println(); sascha@3220: out.printf(Locale.US, "%8d", (int)Math.round(wq.w*100.0)); sascha@3220: lastColumn = 0; sascha@3220: } sascha@3220: for (;lastColumn < column-1; ++lastColumn) { sascha@3220: out.print(ATWriter.EMPTY); sascha@3220: } sascha@3220: ATWriter.printQ(out, wq.q); sascha@3220: sascha@3220: lastColumn = column; sascha@3220: } sascha@3220: out.println(); sascha@3220: } sascha@3220: sascha@3220: protected void printHeader( sascha@3220: PrintWriter out, sascha@3220: CallMeta meta, sascha@3220: String river, sascha@3220: double km sascha@3220: ) { sascha@3220: out.println(Resources.format( sascha@3220: meta, sascha@3220: I18N_HEADER_KEY, sascha@3220: I18N_HEADER_DEFAULT, sascha@3220: river, km)); sascha@3220: } sascha@3220: } sascha@3220: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :