Mercurial > dive4elements > river
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