changeset 8940:82998242ba84

Preparing for additional outputs of SINFO-Tkh
author gernotbelger
date Tue, 06 Mar 2018 18:51:18 +0100
parents 2970368ae1e3
children a9950a3a71e5
files artifacts/doc/conf/artifacts/sinfo.xml artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/Tkh.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java
diffstat 18 files changed, 553 insertions(+), 222 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/sinfo.xml	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/doc/conf/artifacts/sinfo.xml	Tue Mar 06 18:51:18 2018 +0100
@@ -125,8 +125,10 @@
             <!-- REMARK: id's that ends with 'filtered' are handled differently ' -->
             <!-- FIXME: should be filtered according to spec -->
             <facet name="sinfo_flow_depth.tkh" description="Facet for tkh"/>
+            <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
 
-            <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
+            <facet name="sinfo_flow_depth.filtered" description="Facet for mean flow depth, filtered by current zoom state"/>
+            <!--  FIXME: more themes -->
           </facets>
         </outputmode>
       
--- a/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml	Tue Mar 06 18:51:18 2018 +0100
@@ -45,8 +45,8 @@
     <processor class="org.dive4elements.river.exports.process.BedHeightProcessor"          axis="W"/>
 
     <!-- S-INFO -->
-    <processor class="org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthProcessor" axis="flowdepthAxis"/>
+    <processor class="org.dive4elements.river.artifacts.sinfo.common.FlowDepthProcessor" axis="flowdepthAxis"/>
     <processor class="org.dive4elements.river.artifacts.sinfo.common.TkhProcessor" axis="tkhAxis"/>
-    
+
     <chartextender class="org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthChartExtender" />
 </longitudinal-defaults>
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoCalculationResult.java	Tue Mar 06 18:51:18 2018 +0100
@@ -62,6 +62,32 @@
         return Collections.unmodifiableCollection(this.rows);
     }
 
+    public double[][] getFlowDepthPoints() {
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final ROW row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getFlowDepth());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
+    public double[][] getFlowDepthTkhPoints() {
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final ROW row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getFlowDepthWithTkh());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
     public final double[][] getTkhUpPoints() {
         final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
         final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
@@ -90,6 +116,45 @@
         return adjustTkhVisualization(xPoints, yPoints, kinds);
     }
 
+    public double[][] getVelocityPoints() {
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final ROW row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getVelocity());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
+    public double[][] getD50Points() {
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final ROW row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getD50());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
+    public double[][] getTauPoints() {
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final ROW row : this.rows) {
+            xPoints.add(row.getStation());
+            yPoints.add(row.getTau());
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
     /**
      * the up and down points must be further adjusted for visualization, see Mail Hr. Reiß
      * basically we need to introduce extra points when the kind changes, so we get vertical lines in that case
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java	Tue Mar 06 18:51:18 2018 +0100
@@ -0,0 +1,99 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.sinfo.common;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.D4EArtifact;
+import org.dive4elements.river.artifacts.access.RiverAccess;
+import org.dive4elements.river.artifacts.context.RiverContext;
+import org.dive4elements.river.artifacts.math.MovingAverage;
+import org.dive4elements.river.artifacts.model.ZoomScale;
+import org.dive4elements.river.exports.DiagramGenerator;
+import org.dive4elements.river.exports.StyledSeriesBuilder;
+import org.dive4elements.river.jfree.StyledXYSeries;
+import org.dive4elements.river.themes.ThemeDocument;
+
+abstract class AbstractSInfoLineProcessor extends AbstractSInfoProcessor {
+
+    public AbstractSInfoLineProcessor(final String i18nAxisLabel, final Set<String> handledFacetType) {
+        super(i18nAxisLabel, handledFacetType);
+    }
+
+    @Override
+    protected final String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
+
+        final CallContext context = generator.getCallContext();
+        final Map<String, String> metaData = bundle.getFacet().getMetaData();
+
+        final Artifact artifact = bundle.getArtifact();
+
+        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
+        series.putMetaData(metaData, artifact, context);
+
+        final String facetName = bundle.getFacetName();
+        final AbstractSInfoCalculationResult<?> data = (AbstractSInfoCalculationResult<?>) bundle.getData(context);
+        if (data == null) {
+            // Check has been here before so we keep it for security reasons
+            // this should never happen though.
+            throw new IllegalStateException("Data is null for facet: " + facetName);
+        }
+
+        final double[][] points = generatePoints(context, artifact, data, facetName);
+
+        StyledSeriesBuilder.addPoints(series, points, true);
+        generator.addAxisSeries(series, getAxisName(), visible);
+
+        return metaData.get("Y");
+    }
+
+    private Double findRadius(final CallContext context, final Artifact artifact) {
+        final Double start = (Double) context.getContextValue("startkm");
+        final Double end = (Double) context.getContextValue("endkm");
+
+        if (start == null || end == null)
+            return null;
+
+        final RiverContext fc = (RiverContext) context.globalContext();
+        final ZoomScale scales = (ZoomScale) fc.get("zoomscale");
+        final RiverAccess access = new RiverAccess((D4EArtifact) artifact);
+        final String river = access.getRiverName();
+
+        return scales.getRadius(river, start, end);
+    }
+
+    private double[][] generatePoints(final CallContext context, final Artifact artifact, final AbstractSInfoCalculationResult<?> data,
+            final String facetName) {
+
+        final double[][] points = doGetPoints(data, facetName);
+        if( facetName.endsWith(".filtered"))
+        {
+            final Double radius = findRadius(context, artifact);
+            return movingAverage(radius, points);
+        }
+
+        return points;
+    }
+
+    protected abstract double[][] doGetPoints(AbstractSInfoCalculationResult<?> data, String facetName);
+
+    private double[][] movingAverage(final Double radius, final double[][] points) {
+
+        if (radius == null)
+            return points;
+
+        return MovingAverage.weighted(points, radius);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoResultRow.java	Tue Mar 06 18:51:18 2018 +0100
@@ -77,6 +77,26 @@
         return this.tkh.getMeanBedHeight();
     }
 
+    public final double getFlowDepth() {
+        return this.tkh.getFlowDepth();
+    }
+
+    public double getFlowDepthWithTkh() {
+        return this.tkh.getFlowDepthTkh();
+    }
+
+    public double getVelocity() {
+        return this.tkh.getVelocity();
+    }
+
+    public double getD50() {
+        return this.tkh.getD50();
+    }
+
+    public double getTau() {
+        return this.tkh.getTau();
+    }
+
     public final String getLocation() {
         return this.location;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/D50Processor.java	Tue Mar 06 18:51:18 2018 +0100
@@ -0,0 +1,60 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.sinfo.common;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+public final class D50Processor extends AbstractSInfoLineProcessor {
+
+    // FIXME: translate!
+    private static final String I18N_AXIS_LABEL = "sinfo.chart.d50.section.yaxis.label";
+
+    private static final String SINFO_CHART_D50_YAXIS_LABEL = "sinfo.chart.d50.yaxis.label";
+
+    // FIXME: check: filtered or not?
+    private static final String FACET_TKH_D50_FILTERED = "sinfo_tkh_d50.filtered";
+
+    private static final String I18N_FACET_TKH_D50_FILTERED_DESCRIPTION = "sinfo.facet.tkh_d50.filtered.description";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_TKH_D50_FILTERED);
+    }
+
+    public D50Processor() {
+        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
+    }
+
+    @Override
+    protected double[][] doGetPoints(final AbstractSInfoCalculationResult<?> data, final String facetName) {
+
+        if (FACET_TKH_D50_FILTERED.contentEquals(facetName))
+            return data.getD50Points();
+
+        final String error = String.format("Unknown facet name: %s", facetName);
+        throw new UnsupportedOperationException(error);
+    }
+
+    public static Facet createD50Facet(final CallContext context, final String hash, final String id, final AbstractSInfoCalculationResult<?> result,
+            final int index) {
+        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_D50_FILTERED_DESCRIPTION,
+                I18N_FACET_TKH_D50_FILTERED_DESCRIPTION, result.getLabel());
+        return new SInfoResultFacet(index, D50Processor.FACET_TKH_D50_FILTERED, facetFlowDepthFilteredDescription, SINFO_CHART_D50_YAXIS_LABEL,
+                ComputeType.ADVANCE, id, hash);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthProcessor.java	Tue Mar 06 18:51:18 2018 +0100
@@ -0,0 +1,77 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.sinfo.common;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+public final class FlowDepthProcessor extends AbstractSInfoLineProcessor {
+
+    private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label";
+
+    private static final String SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL = "sinfo.chart.flow_depth.yaxis.label";
+
+    /* Theme name, usually defined in 'FacetTypes', but that is soooo bad dependencies... */
+    // REMARK: these mustend with 'filtered' so extra handling happens in chart: point are always recalculated, because data
+    // changes depending on zoom state
+    public static final String FACET_FLOW_DEPTH_FILTERED = "sinfo_flow_depth.filtered";
+
+    private static final String I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.filtered.description";
+
+    private static final String FACET_FLOW_DEPTH_TKH_FILTERED = "sinfo_flow_depth.tkh.filtered";
+
+    private static final String I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.tkh.filtered.description";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_FLOW_DEPTH_FILTERED);
+        HANDLED_FACET_TYPES.add(FACET_FLOW_DEPTH_TKH_FILTERED);
+    }
+
+    public FlowDepthProcessor() {
+        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
+    }
+
+    @Override
+    protected double[][] doGetPoints(final AbstractSInfoCalculationResult<?> data, final String facetName) {
+
+        if (FACET_FLOW_DEPTH_FILTERED.contentEquals(facetName))
+            return data.getFlowDepthPoints();
+
+        if (FACET_FLOW_DEPTH_TKH_FILTERED.contentEquals(facetName))
+            return data.getFlowDepthTkhPoints();
+
+        final String error = String.format("Unknown facet name: %s", facetName);
+        throw new UnsupportedOperationException(error);
+    }
+
+    public static Facet createFlowDepthFacet(final CallContext context, final String hash, final String id, final AbstractSInfoCalculationResult<?> result,
+            final int index) {
+        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION,
+                I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, result.getLabel());
+        return new SInfoResultFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED, facetFlowDepthFilteredDescription, SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL,
+                ComputeType.ADVANCE, id, hash);
+    }
+
+    public static Facet createFlowDepthTkhFacet(final CallContext context, final String hash, final String id, final AbstractSInfoCalculationResult<?> result,
+            final int index) {
+        final String facetFlowDepthTkhFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION,
+                I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION, result.getLabel());
+        return new SInfoResultFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_TKH_FILTERED, facetFlowDepthTkhFilteredDescription,
+                SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, id, hash);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TauProcessor.java	Tue Mar 06 18:51:18 2018 +0100
@@ -0,0 +1,60 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.sinfo.common;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+public final class TauProcessor extends AbstractSInfoLineProcessor {
+
+    // FIXME: translate!
+    private static final String I18N_AXIS_LABEL = "sinfo.chart.tau.section.yaxis.label";
+
+    private static final String SINFO_CHART_TAU_YAXIS_LABEL = "sinfo.chart.tau.yaxis.label";
+
+    // FIXME: check: filtered or not?
+    private static final String FACET_TKH_TAU_FILTERED = "sinfo_tkh_tau.filtered";
+
+    private static final String I18N_FACET_TKH_TAU_FILTERED_DESCRIPTION = "sinfo.facet.tkh_tau.filtered.description";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_TKH_TAU_FILTERED);
+    }
+
+    public TauProcessor() {
+        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
+    }
+
+    @Override
+    protected double[][] doGetPoints(final AbstractSInfoCalculationResult<?> data, final String facetName) {
+
+        if (FACET_TKH_TAU_FILTERED.contentEquals(facetName))
+            return data.getTauPoints();
+
+        final String error = String.format("Unknown facet name: %s", facetName);
+        throw new UnsupportedOperationException(error);
+    }
+
+    public static Facet createD50Facet(final CallContext context, final String hash, final String id, final AbstractSInfoCalculationResult<?> result,
+            final int index) {
+        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_TAU_FILTERED_DESCRIPTION,
+                I18N_FACET_TKH_TAU_FILTERED_DESCRIPTION, result.getLabel());
+        return new SInfoResultFacet(index, TauProcessor.FACET_TKH_TAU_FILTERED, facetFlowDepthFilteredDescription, SINFO_CHART_TAU_YAXIS_LABEL,
+                ComputeType.ADVANCE, id, hash);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java	Tue Mar 06 18:51:18 2018 +0100
@@ -26,11 +26,13 @@
 
 public final class TkhProcessor extends AbstractSInfoProcessor {
 
-    public static String FACET_TKH = "sinfo_flow_depth.tkh";
+    private static String FACET_TKH = "sinfo_flow_depth.tkh";
 
-    public static final String I18N_FACET_TKH_DESCRIPTION = "sinfo.facet.tkh.description";
+    private static final String I18N_AXIS_LABEL = "sinfo.chart.tkh.section.yaxis.label";
 
-    public static final String SINFO_CHART_TKX_YAXIS_LABEL = "sinfo.chart.tkh.yaxis.label";
+    private static final String I18N_FACET_TKH_DESCRIPTION = "sinfo.facet.tkh.description";
+
+    private static final String SINFO_CHART_TKX_YAXIS_LABEL = "sinfo.chart.tkh.yaxis.label";
 
     private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
 
@@ -38,8 +40,6 @@
         HANDLED_FACET_TYPES.add(FACET_TKH);
     }
 
-    private static final String I18N_AXIS_LABEL = "sinfo.chart.tkh.section.yaxis.label";
-
     public TkhProcessor() {
         super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/VelocityProcessor.java	Tue Mar 06 18:51:18 2018 +0100
@@ -0,0 +1,60 @@
+/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * 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.sinfo.common;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
+
+public final class VelocityProcessor extends AbstractSInfoLineProcessor {
+
+    // FIXME: translate!
+    private static final String I18N_AXIS_LABEL = "sinfo.chart.velocity.section.yaxis.label";
+
+    private static final String SINFO_CHART_VELOCITY_YAXIS_LABEL = "sinfo.chart.velocity.yaxis.label";
+
+    // FIXME: check: filtered or not?
+    private static final String FACET_TKH_VELOCITY_FILTERED = "sinfo_tkh_velocity.filtered";
+
+    private static final String I18N_FACET_TKH_VELOCITY_FILTERED_DESCRIPTION = "sinfo.facet.tkh_velocity.filtered.description";
+
+    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
+
+    static {
+        HANDLED_FACET_TYPES.add(FACET_TKH_VELOCITY_FILTERED);
+    }
+
+    public VelocityProcessor() {
+        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
+    }
+
+    @Override
+    protected double[][] doGetPoints(final AbstractSInfoCalculationResult<?> data, final String facetName) {
+
+        if (FACET_TKH_VELOCITY_FILTERED.contentEquals(facetName))
+            return data.getVelocityPoints();
+
+        final String error = String.format("Unknown facet name: %s", facetName);
+        throw new UnsupportedOperationException(error);
+    }
+
+    public static Facet createVelocityFacet(final CallContext context, final String hash, final String id, final AbstractSInfoCalculationResult<?> result,
+            final int index) {
+        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_TKH_VELOCITY_FILTERED_DESCRIPTION,
+                I18N_FACET_TKH_VELOCITY_FILTERED_DESCRIPTION, result.getLabel());
+        return new SInfoResultFacet(index, VelocityProcessor.FACET_TKH_VELOCITY_FILTERED, facetFlowDepthFilteredDescription, SINFO_CHART_VELOCITY_YAXIS_LABEL,
+                ComputeType.ADVANCE, id, hash);
+    }
+}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java	Tue Mar 06 18:51:18 2018 +0100
@@ -15,8 +15,6 @@
 import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
 import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
 
-import gnu.trove.TDoubleArrayList;
-
 /**
  * Contains the results of a {@link FlowDepthCalculation}.
  *
@@ -38,34 +36,4 @@
     public BedHeightInfo getSounding() {
         return this.sounding;
     }
-
-    public double[][] getFlowDepthPoints() {
-
-        final Collection<FlowDepthRow> rows = getRows();
-
-        final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size());
-        final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size());
-
-        for (final FlowDepthRow row : rows) {
-            xPoints.add(row.getStation());
-            yPoints.add(row.getFlowDepth());
-        }
-
-        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
-    }
-
-    public double[][] getFlowDepthTkhPoints() {
-
-        final Collection<FlowDepthRow> rows = getRows();
-
-        final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size());
-        final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size());
-
-        for (final FlowDepthRow row : rows) {
-            xPoints.add(row.getStation());
-            yPoints.add(row.getFlowDepthWithTkh());
-        }
-
-        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
-    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculator.java	Tue Mar 06 18:51:18 2018 +0100
@@ -18,7 +18,6 @@
 import org.dive4elements.river.artifacts.model.WKms;
 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder;
-import org.dive4elements.river.artifacts.sinfo.tkhcalculation.SoilKind;
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator;
 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
@@ -80,18 +79,13 @@
 
             final Tkh tkh = calculateTkh(station, wst);
 
-            final double meanBedHeight = tkh.getMeanBedHeight();
-
-            final double flowDepth = wst - meanBedHeight;
-            final double flowDepthTkh = calculateFlowDepthTkh(tkh, wst, meanBedHeight);
-
             // REMARK: access the location once only during calculation
             final String location = this.riverInfoProvider.getLocation(station);
 
             // REMARK: access the gauge once only during calculation
             final String gaugeLabel = this.riverInfoProvider.findGauge(station);
 
-            this.rows.add(new FlowDepthRow(flowDepth, flowDepthTkh, tkh, this.wstLabel, gaugeLabel, this.bedHeightLabel, location));
+            this.rows.add(new FlowDepthRow(tkh, this.wstLabel, gaugeLabel, this.bedHeightLabel, location));
         }
         catch (final FunctionEvaluationException e) {
             /* should only happen if out of range */
@@ -104,26 +98,10 @@
         if (this.tkhCalculator == null) {
             final double discharge = this.dischargeProvider.getDischarge(station);
             final double meanBedHeight = this.bedHeight.getMeanBedHeight(station);
-            return new Tkh(station, wst, meanBedHeight, discharge);
+            final double flowDepth = wst - meanBedHeight;
+            return new Tkh(station, wst, meanBedHeight, flowDepth, discharge);
         }
 
         return this.tkhCalculator.getTkh(station, wst);
     }
-
-    private double calculateFlowDepthTkh(final Tkh tkh, final double wst, final double meanBedHeight) {
-        final double tkhValue = tkh.getTkh();
-        final SoilKind tkhKind = tkh.getKind();
-
-        if (Double.isNaN(tkhValue) || tkhKind == null)
-            return Double.NaN;
-
-        switch (tkhKind) {
-        case starr:
-            return wst - (meanBedHeight + tkhValue / 100);
-
-        case mobil:
-        default:
-            return wst - (meanBedHeight + tkhValue / 200);
-        }
-    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java	Tue Mar 06 17:14:56 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by
- *  Björnsen Beratende Ingenieure GmbH
- *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
- *
- * 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.sinfo.flowdepth;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
-import org.dive4elements.artifacts.Artifact;
-import org.dive4elements.artifacts.CallContext;
-import org.dive4elements.river.artifacts.D4EArtifact;
-import org.dive4elements.river.artifacts.access.RiverAccess;
-import org.dive4elements.river.artifacts.context.RiverContext;
-import org.dive4elements.river.artifacts.math.MovingAverage;
-import org.dive4elements.river.artifacts.model.ZoomScale;
-import org.dive4elements.river.artifacts.sinfo.common.AbstractSInfoProcessor;
-import org.dive4elements.river.exports.DiagramGenerator;
-import org.dive4elements.river.exports.StyledSeriesBuilder;
-import org.dive4elements.river.jfree.StyledXYSeries;
-import org.dive4elements.river.themes.ThemeDocument;
-
-public final class FlowDepthProcessor extends AbstractSInfoProcessor {
-
-    /* Theme name, usually defined in 'FacetTypes', but that is soooo bad dependencies... */
-    // REMARK: these mustend with 'filtered' so extra handling happens in chart: point are always recalculated, because data
-    // changes depending on zoom state
-    static String FACET_FLOW_DEPTH_FILTERED = "sinfo_flow_depth.filtered";
-
-    static String FACET_FLOW_DEPTH_TKH_FILTERED = "sinfo_flow_depth.tkh.filtered";
-
-    private static final Set<String> HANDLED_FACET_TYPES = new HashSet<>();
-
-    static {
-        HANDLED_FACET_TYPES.add(FACET_FLOW_DEPTH_FILTERED);
-        HANDLED_FACET_TYPES.add(FACET_FLOW_DEPTH_TKH_FILTERED);
-    }
-
-    private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label";
-
-    public FlowDepthProcessor() {
-        super(I18N_AXIS_LABEL, HANDLED_FACET_TYPES);
-    }
-
-    @Override
-    protected final String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
-
-        final CallContext context = generator.getCallContext();
-        final Map<String, String> metaData = bundle.getFacet().getMetaData();
-
-        final Artifact artifact = bundle.getArtifact();
-
-        final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
-        series.putMetaData(metaData, artifact, context);
-
-        final String facetName = bundle.getFacetName();
-        final FlowDepthCalculationResult data = (FlowDepthCalculationResult) bundle.getData(context);
-        if (data == null) {
-            // Check has been here before so we keep it for security reasons
-            // this should never happen though.
-            throw new IllegalStateException("Data is null for facet: " + facetName);
-        }
-
-        final Double radius = findRadius(context, artifact);
-
-        final double[][] points = generatePoints(radius, data, facetName);
-
-        StyledSeriesBuilder.addPoints(series, points, true);
-        generator.addAxisSeries(series, getAxisName(), visible);
-
-        return metaData.get("Y");
-    }
-
-    private Double findRadius(final CallContext context, final Artifact artifact) {
-        final Double start = (Double) context.getContextValue("startkm");
-        final Double end = (Double) context.getContextValue("endkm");
-
-        if (start == null || end == null)
-            return null;
-
-        final RiverContext fc = (RiverContext) context.globalContext();
-        final ZoomScale scales = (ZoomScale) fc.get("zoomscale");
-        final RiverAccess access = new RiverAccess((D4EArtifact) artifact);
-        final String river = access.getRiverName();
-
-        return scales.getRadius(river, start, end);
-    }
-
-    private double[][] generatePoints(final Double radius, final FlowDepthCalculationResult data, final String facetName) {
-
-        if (FACET_FLOW_DEPTH_FILTERED.contentEquals(facetName))
-            return movingAverage(radius, data.getFlowDepthPoints());
-
-        if (FACET_FLOW_DEPTH_TKH_FILTERED.contentEquals(facetName))
-            return movingAverage(radius, data.getFlowDepthTkhPoints());
-
-        final String error = String.format("Unknown facet name: %s", facetName);
-        throw new UnsupportedOperationException(error);
-    }
-
-    private double[][] movingAverage(final Double radius, final double[][] points) {
-
-        if (radius == null)
-            return points;
-
-        return MovingAverage.weighted(points, radius);
-    }
-}
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java	Tue Mar 06 18:51:18 2018 +0100
@@ -20,30 +20,16 @@
 final class FlowDepthRow extends AbstractSInfoResultRow {
     private static final long serialVersionUID = 1L;
 
-    private final double flowDepth;
-
-    private final double flowDepthWithTkh;
-
     private final String soundingLabel;
 
-    public FlowDepthRow(final double flowDepth, final double flowDepthWithTkh, final Tkh tkh, final String waterlevelLabel,
+    public FlowDepthRow(final Tkh tkh, final String waterlevelLabel,
             final String gauge, final String soundingLabel, final String location) {
 
         super(tkh, waterlevelLabel, gauge, location);
 
-        this.flowDepth = flowDepth;
-        this.flowDepthWithTkh = flowDepthWithTkh;
         this.soundingLabel = soundingLabel;
     }
 
-    public double getFlowDepth() {
-        return this.flowDepth;
-    }
-
-    public double getFlowDepthWithTkh() {
-        return this.flowDepthWithTkh;
-    }
-
     public String getSoundageLabel() {
         return this.soundingLabel;
     }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java	Tue Mar 06 18:51:18 2018 +0100
@@ -20,9 +20,8 @@
 import org.dive4elements.river.artifacts.model.EmptyFacet;
 import org.dive4elements.river.artifacts.model.FacetTypes;
 import org.dive4elements.river.artifacts.model.ReportFacet;
-import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
-import org.dive4elements.river.artifacts.sinfo.common.SInfoResultFacet;
+import org.dive4elements.river.artifacts.sinfo.common.FlowDepthProcessor;
 import org.dive4elements.river.artifacts.sinfo.common.TkhProcessor;
 import org.dive4elements.river.artifacts.states.DefaultState;
 
@@ -34,13 +33,6 @@
 
     private static final long serialVersionUID = 1L;
 
-    private static final String I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.filtered.description";
-
-    private static final String I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.tkh.filtered.description";
-
-
-    private static final String SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL = "sinfo.chart.flow_depth.yaxis.label";
-
     /**
      * From this state can only be continued trivially.
      */
@@ -91,17 +83,11 @@
             final FlowDepthCalculationResult result = resultList.get(index);
 
             /* filtered (zoom dependent mean) flow depth */
-            final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION,
-                    I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, result.getLabel());
-            facets.add(new SInfoResultFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED, facetFlowDepthFilteredDescription,
-                    SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
+            facets.add(FlowDepthProcessor.createFlowDepthFacet(context, hash, this.id, result, index));
 
             if (results.isUseTkh()) {
                 /* filtered (zoom dependent mean) flow depth including tkh */
-                final String facetFlowDepthTkhFilteredDescription = Resources.getMsg(context.getMeta(), I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION,
-                        I18N_FACET_FLOW_DEPTH_TKH_FILTERED_DESCRIPTION, result.getLabel());
-                facets.add(new SInfoResultFacet(index, FlowDepthProcessor.FACET_FLOW_DEPTH_TKH_FILTERED, facetFlowDepthTkhFilteredDescription,
-                        SINFO_CHART_FLOW_DEPTH_YAXIS_LABEL, ComputeType.ADVANCE, this.id, hash));
+                facets.add(FlowDepthProcessor.createFlowDepthTkhFacet(context, hash, this.id, result, index));
 
                 facets.add(TkhProcessor.createTkhFacet(context, hash, this.id, result, index));
             }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/Tkh.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/Tkh.java	Tue Mar 06 18:51:18 2018 +0100
@@ -26,6 +26,10 @@
 
     private final double meanBedHeight;
 
+    private final double flowDepth;
+
+    private final double flowDepthTkh;
+
     private final double discharge;
 
     private final SoilKind kind;
@@ -36,20 +40,35 @@
 
     private final double tkhDown;
 
-    public Tkh(final double km, final double wst, final double meanBedHeight, final double discharge) {
-        this(km, wst, meanBedHeight, discharge, null, Double.NaN, Double.NaN, Double.NaN);
+    private final double velocity;
+
+    private final double d50;
+
+    private final double tau;
+
+    public Tkh(final double km, final double wst, final double meanBedHeight, final double flowDepth, final double discharge) {
+        this(km, wst, meanBedHeight, flowDepth, discharge, null);
     }
 
-    public Tkh(final double km, final double wst, final double meanBedHeight, final double discharge, final SoilKind kind, final double tkh, final double tkhUp,
-            final double tkhDown) {
+    public Tkh(final double km, final double wst, final double meanBedHeight, final double flowDepth, final double discharge, final SoilKind kind) {
+        this(km, wst, meanBedHeight, flowDepth, Double.NaN, discharge, kind, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
+    }
+
+    public Tkh(final double km, final double wst, final double meanBedHeight, final double flowDepth, final double flowDepthTkh, final double discharge,
+            final SoilKind kind, final double tkh, final double tkhUp, final double tkhDown, final double velocity, final double d50, final double tau) {
         this.km = km;
         this.wst = wst;
         this.meanBedHeight = meanBedHeight;
+        this.flowDepth = flowDepth;
+        this.flowDepthTkh = flowDepthTkh;
         this.discharge = discharge;
         this.kind = kind;
         this.tkh = tkh;
         this.tkhUp = tkhUp;
         this.tkhDown = tkhDown;
+        this.velocity = velocity;
+        this.d50 = d50;
+        this.tau = tau;
     }
 
     public double getStation() {
@@ -83,4 +102,24 @@
     public double getMeanBedHeight() {
         return this.meanBedHeight;
     }
+
+    public double getFlowDepth() {
+        return this.flowDepth;
+    }
+
+    public double getFlowDepthTkh() {
+        return this.flowDepthTkh;
+    }
+
+    public double getVelocity() {
+        return this.velocity;
+    }
+
+    public double getD50() {
+        return this.d50;
+    }
+
+    public double getTau() {
+        return this.tau;
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java	Tue Mar 06 18:51:18 2018 +0100
@@ -140,6 +140,8 @@
 
         final double meanBedHeight = this.bedHeightsProvider.getMeanBedHeight(km);
 
+        final double flowDepth = wst - meanBedHeight;
+
         final double discharge = getDischarge(km);
         if (Double.isNaN(discharge)) {
 
@@ -150,22 +152,25 @@
             // TODO: nochmal gemeinsam überlegen welche probleme wir loggen, an dieser stelle müsste man ggf. die station
             // mitausgeben
 
-            return new Tkh(km, wst, meanBedHeight, Double.NaN, kind, Double.NaN, Double.NaN, Double.NaN);
+            return new Tkh(km, wst, meanBedHeight, flowDepth, Double.NaN, kind);
         }
 
         final double d50 = getBedMeasurement(km);
         if (Double.isNaN(d50))
-            return new Tkh(km, wst, meanBedHeight, discharge, kind, Double.NaN, Double.NaN, Double.NaN);
+            return new Tkh(km, wst, meanBedHeight, flowDepth, discharge, kind);
 
         if (!this.flowVelocitiesFinder.findKmQValues(km, discharge)) {
             // TODO: ggf. station in Fehlermeldung?
             final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingVelocity", null, this.problemLabel);
             this.problems.addProblem(km, message);
             // FIXME: cumulate problems to one message?
-            return new Tkh(km, wst, meanBedHeight, discharge, kind, Double.NaN, Double.NaN, Double.NaN);
+            return new Tkh(km, wst, meanBedHeight, flowDepth, discharge, kind);
         }
 
-        final double tkh = calculateTkh(wst - meanBedHeight, this.flowVelocitiesFinder.getFindVmainFound(), d50, this.flowVelocitiesFinder.getFindTauFound());
+        final double velocity = this.flowVelocitiesFinder.getFindVmainFound();
+        final double tau = this.flowVelocitiesFinder.getFindTauFound();
+
+        final double tkh = calculateTkh(wst - meanBedHeight, velocity, d50, tau);
         double tkhUp;
         double tkhDown;
         switch (kind) {
@@ -181,7 +186,9 @@
             break;
         }
 
-        return new Tkh(km, wst, meanBedHeight, discharge, kind, tkh, tkhUp, tkhDown);
+        final double flowDepthTkh = calculateFlowDepthTkh(tkhUp, kind, wst, meanBedHeight);
+
+        return new Tkh(km, wst, meanBedHeight, flowDepth, flowDepthTkh, discharge, kind, tkh, tkhUp, tkhDown, velocity, d50, tau);
     }
 
     /**
@@ -217,4 +224,19 @@
 
         return tkh;
     }
+
+    private double calculateFlowDepthTkh(final double tkhValue, final SoilKind tkhKind, final double wst, final double meanBedHeight) {
+
+        if (Double.isNaN(tkhValue) || tkhKind == null)
+            return Double.NaN;
+
+        switch (tkhKind) {
+        case starr:
+            return wst - (meanBedHeight + tkhValue / 100);
+
+        case mobil:
+        default:
+            return wst - (meanBedHeight + tkhValue / 200);
+        }
+    }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java	Tue Mar 06 17:14:56 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhState.java	Tue Mar 06 18:51:18 2018 +0100
@@ -11,6 +11,8 @@
 import java.util.List;
 
 import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.artifactdatabase.state.FacetActivity;
+import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.ChartArtifact;
 import org.dive4elements.river.artifacts.D4EArtifact;
@@ -21,6 +23,7 @@
 import org.dive4elements.river.artifacts.model.FacetTypes;
 import org.dive4elements.river.artifacts.model.ReportFacet;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.sinfo.common.FlowDepthProcessor;
 import org.dive4elements.river.artifacts.sinfo.common.TkhProcessor;
 import org.dive4elements.river.artifacts.states.DefaultState;
 
@@ -32,6 +35,25 @@
 
     private static final long serialVersionUID = 1L;
 
+    static {
+        // Active/deactivate facets.
+        // BEWARE: we can only define one activity for "sinfo", so this is not the right place....
+        FacetActivity.Registry.getInstance().register("sinfo", new FacetActivity() {
+            @Override
+            public Boolean isInitialActive(final Artifact artifact, final Facet facet, final String output) {
+
+                /* only */
+                if ("sinfo_tkk".equals(output)) {
+                    final String name = facet.getName();
+                    if (FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED.equals(name))
+                        return Boolean.FALSE;
+                }
+
+                return null;
+            }
+        });
+    }
+
     /**
      * From this state can only be continued trivially.
      */
@@ -82,6 +104,9 @@
             final TkhCalculationResult result = resultList.get(index);
 
             facets.add(TkhProcessor.createTkhFacet(context, hash, this.id, result, index));
+
+            // FIXME: should only be optionally visible
+            facets.add(FlowDepthProcessor.createFlowDepthTkhFacet(context, hash, this.id, result, index));
         }
 
         if (!resultList.isEmpty()) {

http://dive4elements.wald.intevation.org