Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8877:9f7a285b0ee3
Some work on SINFO FlowDepth
author | gernotbelger |
---|---|
date | Thu, 08 Feb 2018 18:48:24 +0100 |
parents | 1009cab0f86b |
children | 64ca63f79f6f |
comparison
equal
deleted
inserted
replaced
8876:23264d1a528f | 8877:9f7a285b0ee3 |
---|---|
1 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde | 1 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde |
2 * Software engineering by | 2 * Software engineering by |
3 * Björnsen Beratende Ingenieure GmbH | 3 * Björnsen Beratende Ingenieure GmbH |
4 * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt | 4 * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt |
5 * | 5 * |
6 * This file is Free Software under the GNU AGPL (>=v3) | 6 * This file is Free Software under the GNU AGPL (>=v3) |
7 * and comes with ABSOLUTELY NO WARRANTY! Check out the | 7 * and comes with ABSOLUTELY NO WARRANTY! Check out the |
8 * documentation coming with Dive4Elements River for details. | 8 * documentation coming with Dive4Elements River for details. |
15 import org.dive4elements.artifacts.CallContext; | 15 import org.dive4elements.artifacts.CallContext; |
16 import org.dive4elements.river.artifacts.BedHeightsArtifact; | 16 import org.dive4elements.river.artifacts.BedHeightsArtifact; |
17 import org.dive4elements.river.artifacts.model.Calculation; | 17 import org.dive4elements.river.artifacts.model.Calculation; |
18 import org.dive4elements.river.artifacts.model.CalculationResult; | 18 import org.dive4elements.river.artifacts.model.CalculationResult; |
19 import org.dive4elements.river.artifacts.model.LocationProvider; | 19 import org.dive4elements.river.artifacts.model.LocationProvider; |
20 import org.dive4elements.river.artifacts.model.QKms; | |
20 import org.dive4elements.river.artifacts.model.WKms; | 21 import org.dive4elements.river.artifacts.model.WKms; |
21 import org.dive4elements.river.artifacts.resources.Resources; | 22 import org.dive4elements.river.artifacts.resources.Resources; |
22 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; | 23 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; |
23 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; | 24 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; |
24 import org.dive4elements.river.artifacts.states.WDifferencesState; | 25 import org.dive4elements.river.artifacts.states.WDifferencesState; |
30 | 31 |
31 class FlowDepthCalculation { | 32 class FlowDepthCalculation { |
32 | 33 |
33 private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range"; | 34 private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range"; |
34 | 35 |
35 private CallContext context; | 36 private final CallContext context; |
36 | 37 |
37 public FlowDepthCalculation( final CallContext context ) { | 38 public FlowDepthCalculation( final CallContext context ) { |
38 this.context = context; | 39 this.context = context; |
39 } | 40 } |
40 | 41 |
41 public CalculationResult calculate(final SINFOArtifact sinfo) { | 42 public CalculationResult calculate(final SINFOArtifact sinfo) { |
42 | 43 |
43 // FIXME: find user of this artifact; probably only possible by selecting the collection that contains this artifact... | 44 // FIXME: find user of this artifact; probably only possible by selecting the collection that contains this artifact... |
44 final String user = "unbekannt"; | 45 final String user = "unbekannt"; |
45 | |
46 /* access input data */ | |
47 final FlowDepthAccess access = new FlowDepthAccess(sinfo); | |
48 final River river = access.getRiver(); | |
49 | |
50 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); | |
51 | |
52 final double from = access.getFrom(); | |
53 final double to = access.getTo(); | |
54 | 46 |
55 final boolean useTkh = access.isUseTransportBodies(); | 47 /* access input data */ |
48 final FlowDepthAccess access = new FlowDepthAccess(sinfo); | |
49 final River river = access.getRiver(); | |
56 | 50 |
57 /* calculate results for each diff pair */ | 51 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); |
58 final Calculation problems = new Calculation(); | |
59 | 52 |
60 final List<Gauge> gauges = river.determineGauges(from, to); | 53 final double from = access.getFrom(); |
61 final GaugeIndex gaugeIndex = new GaugeIndex(gauges); | 54 final double to = access.getTo(); |
62 | 55 |
63 final String calcModeLabel = Resources.getMsg(context.getMeta(),sinfo.getCalculationMode().name() ); | 56 final boolean useTkh = access.isUseTransportBodies(); |
64 | 57 |
65 | 58 /* calculate results for each diff pair */ |
59 final Calculation problems = new Calculation(); | |
60 | |
61 final List<Gauge> gauges = river.determineGauges(from, to); | |
62 final GaugeIndex gaugeIndex = new GaugeIndex(gauges); | |
63 | |
64 final String calcModeLabel = Resources.getMsg(this.context.getMeta(),sinfo.getCalculationMode().name() ); | |
65 | |
66 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from, to, useTkh); | 66 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from, to, useTkh); |
67 | 67 |
68 for (final DifferencesPair diffPair : diffPairs) { | 68 for (final DifferencesPair diffPair : diffPairs) { |
69 final FlowDepthCalculationResult result = calculateResult( river, from, to, diffPair, problems, gaugeIndex ); | 69 final FlowDepthCalculationResult result = calculateResult( river, from, to, diffPair, problems, gaugeIndex ); |
70 if( result != null ) | 70 if( result != null ) |
71 results.addResult(result); | 71 results.addResult(result); |
72 } | 72 } |
73 | 73 |
74 return new CalculationResult(results,problems); | 74 return new CalculationResult(results,problems); |
75 } | 75 } |
76 | 76 |
77 private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair, final Calculation problems, final GaugeIndex gaugeIndex) { | 77 private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair, final Calculation problems, final GaugeIndex gaugeIndex) { |
78 | 78 |
79 /* access real input data from database */ | 79 /* access real input data from database */ |
80 final String soundingId = diffPair.getSoundingId(); | 80 final String soundingId = diffPair.getSoundingId(); |
81 final String wstId = diffPair.getWstId(); | 81 final String wstId = diffPair.getWstId(); |
82 | 82 |
83 final BedHeight bedHeight = loadBedHeight( soundingId, from, to ); | 83 final BedHeight bedHeight = loadBedHeight( soundingId, from, to ); |
84 final WKms wstKms = new WDifferencesState().getWKms(wstId, context, from, to); | 84 if( bedHeight == null ) |
85 if( bedHeight == null || wstKms == null ) | 85 { |
86 return null; | 86 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); |
87 problems.addProblem(message); | |
88 return null; | |
89 } | |
87 | 90 |
88 final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(wstKms.getName(), bedHeight.getDescription()); | 91 final WKms wstKms = new WDifferencesState().getWKms(wstId, this.context, from, to); |
92 if( wstKms == null ) | |
93 { | |
94 final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'", wstId); | |
95 problems.addProblem(message); | |
96 return null; | |
97 } | |
89 | 98 |
90 final String notinrange = Resources.getMsg(context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); | 99 // FIXME: woher bekommen? |
100 final int wspYear = 0; | |
91 | 101 |
92 // TODO: unklarheiten | 102 final String wspLabel = wstKms.getName(); |
93 // 'idealerweise alle 100m' was heisst das? kann doch nur durch datenverfügbarkeit bestimmt werden | 103 final String soundingLabel = bedHeight.getDescription(); |
94 // wie mit unterschiedlichen Ranges umgehen? Schnitt bilden? Fehlermeldung? ...? | 104 final String label = String.format("%s - %s", wspLabel, soundingLabel); |
95 // wie interpolieren? wst interpolieren? peilung interpolieren? | |
96 | 105 |
97 // FIXME: für die Berechnung der TKH sind weitere 'in FLYS vorliegende' Daten notwendig. | 106 final BedHeightInfo sounding = BedHeightInfo.from(bedHeight); |
98 // aktuell unklar ob das durch andere Barten berechnete Werte oder Basisdaten sind | 107 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear); |
99 // TODO: check Vergleiche BArt 'Transportkörperhöhen' | |
100 | |
101 // TODO: Berechnung der Transportkörperhöhen | |
102 // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht einmal berechnen und in db ablegen? | |
103 | 108 |
104 final String bedHeightLabel = bedHeight.getDescription(); | 109 final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding); |
105 final String wstLabel = wstKms.getName(); | |
106 | 110 |
107 for (int i = 0; i < wstKms.size(); i++) { | 111 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); |
108 | 112 |
109 final double km = wstKms.getKm(i); | 113 // TODO: prüfe diskretisierung wsp --> > 1000m --> Fehlermeldung |
110 final double wst = wstKms.getW(i); | |
111 // FIXME: interpolate from bedheights? | |
112 final double meanBedHeight = 79.32; | |
113 | 114 |
114 final double flowDepth = wst - meanBedHeight; | 115 // TODO: Berechnung der Transportkörperhöhen |
115 | 116 // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht einmal berechnen und in db ablegen? |
116 final double tkh = 0; | |
117 final double flowDepthTkh = flowDepth - tkh; | |
118 | |
119 // FIXME: discharge not available for all wst? or any? | |
120 final double discharge = 0.0; | |
121 | 117 |
122 // REMARK: access the location once only during calculation | 118 // Benötigte Daten |
123 final String location = LocationProvider.getLocation(river.getName(), km); | 119 // - Abfluss / Station |
124 | 120 // - kein Abfluss --> Fehler |
125 // REMARK: access the gauge once only during calculation | 121 if( !(wstKms instanceof QKms)) |
126 final Gauge gauge = gaugeIndex.findGauge(km); | 122 { |
127 final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); | 123 final String message = Resources.format(this.context.getMeta(), "{0}: keine Abflussdaten vorhanden, Transportkörperhöhenberechnung nicht möglich", label); |
128 | 124 problems.addProblem(message); |
129 resultData.addRow( km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel, location ); | 125 // TODO: keine Berechnung TKH |
130 } | 126 } |
131 | |
132 return resultData; | |
133 } | |
134 | 127 |
135 private BedHeight loadBedHeight(final String soundingId, final double from, final double to) { | 128 // - Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb) |
136 | 129 // - Abhängig von Peiljahr |
137 // FIXME: absolutely unbelievable.... | 130 // - kein D50 vorhanden --> Fehler |
138 // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type throughout flys. | 131 // - Art der Gewässersohle (starr/mobil) |
139 // The knowledge on how to parse the datacage-ids is spread thorugh the complete code-base... | |
140 | 132 |
141 // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but this is plain random | |
142 final String[] parts = soundingId.split(";"); | |
143 | 133 |
144 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], context); | 134 final String bedHeightLabel = bedHeight.getDescription(); |
135 final String wstLabel = wstKms.getName(); | |
145 | 136 |
146 final Integer bedheightId = artifact.getDataAsInteger("height_id"); | 137 // FIXME: basis der diskretisierung ist bedHeight, die wspl werden interpoliert |
147 // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the other type means) | 138 for (int i = 0; i < wstKms.size(); i++) { |
148 // Luckily, the requirement is to only access 'single' data here. | 139 |
149 // final String bedheightType = artifact.getDataAsString("type"); | 140 final double km = wstKms.getKm(i); |
150 | 141 final double wst = wstKms.getW(i); |
151 // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight | 142 // FIXME: interpolate from bedheights? |
152 // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via hibernate stuff | 143 final double meanBedHeight = 79.32; |
153 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. | 144 |
154 //return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); | 145 final double flowDepth = wst - meanBedHeight; |
155 | 146 |
156 return BedHeight.getBedHeightById(bedheightId); | 147 final double discharge = wstKms instanceof QKms ? ((QKms) wstKms).getQ(i) : Double.NaN; |
157 } | 148 |
149 // FIXME: calculate tkh | |
150 final double tkh = 0; | |
151 final double flowDepthTkh = flowDepth - tkh; | |
152 | |
153 | |
154 // REMARK: access the location once only during calculation | |
155 final String location = LocationProvider.getLocation(river.getName(), km); | |
156 | |
157 // REMARK: access the gauge once only during calculation | |
158 // FIXME: copy specific handling from original wst | |
159 final Gauge gauge = gaugeIndex.findGauge(km); | |
160 final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); | |
161 | |
162 resultData.addRow( km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel, location ); | |
163 } | |
164 | |
165 return resultData; | |
166 } | |
167 | |
168 private BedHeight loadBedHeight(final String soundingId, final double from, final double to) { | |
169 | |
170 // FIXME: absolutely unbelievable.... | |
171 // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type throughout flys. | |
172 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... | |
173 | |
174 // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but this is plain random | |
175 final String[] parts = soundingId.split(";"); | |
176 | |
177 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context); | |
178 | |
179 final Integer bedheightId = artifact.getDataAsInteger("height_id"); | |
180 // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the other type means) | |
181 // Luckily, the requirement is to only access 'single' data here. | |
182 // final String bedheightType = artifact.getDataAsString("type"); | |
183 | |
184 // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight | |
185 // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via hibernate stuff | |
186 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. | |
187 //return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); | |
188 | |
189 return BedHeight.getBedHeightById(bedheightId); | |
190 } | |
158 } | 191 } |