Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhcalculation/TkhCalculator.java @ 9532:8e6b9cb9486a
Fixed BedQuality finder
author | gernotbelger |
---|---|
date | Tue, 02 Oct 2018 18:19:44 +0200 |
parents | 144a184a414d |
children |
line wrap: on
line source
/** 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.tkhcalculation; import org.apache.commons.lang.math.DoubleRange; import org.dive4elements.river.artifacts.common.GeneralResultType; import org.dive4elements.river.artifacts.common.ResultRow; import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; import org.dive4elements.river.model.River; /** * @author Gernot Belger */ public final class TkhCalculator { /** * Return type of the tkh calculation * */ public enum TkhCalculateState { SUCCESS, NO_W, NO_BED_HEIGHT, NO_DISCHARGE, NO_SOILKIND, NO_D50, NO_VELOCITY, NO_TKH } private final BedQualityD50KmValueFinder bedMeasurementsFinder; private final SoilKindKmValueFinder soilKindFinder; private final BedHeightsFinder bedHeightsProvider; private final WaterlevelValuesFinder waterlevelProvider; private final DischargeValuesFinder dischargeProvider; private final FlowVelocityModelKmValueFinder flowVelocitiesFinder; public static TkhCalculator buildTkhCalculator(final boolean useTkh, final Calculation problems, final String label, final River river, final DoubleRange calcRange, final WaterlevelValuesFinder waterlevelProvider, final DischargeValuesFinder dischargeProvider, final BedHeightsFinder bedHeightsProvider) { if (!useTkh) return new TkhCalculator(null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); if (!dischargeProvider.isValid()) { problems.addProblem("sinfo_calc_flow_depth.warning.missingQ", label); return new TkhCalculator(null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); } /* access bed quality data */ final int soundingYear = bedHeightsProvider.getInfo().getYear(); final BedQualityD50KmValueFinder bedMeasurementsFinder = BedQualityD50KmValueFinder.loadBedMeasurements(problems, river, calcRange, soundingYear); if (bedMeasurementsFinder == null) return new TkhCalculator(null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); /* access bed soil kind data */ final SoilKindKmValueFinder soilKindFinder = SoilKindKmValueFinder.loadValues(problems, river, calcRange); if (soilKindFinder == null) return new TkhCalculator(null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); final DoubleRange qRange = dischargeProvider.getRange(); final FlowVelocityModelKmValueFinder flowVelocitiesFinder = FlowVelocityModelKmValueFinder.loadValues(problems, river, calcRange, qRange); if (flowVelocitiesFinder == null) return new TkhCalculator(null, waterlevelProvider, dischargeProvider, bedHeightsProvider, null, null); return new TkhCalculator(bedMeasurementsFinder, waterlevelProvider, dischargeProvider, bedHeightsProvider, soilKindFinder, flowVelocitiesFinder); } private TkhCalculator(final BedQualityD50KmValueFinder bedMeasurementsFinder, final WaterlevelValuesFinder waterlevelProvider, final DischargeValuesFinder dischargeProvider, final BedHeightsFinder bedHeightsProvider, final SoilKindKmValueFinder soilKindFinder, final FlowVelocityModelKmValueFinder flowVelocitiesFinder) { this.bedMeasurementsFinder = bedMeasurementsFinder; this.waterlevelProvider = waterlevelProvider; this.dischargeProvider = dischargeProvider; this.bedHeightsProvider = bedHeightsProvider; this.soilKindFinder = soilKindFinder; this.flowVelocitiesFinder = flowVelocitiesFinder; } public boolean hasTkh() { if (this.dischargeProvider == null || !this.dischargeProvider.isValid()) return false; if (this.bedMeasurementsFinder == null) return false; if (this.soilKindFinder == null) return false; if (this.flowVelocitiesFinder == null) return false; return true; } private SoilKind getSoilKind(final double km) { if (this.soilKindFinder == null) return null; return this.soilKindFinder.findSoilKind(km); } private double getBedMeasurement(final double km) { return this.bedMeasurementsFinder.findD50(km); } public TkhCalculateState calculateTkh(final double km, final ResultRow row) { row.putValue(GeneralResultType.station, km); final SoilKind kind = getSoilKind(km); row.putValue(SInfoResultType.soilkind, kind); final double wst = this.waterlevelProvider.getWaterlevel(km); row.putValue(SInfoResultType.waterlevel, wst); if (Double.isNaN(wst)) return TkhCalculateState.NO_W; final double meanBedHeight = this.bedHeightsProvider.getMeanBedHeight(km); row.putValue(SInfoResultType.meanBedHeight, meanBedHeight); if (Double.isNaN(meanBedHeight)) return TkhCalculateState.NO_BED_HEIGHT; final double flowDepth = wst - meanBedHeight; row.putValue(SInfoResultType.flowdepth, flowDepth); final double discharge = this.dischargeProvider.getDischarge(km); row.putValue(SInfoResultType.discharge, discharge); if (!this.hasTkh()) return TkhCalculateState.SUCCESS; // Missing discharge or kind is only a problem if we want to calculate tkh if (Double.isNaN(discharge)) return TkhCalculateState.NO_DISCHARGE; if (kind == null) return TkhCalculateState.NO_SOILKIND; final double d50 = getBedMeasurement(km); row.putValue(SInfoResultType.d50, d50 * 1000); if (Double.isNaN(d50)) return TkhCalculateState.NO_D50; if (!this.flowVelocitiesFinder.findKmQValues(km, discharge)) return TkhCalculateState.NO_VELOCITY; final double velocity = this.flowVelocitiesFinder.getFindVmainFound(); row.putValue(SInfoResultType.velocity, velocity); if (Double.isNaN(velocity)) return TkhCalculateState.NO_VELOCITY; final double tau = this.flowVelocitiesFinder.getFindTauFound(); row.putValue(SInfoResultType.tau, tau); if (Double.isNaN(tau)) return TkhCalculateState.NO_VELOCITY; final double tkh = calculateTkh(flowDepth, velocity, d50, tau); row.putValue(SInfoResultType.tkh, tkh); if (Double.isNaN(tkh)) return TkhCalculateState.NO_TKH; switch (kind) { case starr: row.putValue(SInfoResultType.tkhup, Math.rint(tkh)); row.putValue(SInfoResultType.tkhdown, 0.0); break; case mobil: default: row.putValue(SInfoResultType.tkhup, Math.rint(tkh / 2)); row.putValue(SInfoResultType.tkhdown, -(Math.rint(tkh / 2))); break; } final double flowDepthTkh = calculateFlowDepthTkh(tkh, kind, flowDepth); row.putValue(SInfoResultType.flowdepthtkh, flowDepthTkh); return TkhCalculateState.SUCCESS; } /** * 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 (!), never negative */ private double calculateTkh(final double h, final double vm, final double d50, final 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; final double tkh = 100 * h * (1 - Math.pow(froude, 2)) / (2 * PHYS_VELOCCOEFF_N * PHYS_FORMCOEFF_ALPHA) * (1 - critTau / tau); // Some regular input values may give a negative calculation result; that is unwanted if (tkh < 0.0) return 0.0; return tkh; } private double calculateFlowDepthTkh(final double tkhValue, final SoilKind tkhKind, final double flowDepth) { switch (tkhKind) { case starr: return flowDepth - Math.rint(tkhValue) / 100.0; case mobil: default: return flowDepth - Math.rint(tkhValue / 2) / 100.0; } } }