diff artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentCalculation.java @ 8951:322b0e6298ea

Work on SINFO FlowDepth-Development
author gernotbelger
date Fri, 16 Mar 2018 18:08:38 +0100
parents
children c40db8e8dcae
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/FlowDepthDevelopmentCalculation.java	Fri Mar 16 18:08:38 2018 +0100
@@ -0,0 +1,197 @@
+/** 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.flowdepthdev;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.model.Calculation;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.model.WKms;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
+import org.dive4elements.river.artifacts.sinfo.common.SInfoResultRow;
+import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType;
+import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthUtils;
+import org.dive4elements.river.artifacts.sinfo.flowdepth.WstSoundingIdPair;
+import org.dive4elements.river.artifacts.sinfo.tkhcalculation.WaterlevelValuesFinder;
+import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder;
+import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
+import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
+import org.dive4elements.river.artifacts.states.WaterlevelData;
+import org.dive4elements.river.artifacts.states.WaterlevelFetcher;
+import org.dive4elements.river.model.River;
+
+/**
+ * @author Gernot Belger
+ */
+final class FlowDepthDevelopmentCalculation {
+
+    private final CallContext context;
+
+    public FlowDepthDevelopmentCalculation(final CallContext context) {
+        this.context = context;
+    }
+
+    public CalculationResult calculate(final SINFOArtifact sinfo) {
+
+        final String user = CalculationUtils.findArtifactUser(this.context, sinfo);
+
+        /* access input data */
+        final FlowDepthDevelopmentAccess access = new FlowDepthDevelopmentAccess(sinfo);
+        final River river = access.getRiver();
+        final RiverInfo riverInfo = new RiverInfo(river);
+
+        final WstSoundingIdPair currentPair = access.getCurrentPair();
+        final WstSoundingIdPair histPair = access.getHistoricalPair();
+
+        final DoubleRange calcRange = access.getRange();
+
+        /* calculate results for each diff pair */
+        final Calculation problems = new Calculation();
+
+        final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange);
+
+        final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
+
+        final FlowDepthDevelopmentCalculationResults results = new FlowDepthDevelopmentCalculationResults(calcModeLabel, user, riverInfo, calcRange);
+
+        final FlowDepthDevelopmentCalculationResult result = calculateResult(calcRange, currentPair, histPair, problems, infoProvider);
+        if (result != null)
+            results.addResult(result);
+
+        return new CalculationResult(results, problems);
+    }
+
+    private FlowDepthDevelopmentCalculationResult calculateResult(final DoubleRange calcRange, final WstSoundingIdPair currentPair,
+            final WstSoundingIdPair histPair, final Calculation problems, final RiverInfoProvider infoProvider) {
+
+        /* access real input data from database */
+        final WaterlevelData currentWaterlevel = loadWaterlevel(currentPair, problems);
+        if (currentWaterlevel == null)
+            return null;
+
+        final WaterlevelData historicalWaterlevel = loadWaterlevel(histPair, problems);
+        if (historicalWaterlevel == null)
+            return null;
+
+        final BedHeightsFinder currentSounding = loadBedHeight(currentPair, calcRange, problems);
+        if (currentSounding == null)
+            return null;
+
+        final BedHeightsFinder historicalSounding = loadBedHeight(histPair, calcRange, problems);
+        if (historicalSounding == null)
+            return null;
+
+        // FIXME: check current/hist wst have same discharge...
+
+        final BedHeightInfo currentSoundingInfo = currentSounding.getInfo();
+        final BedHeightInfo historicalSoundingInfo = historicalSounding.getInfo();
+
+        // final String label = createLabel(waterlevel, minBedHeight, maxBedHeight);
+
+        // final WKms wstKms = waterlevel.getWkms();
+        final int currentWstYear = currentWaterlevel.getYear();
+        final int historicalWstYear = historicalWaterlevel.getYear();
+        final int currentSoundingYear = currentSoundingInfo.getYear();
+        final int historicalSoundingYear = historicalSoundingInfo.getYear();
+
+        // FIXME: distinguish error messages
+        FlowDepthUtils.checkYearDifference("", currentWstYear, currentSoundingYear, problems);
+        FlowDepthUtils.checkYearDifference("", historicalWstYear, historicalSoundingYear, problems);
+
+        // checkWaterlevelDiscretisation(wstKms, calcRange, problems);
+        // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden
+
+        /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */
+        final RiverInfoProvider currentRiverInfoProvider = infoProvider.forWaterlevel(currentWaterlevel);
+        final RiverInfoProvider histRiverInfoProvider = infoProvider.forWaterlevel(historicalWaterlevel);
+
+        final WstInfo currentWstInfo = new WstInfo(currentWaterlevel.getName(), currentWstYear, currentRiverInfoProvider.getReferenceGauge());
+        final WstInfo historicalWstInfo = new WstInfo(historicalWaterlevel.getName(), historicalWstYear, histRiverInfoProvider.getReferenceGauge());
+
+        final WKms currentWkms = currentWaterlevel.getWkms();
+        final WaterlevelValuesFinder currentWstProvider = WaterlevelValuesFinder.fromKms(currentWkms);
+        // final DischargeValuesFinder currentDischargeProvider = DischargeValuesFinder.fromKms(currentWkms);
+
+        final WKms historicalWkms = historicalWaterlevel.getWkms();
+        final WaterlevelValuesFinder historicalWstProvider = WaterlevelValuesFinder.fromKms(historicalWkms);
+        // final DischargeValuesFinder historicalDischargeProvider = DischargeValuesFinder.fromKms(historicalWkms);
+
+        final int currentMeanYear = (currentWstYear + currentSoundingYear) / 2;
+        final int historcialMeanYear = (historicalWstYear + historicalSoundingYear) / 2;
+
+        // final String waterlevelLabel = waterlevel.getName();
+        // final String soundingLabel = buildSoundingLabel(minBedHeight, maxBedHeight);
+
+        final double diffYear = currentMeanYear - historcialMeanYear;
+
+        /* real calculation loop */
+        final Collection<SInfoResultRow> rows = new ArrayList<>();
+
+        // FIXME: determine what is the spatial discretisation that we will use...
+        final double[] allKms = currentWkms.allKms().toNativeArray();
+        for (final double station : allKms) {
+            if (calcRange.containsDouble(station)) {
+
+                final double currentWst = currentWstProvider.getWaterlevel(station);
+                // final double currentDischarge = currentDischargeProvider.getDischarge(station);
+                final double currentBedHeight = currentSounding.getMeanBedHeight(station);
+
+                final double historicalWst = historicalWstProvider.getWaterlevel(station);
+                // final double historicalDischarge = historicalDischargeProvider.getDischarge(station);
+                final double historicalBedHeight = historicalSounding.getMeanBedHeight(station);
+
+                final double diffWst = (currentWst - historicalWst) * 100;
+                final double diffBedHeight = (currentBedHeight - historicalBedHeight) * 100;
+
+                final double flowDepthDevelopment = diffWst - diffBedHeight;
+
+                final double flowDepthDevelopmentPerYear = flowDepthDevelopment / diffYear;
+
+                final double currentFlowDepth = currentWst - currentBedHeight;
+                final double historicalFlowDepth = historicalWst - historicalBedHeight;
+
+                // REMARK: access the location once only during calculation
+                final String location = currentRiverInfoProvider.getLocation(station);
+
+                final SInfoResultRow row = SInfoResultRow.create().//
+                        putValue(SInfoResultType.station, station). //
+                        putValue(SInfoResultType.flowdepthDevelopment, flowDepthDevelopment). //
+                        putValue(SInfoResultType.flowdepthDevelopmentPerYear, flowDepthDevelopmentPerYear). //
+                        putValue(SInfoResultType.waterlevelDifference, diffWst). //
+                        putValue(SInfoResultType.bedHeightDifference, diffBedHeight). //
+                        putValue(SInfoResultType.flowdepthCurrent, currentFlowDepth). //
+                        putValue(SInfoResultType.flowdepthHistorical, historicalFlowDepth). //
+                        putValue(SInfoResultType.location, location);
+                rows.add(row);
+            }
+        }
+
+        return new FlowDepthDevelopmentCalculationResult("", currentWstInfo, historicalWstInfo, currentSoundingInfo, historicalSoundingInfo,
+                rows);
+    }
+
+    /* REMARK: fetch ALL wst kms, because we need to determine the original reference gauge */
+    private WaterlevelData loadWaterlevel(final WstSoundingIdPair pair, final Calculation problems) {
+        final String wstId = pair.getWstId();
+        return new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN, problems);
+    }
+
+    private BedHeightsFinder loadBedHeight(final WstSoundingIdPair pair, final DoubleRange calcRange, final Calculation problems) {
+        final String soundingId = pair.getSoundingId();
+        return BedHeightsFinder.forId(this.context, soundingId, calcRange, problems);
+    }
+}
\ No newline at end of file

http://dive4elements.wald.intevation.org