Mercurial > dive4elements > river
diff artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8883:a536e1aacf0f
Further work on SINFO-FlowDepth
author | gernotbelger |
---|---|
date | Fri, 09 Feb 2018 18:07:22 +0100 |
parents | f762fadc5313 |
children | 7a8c12706834 |
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Fri Feb 09 16:11:47 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Fri Feb 09 18:07:22 2018 +0100 @@ -9,9 +9,13 @@ */ package org.dive4elements.river.artifacts.sinfo.flowdepth; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.UnivariateRealFunction; import org.dive4elements.artifacts.ArtifactDatabase; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.BedHeightsArtifact; @@ -26,8 +30,10 @@ import org.dive4elements.river.artifacts.states.WaterlevelData; import org.dive4elements.river.artifacts.states.WaterlevelFetcher; import org.dive4elements.river.model.BedHeight; +import org.dive4elements.river.model.BedHeightValue; import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.River; +import org.dive4elements.river.utils.DoubleUtil; import org.dive4elements.river.utils.GaugeIndex; import org.dive4elements.river.utils.RiverUtils; @@ -107,10 +113,12 @@ } final WKms wstKms = waterlevel.getWkms(); - checkWaterlevelDiscretisation(wstKms, problems); + final String wspLabel = wstKms.getName(); + final String soundingLabel = bedHeight.getDescription(); + final String label = String.format("%s - %s", wspLabel, soundingLabel); - // FIXME: woher bekommen? - final int wspYear = 0; + checkYearDifference(label, waterlevel, bedHeight, problems); + checkWaterlevelDiscretisation(wstKms, problems); /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, @@ -119,22 +127,14 @@ final Gauge refGauge = waterlevel.findReferenceGauge(river); final String refGaugeName = refGauge == null ? notinrange : refGauge.getName(); - final String wspLabel = wstKms.getName(); - final String soundingLabel = bedHeight.getDescription(); - final String label = String.format("%s - %s", wspLabel, soundingLabel); - final BedHeightInfo sounding = BedHeightInfo.from(bedHeight); + final int wspYear = waterlevel.getYear(); final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, refGaugeName); final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding); - // TODO: Berechnung der Transportkörperhöhen - // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht - // einmal berechnen und in db ablegen? - - // Benötigte Daten - // - Abfluss / Station - // - kein Abfluss --> Fehler + // FIXME: nur prüfen/beschaffen wenn TKH Berechnung aktiv + /* Abflusswerte vorhanden? */ if (!(wstKms instanceof QKms)) { final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ", null, label); @@ -145,42 +145,115 @@ // - Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb) // - Abhängig von Peiljahr // - kein D50 vorhanden --> Fehler + // - Art der Gewässersohle (starr/mobil) final String bedHeightLabel = bedHeight.getDescription(); final String wstLabel = wstKms.getName(); - // FIXME: basis der diskretisierung ist bedHeight, die wspl werden interpoliert - for (int i = 0; i < wstKms.size(); i++) { - - final double km = wstKms.getKm(i); - final double wst = wstKms.getW(i); - // FIXME: interpolate from bedheights? - final double meanBedHeight = 79.32; - - final double flowDepth = wst - meanBedHeight; - - final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN; + final UnivariateRealFunction wstInterpolator = DoubleUtil.getLinearInterpolator(wstKms.allKms(), + wstKms.allWs()); - // FIXME: calculate tkh - final double tkh = 0; - final double flowDepthTkh = flowDepth - tkh; - - // REMARK: access the location once only during calculation - final String location = LocationProvider.getLocation(river.getName(), km); + // FIXME: sort by station first, but in what direction? + final List<BedHeightValue> values = bedHeight.getValues(); - // REMARK: access the gauge once only during calculation - final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km); + final List<BedHeightValue> sortedValues = new ArrayList<>(values); + Collections.sort(sortedValues, new BedHeightStationComparator()); - final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); + for (final BedHeightValue bedHeightValue : sortedValues) { - resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, - bedHeightLabel, location); + final Double station = bedHeightValue.getStation(); + if (station == null || station.isNaN()) + continue; + + final Double meanBedHeightDbl = bedHeightValue.getHeight(); + if (meanBedHeightDbl == null || meanBedHeightDbl.isNaN()) + continue; + + final double km = station; + final double meanBedHeight = meanBedHeightDbl; + + try { + // FIXME: check out of range + final double wst = wstInterpolator.value(km); + + final double flowDepth = wst - meanBedHeight; + + // FIXME: piecewise constant interpolation? + // final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN; + final double discharge = Double.NaN; + + // FIXME: calculate tkh + final double tkh = 0; + final double flowDepthTkh = flowDepth - tkh; + + // REMARK: access the location once only during calculation + final String location = LocationProvider.getLocation(river.getName(), km); + + // REMARK: access the gauge once only during calculation + final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km); + + final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); + + resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, + bedHeightLabel, location); + } + catch (final FunctionEvaluationException e) { + /* should only happen if out of range */ + e.printStackTrace(); + /* simply ignore */ + } + } return resultData; } + /** + * Checks the year difference between waterlevels and sounding, and issues a warning if too big. + * + * Zeitraum Zeitliche Differenz [a] + * X ≥ 1998 ± 3 + * 1958 ≤ X < 1998 ± 6 + * 1918 ≤ X < 1958 ± 12 + * X < 1918 ± 25 + */ + private void checkYearDifference(final String label, final WaterlevelData waterlevel, final BedHeight sounding, + final Calculation problems) { + + final Integer soundingYear = sounding.getYear(); + if (soundingYear == null) + return; + + final int wstYear = waterlevel.getYear(); + if (wstYear < 0) + return; + + final int maxDifference = getMaxDifferenceYears(soundingYear); + + final int difference = Math.abs(soundingYear - wstYear); + if (difference > maxDifference) { + final String message = Resources.getMsg(this.context.getMeta(), + "sinfo_calc_flow_depth.warning.year_difference", null, label, difference); + problems.addProblem(message); + } + } + + private int getMaxDifferenceYears(final int year) { + + if (year < 1918) + return 25; + + if (1918 <= year && year < 1958) + return 12; + + if (1958 <= year && year < 1998) + return 6; + + /* >= 1998 */ + return 3; + } + private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex, final double km) { @@ -216,7 +289,7 @@ private BedHeight loadBedHeight(final String soundingId, final double from, final double to) { - // FIXME: absolutely unbelievable.... + // REMARK: absolutely unbelievable.... // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type // throughout flys. // The knowledge on how to parse the datacage-ids is spread through the complete code-base... @@ -228,17 +301,17 @@ final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context); final Integer bedheightId = artifact.getDataAsInteger("height_id"); - // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the + // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the // other type means) // Luckily, the requirement is to only access 'single' data here. // final String bedheightType = artifact.getDataAsString("type"); - // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight - // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via + // REMARK: BedDifferences uses this, but we also need the metadata of the BedHeight + // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via // hibernate stuff // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); return BedHeight.getBedHeightById(bedheightId); } -} \ No newline at end of file +}