changeset 8898:89f3c5462a16

Implemented S-INFO Flowdepth TKH calculation
author mschaefer
date Thu, 22 Feb 2018 12:03:31 +0100
parents f431aec10d2c
children 3dd0c77a4b27
files .hgignore artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowVelocityKmModelValues.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowVelocityModelKmValueFinder.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/SoilKindKmValueFinder.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties gwt-client/pom.xml gwt-client/src/main/webapp/WEB-INF/web.xml
diffstat 10 files changed, 1270 insertions(+), 591 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Feb 14 19:06:21 2018 +0100
+++ b/.hgignore	Thu Feb 22 12:03:31 2018 +0100
@@ -25,3 +25,30 @@
 \.swo
 \.pyc
 TAGS
+
+\.checkstyle
+\.log
+syntax: regexp
+^artifacts/doc/conf/log4j\.properties$
+syntax: regexp
+^artifacts/doc/conf/seddb-db\.xml$
+syntax: regexp
+^artifacts/doc$
+syntax: regexp
+^artifacts/artifactsdb$
+syntax: regexp
+^artifacts/cache$
+syntax: regexp
+^artifacts/datacagedb$
+syntax: regexp
+^artifacts/contrib$
+syntax: regexp
+^artifacts/conf$
+syntax: regexp
+\.map$
+syntax: regexp
+^gwt-client/debug_user_file\.txt$
+gwt-client/pom\.xml
+syntax: glob
+contrib/.project
+doc/.project
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/BedQualityD50KmValueFinder.java	Thu Feb 22 12:03:31 2018 +0100
@@ -0,0 +1,209 @@
+/* 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.Date;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.ArgumentOutsideDomainException;
+import org.apache.commons.math.analysis.interpolation.LinearInterpolator;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.log4j.Logger;
+import org.dive4elements.river.artifacts.model.DateRange;
+import org.dive4elements.river.backend.SedDBSessionHolder;
+import org.dive4elements.river.model.River;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+/**
+ * Searchable sorted km array with parallel bed measurements value array and linear interpolation for km and d50 between the array elements.
+ * @author Matthias Schäfer
+ *
+ */
+public class BedQualityD50KmValueFinder {
+
+    /***** INNER CLASSES *****/
+    
+    /**
+     * A bed measurements aggregate with its d50 characteristic grain diameter 
+     */
+    private class D50Measurement {
+        private double km;
+        public double getKm() {
+            return km;
+        }
+        private Date mindate;
+        public Date getMinDate() {
+            return mindate;
+        }
+        private Date maxdate;
+        public Date getMaxDate() {
+            return maxdate;
+        }
+        private int cnt;
+        public int getCnt() {
+            return cnt;
+        }
+        private double mindepth;
+        public double getMinDepth() {
+            return mindepth;
+        }
+        private double maxdepth;
+        public double getMaxDepth() {
+            return maxdepth;
+        }
+        private double d50;
+        /**
+         * D50 in m
+         */
+        public double getD50() {
+            return d50;
+        }
+        /**
+         * Parameter constructor
+         */
+        public D50Measurement(double km, Date mindate, Date maxdate, int cnt, double mindepth, double maxdepth, double d50mm) {
+            this.km = km;
+            this.mindate = mindate;
+            this.maxdate = maxdate;
+            this.cnt = cnt;
+            this.mindepth = mindepth;
+            this.maxdepth = maxdepth;
+            this.d50 = d50mm / 1000;
+        }
+
+        /**
+         * Query result row constructor
+         */
+        public D50Measurement(Object[] tuple, String[] aliases) {
+            km = 0;
+            mindate = null;
+            maxdate = null;
+            cnt = 0;
+            mindepth = Double.NaN;
+            maxdepth = Double.NaN;
+            d50 = Double.NaN;
+            for (int i = 0; i < tuple.length; ++i) {
+                if (tuple[i] == null)
+                    continue;
+                switch (aliases[i]) {
+                case "km":
+                    km = ((Number) tuple[i]).doubleValue();
+                    break;
+                case "mindate":
+                    mindate = (Date) tuple[i];
+                    break;
+                case "maxdate":
+                    maxdate = (Date) tuple[i];
+                    break;
+                case "cnt":
+                     cnt = ((Number) tuple[i]).intValue();
+                   break;
+                case "mindepth":
+                     mindepth = ((Number) tuple[i]).doubleValue();
+                   break;
+                case "maxdepth":
+                    maxdepth = ((Number) tuple[i]).doubleValue();
+                    break;
+                case "d50":
+                    d50 = ((Number) tuple[i]).doubleValue() / 1000;     // mm to m
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+    }
+    
+    /***** FIELDS *****/
+    
+    /**
+     * Private log to use here.
+     */
+    private static Logger log = Logger.getLogger(BedQualityD50KmValueFinder.class);
+
+    /**
+     * Query that aggregates by km for a km range and a time period all sub layer bed measurements with their d50<br />
+     * <br />
+     * A km may have bed measurements for multiple dates, multiple distances from the river bank, and multiple depth layers.
+     * The query filters by km range, time period and layer (sub layer: below bed to max. 50 cm depth).
+     * Those measurements are then grouped by km, and the D50 aggregated as average value.
+     */
+    private static final String SQL_BED_D50_SUBLAYER_MEASUREMENT =
+            "SELECT t.km, MIN(t.datum) AS mindate, MAX(t.datum) AS maxdate, COUNT(*) AS cnt,"
+                + " MIN(p.tiefevon) AS mindepth, MAX(p.tiefebis) AS maxdepth, AVG(a.d50) AS d50"
+                + " FROM sohltest t INNER JOIN station s ON t.stationid = s.stationid"
+                + "    INNER JOIN gewaesser g ON s.gewaesserid = g.gewaesserid"
+                + "    INNER JOIN sohlprobe p ON t.sohltestid = p.sohltestid"
+                + "    INNER JOIN siebanalyse a ON p.sohlprobeid = a.sohlprobeid"
+                + " WHERE (g.name = :name) AND (s.km BETWEEN :fromkm - 0.0001 AND :tokm + 0.0001)"
+                + "    AND (p.tiefevon > 0.0) AND (p.tiefebis <= 0.5)"
+                + "    AND (t.datum BETWEEN :fromdate AND :todate)"
+                + " GROUP BY t.km"
+                + " ORDER BY t.km";
+    private static final String[] SQL_BED_D50_SELECT_ALIAS = {"km", "mindate", "maxdate", "cnt", "mindepth", "maxdepth", "d50"};
+
+    /**
+     * Real linear interpolator for kms and d50 values
+     */
+    private PolynomialSplineFunction interpolator;
+    
+    /***** METHODS *****/
+    
+    /**
+     * Returns the d50 value interpolated according to a km
+     * @throws ArgumentOutsideDomainException
+     */
+    public double findD50(double km) throws ArgumentOutsideDomainException {
+        return interpolator.value(km);
+    }
+    
+    /**
+     * Loads the range of the river's kms with their associated values.
+     * @return Whether the load has been successful
+     */
+    public boolean loadValues(final River river, final DoubleRange kmRange, final DateRange dateRange) {
+        log.debug(String.format("loadValues km %.3f - %.3f %tF - %tF", kmRange.getMinimumDouble(), kmRange.getMaximumDouble(), dateRange.getFrom(), dateRange.getTo()));
+        Session session = SedDBSessionHolder.HOLDER.get();
+        SQLQuery sqlQuery = session.createSQLQuery(SQL_BED_D50_SUBLAYER_MEASUREMENT)
+                .addScalar("km", StandardBasicTypes.DOUBLE)
+                .addScalar("mindate", StandardBasicTypes.DATE)
+                .addScalar("maxdate", StandardBasicTypes.DATE)
+                .addScalar("cnt", StandardBasicTypes.INTEGER)
+                .addScalar("mindepth", StandardBasicTypes.DOUBLE)
+                .addScalar("maxdepth", StandardBasicTypes.DOUBLE)
+                .addScalar("d50", StandardBasicTypes.DOUBLE);
+        String seddbRiver = river.nameForSeddb();
+        sqlQuery.setString("name", seddbRiver);
+        sqlQuery.setDouble("fromkm", kmRange.getMinimumDouble());
+        sqlQuery.setDouble("tokm", kmRange.getMaximumDouble());
+        sqlQuery.setDate("fromdate", dateRange.getFrom());
+        sqlQuery.setDate("todate", dateRange.getTo());
+        @SuppressWarnings("unchecked")
+        final List<Object[]> rows = sqlQuery.list();
+        final double[] kms = new double[rows.size()];
+        final double[] values = new double[rows.size()];
+        D50Measurement measurement;
+        int i = -1;
+        for (Object[] row : rows) {
+            measurement = new D50Measurement(row, SQL_BED_D50_SELECT_ALIAS);
+            i++;
+            kms[i] = measurement.getKm();
+            values[i] = measurement.getD50();
+            log.debug(String.format("loadValues km %.3f d50(mm) %.1f count %d", kms[i], values[i], measurement.getCnt()));
+        }
+        interpolator = new LinearInterpolator().interpolate(kms, values);
+        return true;
+    }
+
+}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java	Wed Feb 14 19:06:21 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java	Thu Feb 22 12:03:31 2018 +0100
@@ -16,18 +16,19 @@
 import java.util.Date;
 import java.util.List;
 
+import org.apache.commons.lang.math.DoubleRange;
 import org.apache.commons.math.FunctionEvaluationException;
 import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.ArtifactDatabase;
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.BedHeightsArtifact;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.DateRange;
 import org.dive4elements.river.artifacts.model.LocationProvider;
-import org.dive4elements.river.artifacts.model.QKms;
+import org.dive4elements.river.artifacts.model.WQKms;
 import org.dive4elements.river.artifacts.model.WKms;
-import org.dive4elements.river.artifacts.model.minfo.QualityMeasurementFactory;
-import org.dive4elements.river.artifacts.model.minfo.QualityMeasurements;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair;
@@ -43,6 +44,8 @@
 
 class FlowDepthCalculation {
 
+    private static Logger log = Logger.getLogger(FlowDepthCalculation.class);
+
     private static final int VALID_BED_MEASUREMENT_YEARS = 20;
 
     private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range";
@@ -70,6 +73,7 @@
 
         final double from = access.getFrom();
         final double to = access.getTo();
+        final DoubleRange calcRange = new DoubleRange(from, to);
 
         final boolean useTkh = access.isUseTransportBodies();
 
@@ -84,7 +88,7 @@
         final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from, to, useTkh);
 
         for (final DifferencesPair diffPair : diffPairs) {
-            final FlowDepthCalculationResult result = calculateResult(river, from, to, diffPair, problems, gaugeIndex);
+            final FlowDepthCalculationResult result = calculateResult(river, calcRange, diffPair, problems, gaugeIndex, useTkh);
             if (result != null)
                 results.addResult(result);
         }
@@ -92,14 +96,17 @@
         return new CalculationResult(results, problems);
     }
 
-    private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair,
-            final Calculation problems, final GaugeIndex gaugeIndex) {
+    /**
+     * Calculates one W-MSH differences pair.
+     */
+    private FlowDepthCalculationResult calculateResult(final River river, final DoubleRange calcRange, final DifferencesPair diffPair,
+            final Calculation problems, final GaugeIndex gaugeIndex, final boolean useTkh) {
 
         /* access real input data from database */
         final String soundingId = diffPair.getSoundingId();
         final String wstId = diffPair.getWstId();
 
-        final BedHeight bedHeight = loadBedHeight(soundingId, from, to);
+        final BedHeight bedHeight = loadBedHeight(soundingId);
         if (bedHeight == null) {
             final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId);
             problems.addProblem(message);
@@ -136,36 +143,49 @@
 
         // FIXME: nur prüfen/beschaffen wenn TKH Berechnung aktiv
         /* Abflusswerte vorhanden? */
-        if (!(wstKms instanceof QKms)) {
+        if (!(wstKms instanceof WQKms)) {
             final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label);
             problems.addProblem(message);
             // TODO: keine Berechnung TKH
         }
 
-        final QualityMeasurements bedMeasurements = getBedMeasurements(river, from, to, sounding.getYear());
-        // FIXME: prüfung ob (genug) werte vorhanden sind? was sind genau die kriterien? falls nein, problemhinzufügen und keine
+        BedQualityD50KmValueFinder bedMeasurementsFinder = null;
+        if (useTkh)
+            bedMeasurementsFinder = loadBedMeasurements(river, calcRange, sounding.getYear());
+        // FIXME: prüfung ob (genug) werte vorhanden sind? was sind genau die kriterien? falls nein, problem hinzufügen und keine
         // berechnung tkh
-        // FIXME: wie wird ggf. interpoliert? --> absprache?
-        // FIXME: mir direkt aufgefallen, die Beispieldatenbank liefert Werte zum gleichen km und zeitpunkt, die messwerte sind
-        // aber unterschiedlich....???
-        // FIXME: die eigentlichen daten extrahieren, ggf. wenn esswerte zum gleichen datum voriliegen. das neueste nehmen? oder
-        // das näheste zum Peiljahr?
-
-        // FIXME Art der Gewässersohle (starr/mobil)
-        // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden?
 
         final String bedHeightLabel = bedHeight.getDescription();
         final String wstLabel = wstKms.getName();
 
         final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs());
-
+        UnivariateRealFunction qInterpolator = null;
+        DoubleRange qRange = null;
+        if (useTkh && (wstKms instanceof WQKms)) {
+            qInterpolator = DoubleUtil.getLinearInterpolator(((WQKms) wstKms).allKms(), ((WQKms) wstKms).allQs());
+            qRange = new DoubleRange( ((WQKms) wstKms).allQs().min(), ((WQKms) wstKms).allQs().max());
+        }
+        
         // FIXME: sort by station first, but in what direction?
+        // FIXME: using river.getKmUp()?
         final List<BedHeightValue> values = bedHeight.getValues();
 
         final List<BedHeightValue> sortedValues = new ArrayList<>(values);
         Collections.sort(sortedValues, new BedHeightStationComparator());
 
-        SoilKind lastKind = SoilKind.mobil;
+        // FIXME: wie wird ggf. interpoliert? prüfung ob werte vorhanden?
+        /* SoilKind lastKind = SoilKind.mobil; */
+        SoilKindKmValueFinder soilKindFinder = null;
+        if (useTkh) {
+            soilKindFinder = new SoilKindKmValueFinder();
+            soilKindFinder.loadValues(river, calcRange);
+        }
+        
+        FlowVelocityModelKmValueFinder flowVelocitiesFinder = null;
+        if (useTkh) {
+            flowVelocitiesFinder = new FlowVelocityModelKmValueFinder();
+            flowVelocitiesFinder.loadValues(river, calcRange, qRange);
+        }
 
         for (final BedHeightValue bedHeightValue : sortedValues) {
 
@@ -180,6 +200,9 @@
             final double km = station;
             final double meanBedHeight = meanBedHeightDbl;
 
+            if (!calcRange.containsDouble(km))
+                continue;
+            
             try {
                 // FIXME: check out of range
                 final double wst = wstInterpolator.value(km);
@@ -188,30 +211,63 @@
 
                 // FIXME: piecewise constant interpolation?
                 // final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN;
-                final double discharge = Double.NaN;
+                double discharge;
+                if (qInterpolator != null)
+                    discharge = qInterpolator.value(km);
+                else
+                    discharge = Double.NaN;
 
                 // FIXME: calculate tkh
-
-                // REMARK: bissl spielerei zum testen damit die sohlart nicht zu schnell wechselt
+                double tkh = 0;
+                if (useTkh) {
+                    double d50 = 0;
+                    try {
+                        d50 = bedMeasurementsFinder.findD50(km);
+                    } catch (Exception e) {
+                        final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingD50", null, label);
+                        problems.addProblem(km, message);
+                        //FIXME: cumulate problems
+                    }
+                    if (flowVelocitiesFinder.findKmQValues(km, discharge)) {
+                        tkh = calculateTkh(wst - meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), d50, flowVelocitiesFinder.getFindTauFound());
+                        log.debug(String.format("calculateTkh km %.3f q %.0f w %.2f mbh %.2f vm %.1f tau %.1f d50(mm) %.1f tkh(cm) %.1f",
+                            km, discharge, wst, meanBedHeight, flowVelocitiesFinder.getFindVmainFound(), flowVelocitiesFinder.getFindTauFound(), d50*1000, tkh));
+                    }
+                    else
+                        tkh = Double.NaN;
+                }
+                
+                // Soil kind
+                SoilKind kind = SoilKind.starr;
+                if (useTkh) {
+                    try {
+                        kind = soilKindFinder.findSoilKind(km);                        
+                    } catch (Exception e) {
+                        final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingSoilKind", null, label);
+                        problems.addProblem(km, message);
+                        //FIXME: cumulate problems
+                    }
+                }
+                
+                /* // REMARK: bissl spielerei zum testen damit die sohlart nicht zu schnell wechselt
+                SoilKind kind;
                 final boolean changeKind = Math.random() > 0.95;
-                SoilKind kind;
                 if (changeKind) {
                     switch (lastKind) {
                     case starr:
                         kind = SoilKind.mobil;
                         break;
-
                     case mobil:
                     default:
                         kind = SoilKind.starr;
                         break;
-
                     }
                 } else
                     kind = lastKind;
                 lastKind = kind;
-
-                final double tkh = 100 + 10 * (Math.random() - 0.5);
+                */
+                
+                //tkh = 100 + 10 * (Math.random() - 0.5);
 
                 final double flowDepthTkh;
                 final double tkhUp;
@@ -240,8 +296,8 @@
 
                 final String gaugeLabel = gauge == null ? notinrange : gauge.getName();
 
-                resultData.addRow(km, flowDepth, flowDepthTkh, kind, tkh, tkhUp, tkhDown, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel,
-                        location);
+                resultData.addRow(km, flowDepth, flowDepthTkh, kind, tkh, tkhUp, tkhDown, wst, discharge, wstLabel,
+                        gaugeLabel, meanBedHeight, bedHeightLabel, location);
             }
             catch (final FunctionEvaluationException e) {
                 /* should only happen if out of range */
@@ -258,7 +314,7 @@
      * Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
      * Abhängig von Peiljahr
      */
-    private QualityMeasurements getBedMeasurements(final River river, final double from, final double to, final int soundingYear) {
+    private BedQualityD50KmValueFinder loadBedMeasurements(final River river, final DoubleRange kmRange, final int soundingYear) {
 
         /* construct valid measurement time range */
         final Calendar cal = Calendar.getInstance();
@@ -270,7 +326,11 @@
         cal.set(soundingYear + VALID_BED_MEASUREMENT_YEARS, 11, 31);
         final Date endTime = cal.getTime();
 
-        return QualityMeasurementFactory.getBedMeasurements(river.getName(), from, to, startTime, endTime);
+        final BedQualityD50KmValueFinder finder = new BedQualityD50KmValueFinder();
+        if (finder.loadValues(river, kmRange, new DateRange(startTime, endTime)))
+            return finder;
+        else
+            return null;
     }
 
     /**
@@ -348,10 +408,10 @@
         }
     }
 
-    private BedHeight loadBedHeight(final String soundingId, final double from, final double to) {
+    private BedHeight loadBedHeight(final String soundingId) {
 
         // REMARK: absolutely unbelievable....
-        // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type
+        // The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type
         // throughout flys.
         // The knowledge on how to parse the datacage-ids is spread through the complete code-base...
 
@@ -375,4 +435,28 @@
 
         return BedHeight.getBedHeightById(bedheightId);
     }
+    
+    /**
+     * Calculates a transport body height
+     * @param h flow depth in m
+     * @param vm flow velocity in m
+     * @param d50 grain diameter D50 in m (!)
+     * @param tau shear stress in N/m^2
+     * @return transport body height in cm (!)
+     */
+    private double calculateTkh(double h, double vm, double d50, double tau) {
+        final double PHYS_G = 9.81;
+        final double PHYS_SPECGRAV_S = 2.6;
+        final double PHYS_VELOCCOEFF_N = 6;
+        final double PHYS_FORMCOEFF_ALPHA = 0.7;
+        final double PHYS_VISCOSITY_NUE = 1.3e-6;
+        final double PHYS_GRAIN_DENSITY_RHOS = 2603;
+        final double PHYS_WATER_DENSITY_RHO = 999.97;
+        
+        final double froude = vm / Math.sqrt(PHYS_G * h);
+        final double partReynolds = Math.sqrt((PHYS_SPECGRAV_S - 1) * PHYS_G * d50) / PHYS_VISCOSITY_NUE * d50;
+        final double critShields = 0.22 * Math.pow(partReynolds, -0.6) + 0.06 * Math.pow(10,  7.7 * Math.pow(partReynolds, -0.6));
+        final double critTau = critShields * (PHYS_GRAIN_DENSITY_RHOS - PHYS_WATER_DENSITY_RHO) * PHYS_G * d50;
+        return 100 * h * (1 - Math.pow(froude, 2)) / (2 * PHYS_VELOCCOEFF_N * PHYS_FORMCOEFF_ALPHA) * (1 - critTau / tau);
+    }
 }
\ 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/flowdepth/FlowVelocityKmModelValues.java	Thu Feb 22 12:03:31 2018 +0100
@@ -0,0 +1,186 @@
+/* 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 org.apache.commons.math.analysis.interpolation.LinearInterpolator;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+
+import gnu.trove.TDoubleArrayList;
+
+/**
+ * Sorted arrays of a station's q, v, and tau model values, running in parallel
+ * @author Matthias Schäfer
+ *
+ */
+public class FlowVelocityKmModelValues {
+
+    /***** FIELDS *****/
+    
+    /**
+     * Km
+     */
+    private double km;
+    
+    /**
+     * The station's discharge model values, sorted in ascending order
+     */
+    private TDoubleArrayList qs;
+    
+    /**
+     * The station's main section velocity for the q values
+     */
+    private TDoubleArrayList vmains;
+    
+    /**
+     * The station's shear stress (tau) values for the q values
+     */
+    private TDoubleArrayList taus;
+
+    /**
+     * Discharge found by the last findQ
+     */
+    private double findQ;
+    
+    /**
+     * Velocity found by the last {@link findQ}
+     */
+    private double vmainFound;
+    
+    /**
+     * Shear stress found by the last {@link findQ}
+     */
+    private double tauFound;
+    
+    /**
+     * Whether qFound has been interpolated
+     */
+    private boolean isInterpolated;
+    
+    /**
+     * Real linear interpolator for q and v values
+     */
+    private PolynomialSplineFunction vInterpolator;
+    
+    /**
+     * Real linear interpolator for q and tau values
+     */
+    private PolynomialSplineFunction tauInterpolator;
+    
+    
+    /***** CONSTRUCTORS *****/
+    
+    /**
+     * Constructor with km parameter
+     */
+    public FlowVelocityKmModelValues(double km) {
+        this.km = km;
+        qs = new TDoubleArrayList();
+        vmains = new TDoubleArrayList();
+        taus = new TDoubleArrayList();
+        vInterpolator = null;
+        tauInterpolator = null;
+    }
+
+    /**
+     * Copy constructor with new km
+     */
+    public FlowVelocityKmModelValues(double km, FlowVelocityKmModelValues src) {
+        this(km);
+        src.copyTo(qs, vmains, taus);
+    }
+    
+    /***** METHODS *****/
+    
+    /**
+     * Number of the q-v-tau tuples
+     */
+    public int size() {
+        if (qs != null)
+            return qs.size();
+        else
+            return 0;
+    }
+    
+    /**
+     * Km
+     */
+    public double getKm() {
+        return km;
+    }
+    
+    /**
+     * Adds all q-v-tau to another set of arrays
+     */
+    void copyTo(TDoubleArrayList dstqs, TDoubleArrayList dstvmains, TDoubleArrayList dsttaus) {
+        for (int i = 0; i <= qs.size(); i++) {
+            dstqs.add(qs.getQuick(i));
+            dstvmains.add(vmains.getQuick(i));
+            dsttaus.add(taus.getQuick(i));
+        }
+    }
+    
+    /**
+     * Discharge found by the last {@link findQ}
+     * @return
+     */
+    public double getFindQ() {
+        return findQ;
+    }
+    
+    /**
+     * Velocity found by the last {@link findQ}
+     */
+    public double getVmainFound() {
+        return vmainFound;
+    }
+    
+    /**
+     * Shear stress found by the last {@link findQ}
+     */
+    public double getTauFound() {
+        return tauFound;
+    }
+    
+    /**
+     * Whether qFound has been interpolated 
+     */
+    public boolean getIsInterpolated() {
+        return isInterpolated;
+    }
+    
+    /**
+     * Adds a q-v-tau value triple. 
+     */
+    public void addValues(double q, double vmain, double tau) {
+        qs.add(q);
+        vmains.add(vmain);
+        taus.add(tau);
+    }
+    
+    /**
+     * Searches a discharge value and returns it or the interpolated value
+     * @return Found or interpolated discharge, or NaN otherwise
+     */
+    public double findQ(double q) {
+        if (vInterpolator == null) {
+            vInterpolator = new LinearInterpolator().interpolate(qs.toNativeArray(), vmains.toNativeArray());
+            tauInterpolator = new LinearInterpolator().interpolate(qs.toNativeArray(), taus.toNativeArray());
+        }
+        findQ = q;
+        try {
+            vmainFound = vInterpolator.value(q);
+            tauFound = tauInterpolator.value(q);
+        } catch (Exception e) {
+            q = Double.NaN;
+        }
+        return q;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowVelocityModelKmValueFinder.java	Thu Feb 22 12:03:31 2018 +0100
@@ -0,0 +1,330 @@
+/* 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.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.log4j.Logger;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+import gnu.trove.TDoubleArrayList;
+
+import org.dive4elements.river.artifacts.math.Linear;
+import org.dive4elements.river.artifacts.math.Utils;
+import org.dive4elements.river.backend.SessionHolder;
+import org.dive4elements.river.model.River;
+
+/**
+ * Searchable sorted km array with parallel FlowVelocityKmModelValues array and linear interpolation for km and the model values between the array elements.<br />
+ * {@link loadValues} loads all the model values for a given km range of a river.<br />
+ * {@link findKmQValues} then searches a km in the values table or the nearest including km interval, resp.
+ * The v and tau values for a given discharge are either found directly or also interpolated linearly.<br />
+ * 
+ * (Created based on a copy of FlowVelocityMeasurementFactory.)
+ * 
+ * @author Matthias Schäfer
+ *
+ */
+public class FlowVelocityModelKmValueFinder
+{
+    /***** FIELDS *****/
+    
+    /**
+     * Private log to use here.
+     */
+    private static Logger log = Logger.getLogger(FlowVelocityModelKmValueFinder.class);
+    
+    /**
+     * Query for a range of stations of a river with all their q, main-v and tau values.<br />
+     * (Might be several 10000 rows if many stations and large q range)
+     */
+    private static final String SQL_SELECT_ALL =
+        "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau" 
+        + "  FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)" 
+        + "    INNER JOIN flow_velocity_model_values fvmv ON fvm.id = fvmv.flow_velocity_model_id" 
+        + "  WHERE (dz.river_id = :river_id) AND (fvmv.station BETWEEN :kmfrom - 0.0001 AND :kmto + 0.0001)" 
+        /* + "  WHERE (dz.river_id = :river_id) AND (fvmv.q BETWEEN :qmin AND :qmax)" */
+        + "  ORDER BY fvmv.station ASC, fvmv.q ASC";
+
+    /**
+     * Query for a river's max km below a limit with all its q, main-v and tau values.
+     */
+    private static final String SQL_SELECT_KMLOWER =
+        "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
+        + "  FROM flow_velocity_model_values fvmv"
+        + "    INNER JOIN (SELECT MAX(fvmvi.station) AS kmmax"
+        + "      FROM(discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)"
+        + "        INNER JOIN flow_velocity_model_values fvmvi ON fvm.id = fvmvi.flow_velocity_model_id"
+        + "        WHERE (dz.river_id = :river_id) AND (fvmvi.station < :kmfrom - 0.0001)) finf ON fvmv.station = finf.kmmax" 
+        + "  ORDER BY fvmv.q ASC";
+
+    /**
+     * Query for a river's min km above a limit with all its q, main-v and tau values.
+     */
+    private static final String SQL_SELECT_KMUPPER =
+        "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau" 
+        + "  FROM flow_velocity_model_values fvmv"
+        + "    INNER JOIN (SELECT MIN(fvmvi.station) AS kmmin"
+        + "      FROM(discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)" 
+        + "        INNER JOIN flow_velocity_model_values fvmvi ON fvm.id = fvmvi.flow_velocity_model_id"
+        + "        WHERE (dz.river_id = :river_id) AND (fvmvi.station > :kmto + 0.0001)) fsup ON fvmv.station = fsup.kmmin" 
+        + "  ORDER BY fvmv.q ASC";
+
+    /**
+     * Query to select all km-q-v-tau of a river that are the q maxima below a q limit
+     */
+    private static final String SQL_SELECT_QLOWER =
+        "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
+        + "  FROM flow_velocity_model_values fvmv"
+        + "    INNER JOIN (SELECT fv2.station, MAX(fv2.q) AS q"
+        + "      FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)" 
+        + "        INNER JOIN flow_velocity_model_values fv2 ON fvm.id = fv2.flow_velocity_model_id" 
+        + "      WHERE (dz.river_id = :river_id) AND (fv2.q < :qlim) GROUP BY fv2.station) qx"
+        + "    ON (fvmv.station=qx.station) AND (fvmv.q=qx.q)" 
+        + "  ORDER BY fvmv.station ASC";
+        
+    /**
+     * Query to select all km-q-v-tau of a river that are the q minima above a q limit
+     */
+    private static final String SQL_SELECT_QUPPER =
+            "SELECT fvmv.station AS station, fvmv.q AS q, fvmv.main_channel AS vmain, fvmv.shear_stress AS tau"
+            + "  FROM flow_velocity_model_values fvmv"
+            + "    INNER JOIN (SELECT fv2.station, MIN(fv2.q) AS q"
+            + "      FROM (discharge_zone dz INNER JOIN flow_velocity_model fvm ON dz.id = fvm.discharge_zone_id)" 
+            + "        INNER JOIN flow_velocity_model_values fv2 ON fvm.id = fv2.flow_velocity_model_id" 
+            + "      WHERE (dz.river_id = :river_id) AND (fv2.q > :qlim) GROUP BY fv2.station) qx"
+            + "    ON (fvmv.station=qx.station) AND (fvmv.q=qx.q)" 
+            + "  ORDER BY fvmv.station ASC";
+            
+    /**
+     * Kms of the loaded river range
+     */
+    private TDoubleArrayList kms;
+    
+    /**
+     * For each km in kms a list of q-v-tau-tupels
+     */
+    private List<FlowVelocityKmModelValues> values;
+
+    /**
+     * Searched km of the last findKmValue
+     */
+    private double findKm;
+    
+    /**
+     * kms and values index of the interval start found by the last findKmValue
+     */
+    private int leftIndexFound = -1;
+
+    /**
+     * kms and values index of the interval end found by the last findKmValue
+     */
+    private int rightIndexFound = -1;
+
+    /**
+     * Q of the last findKmQValues
+     */
+    private double findQ;
+
+    /***** METHODS *****/
+    
+    /**
+     * Discharge of the last {@link findKmQValue}
+     */
+    public double getFindQ() {
+        return findQ;
+    }
+    
+    /**
+     * Velocity of the last {@link findKmQValues}
+     */
+    public double getFindVmainFound() {
+        if (leftIndexFound < 0)
+            return Double.NaN;
+        else if (leftIndexFound == rightIndexFound)
+            return getLeftValues().getVmainFound();
+        else
+            return Linear.linear(findKm, getLeftValues().getKm(), getRightValues().getKm(), getLeftValues().getVmainFound(), getRightValues().getVmainFound());
+    }
+    
+    /**
+     * Shear stress tau of the last {@link findKmQValues}
+     */
+    public double getFindTauFound() {
+        if (leftIndexFound < 0)
+            return Double.NaN;
+        else if (leftIndexFound == rightIndexFound)
+            return getLeftValues().getTauFound();
+        else
+            return Linear.linear(findKm, getLeftValues().getKm(), getRightValues().getKm(), getLeftValues().getTauFound(), getRightValues().getTauFound());
+    }
+    
+    /**
+     * Whether the discharge has been interpolated in the last {@link findKmQValues} 
+     */
+    public boolean getFindIsQInterpolated() {
+        return (getLeftValues() != null) && (getLeftValues().getIsInterpolated() || getRightValues().getIsInterpolated());
+    }
+    
+    /**
+     * Queries a range of a river's kms with all their q-v-tau values.
+     * @return Whether the load has been successful
+     */
+    @SuppressWarnings("unchecked")
+    public boolean loadValues(River river, DoubleRange kmRange, DoubleRange qRange) {
+        // DB session
+        log.debug(String.format("loadValues km %.3f - %.3f / q %.1f - %.1f", kmRange.getMinimumDouble(), kmRange.getMaximumDouble(), qRange.getMinimumDouble(), qRange.getMaximumDouble()));
+        kms = new TDoubleArrayList();
+        values = new ArrayList<FlowVelocityKmModelValues>();
+        boolean isDemoValuesCorrection = river.getName().equalsIgnoreCase("beispielfluss");
+        final Session session = SessionHolder.HOLDER.get();
+        
+        // Select km infimum
+        SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_KMLOWER)
+            .addScalar("station", StandardBasicTypes.DOUBLE)
+            .addScalar("q", StandardBasicTypes.DOUBLE)
+            .addScalar("vmain", StandardBasicTypes.DOUBLE)
+            .addScalar("tau", StandardBasicTypes.DOUBLE);
+        sqlQuery.setParameter("river_id", river.getId());
+        sqlQuery.setParameter("kmfrom", kmRange.getMinimumDouble());
+        addKms(sqlQuery.list(), isDemoValuesCorrection);
+
+        // Select km range
+        sqlQuery = session.createSQLQuery(SQL_SELECT_ALL)
+            .addScalar("station", StandardBasicTypes.DOUBLE)
+            .addScalar("q", StandardBasicTypes.DOUBLE)
+            .addScalar("vmain", StandardBasicTypes.DOUBLE)
+            .addScalar("tau", StandardBasicTypes.DOUBLE);
+        sqlQuery.setParameter("river_id", river.getId());
+        sqlQuery.setParameter("kmfrom", kmRange.getMinimumDouble());
+        sqlQuery.setParameter("kmto", kmRange.getMaximumDouble());
+        //sqlQuery.setParameter("qmin", qRange.getMinimumDouble());
+        //sqlQuery.setParameter("qmax", qRange.getMaximumDouble());
+        int kmcount = kms.size();
+        int rowcount = addKms(sqlQuery.list(), isDemoValuesCorrection);
+        kmcount = kms.size() - kmcount;
+        
+        // Select km supremum 
+        sqlQuery = session.createSQLQuery(SQL_SELECT_KMUPPER)
+            .addScalar("station", StandardBasicTypes.DOUBLE)
+            .addScalar("q", StandardBasicTypes.DOUBLE)
+            .addScalar("vmain", StandardBasicTypes.DOUBLE)
+            .addScalar("tau", StandardBasicTypes.DOUBLE);
+        sqlQuery.setParameter("river_id", river.getId());
+        sqlQuery.setParameter("kmto", kmRange.getMaximumDouble());
+        int supcnt = addKms(sqlQuery.list(), isDemoValuesCorrection);
+
+        // Add copy of last km for search of max km value
+        if ((supcnt == 0) && (values.size() >= 1)) {
+            kms.add(kms.getQuick(kms.size()) + 0.0001);
+            values.add(new FlowVelocityKmModelValues(kms.getQuick(kms.size()-1), values.get(values.size()-1)));
+        }
+        
+        // log.debug
+        if (values.size() - 1 >= 0) {
+            log.debug(String.format("loadValues %d: km %.3f - %d values", 0, values.get(0).getKm(), values.get(0).size()));
+            if (values.size() - 1 >= 1) {
+                log.debug(String.format("loadValues %d: km %.3f - %d values", 1, values.get(1).getKm(), values.get(1).size()));
+                if (values.size() - 1 >= 2)
+                    log.debug("loadValues ...");
+                if (values.size() - 2 >= 3)
+                    log.debug(String.format("loadValues %d: km %.3f - %d values", values.size()-2, values.get(values.size()-2).getKm(), values.get(values.size()-2).size()));
+                if (values.size() - 1 >= 3)
+                    log.debug(String.format("loadValues %d: km %.3f - %d values", values.size()-1, values.get(values.size()-1).getKm(), values.get(values.size()-1).size()));
+            }
+        }
+        log.debug(String.format("loadValues %d kms, %d values loaded", kmcount, rowcount));
+        return (kms.size() >= 1);
+    }
+    
+    /**
+     * Adds the km-q-v-tau values of a query result row to the last km of the list, or a new one resp.
+     * @return Number of rows
+     */
+    private int addKms(List<Object[]> rows, boolean isDemoValuesCorrection) {
+        for (Object[] row : rows) {
+            if ((kms.size() == 0) || !Utils.epsilonEquals(kms.get(kms.size()-1), (double) row[0], 0.0001)) {
+                kms.add((double) row[0]);
+                values.add(new FlowVelocityKmModelValues(kms.get(kms.size()-1)));
+            }
+            if (isDemoValuesCorrection)
+                // "Verfremdung" der v-Werte etwas korrigieren (Originalwerte wurden mit Zufallswert zwischen 10 und 20 multipliziert)
+                values.get(values.size()-1).addValues((double) row[1], ((double) row[2]) / 10, (double) row[3]);
+            else
+                values.get(values.size()-1).addValues((double) row[1], (double) row[2], (double) row[3]);
+        }
+        return rows.size();
+    }
+    
+    /**
+     * Searches a km and finds or interpolates the velocity and shear stress values for a discharge<br />
+     * The values may be got via {@link getVmainFound} etc.
+     * @return Whether values have been found
+     */
+    public boolean findKmQValues(double km, double q) {
+        findQ = q;
+        if (!searchKm(km))
+            return false;
+        if (leftIndexFound == rightIndexFound) {
+            // Exact km match
+            final double qfound = getLeftValues().findQ(q);
+            log.debug(String.format("findKmQValues km %.3f q %.0f = %.0f (%d)", km, q, qfound, leftIndexFound));
+            return !Double.isNaN(qfound);
+        }
+        else {
+            final double[] qfound = {getLeftValues().findQ(q), getRightValues().findQ(q)};
+            log.debug(String.format("findKmQValues km %.3f q %.0f = %.0f (%d, %.3f) - %.0f (%d, %.3f)", km, q, qfound[0], leftIndexFound,
+                    getLeftValues().getKm(), qfound[1], rightIndexFound, getRightValues().getKm()));
+            return !Double.isNaN(qfound[0]) && !Double.isNaN(qfound[1]);
+        }
+    }
+    
+    /**
+     * Searches a km
+     * @return Whether the km was within the supported range
+     */
+    private boolean searchKm(double km) {
+        findKm = km;
+        leftIndexFound = -1;
+        rightIndexFound = -1;
+        if ((kms == null) || (kms.size() == 0))
+            return false;
+        int i = kms.binarySearch(km);
+        if (i >= 0) {
+            // Exact km match
+            leftIndexFound = i;
+            rightIndexFound = i;
+            return true;
+        }
+        else {
+            // Out of range or within km interval
+            if (i < 0)
+                i = -i - 1;
+            if ((i <= 0) || (i >= kms.size()))
+                return false;
+            leftIndexFound = i - 1;
+            rightIndexFound = i;
+            return true;
+        }
+    }
+    
+    private FlowVelocityKmModelValues getLeftValues() {
+        return values.get(leftIndexFound);
+    }
+    private FlowVelocityKmModelValues getRightValues() {
+        return values.get(rightIndexFound);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/SoilKindKmValueFinder.java	Thu Feb 22 12:03:31 2018 +0100
@@ -0,0 +1,106 @@
+/* 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.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.apache.commons.math.ArgumentOutsideDomainException;
+import org.apache.log4j.Logger;
+import org.dive4elements.river.model.River;
+
+import gnu.trove.TDoubleArrayList;
+
+/**
+ * @author matthias
+ *
+ */
+public class SoilKindKmValueFinder
+{
+    /**
+     * Private log to use here.
+     */
+    private static Logger log = Logger.getLogger(SoilKindKmValueFinder.class);
+
+    private TDoubleArrayList kms;
+    
+    private List<SoilKind> values;
+    
+    /***** METHODS *****/
+    
+    /**
+     * Searches a km with its soil kind
+     */
+    public SoilKind findSoilKind(double km) throws ArgumentOutsideDomainException {
+        if ((kms == null) || (kms.size() == 0))
+            throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN);
+        int i = kms.binarySearch(km);
+        if (i >= 0) {
+            // Exact km match
+            return values.get(i);
+        }
+        else {
+            // Out of range or within km interval
+            if (i < 0)
+                i = -i - 1;
+            if ((i <= 0) || (i >= kms.size()))
+                throw new ArgumentOutsideDomainException(km, Double.NaN, Double.NaN);
+            if (km <= ((kms.get(i-1) + kms.get(i)) / 2))
+                return values.get(i-1);
+            else
+                return values.get(i);
+        }
+    }
+
+    /**
+     * Loads the range of the river's kms with their soil kind.
+     * @return Whether the load has been successful
+     */
+    public boolean loadValues(River river, DoubleRange kmRange) {
+        kms = new TDoubleArrayList();
+        values = new ArrayList<SoilKind>();
+        //FIXME Echte Daten aus der Datenbank abfragen
+        addKmKind(0, SoilKind.starr);
+        addKmKind(15.7, SoilKind.mobil);
+        addKmKind(15.8, SoilKind.mobil);
+        addKmKind(15.9, SoilKind.starr);
+        addKmKind(108.7, SoilKind.mobil);
+        addKmKind(108.8, SoilKind.mobil);
+        addKmKind(108.9, SoilKind.starr);
+        addKmKind(119.1, SoilKind.mobil);
+        addKmKind(119.4, SoilKind.mobil);
+        addKmKind(119.5, SoilKind.starr);
+        addKmKind(128.3, SoilKind.mobil);
+        addKmKind(128.9, SoilKind.mobil);
+        addKmKind(129, SoilKind.starr);
+        addKmKind(133.1, SoilKind.mobil);
+        addKmKind(135.9, SoilKind.mobil);
+        addKmKind(136, SoilKind.starr);
+        addKmKind(136.5, SoilKind.mobil);
+        addKmKind(139.9, SoilKind.mobil);
+        addKmKind(140, SoilKind.starr);
+        addKmKind(140.5, SoilKind.mobil);
+        addKmKind(165, SoilKind.mobil);
+        addKmKind(165.1, SoilKind.starr);
+        addKmKind(165.9, SoilKind.mobil);
+        addKmKind(180.8, SoilKind.mobil);
+        addKmKind(180.9, SoilKind.starr);
+        addKmKind(182, SoilKind.mobil);
+        addKmKind(221.3, SoilKind.mobil);
+        return true;
+    }
+    
+    private void addKmKind(double km, SoilKind kind) {
+        kms.add(km);
+        values.add(kind);
+    }
+}
--- a/artifacts/src/main/resources/messages.properties	Wed Feb 14 19:06:21 2018 +0100
+++ b/artifacts/src/main/resources/messages.properties	Thu Feb 22 12:03:31 2018 +0100
@@ -773,6 +773,8 @@
 sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 sinfo_calc_flow_depth.warning.waterlevel_discretisation  = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
 sinfo_calc_flow_depth.warning.year_difference = {0}: Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
+sinfo_calc_flow_depth.warning.missingSoilKind = {0}: no soil kind available
+sinfo_calc_flow_depth.warning.missingD50 = {0}: no d50 available
 
 sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
 sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
--- a/artifacts/src/main/resources/messages_de.properties	Wed Feb 14 19:06:21 2018 +0100
+++ b/artifacts/src/main/resources/messages_de.properties	Thu Feb 22 12:03:31 2018 +0100
@@ -779,6 +779,8 @@
 sinfo_calc_flow_depth.warning.missingQ = {0}: keine Abflussdaten vorhanden, Transportk\u00f6rperh\u00f6henberechnung nicht m\u00f6glich
 sinfo_calc_flow_depth.warning.waterlevel_discretisation  = Wasserspiegel {0}: r\u00e4umliche Aufl\u00f6sung betr\u00e4gt mehr als 1000m
 sinfo_calc_flow_depth.warning.year_difference = {0}: Zeitliche Abweichung betr\u00e4gt {1} Jahre. Dies kann zu unplausiblen Ergebnissen f\u00fchren
+sinfo_calc_flow_depth.warning.missingSoilKind = {0}: keine Sohlart vorhanden
+sinfo_calc_flow_depth.warning.missingD50 = {0}: kein D50 vorhanden
 
 sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung
 sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe
--- a/gwt-client/pom.xml	Wed Feb 14 19:06:21 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-  <!-- POM file generated with GWT webAppCreator -->
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.dive4elements.river</groupId>
-  <artifactId>gwt-client</artifactId>
-  <packaging>war</packaging>
-  <version>1.0-SNAPSHOT</version>
-  <name>org.dive4elements.river.client</name>
-
-  <properties>
-      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-      <!-- Convenience property to set the GWT version -->
-      <gwtVersion>2.4.0</gwtVersion>
-      <!-- GWT needs at least java 1.5 -->
-      <maven.compiler.source>1.6</maven.compiler.source>
-      <maven.compiler.target>1.6</maven.compiler.target>
-  </properties>
-
-  <dependencies>
-    <dependency>
-      <groupId>com.google.gwt</groupId>
-      <artifactId>gwt-servlet</artifactId>
-      <version>${gwtVersion}</version>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.google.gwt</groupId>
-      <artifactId>gwt-user</artifactId>
-      <version>${gwtVersion}</version>
-      <scope>provided</scope>
-    </dependency>
-
-<!-- The following probably does not work. In that case
-     take a look at http://www.smartclient.com/builds/SmartGWT/
-     select a recent version and install it manually to fullfill
-     the smartgwt dependency:
-
-     mvn com.isomorphic:isc-maven-plugin:install -Dproduct=SMARTGWT \
-     -Dlicense=LGPL -DbuildNumber=4.1p -DbuildDate=2014-11-19
-
-     As patch builds for smartgwt do have regressions and are
-     regulararly removed from their repository we use a specific
-     version here that is known to work for us.
-
-     "Theoretically" any smartgwt version > 4.1 should do.
--->
-    <dependency>
-      <groupId>com.isomorphic.smartgwt.lgpl</groupId>
-      <artifactId>smartgwt-lgpl</artifactId>
-      <version>4.1-p20141119</version>
-    </dependency>
-    <dependency>
-      <groupId>org.dive4elements</groupId>
-      <artifactId>artifacts-common</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-        <groupId>org.dive4elements</groupId>
-        <artifactId>http-client</artifactId>
-        <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-        <groupId>net.sf.opencsv</groupId>
-        <artifactId>opencsv</artifactId>
-        <version>2.0</version>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.4</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>commons-lang</groupId>
-      <artifactId>commons-lang</artifactId>
-      <version>2.6</version>
-    </dependency>
-    <dependency>
-      <groupId>commons-fileupload</groupId>
-      <artifactId>commons-fileupload</artifactId>
-      <version>1.2.1</version>
-    </dependency>
-    <dependency>
-      <groupId>org.gwtopenmaps.openlayers</groupId>
-      <artifactId>gwt-openlayers-client</artifactId>
-      <version>0.6</version>
-    </dependency>
-    <dependency>
-      <groupId>commons-httpclient</groupId>
-      <artifactId>commons-httpclient</artifactId>
-      <version>3.1</version>
-    </dependency>
-    <dependency>
-        <groupId>org.apache.httpcomponents</groupId>
-        <artifactId>httpclient</artifactId>
-        <version>4.2</version>
-    </dependency>
-    <dependency>
-      <groupId>log4j</groupId>
-      <artifactId>log4j</artifactId>
-      <version>1.2.14</version>
-    </dependency>
-    <dependency>
-      <groupId>org.mapfish.print</groupId>
-      <artifactId>print-lib</artifactId>
-      <version>1.2.0</version>
-    </dependency>
-    <dependency>
-        <groupId>org.jdom</groupId>
-        <artifactId>jdom</artifactId>
-        <version>1.1.3</version>
-    </dependency>
-    <dependency>
-        <groupId>commons-io</groupId>
-        <artifactId>commons-io</artifactId>
-        <version>2.2</version>
-    </dependency>
-    <dependency>
-    	<groupId>commons-codec</groupId>
-    	<artifactId>commons-codec</artifactId>
-    	<version>1.4</version>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <!-- Generate compiled stuff in the folder used for developing mode -->
-    <outputDirectory>target/www/WEB-INF/classes</outputDirectory>
-
-    <plugins>
-
-      <!-- GWT Maven Plugin-->
-      <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>gwt-maven-plugin</artifactId>
-        <version>${gwtVersion}</version>
-        <dependencies>
-          <dependency>
-            <groupId>com.google.gwt</groupId>
-            <artifactId>gwt-user</artifactId>
-            <version>${gwtVersion}</version>
-          </dependency>
-          <dependency>
-            <groupId>com.google.gwt</groupId>
-            <artifactId>gwt-dev</artifactId>
-            <version>${gwtVersion}</version>
-          </dependency>
-        </dependencies>
-        <!-- JS is only needed in the package phase, this speeds up testing -->
-        <executions>
-          <execution>
-            <phase>prepare-package</phase>
-            <goals>
-              <goal>compile</goal>
-            </goals>
-          </execution>
-        </executions>
-        <!-- Plugin configuration. There are many available options,
-             see gwt-maven-plugin documentation at codehaus.org -->
-        <configuration>
-          <!-- URL that should be automatically opened in the GWT shell (gwt:run). -->
-          <runTarget>FLYS.html</runTarget>
-          <!-- Location of the develop-mode web application structure (gwt:run). -->
-          <hostedWebapp>target/www</hostedWebapp>
-          <!-- Ask GWT to create the Story of Your Compile (SOYC) (gwt:compile) -->
-          <soyc>true</soyc>
-        </configuration>
-      </plugin>
-
-      <!-- Add source folders to test classpath in order to run gwt-tests as normal junit-tests -->
-      <plugin>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <additionalClasspathElements>
-            <additionalClasspathElement>${project.build.sourceDirectory}</additionalClasspathElement>
-            <additionalClasspathElement>${project.build.testSourceDirectory}</additionalClasspathElement>
-          </additionalClasspathElements>
-          <useManifestOnlyJar>false</useManifestOnlyJar>
-          <forkMode>always</forkMode>
-
-          <!-- Folder for generated testing stuff -->
-          <systemProperties>
-            <property>
-              <name>gwt.args</name>
-              <value>-out target/www</value>
-            </property>
-          </systemProperties>
-        </configuration>
-      </plugin>
-
-      <!-- Copy static web files before executing gwt:run -->
-      <plugin>
-        <artifactId>maven-resources-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>compile</phase>
-            <goals>
-              <goal>copy-resources</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>target/www</outputDirectory>
-              <resources>
-                <resource>
-                  <directory>src/main/webapp</directory>
-                </resource>
-              </resources>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-
-      <!-- Delete gwt generated stuff -->
-      <plugin>
-        <artifactId>maven-clean-plugin</artifactId>
-        <configuration>
-          <filesets>
-            <fileset><directory>src/main/webapp/flys</directory></fileset>
-            <fileset><directory>src/main/webapp/WEB-INF/classes</directory></fileset>
-            <fileset><directory>tomcat</directory></fileset>
-            <fileset><directory>www-test</directory></fileset>
-            <fileset><directory>.gwt-tmp</directory></fileset>
-          </filesets>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>3.0.0</version>
-        <configuration>
-          <configLocation>../checkstyle.xml</configLocation>
-          <encoding>UTF-8</encoding>
-        </configuration>
-        <executions>
-          <execution>
-            <id>validate</id>
-            <phase>validate</phase>
-            <configuration>
-              <consoleOutput>true</consoleOutput>
-              <failsOnError>true</failsOnError>
-            </configuration>
-            <goals>
-              <goal>check</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-
-    </plugins>
-    </build>
-      <repositories>
-        <repository>
-           <id>com.smartgwt</id>
-           <name>SmartGWT</name>
-           <url>http://www.smartclient.com/maven2</url>
-      </repository>
-      <repository>
-          <id>osgeo</id>
-          <name>Open Source Geospatial Foundation Repository</name>
-          <url>http://download.osgeo.org/webdav/geotools/</url>
-      </repository>
-    </repositories>
-</project>
--- a/gwt-client/src/main/webapp/WEB-INF/web.xml	Wed Feb 14 19:06:21 2018 +0100
+++ b/gwt-client/src/main/webapp/WEB-INF/web.xml	Thu Feb 22 12:03:31 2018 +0100
@@ -69,6 +69,30 @@
         <param-value>/WEB-INF/log4j.properties</param-value>
     </context-param>
 
+  <filter>
+    <filter-name>GGInAFilter</filter-name>
+    <filter-class>org.dive4elements.river.client.server.filter.GGInAFilter</filter-class>
+    <init-param>
+        <param-name>deactivate</param-name>
+        <param-value>false</param-value>
+    </init-param>
+  </filter>
+
+  <filter>
+    <filter-name>NoCacheFilter</filter-name>
+    <filter-class>org.dive4elements.river.client.server.filter.NoCacheFilter</filter-class>
+  </filter>
+
+  <filter-mapping>
+    <filter-name>GGInAFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+
+  <filter-mapping>
+    <filter-name>NoCacheFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+
     <listener>
         <listener-class>org.dive4elements.river.client.server.BaseServletContextListener</listener-class>
     </listener>
@@ -80,264 +104,132 @@
     <servlet-class>org.dive4elements.river.client.server.UserServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>user</servlet-name>
-    <url-pattern>/flys/user</url-pattern>
-  </servlet-mapping>
-
-  <!-- FIXME: mixing the order of elements here i.e. (servlet - servlet-mapping - servlet) results in errors when validating against the official DTD -->
-
   <servlet>
     <servlet-name>server-info</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ServerInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>server-info</servlet-name>
-    <url-pattern>/flys/server-info</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>artifact</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ArtifactServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>artifact</servlet-name>
-    <url-pattern>/flys/artifact</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>getartifact</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.GetArtifactServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>getartifact</servlet-name>
-    <url-pattern>/flys/getartifact</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>cross-section-km</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.CrossSectionKMServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>cross-section-km</servlet-name>
-    <url-pattern>/flys/cross-section-km</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>create-collection</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.CreateCollectionServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>create-collection</servlet-name>
-    <url-pattern>/flys/create-collection</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>rivers</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.RiverServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>rivers</servlet-name>
-    <url-pattern>/flys/rivers</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>riverinfo</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.RiverInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>riverinfo</servlet-name>
-    <url-pattern>/flys/riverinfo</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>forward</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.StepForwardServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>forward</servlet-name>
-    <url-pattern>/flys/forward</url-pattern>
-  </servlet-mapping>
-
-  <servlet>
-    <servlet-name>feed</servlet-name>
-    <servlet-class>org.dive4elements.river.client.server.FeedServiceImpl</servlet-class>
-  </servlet>
-
-  <servlet-mapping>
-    <servlet-name>feed</servlet-name>
-    <url-pattern>/flys/feed</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>fixings-overview</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.FixingsOverviewServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>fixings-overview</servlet-name>
-    <url-pattern>/flys/fixings-overview</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>advance</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.AdvanceServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>advance</servlet-name>
-    <url-pattern>/flys/advance</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>add-artifact</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.AddArtifactServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>add-artifact</servlet-name>
-    <url-pattern>/flys/add-artifact</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>load-artifact</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.LoadArtifactServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>load-artifact</servlet-name>
-    <url-pattern>/flys/load-artifact</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>describe-collection</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DescribeCollectionServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>describe-collection</servlet-name>
-    <url-pattern>/flys/describe-collection</url-pattern>
-  </servlet-mapping>
-
-    <servlet>
+  <servlet>
     <servlet-name>user-collections</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.UserCollectionsServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>user-collections</servlet-name>
-    <url-pattern>/flys/user-collections</url-pattern>
-  </servlet-mapping>
+  <servlet>
+    <servlet-name>feed</servlet-name>
+    <servlet-class>org.dive4elements.river.client.server.FeedServiceImpl</servlet-class>
+  </servlet>
 
   <servlet>
     <servlet-name>distanceinfo</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DistanceInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>distanceinfo</servlet-name>
-    <url-pattern>/flys/distanceinfo</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>dischargeinfo</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DischargeInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>dischargeinfo</servlet-name>
-    <url-pattern>/flys/dischargeinfo</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>DischargeInfoXML</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DischargeInfoXML</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>DischargeInfoXML</servlet-name>
-    <url-pattern>/flys/dischargeinfoxml</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>meta-data</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.MetaDataServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>meta-data</servlet-name>
-    <url-pattern>/flys/meta-data</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>mainvalues</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.WQInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>mainvalues</servlet-name>
-    <url-pattern>/flys/mainvalues</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>gaugeinfo</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.GaugeInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>gaugeinfo</servlet-name>
-    <url-pattern>/flys/gaugeinfo</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>csv</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.CSVExportServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>csv</servlet-name>
-    <url-pattern>/flys/csv</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>ChartOutputService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ChartOutputServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>ChartOutputService</servlet-name>
-    <url-pattern>/flys/chart</url-pattern>
-  </servlet-mapping>
-
   <servlet>
   	<servlet-name>DischargeTablesOverviewService</servlet-name>
   	<servlet-class>org.dive4elements.river.client.server.DischargeTablesServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-  	<servlet-name>DischargeTablesOverviewService</servlet-name>
-  	<url-pattern>/flys/dischargetablesoverview</url-pattern>
-  </servlet-mapping>
-
   <!-- MapFish Print -->
   <servlet>
     <servlet-name>MapOutputService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.MapOutputServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>MapOutputService</servlet-name>
-    <url-pattern>/flys/map</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>mapfish.print</servlet-name>
     <servlet-class>org.mapfish.print.servlet.MapPrinterServlet</servlet-class>
@@ -347,11 +239,6 @@
     </init-param>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>mapfish.print</servlet-name>
-    <url-pattern>/flys/mapfish-print/*</url-pattern>
-  </servlet-mapping>
-
   <!-- Servlet to bridge between MapFish Print and FLYS3 -->
   <servlet>
     <servlet-name>MapPrintService</servlet-name>
@@ -366,286 +253,397 @@
     </init-param>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>MapPrintService</servlet-name>
-    <url-pattern>/flys/map-print</url-pattern>
-  </servlet-mapping>
-
-
   <servlet>
     <servlet-name>FixingsKMChartService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.FixingsKMChartServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>FixingsKMChartService</servlet-name>
-    <url-pattern>/flys/fixings-km-chart</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>DistanceInfoXML</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DistanceInfoXML</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>DistanceInfoXML</servlet-name>
-    <url-pattern>/flys/distanceinfoxml</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>ExportService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ExportServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>ExportService</servlet-name>
-    <url-pattern>/flys/export</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>CollectionAttributeService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.CollectionAttributeServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>CollectionAttributeService</servlet-name>
-    <url-pattern>/flys/collection-attribute</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>CollectionItemAttributeService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.CollectionItemAttributeServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>CollectionItemAttributeService</servlet-name>
-    <url-pattern>/flys/collection-item-attribute</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>ChartInfoService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ChartInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>ChartInfoService</servlet-name>
-    <url-pattern>/flys/chart-info</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>ReportService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ReportServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>ReportService</servlet-name>
-    <url-pattern>/flys/report</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>SetCollectionNameService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.SetCollectionNameServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>SetCollectionNameService</servlet-name>
-    <url-pattern>/flys/set-collectionname</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>SetCollectionTTLService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.SetCollectionTTLServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>SetCollectionTTLService</servlet-name>
-    <url-pattern>/flys/set-collectionttl</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>DeleteCollectionService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DeleteCollectionServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>DeleteCollectionService</servlet-name>
-    <url-pattern>/flys/delete-collection</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>MapInfoService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.MapInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>MapInfoService</servlet-name>
-    <url-pattern>/flys/map-info</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>getfeatureinfo</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.GFIServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>getfeatureinfo</servlet-name>
-    <url-pattern>/flys/getfeatureinfo</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>getcapabilities</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.GCServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>getcapabilities</servlet-name>
-    <url-pattern>/flys/getcapabilities</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>DescribeArtifactService</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.DescribeArtifactServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>DescribeArtifactService</servlet-name>
-    <url-pattern>/flys/describe</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>remove-artifact</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.RemoveArtifactServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>remove-artifact</servlet-name>
-    <url-pattern>/flys/remove-artifact</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>GetWMSUrls</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.MapUrlServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>GetWMSUrls</servlet-name>
-    <url-pattern>/flys/map-urls</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>FileUpload</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.FileUploadServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>FileUpload</servlet-name>
-    <url-pattern>/flys/fileupload</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>themelisting</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ThemeListingServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>themelisting</servlet-name>
-    <url-pattern>/flys/themelisting</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>SQKMChart</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.SQKMChartServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>SQKMChart</servlet-name>
-    <url-pattern>/flys/sq-km-chart</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>BedKMChart</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.BedKMChartServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>BedKMChart</servlet-name>
-    <url-pattern>/flys/bed-km-chart</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>BedloadKMChart</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.BedloadKMChartServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>BedloadKMChart</servlet-name>
-    <url-pattern>/flys/bedload-km-chart</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>SedimentLoadInfo</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.SedimentLoadInfoServiceImpl</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>SedimentLoadInfo</servlet-name>
-    <url-pattern>/flys/sedimentloadinfo</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>login</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.LoginServlet</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>login</servlet-name>
-    <url-pattern>/flys/login</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>saml</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.SamlServlet</servlet-class>
   </servlet>
 
-  <servlet-mapping>
-    <servlet-name>saml</servlet-name>
-    <url-pattern>/flys/saml</url-pattern>
-  </servlet-mapping>
-
   <servlet>
     <servlet-name>modules</servlet-name>
     <servlet-class>org.dive4elements.river.client.server.ModuleServiceImpl</servlet-class>
   </servlet>
 
   <servlet-mapping>
+    <servlet-name>user</servlet-name>
+    <url-pattern>/flys/user</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>server-info</servlet-name>
+    <url-pattern>/flys/server-info</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>artifact</servlet-name>
+    <url-pattern>/flys/artifact</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>getartifact</servlet-name>
+    <url-pattern>/flys/getartifact</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>cross-section-km</servlet-name>
+    <url-pattern>/flys/cross-section-km</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>create-collection</servlet-name>
+    <url-pattern>/flys/create-collection</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>rivers</servlet-name>
+    <url-pattern>/flys/rivers</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>riverinfo</servlet-name>
+    <url-pattern>/flys/riverinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>forward</servlet-name>
+    <url-pattern>/flys/forward</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>feed</servlet-name>
+    <url-pattern>/flys/feed</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>fixings-overview</servlet-name>
+    <url-pattern>/flys/fixings-overview</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>advance</servlet-name>
+    <url-pattern>/flys/advance</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>add-artifact</servlet-name>
+    <url-pattern>/flys/add-artifact</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>load-artifact</servlet-name>
+    <url-pattern>/flys/load-artifact</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>describe-collection</servlet-name>
+    <url-pattern>/flys/describe-collection</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>user-collections</servlet-name>
+    <url-pattern>/flys/user-collections</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>distanceinfo</servlet-name>
+    <url-pattern>/flys/distanceinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>dischargeinfo</servlet-name>
+    <url-pattern>/flys/dischargeinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>DischargeInfoXML</servlet-name>
+    <url-pattern>/flys/dischargeinfoxml</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>meta-data</servlet-name>
+    <url-pattern>/flys/meta-data</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>mainvalues</servlet-name>
+    <url-pattern>/flys/mainvalues</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>gaugeinfo</servlet-name>
+    <url-pattern>/flys/gaugeinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>csv</servlet-name>
+    <url-pattern>/flys/csv</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>ChartOutputService</servlet-name>
+    <url-pattern>/flys/chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+  	<servlet-name>DischargeTablesOverviewService</servlet-name>
+  	<url-pattern>/flys/dischargetablesoverview</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>MapOutputService</servlet-name>
+    <url-pattern>/flys/map</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>mapfish.print</servlet-name>
+    <url-pattern>/flys/mapfish-print/*</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>MapPrintService</servlet-name>
+    <url-pattern>/flys/map-print</url-pattern>
+  </servlet-mapping>
+
+
+  <servlet-mapping>
+    <servlet-name>FixingsKMChartService</servlet-name>
+    <url-pattern>/flys/fixings-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>DistanceInfoXML</servlet-name>
+    <url-pattern>/flys/distanceinfoxml</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>ExportService</servlet-name>
+    <url-pattern>/flys/export</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>CollectionAttributeService</servlet-name>
+    <url-pattern>/flys/collection-attribute</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>CollectionItemAttributeService</servlet-name>
+    <url-pattern>/flys/collection-item-attribute</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>ChartInfoService</servlet-name>
+    <url-pattern>/flys/chart-info</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>ReportService</servlet-name>
+    <url-pattern>/flys/report</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>SetCollectionNameService</servlet-name>
+    <url-pattern>/flys/set-collectionname</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>SetCollectionTTLService</servlet-name>
+    <url-pattern>/flys/set-collectionttl</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>DeleteCollectionService</servlet-name>
+    <url-pattern>/flys/delete-collection</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>MapInfoService</servlet-name>
+    <url-pattern>/flys/map-info</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>getfeatureinfo</servlet-name>
+    <url-pattern>/flys/getfeatureinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>getcapabilities</servlet-name>
+    <url-pattern>/flys/getcapabilities</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>DescribeArtifactService</servlet-name>
+    <url-pattern>/flys/describe</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>remove-artifact</servlet-name>
+    <url-pattern>/flys/remove-artifact</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>GetWMSUrls</servlet-name>
+    <url-pattern>/flys/map-urls</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>FileUpload</servlet-name>
+    <url-pattern>/flys/fileupload</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>themelisting</servlet-name>
+    <url-pattern>/flys/themelisting</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>SQKMChart</servlet-name>
+    <url-pattern>/flys/sq-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>BedKMChart</servlet-name>
+    <url-pattern>/flys/bed-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>BedloadKMChart</servlet-name>
+    <url-pattern>/flys/bedload-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>SedimentLoadInfo</servlet-name>
+    <url-pattern>/flys/sedimentloadinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>login</servlet-name>
+    <url-pattern>/flys/login</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>saml</servlet-name>
+    <url-pattern>/flys/saml</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
     <servlet-name>modules</servlet-name>
     <url-pattern>/flys/modules</url-pattern>
   </servlet-mapping>
 
-  <filter>
-    <filter-name>GGInAFilter</filter-name>
-    <filter-class>org.dive4elements.river.client.server.filter.GGInAFilter</filter-class>
-    <init-param>
-        <param-name>deactivate</param-name>
-        <param-value>false</param-value>
-    </init-param>
-  </filter>
-
-  <filter-mapping>
-    <filter-name>GGInAFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-  </filter-mapping>
-
-  <filter>
-    <filter-name>NoCacheFilter</filter-name>
-    <filter-class>org.dive4elements.river.client.server.filter.NoCacheFilter</filter-class>
-  </filter>
-
-  <filter-mapping>
-    <filter-name>NoCacheFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-  </filter-mapping>
-
 
   <!-- Default page to serve -->
   <welcome-file-list>

http://dive4elements.wald.intevation.org