comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8882:f762fadc5313

Further work on SINFO-FlowDepth
author gernotbelger
date Fri, 09 Feb 2018 16:11:47 +0100
parents 64ca63f79f6f
children a536e1aacf0f
comparison
equal deleted inserted replaced
8881:6b93a2498e06 8882:f762fadc5313
21 import org.dive4elements.river.artifacts.model.QKms; 21 import org.dive4elements.river.artifacts.model.QKms;
22 import org.dive4elements.river.artifacts.model.WKms; 22 import org.dive4elements.river.artifacts.model.WKms;
23 import org.dive4elements.river.artifacts.resources.Resources; 23 import org.dive4elements.river.artifacts.resources.Resources;
24 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; 24 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
25 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; 25 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair;
26 import org.dive4elements.river.artifacts.states.WDifferencesState; 26 import org.dive4elements.river.artifacts.states.WaterlevelData;
27 import org.dive4elements.river.artifacts.states.WaterlevelFetcher;
27 import org.dive4elements.river.model.BedHeight; 28 import org.dive4elements.river.model.BedHeight;
28 import org.dive4elements.river.model.Gauge; 29 import org.dive4elements.river.model.Gauge;
29 import org.dive4elements.river.model.River; 30 import org.dive4elements.river.model.River;
30 import org.dive4elements.river.utils.GaugeIndex; 31 import org.dive4elements.river.utils.GaugeIndex;
31 import org.dive4elements.river.utils.RiverUtils; 32 import org.dive4elements.river.utils.RiverUtils;
34 35
35 private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range"; 36 private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range";
36 37
37 private final CallContext context; 38 private final CallContext context;
38 39
39 public FlowDepthCalculation( final CallContext context ) { 40 public FlowDepthCalculation(final CallContext context) {
40 this.context = context; 41 this.context = context;
41 } 42 }
42 43
43 public CalculationResult calculate(final SINFOArtifact sinfo) { 44 public CalculationResult calculate(final SINFOArtifact sinfo) {
44 45
64 final Calculation problems = new Calculation(); 65 final Calculation problems = new Calculation();
65 66
66 final List<Gauge> gauges = river.determineGauges(from, to); 67 final List<Gauge> gauges = river.determineGauges(from, to);
67 final GaugeIndex gaugeIndex = new GaugeIndex(gauges); 68 final GaugeIndex gaugeIndex = new GaugeIndex(gauges);
68 69
69 final String calcModeLabel = Resources.getMsg(this.context.getMeta(),sinfo.getCalculationMode().name() ); 70 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name());
70 71
71 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from, to, useTkh); 72 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, river, from,
73 to, useTkh);
72 74
73 for (final DifferencesPair diffPair : diffPairs) { 75 for (final DifferencesPair diffPair : diffPairs) {
74 final FlowDepthCalculationResult result = calculateResult( river, from, to, diffPair, problems, gaugeIndex ); 76 final FlowDepthCalculationResult result = calculateResult(river, from, to, diffPair, problems, gaugeIndex);
75 if( result != null ) 77 if (result != null)
76 results.addResult(result); 78 results.addResult(result);
77 } 79 }
78 80
79 return new CalculationResult(results,problems); 81 return new CalculationResult(results, problems);
80 } 82 }
81 83
82 private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair, final Calculation problems, final GaugeIndex gaugeIndex) { 84 private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to,
85 final DifferencesPair diffPair, final Calculation problems, final GaugeIndex gaugeIndex) {
83 86
84 /* access real input data from database */ 87 /* access real input data from database */
85 final String soundingId = diffPair.getSoundingId(); 88 final String soundingId = diffPair.getSoundingId();
86 final String wstId = diffPair.getWstId(); 89 final String wstId = diffPair.getWstId();
87 90
88 final BedHeight bedHeight = loadBedHeight( soundingId, from, to ); 91 final BedHeight bedHeight = loadBedHeight(soundingId, from, to);
89 if( bedHeight == null ) 92 if (bedHeight == null) {
90 { 93 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'",
91 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); 94 soundingId);
92 problems.addProblem(message); 95 problems.addProblem(message);
93 return null; 96 return null;
94 } 97 }
95 98
96 final WKms wstKms = new WDifferencesState().getWKms(wstId, this.context, from, to); 99 /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */
97 if( wstKms == null ) 100 final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN,
98 { 101 Double.NaN);
99 final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'", wstId); 102 if (waterlevel == null) {
103 final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'",
104 wstId);
100 problems.addProblem(message); 105 problems.addProblem(message);
101 return null; 106 return null;
102 } 107 }
108 final WKms wstKms = waterlevel.getWkms();
109
110 checkWaterlevelDiscretisation(wstKms, problems);
103 111
104 // FIXME: woher bekommen? 112 // FIXME: woher bekommen?
105 final int wspYear = 0; 113 final int wspYear = 0;
106 // FIXME: angeblich metadatum bestimmter wsps? 114
107 // Könnte 'source' an 'wst_columns' sein 115 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */
108 final String wspSource = "FIXME"; 116 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE,
109 // FIXME: Umsetzung IDENTISCH zu allen möglichen Arten wie ein WSPL berechnet wird.... 117 CSV_NOT_IN_GAUGE_RANGE);
110 final String wspGauge = "FIXME"; 118
119 final Gauge refGauge = waterlevel.findReferenceGauge(river);
120 final String refGaugeName = refGauge == null ? notinrange : refGauge.getName();
111 121
112 final String wspLabel = wstKms.getName(); 122 final String wspLabel = wstKms.getName();
113 final String soundingLabel = bedHeight.getDescription(); 123 final String soundingLabel = bedHeight.getDescription();
114 final String label = String.format("%s - %s", wspLabel, soundingLabel); 124 final String label = String.format("%s - %s", wspLabel, soundingLabel);
115 125
116 final BedHeightInfo sounding = BedHeightInfo.from(bedHeight); 126 final BedHeightInfo sounding = BedHeightInfo.from(bedHeight);
117 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, wspSource, wspGauge); 127 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, refGaugeName);
118 128
119 final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding); 129 final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(label, wstInfo, sounding);
120 130
121 final String notinrange = Resources.getMsg(this.context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE);
122
123 // TODO: prüfe diskretisierung wsp --> > 1000m --> Fehlermeldung
124
125 // TODO: Berechnung der Transportkörperhöhen 131 // TODO: Berechnung der Transportkörperhöhen
126 // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht einmal berechnen und in db ablegen? 132 // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht
133 // einmal berechnen und in db ablegen?
127 134
128 // Benötigte Daten 135 // Benötigte Daten
129 // - Abfluss / Station 136 // - Abfluss / Station
130 // - kein Abfluss --> Fehler 137 // - kein Abfluss --> Fehler
131 if( !(wstKms instanceof QKms)) 138 if (!(wstKms instanceof QKms)) {
132 { 139 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.missingQ",
133 final String message = Resources.format(this.context.getMeta(), "{0}: keine Abflussdaten vorhanden, Transportkörperhöhenberechnung nicht möglich", label); 140 null, label);
134 problems.addProblem(message); 141 problems.addProblem(message);
135 // TODO: keine Berechnung TKH 142 // TODO: keine Berechnung TKH
136 } 143 }
137 144
138 // - Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb) 145 // - Sohlbeschaffenheit (D50 Korndurchmesser aus Seddb)
139 // - Abhängig von Peiljahr 146 // - Abhängig von Peiljahr
140 // - kein D50 vorhanden --> Fehler 147 // - kein D50 vorhanden --> Fehler
141 // - Art der Gewässersohle (starr/mobil) 148 // - Art der Gewässersohle (starr/mobil)
142
143 149
144 final String bedHeightLabel = bedHeight.getDescription(); 150 final String bedHeightLabel = bedHeight.getDescription();
145 final String wstLabel = wstKms.getName(); 151 final String wstLabel = wstKms.getName();
146 152
147 // FIXME: basis der diskretisierung ist bedHeight, die wspl werden interpoliert 153 // FIXME: basis der diskretisierung ist bedHeight, die wspl werden interpoliert
162 168
163 // REMARK: access the location once only during calculation 169 // REMARK: access the location once only during calculation
164 final String location = LocationProvider.getLocation(river.getName(), km); 170 final String location = LocationProvider.getLocation(river.getName(), km);
165 171
166 // REMARK: access the gauge once only during calculation 172 // REMARK: access the gauge once only during calculation
167 // FIXME: copy specific handling from original wst 173 final Gauge gauge = findGauge(waterlevel, refGauge, gaugeIndex, km);
168 final Gauge gauge = gaugeIndex.findGauge(km); 174
169 final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); 175 final String gaugeLabel = gauge == null ? notinrange : gauge.getName();
170 176
171 resultData.addRow( km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel, location ); 177 resultData.addRow(km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight,
178 bedHeightLabel, location);
172 } 179 }
173 180
174 return resultData; 181 return resultData;
175 } 182 }
176 183
184 private Gauge findGauge(final WaterlevelData waterlevel, final Gauge refGauge, final GaugeIndex gaugeIndex,
185 final double km) {
186
187 // REMARK: using same logic as in WaterlevelExporter here
188
189 final boolean showAllGauges = waterlevel.isShowAllGauges();
190
191 if (showAllGauges)
192 return gaugeIndex.findGauge(km);
193
194 if (refGauge.getRange().contains(km))
195 return refGauge;
196
197 return null;
198 }
199
200 /* Checks if the discretisation of the waterlevel exceeds 1000m */
201 private void checkWaterlevelDiscretisation(final WKms wstKms, final Calculation problems) {
202 final int size = wstKms.size();
203 for (int i = 0; i < size - 2; i++) {
204 final double kmPrev = wstKms.getKm(i);
205 final double kmNext = wstKms.getKm(i + 1);
206
207 if (Math.abs(kmPrev - kmNext) > 1) {
208 final String label = wstKms.getName();
209
210 final String message = Resources.getMsg(this.context.getMeta(),
211 "sinfo_calc_flow_depth.warning.waterlevel_discretisation", null, label);
212 problems.addProblem(kmPrev, message);
213 }
214 }
215 }
216
177 private BedHeight loadBedHeight(final String soundingId, final double from, final double to) { 217 private BedHeight loadBedHeight(final String soundingId, final double from, final double to) {
178 218
179 // FIXME: absolutely unbelievable.... 219 // FIXME: absolutely unbelievable....
180 // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type throughout flys. 220 // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type
221 // throughout flys.
181 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... 222 // The knowledge on how to parse the datacage-ids is spread through the complete code-base...
182 223
183 // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but this is plain random 224 // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but
225 // this is plain random
184 final String[] parts = soundingId.split(";"); 226 final String[] parts = soundingId.split(";");
185 227
186 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context); 228 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context);
187 229
188 final Integer bedheightId = artifact.getDataAsInteger("height_id"); 230 final Integer bedheightId = artifact.getDataAsInteger("height_id");
189 // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the other type means) 231 // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the
232 // other type means)
190 // Luckily, the requirement is to only access 'single' data here. 233 // Luckily, the requirement is to only access 'single' data here.
191 // final String bedheightType = artifact.getDataAsString("type"); 234 // final String bedheightType = artifact.getDataAsString("type");
192 235
193 // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight 236 // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight
194 // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via hibernate stuff 237 // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via
238 // hibernate stuff
195 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. 239 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes.
196 //return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); 240 // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to);
197 241
198 return BedHeight.getBedHeightById(bedheightId); 242 return BedHeight.getBedHeightById(bedheightId);
199 } 243 }
200 } 244 }

http://dive4elements.wald.intevation.org