gernotbelger@8915: /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde gernotbelger@8915: * Software engineering by gernotbelger@8915: * Björnsen Beratende Ingenieure GmbH gernotbelger@8915: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt gernotbelger@8915: * gernotbelger@8915: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@8915: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@8915: * documentation coming with Dive4Elements River for details. gernotbelger@8915: */ gernotbelger@8915: package org.dive4elements.river.artifacts.sinfo.flowdepth; gernotbelger@8915: gernotbelger@8915: import java.util.ArrayList; gernotbelger@8915: import java.util.Collection; gernotbelger@8915: gernotbelger@8915: import org.apache.commons.lang.math.DoubleRange; gernotbelger@8915: import org.apache.commons.math.FunctionEvaluationException; gernotbelger@8915: import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction; gernotbelger@8915: import org.dive4elements.river.artifacts.model.WKms; 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.SoilKind; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; gernotbelger@8915: import org.dive4elements.river.artifacts.sinfo.util.WstInfo; gernotbelger@8915: import org.dive4elements.river.utils.DoubleUtil; gernotbelger@8915: gernotbelger@8915: /** gernotbelger@8915: * @author Gernot Belger gernotbelger@8915: */ gernotbelger@8915: final class FlowDepthCalculator { gernotbelger@8915: gernotbelger@8915: private final Collection rows = new ArrayList<>(); gernotbelger@8915: gernotbelger@8915: private final DischargeValuesFinder dischargeProvider; gernotbelger@8915: gernotbelger@8915: private final BedHeightsFinder bedHeight; gernotbelger@8915: gernotbelger@8915: private final TkhCalculator tkhCalculator; gernotbelger@8915: gernotbelger@8915: private final PolynomialSplineFunction wstInterpolator; gernotbelger@8915: gernotbelger@8915: private final RiverInfoProvider riverInfoProvider; gernotbelger@8915: gernotbelger@8915: private final String bedHeightLabel; gernotbelger@8915: gernotbelger@8915: private final String wstLabel; gernotbelger@8915: gernotbelger@8915: public FlowDepthCalculator(final RiverInfoProvider riverInfoProvider, final WKms wstKms, gernotbelger@8915: final DischargeValuesFinder dischargeProvider, final BedHeightsFinder bedHeight, final TkhCalculator tkhCalculator) { gernotbelger@8915: gernotbelger@8915: this.riverInfoProvider = riverInfoProvider; gernotbelger@8915: gernotbelger@8915: this.dischargeProvider = dischargeProvider; gernotbelger@8915: this.bedHeight = bedHeight; gernotbelger@8915: this.tkhCalculator = tkhCalculator; gernotbelger@8915: gernotbelger@8915: this.wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), wstKms.allWs()); gernotbelger@8915: gernotbelger@8915: this.bedHeightLabel = bedHeight.getInfo().getDescription(); gernotbelger@8915: this.wstLabel = wstKms.getName(); gernotbelger@8915: } gernotbelger@8915: gernotbelger@8915: public FlowDepthCalculationResult execute(final String label, final WstInfo wstInfo, final DoubleRange calcRange) { gernotbelger@8915: gernotbelger@8915: final Collection stations = this.bedHeight.getStations(); gernotbelger@8915: for (final Double station : stations) { gernotbelger@8915: if (calcRange.containsDouble(station)) gernotbelger@8915: calculateResultRow(station); gernotbelger@8915: } gernotbelger@8915: gernotbelger@8915: return new FlowDepthCalculationResult(label, wstInfo, this.bedHeight.getInfo(), this.tkhCalculator != null, this.rows); gernotbelger@8915: } gernotbelger@8915: gernotbelger@8915: private void calculateResultRow(final double station) { gernotbelger@8915: gernotbelger@8915: try { gernotbelger@8915: // FIXME: check out of range of waterlevel? gernotbelger@8915: final double wst = this.wstInterpolator.value(station); gernotbelger@8915: gernotbelger@8915: final Tkh tkh = calculateTkh(station, wst); gernotbelger@8915: gernotbelger@8915: final double meanBedHeight = tkh.getMeanBedHeight(); gernotbelger@8915: gernotbelger@8915: final double flowDepth = wst - meanBedHeight; gernotbelger@8915: final double flowDepthTkh = calculateFlowDepthTkh(tkh, wst, meanBedHeight); gernotbelger@8915: gernotbelger@8915: // REMARK: access the location once only during calculation gernotbelger@8915: final String location = this.riverInfoProvider.getLocation(station); gernotbelger@8915: gernotbelger@8915: // REMARK: access the gauge once only during calculation gernotbelger@8915: final String gaugeLabel = this.riverInfoProvider.findGauge(station); gernotbelger@8915: gernotbelger@8915: this.rows.add(new FlowDepthRow(flowDepth, flowDepthTkh, tkh, this.wstLabel, gaugeLabel, this.bedHeightLabel, location)); gernotbelger@8915: } gernotbelger@8915: catch (final FunctionEvaluationException e) { gernotbelger@8915: /* should only happen if out of range */ gernotbelger@8915: e.printStackTrace(); gernotbelger@8915: /* simply ignore */ gernotbelger@8915: } gernotbelger@8915: } gernotbelger@8915: gernotbelger@8915: private Tkh calculateTkh(final double station, final double wst) throws FunctionEvaluationException { gernotbelger@8915: if (this.tkhCalculator == null) { gernotbelger@8915: final double discharge = this.dischargeProvider.getDischarge(station); gernotbelger@8915: final double meanBedHeight = this.bedHeight.getMeanBedHeight(station); gernotbelger@8915: return new Tkh(station, wst, meanBedHeight, discharge); gernotbelger@8915: } gernotbelger@8915: gernotbelger@8915: return this.tkhCalculator.getTkh(station, wst); gernotbelger@8915: } gernotbelger@8915: gernotbelger@8915: private double calculateFlowDepthTkh(final Tkh tkh, final double wst, final double meanBedHeight) { gernotbelger@8915: final double tkhValue = tkh.getTkh(); gernotbelger@8915: final SoilKind tkhKind = tkh.getKind(); gernotbelger@8915: gernotbelger@8915: if (Double.isNaN(tkhValue) || tkhKind == null) gernotbelger@8915: return Double.NaN; gernotbelger@8915: gernotbelger@8915: switch (tkhKind) { gernotbelger@8915: case starr: gernotbelger@8915: return wst - (meanBedHeight + tkhValue / 100); gernotbelger@8915: gernotbelger@8915: case mobil: gernotbelger@8915: default: gernotbelger@8915: return wst - (meanBedHeight + tkhValue / 200); gernotbelger@8915: } gernotbelger@8915: } gernotbelger@8915: }