gernotbelger@8854: /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde gernotbelger@8877: * Software engineering by gernotbelger@8877: * Björnsen Beratende Ingenieure GmbH gernotbelger@8854: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt gernotbelger@8854: * gernotbelger@8854: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@8854: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@8854: * documentation coming with Dive4Elements River for details. gernotbelger@8854: */ gernotbelger@8854: package org.dive4elements.river.artifacts.sinfo.flowdepth; gernotbelger@8854: gernotbelger@8854: import java.util.Collection; gernotbelger@8854: gernotbelger@8894: import org.apache.commons.lang.math.DoubleRange; gernotbelger@8854: import org.dive4elements.artifacts.CallContext; gernotbelger@8854: import org.dive4elements.river.artifacts.model.Calculation; gernotbelger@8854: import org.dive4elements.river.artifacts.model.CalculationResult; gernotbelger@8854: import org.dive4elements.river.artifacts.model.WKms; gernotbelger@8854: import org.dive4elements.river.artifacts.resources.Resources; gernotbelger@8854: import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator; gernotbelger@8946: import org.dive4elements.river.artifacts.sinfo.tkhcalculation.WaterlevelValuesFinder; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; gernotbelger@8894: import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; gernotbelger@8894: import org.dive4elements.river.artifacts.sinfo.util.WstInfo; gernotbelger@8882: import org.dive4elements.river.artifacts.states.WaterlevelData; gernotbelger@8882: import org.dive4elements.river.artifacts.states.WaterlevelFetcher; gernotbelger@8854: import org.dive4elements.river.model.River; gernotbelger@8854: gernotbelger@8854: class FlowDepthCalculation { gernotbelger@8854: gernotbelger@8914: // private static Logger log = Logger.getLogger(FlowDepthCalculation.class); mschaefer@8898: gernotbelger@8877: private final CallContext context; gernotbelger@8854: gernotbelger@8882: public FlowDepthCalculation(final CallContext context) { gernotbelger@8877: this.context = context; gernotbelger@8854: } gernotbelger@8854: gernotbelger@8877: public CalculationResult calculate(final SINFOArtifact sinfo) { gernotbelger@8854: gernotbelger@8915: final String user = CalculationUtils.findArtifactUser(this.context, sinfo); gernotbelger@8854: gernotbelger@8877: /* access input data */ gernotbelger@8877: final FlowDepthAccess access = new FlowDepthAccess(sinfo); gernotbelger@8877: final River river = access.getRiver(); gernotbelger@8894: final RiverInfo riverInfo = new RiverInfo(river); gernotbelger@8854: gernotbelger@8946: final Collection diffPairs = access.getDifferencePairs(); gernotbelger@8877: gernotbelger@8915: final DoubleRange calcRange = access.getRange(); gernotbelger@8877: gernotbelger@8877: final boolean useTkh = access.isUseTransportBodies(); gernotbelger@8877: gernotbelger@8877: /* calculate results for each diff pair */ gernotbelger@8877: final Calculation problems = new Calculation(); gernotbelger@8877: gernotbelger@8915: final RiverInfoProvider infoProvider = RiverInfoProvider.forRange(this.context, river, calcRange); gernotbelger@8877: gernotbelger@8882: final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); gernotbelger@8877: gernotbelger@8894: final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); gernotbelger@8877: gernotbelger@8946: for (final WstSoundingIdPair diffPair : diffPairs) { gernotbelger@8915: final FlowDepthCalculationResult result = calculateResult(calcRange, diffPair, problems, infoProvider, useTkh); gernotbelger@8882: if (result != null) gernotbelger@8877: results.addResult(result); gernotbelger@8877: } gernotbelger@8877: gernotbelger@8882: return new CalculationResult(results, problems); gernotbelger@8877: } gernotbelger@8877: mschaefer@8898: /** mschaefer@8898: * Calculates one W-MSH differences pair. gernotbelger@8915: * gernotbelger@8915: * @param infoProvider mschaefer@8898: */ gernotbelger@8946: private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final WstSoundingIdPair diffPair, final Calculation problems, gernotbelger@8946: final RiverInfoProvider infoProvider, final boolean useTkh) { gernotbelger@8877: gernotbelger@8877: /* access real input data from database */ gernotbelger@8877: final String soundingId = diffPair.getSoundingId(); gernotbelger@8877: final String wstId = diffPair.getWstId(); gernotbelger@8877: gernotbelger@8946: final BedHeightsFinder bedHeight = BedHeightsFinder.forId(this.context, soundingId, calcRange, problems); gernotbelger@8946: if (bedHeight == null) gernotbelger@8877: return null; gernotbelger@8877: gernotbelger@8882: /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */ gernotbelger@8946: final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN, problems); gernotbelger@8946: if (waterlevel == null) gernotbelger@8877: return null; gernotbelger@8946: gernotbelger@8882: final WKms wstKms = waterlevel.getWkms(); gernotbelger@8882: gernotbelger@8883: final String wspLabel = wstKms.getName(); gernotbelger@8915: final String soundingLabel = bedHeight.getInfo().getDescription(); gernotbelger@8883: final String label = String.format("%s - %s", wspLabel, soundingLabel); gernotbelger@8877: gernotbelger@8946: FlowDepthUtils.checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems); gernotbelger@8894: checkWaterlevelDiscretisation(wstKms, calcRange, problems); mschaefer@8901: // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden gernotbelger@8882: gernotbelger@8882: /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ gernotbelger@8915: final RiverInfoProvider riverInfoProvider = infoProvider.forWaterlevel(waterlevel); gernotbelger@8894: gernotbelger@8915: final int wspYear = waterlevel.getYear(); gernotbelger@8915: final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge()); gernotbelger@8914: gernotbelger@8946: final WaterlevelValuesFinder waterlevelProvider = WaterlevelValuesFinder.fromKms(wstKms); gernotbelger@8915: final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms); gernotbelger@8886: gernotbelger@8915: final River river = riverInfoProvider.getRiver(); gernotbelger@8946: final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, waterlevelProvider, gernotbelger@8946: dischargeProvider, gernotbelger@8915: bedHeight); gernotbelger@8883: gernotbelger@8946: final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wspLabel, bedHeight, tkhCalculator); gernotbelger@8915: return calculator.execute(label, wstInfo, calcRange); gernotbelger@8877: } gernotbelger@8877: gernotbelger@8882: /* Checks if the discretisation of the waterlevel exceeds 1000m */ gernotbelger@8894: private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { gernotbelger@8894: gernotbelger@8882: final int size = wstKms.size(); gernotbelger@8882: for (int i = 0; i < size - 2; i++) { gernotbelger@8882: final double kmPrev = wstKms.getKm(i); gernotbelger@8882: final double kmNext = wstKms.getKm(i + 1); gernotbelger@8882: gernotbelger@8894: /* only check if we are within the calculation range */ gernotbelger@8894: if (calcRange.overlapsRange(new DoubleRange(kmPrev, kmNext))) { gernotbelger@8894: if (Math.abs(kmPrev - kmNext) > 1) { gernotbelger@8894: final String label = wstKms.getName(); gernotbelger@8882: gernotbelger@8894: final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label); gernotbelger@8894: problems.addProblem(kmPrev, message); gernotbelger@8894: } gernotbelger@8882: } gernotbelger@8882: } gernotbelger@8882: } gernotbelger@8884: }