comparison artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/TkhCalculation.java @ 8942:11bf13cf0463

Minor changes to tkh calculation. Loading default bed heights form config file.
author gernotbelger
date Fri, 09 Mar 2018 18:47:06 +0100
parents 9c02733a1b3c
children 5d5d482da3e9
comparison
equal deleted inserted replaced
8941:a9950a3a71e5 8942:11bf13cf0463
9 */ 9 */
10 package org.dive4elements.river.artifacts.sinfo.tkhstate; 10 package org.dive4elements.river.artifacts.sinfo.tkhstate;
11 11
12 import java.util.ArrayList; 12 import java.util.ArrayList;
13 import java.util.Collection; 13 import java.util.Collection;
14 import java.util.HashMap;
14 import java.util.List; 15 import java.util.List;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Set;
15 19
16 import org.apache.commons.lang.math.DoubleRange; 20 import org.apache.commons.lang.math.DoubleRange;
21 import org.apache.commons.lang.math.NumberRange;
17 import org.dive4elements.artifacts.CallContext; 22 import org.dive4elements.artifacts.CallContext;
18 import org.dive4elements.river.artifacts.WINFOArtifact; 23 import org.dive4elements.river.artifacts.WINFOArtifact;
19 import org.dive4elements.river.artifacts.model.Calculation; 24 import org.dive4elements.river.artifacts.model.Calculation;
20 import org.dive4elements.river.artifacts.model.Calculation.Problem; 25 import org.dive4elements.river.artifacts.model.Calculation.Problem;
21 import org.dive4elements.river.artifacts.model.CalculationResult; 26 import org.dive4elements.river.artifacts.model.CalculationResult;
24 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; 29 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
25 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider; 30 import org.dive4elements.river.artifacts.sinfo.common.RiverInfoProvider;
26 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder; 31 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.DischargeValuesFinder;
27 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh; 32 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.Tkh;
28 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator; 33 import org.dive4elements.river.artifacts.sinfo.tkhcalculation.TkhCalculator;
34 import org.dive4elements.river.artifacts.sinfo.util.BedHeightInfo;
29 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; 35 import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
30 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; 36 import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
31 import org.dive4elements.river.artifacts.sinfo.util.WstInfo; 37 import org.dive4elements.river.artifacts.sinfo.util.WstInfo;
32 import org.dive4elements.river.artifacts.states.WaterlevelData; 38 import org.dive4elements.river.artifacts.states.WaterlevelData;
33 import org.dive4elements.river.exports.WaterlevelDescriptionBuilder; 39 import org.dive4elements.river.exports.WaterlevelDescriptionBuilder;
40 import org.dive4elements.river.model.BedHeight;
34 import org.dive4elements.river.model.River; 41 import org.dive4elements.river.model.River;
35 42
36 /** 43 /**
37 * @author Gernot Belger 44 * @author Gernot Belger
38 */ 45 */
53 final DoubleRange calcRange = access.getRange(); 60 final DoubleRange calcRange = access.getRange();
54 61
55 final Calculation problems = new Calculation(); 62 final Calculation problems = new Calculation();
56 63
57 /* find relevant bed-heights */ 64 /* find relevant bed-heights */
58 final Collection<BedHeightsFinder> bedHeights = BedHeightsFinder.createTkhBedHeights(river, problems, calcRange); 65 final List<BedHeight> defaultBedHeights = new DefaultBedHeights(river).getBedHeights(problems);
66 final Collection<BedHeightsFinder> bedHeights = BedHeightsFinder.createTkhBedHeights(calcRange, defaultBedHeights);
59 67
60 /* misuse winfo-artifact to calculate waterlevels in the same way */ 68 /* misuse winfo-artifact to calculate waterlevels in the same way */
61 final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo); 69 final WINFOArtifact winfo = new WinfoArtifactWrapper(sinfo);
62 70
63 /* calculate waterlevels */ 71 /* calculate waterlevels */
116 // FIXME: check with winfo how the name is generated 124 // FIXME: check with winfo how the name is generated
117 final String wstLabel = waterlevel.getName(); 125 final String wstLabel = waterlevel.getName();
118 126
119 final WstInfo wstInfo = new WstInfo(wstLabel, wspYear, riverInfoProvider.getReferenceGauge()); 127 final WstInfo wstInfo = new WstInfo(wstLabel, wspYear, riverInfoProvider.getReferenceGauge());
120 128
129 /* build tkh calculators per bedheight */
130 final Map<NumberRange, TkhCalculator> calculatorsByRanges = buildCalculators(calcRange, wkms, bedHeights, problems, riverInfoProvider, wstLabel);
131 if (calculatorsByRanges.isEmpty()) {
132 /* there should already be some problems, so just abort */
133 return null;
134 }
135
121 final Collection<TkhResultRow> rows = new ArrayList<>(); 136 final Collection<TkhResultRow> rows = new ArrayList<>();
122 137
123 /* 138 /* using wst-kms as basis, because we know that they are generated wst's with a fixed km-step */
124 * for each separate bed height dataset we do the calculation and put everything into one result, bed heights must not 139 // FIXME: das führt dazu, das aktuell die Sohlhöhen beliebig linear interpolierrt werden. ist das immer richtig? z.b.
125 * overlap accordingly 140 // bei großen abständen?
126 */ 141
142 final int size = wkms.size();
143 for (int i = 0; i < size; i++) {
144
145 final double station = wkms.getKm(i);
146 final double wst = wkms.getW(i);
147
148 /* find the right calculator (i.e. bedheigh) depending on station, there should only be one maximal */
149 final TkhCalculator tkhCalculator = findCalculator(calculatorsByRanges, station);
150 if (tkhCalculator == null)
151 continue;
152
153 final Tkh tkh = tkhCalculator.getTkh(station, wst);
154
155 final String description = descBuilder.getDesc(wkms);
156 final String gaugeLabel = riverInfoProvider.findGauge(station);
157 final String location = riverInfoProvider.getLocation(station);
158
159 rows.add(new TkhResultRow(tkh, description, gaugeLabel, location));
160 }
161
162 return new TkhCalculationResult(wstLabel, wstInfo, true, rows);
163 }
164
165 private TkhCalculator findCalculator(final Map<NumberRange, TkhCalculator> calculators, final double station) {
166
167 // REMAKR: linear search at this point, put we expect the number of bed heights to be very small (1-2 items)
168 final Set<Entry<NumberRange, TkhCalculator>> x = calculators.entrySet();
169 for (final Entry<NumberRange, TkhCalculator> entry : x) {
170 final NumberRange range = entry.getKey();
171 // FIXME: check if we need comparison with a tolerance
172 if (range.containsDouble(station))
173 return entry.getValue();
174 }
175
176 return null;
177 }
178
179 private Map<NumberRange, TkhCalculator> buildCalculators(final DoubleRange calcRange, final WQKms wkms, final Collection<BedHeightsFinder> bedHeights,
180 final Calculation problems, final RiverInfoProvider riverInfoProvider, final String wstLabel) {
181 final Map<NumberRange, TkhCalculator> calculatorByRanges = new HashMap<>();
127 for (final BedHeightsFinder bedHeightsProvider : bedHeights) { 182 for (final BedHeightsFinder bedHeightsProvider : bedHeights) {
183
184 final BedHeightInfo info = bedHeightsProvider.getInfo();
185
186 final NumberRange range = new NumberRange(info.getFrom(), info.getTo());
128 187
129 final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wkms); 188 final DischargeValuesFinder dischargeProvider = DischargeValuesFinder.fromKms(wkms);
130 189
131 /* initialize tkh calculator */ 190 /* initialize tkh calculator */
132 final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(true, this.context, problems, wstLabel, riverInfoProvider.getRiver(), 191 final TkhCalculator tkhCalculator = TkhCalculator.buildTkhCalculator(true, this.context, problems, wstLabel, riverInfoProvider.getRiver(),
133 calcRange, 192 calcRange, dischargeProvider, bedHeightsProvider);
134 dischargeProvider, bedHeightsProvider); 193
135 if (tkhCalculator == null) { 194 if (tkhCalculator != null) {
136 /* just abort, problems have already been updated by buildTkhCalculator() */ 195 /* just ignore null ones, problems have already been updated by buildTkhCalculator() */
137 return null; 196 calculatorByRanges.put(range, tkhCalculator);
138 } 197 }
139 198 }
140 /* using wst-kms as basis, because we know that they are generated wst's with a fixed km-step */ 199
141 200 return calculatorByRanges;
142 // FIXME: das führt dazu, das aktuell die Sohlhöhen beliebig linear interpolierrt werden. ist das immer richtig? z.b.
143 // bei großen abständen?
144
145 final int size = wkms.size();
146 for (int i = 0; i < size; i++) {
147
148 final double station = wkms.getKm(i);
149 final double wst = wkms.getW(i);
150
151 final Tkh tkh = tkhCalculator.getTkh(station, wst);
152
153 final String description = descBuilder.getDesc(wkms);
154 final String gaugeLabel = riverInfoProvider.findGauge(station);
155 final String location = riverInfoProvider.getLocation(station);
156
157 rows.add(new TkhResultRow(tkh, description, gaugeLabel, location));
158 }
159 }
160
161 return new TkhCalculationResult(wstLabel, wstInfo, true, rows);
162 } 201 }
163 } 202 }

http://dive4elements.wald.intevation.org