Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java @ 8946:5d5d482da3e9
Implementing SINFO - FlowDepthMinMax calculation
author | gernotbelger |
---|---|
date | Tue, 13 Mar 2018 18:49:33 +0100 |
parents | d9dbf0b74bc2 |
children | 322b0e6298ea |
comparison
equal
deleted
inserted
replaced
8945:4a6b6a3c279c | 8946:5d5d482da3e9 |
---|---|
11 | 11 |
12 import java.util.Collection; | 12 import java.util.Collection; |
13 | 13 |
14 import org.apache.commons.lang.math.DoubleRange; | 14 import org.apache.commons.lang.math.DoubleRange; |
15 import org.dive4elements.artifacts.CallContext; | 15 import org.dive4elements.artifacts.CallContext; |
16 import org.dive4elements.river.artifacts.BedHeightsArtifact; | |
17 import org.dive4elements.river.artifacts.model.Calculation; | 16 import org.dive4elements.river.artifacts.model.Calculation; |
18 import org.dive4elements.river.artifacts.model.CalculationResult; | 17 import org.dive4elements.river.artifacts.model.CalculationResult; |
19 import org.dive4elements.river.artifacts.model.WKms; | 18 import org.dive4elements.river.artifacts.model.WKms; |
20 import org.dive4elements.river.artifacts.resources.Resources; | 19 import org.dive4elements.river.artifacts.resources.Resources; |
21 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; | 20 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; |
22 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; | 21 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; |
23 import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; | |
24 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder; | 22 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder; |
25 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator; | 23 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator; |
24 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.WaterlevelValuesFinder; | |
26 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; | 25 import org.dive4elements.river.artifacts.sinfo.tkhstate.BedHeightsFinder; |
27 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; | 26 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; |
28 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; | 27 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; |
29 import org.dive4elements.river.artifacts.sinfo.util.WstInfo; | 28 import org.dive4elements.river.artifacts.sinfo.util.WstInfo; |
30 import org.dive4elements.river.artifacts.states.WaterlevelData; | 29 import org.dive4elements.river.artifacts.states.WaterlevelData; |
31 import org.dive4elements.river.artifacts.states.WaterlevelFetcher; | 30 import org.dive4elements.river.artifacts.states.WaterlevelFetcher; |
32 import org.dive4elements.river.model.River; | 31 import org.dive4elements.river.model.River; |
33 import org.dive4elements.river.utils.RiverUtils; | |
34 | 32 |
35 class FlowDepthCalculation { | 33 class FlowDepthCalculation { |
36 | 34 |
37 // private static Logger log = Logger.getLogger(FlowDepthCalculation.class); | 35 // private static Logger log = Logger.getLogger(FlowDepthCalculation.class); |
38 | 36 |
49 /* access input data */ | 47 /* access input data */ |
50 final FlowDepthAccess access = new FlowDepthAccess(sinfo); | 48 final FlowDepthAccess access = new FlowDepthAccess(sinfo); |
51 final River river = access.getRiver(); | 49 final River river = access.getRiver(); |
52 final RiverInfo riverInfo = new RiverInfo(river); | 50 final RiverInfo riverInfo = new RiverInfo(river); |
53 | 51 |
54 final Collection<DifferencesPair> diffPairs = access.getDifferencePairs(); | 52 final Collection<WstSoundingIdPair> diffPairs = access.getDifferencePairs(); |
55 | 53 |
56 final DoubleRange calcRange = access.getRange(); | 54 final DoubleRange calcRange = access.getRange(); |
57 | 55 |
58 final boolean useTkh = access.isUseTransportBodies(); | 56 final boolean useTkh = access.isUseTransportBodies(); |
59 | 57 |
64 | 62 |
65 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); | 63 final String calcModeLabel = Resources.getMsg(this.context.getMeta(), sinfo.getCalculationMode().name()); |
66 | 64 |
67 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); | 65 final FlowDepthCalculationResults results = new FlowDepthCalculationResults(calcModeLabel, user, riverInfo, calcRange, useTkh); |
68 | 66 |
69 for (final DifferencesPair diffPair : diffPairs) { | 67 for (final WstSoundingIdPair diffPair : diffPairs) { |
70 final FlowDepthCalculationResult result = calculateResult(calcRange, diffPair, problems, infoProvider, useTkh); | 68 final FlowDepthCalculationResult result = calculateResult(calcRange, diffPair, problems, infoProvider, useTkh); |
71 if (result != null) | 69 if (result != null) |
72 results.addResult(result); | 70 results.addResult(result); |
73 } | 71 } |
74 | 72 |
78 /** | 76 /** |
79 * Calculates one W-MSH differences pair. | 77 * Calculates one W-MSH differences pair. |
80 * | 78 * |
81 * @param infoProvider | 79 * @param infoProvider |
82 */ | 80 */ |
83 private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final DifferencesPair diffPair, | 81 private FlowDepthCalculationResult calculateResult(final DoubleRange calcRange, final WstSoundingIdPair diffPair, final Calculation problems, |
84 final Calculation problems, final RiverInfoProvider infoProvider, final boolean useTkh) { | 82 final RiverInfoProvider infoProvider, final boolean useTkh) { |
85 | 83 |
86 /* access real input data from database */ | 84 /* access real input data from database */ |
87 final String soundingId = diffPair.getSoundingId(); | 85 final String soundingId = diffPair.getSoundingId(); |
88 final String wstId = diffPair.getWstId(); | 86 final String wstId = diffPair.getWstId(); |
89 | 87 |
90 final BedHeightsFinder bedHeight = loadBedHeight(soundingId, calcRange); | 88 final BedHeightsFinder bedHeight = BedHeightsFinder.forId(this.context, soundingId, calcRange, problems); |
91 if (bedHeight == null) { | 89 if (bedHeight == null) |
92 final String message = Resources.format(this.context.getMeta(), "Failed to access sounding with id '{0}'", soundingId); | |
93 problems.addProblem(message); | |
94 return null; | 90 return null; |
95 } | |
96 | 91 |
97 /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */ | 92 /* REMARK: fetch ALL wst kms, because we want to determine the original reference gauge */ |
98 final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN); | 93 final WaterlevelData waterlevel = new WaterlevelFetcher().findWaterlevel(this.context, wstId, Double.NaN, Double.NaN, problems); |
99 if (waterlevel == null) { | 94 if (waterlevel == null) |
100 final String message = Resources.format(this.context.getMeta(), "Failed to access waterlevel with id '{0}'", wstId); | |
101 problems.addProblem(message); | |
102 return null; | 95 return null; |
103 } | 96 |
104 final WKms wstKms = waterlevel.getWkms(); | 97 final WKms wstKms = waterlevel.getWkms(); |
105 | 98 |
106 final String wspLabel = wstKms.getName(); | 99 final String wspLabel = wstKms.getName(); |
107 final String soundingLabel = bedHeight.getInfo().getDescription(); | 100 final String soundingLabel = bedHeight.getInfo().getDescription(); |
108 final String label = String.format("%s - %s", wspLabel, soundingLabel); | 101 final String label = String.format("%s - %s", wspLabel, soundingLabel); |
109 | 102 |
110 checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems); | 103 FlowDepthUtils.checkYearDifference(label, waterlevel, bedHeight.getInfo().getYear(), problems); |
111 checkWaterlevelDiscretisation(wstKms, calcRange, problems); | 104 checkWaterlevelDiscretisation(wstKms, calcRange, problems); |
112 // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden | 105 // TODO: prüfen, ob sohlhöhen die calcRange abdecken/überschneiden |
113 | 106 |
114 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ | 107 /* re-determine the reference gauge, in the same way as the WaterlevelArtifact would do it */ |
115 final RiverInfoProvider riverInfoProvider = infoProvider.forWaterlevel(waterlevel); | 108 final RiverInfoProvider riverInfoProvider = infoProvider.forWaterlevel(waterlevel); |
116 | 109 |
117 final int wspYear = waterlevel.getYear(); | 110 final int wspYear = waterlevel.getYear(); |
118 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge()); | 111 final WstInfo wstInfo = new WstInfo(wspLabel, wspYear, riverInfoProvider.getReferenceGauge()); |
119 | 112 |
113 final WaterlevelValuesFinder waterlevelProvider = WaterlevelValuesFinder.fromKms(wstKms); | |
120 final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms); | 114 final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wstKms); |
121 | 115 |
122 final River river = riverInfoProvider.getRiver(); | 116 final River river = riverInfoProvider.getRiver(); |
123 final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, dischargeProvider, | 117 final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(useTkh, this.context, problems, label, river, calcRange, waterlevelProvider, |
118 dischargeProvider, | |
124 bedHeight); | 119 bedHeight); |
125 | 120 |
126 final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wstKms, dischargeProvider, bedHeight, tkhCalculator); | 121 final FlowDepthCalculator calculator = new FlowDepthCalculator(riverInfoProvider, wspLabel, bedHeight, tkhCalculator); |
127 return calculator.execute(label, wstInfo, calcRange); | 122 return calculator.execute(label, wstInfo, calcRange); |
128 } | 123 } |
129 | 124 |
130 | |
131 /** | |
132 * Checks the year difference between waterlevels and sounding, and issues a warning if too big. | |
133 * | |
134 * Zeitraum Zeitliche Differenz [a] | |
135 * X ≥ 1998 ± 3 | |
136 * 1958 ≤ X < 1998 ± 6 | |
137 * 1918 ≤ X < 1958 ± 12 | |
138 * X < 1918 ± 25 | |
139 */ | |
140 private void checkYearDifference(final String label, final WaterlevelData waterlevel, final Integer soundingYear, final Calculation problems) { | |
141 if (soundingYear == null) | |
142 return; | |
143 | |
144 final int wstYear = waterlevel.getYear(); | |
145 if (wstYear < 0) | |
146 return; | |
147 | |
148 final int maxDifference = getMaxDifferenceYears(soundingYear); | |
149 | |
150 final int difference = Math.abs(soundingYear - wstYear); | |
151 if (difference > maxDifference) { | |
152 final String message = Resources.getMsg(this.context.getMeta(), "sinfo_calc_flow_depth.warning.year_difference", null, label, wstYear, | |
153 soundingYear); | |
154 problems.addProblem(message); | |
155 } | |
156 } | |
157 | |
158 private int getMaxDifferenceYears(final int year) { | |
159 | |
160 if (year < 1918) | |
161 return 25; | |
162 | |
163 if (1918 <= year && year < 1958) | |
164 return 12; | |
165 | |
166 if (1958 <= year && year < 1998) | |
167 return 6; | |
168 | |
169 /* >= 1998 */ | |
170 return 3; | |
171 } | |
172 | |
173 /* Checks if the discretisation of the waterlevel exceeds 1000m */ | 125 /* Checks if the discretisation of the waterlevel exceeds 1000m */ |
174 | |
175 private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { | 126 private void checkWaterlevelDiscretisation(final WKms wstKms, final DoubleRange calcRange, final Calculation problems) { |
176 | 127 |
177 final int size = wstKms.size(); | 128 final int size = wstKms.size(); |
178 for (int i = 0; i < size - 2; i++) { | 129 for (int i = 0; i < size - 2; i++) { |
179 final double kmPrev = wstKms.getKm(i); | 130 final double kmPrev = wstKms.getKm(i); |
188 problems.addProblem(kmPrev, message); | 139 problems.addProblem(kmPrev, message); |
189 } | 140 } |
190 } | 141 } |
191 } | 142 } |
192 } | 143 } |
193 | |
194 private BedHeightsFinder loadBedHeight(final String soundingId, final DoubleRange calcRange) { | |
195 | |
196 // REMARK: absolutely unbelievable.... | |
197 // The way how bed-heights (and other data too) is accessed is different for nearly every calculation-type | |
198 // throughout flys. | |
199 // The knowledge on how to parse the datacage-ids is spread through the complete code-base... | |
200 | |
201 // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but | |
202 // this is plain random | |
203 final String[] parts = soundingId.split(";"); | |
204 | |
205 final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], this.context); | |
206 | |
207 final Integer bedheightId = artifact.getDataAsInteger("height_id"); | |
208 if (bedheightId == null) { | |
209 // FIXME: error message! | |
210 return null; | |
211 } | |
212 | |
213 // REMARK: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the | |
214 // other type means) | |
215 // Luckily, the requirement is to only access 'single' data here. | |
216 // final String bedheightType = artifact.getDataAsString("type"); | |
217 | |
218 // REMARK: BedDifferences uses this, but we also need the metadata of the BedHeight | |
219 // REMARK: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via | |
220 // hibernate stuff | |
221 // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. | |
222 // return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); | |
223 | |
224 return BedHeightsFinder.forId(bedheightId, calcRange); | |
225 } | |
226 } | 144 } |