comparison artifacts/src/main/java/org/dive4elements/river/artifacts/model/Calculation4.java @ 9479:2b83d3a96703

i18n TODO "benutzerdefiniert" = "custom" fixed
author gernotbelger
date Mon, 10 Sep 2018 15:31:55 +0200
parents 5e38e2924c07
children 33ce8eba9806
comparison
equal deleted inserted replaced
9478:7e2eebc14e1f 9479:2b83d3a96703
6 * documentation coming with Dive4Elements River for details. 6 * documentation coming with Dive4Elements River for details.
7 */ 7 */
8 8
9 package org.dive4elements.river.artifacts.model; 9 package org.dive4elements.river.artifacts.model;
10 10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.List;
14
15 import org.apache.log4j.Logger;
16 import org.dive4elements.artifacts.CallMeta;
11 import org.dive4elements.river.artifacts.access.Calculation4Access; 17 import org.dive4elements.river.artifacts.access.Calculation4Access;
12
13 import org.dive4elements.river.artifacts.math.BackJumpCorrector; 18 import org.dive4elements.river.artifacts.math.BackJumpCorrector;
14 import org.dive4elements.river.artifacts.math.Function; 19 import org.dive4elements.river.artifacts.math.Function;
15 import org.dive4elements.river.artifacts.math.Identity; 20 import org.dive4elements.river.artifacts.math.Identity;
16 import org.dive4elements.river.artifacts.math.Linear; 21 import org.dive4elements.river.artifacts.math.Linear;
17
18 import org.dive4elements.river.artifacts.model.WstValueTable.QPosition; 22 import org.dive4elements.river.artifacts.model.WstValueTable.QPosition;
19 23 import org.dive4elements.river.artifacts.resources.Resources;
20 import org.dive4elements.river.model.River; 24 import org.dive4elements.river.model.River;
21
22 import org.dive4elements.river.utils.DoubleUtil; 25 import org.dive4elements.river.utils.DoubleUtil;
23 26
24 import java.util.ArrayList; 27 public class Calculation4 extends Calculation {
25 import java.util.Arrays;
26 import java.util.List;
27
28 import org.apache.log4j.Logger;
29
30 public class Calculation4
31 extends Calculation
32 {
33 private static Logger log = Logger.getLogger(Calculation4.class); 28 private static Logger log = Logger.getLogger(Calculation4.class);
34 29
35 public static final double MINIMAL_STEP_WIDTH = 1e-5; 30 public static final double MINIMAL_STEP_WIDTH = 1e-5;
36 31
37 protected List<Segment> segments; 32 protected List<Segment> segments;
38 33
39 protected boolean isQ; 34 protected boolean isQ;
40 protected double from; 35 protected double from;
41 protected double to; 36 protected double to;
42 protected double step; 37 protected double step;
43 protected String river; 38 protected String river;
44 39
45 public Calculation4() { 40 public Calculation4() {
46 } 41 }
47 42
48 public Calculation4(Calculation4Access access) { 43 public Calculation4(final Calculation4Access access) {
49 log.debug("Calculation4Access.cnst"); 44 log.debug("Calculation4Access.cnst");
50 String river = access.getRiverName(); 45 final String river = access.getRiverName();
51 List<Segment> segments = access.getSegments(); 46 final List<Segment> segments = access.getSegments();
52 double [] range = access.getFromToStep(); 47 final double[] range = access.getFromToStep();
53 boolean isQ = access.isQ(); 48 final boolean isQ = access.isQ();
54 49
55 if (river == null) { 50 if (river == null) {
56 addProblem("no.river.selected"); 51 addProblem("no.river.selected");
57 } 52 }
58 53
63 if (segments == null || segments.isEmpty()) { 58 if (segments == null || segments.isEmpty()) {
64 addProblem("cannot.create.segments"); 59 addProblem("cannot.create.segments");
65 } 60 }
66 61
67 if (!hasProblems()) { 62 if (!hasProblems()) {
68 this.river = river; 63 this.river = river;
69 this.segments = segments; 64 this.segments = segments;
70 this.from = range[0]; 65 this.from = range[0];
71 this.to = range[1]; 66 this.to = range[1];
72 this.step = range[2]; 67 this.step = range[2];
73 this.isQ = isQ; 68 this.isQ = isQ;
74 } 69 }
75 } 70 }
76 71
77 public CalculationResult calculate() { 72 public CalculationResult calculate(final CallMeta meta) {
78 if (hasProblems()) { 73 if (hasProblems()) {
79 return new CalculationResult(new WQKms[0], this); 74 return new CalculationResult(new WQKms[0], this);
80 } 75 }
81 76
82 WstValueTable table = null; 77 WstValueTable table = null;
83 River r = RiverFactory.getRiver(river); 78 final River r = RiverFactory.getRiver(this.river);
84 if (r == null) { 79 if (r == null) {
85 addProblem("no.river.found"); 80 addProblem("no.river.found");
86 } 81 } else {
87 else {
88 table = WstValueTableFactory.getTable(r); 82 table = WstValueTableFactory.getTable(r);
89 if (table == null) { 83 if (table == null) {
90 addProblem("no.wst.for.river"); 84 addProblem("no.wst.for.river");
91 } 85 } else {
92 else { 86 Segment.setReferencePointConvertQ(this.segments, r, this.isQ, this);
93 Segment.setReferencePointConvertQ(segments, r, isQ, this); 87 }
94 } 88 }
95 } 89
96 90 return hasProblems() ? new CalculationResult(new WQKms[0], this) : innerCalculate(table, meta);
97 return hasProblems() 91 }
98 ? new CalculationResult(new WQKms[0], this) 92
99 : innerCalculate(table); 93 protected CalculationResult innerCalculate(final WstValueTable table, final CallMeta meta) {
100 } 94 final boolean debug = log.isDebugEnabled();
101
102 protected CalculationResult innerCalculate(WstValueTable table) {
103 boolean debug = log.isDebugEnabled();
104 95
105 if (debug) { 96 if (debug) {
106 log.debug( 97 log.debug("calculate from " + this.from + " to " + this.to + " step " + this.step);
107 "calculate from " + from + " to " + to + " step " + step); 98 log.debug("# segments: " + this.segments.size());
108 log.debug("# segments: " + segments.size()); 99 for (final Segment segment : this.segments) {
109 for (Segment segment: segments) {
110 log.debug(" " + segment); 100 log.debug(" " + segment);
111 } 101 }
112 } 102 }
113 103
114 int numResults = segments.get(0).values.length; 104 final int numResults = this.segments.get(0).values.length;
115 105
116 if (numResults < 1) { 106 if (numResults < 1) {
117 log.debug("no values given"); 107 log.debug("no values given");
118 addProblem("no.values.given"); 108 addProblem("no.values.given");
119 return new CalculationResult(new WQKms[0], this); 109 return new CalculationResult(new WQKms[0], this);
120 } 110 }
121 111
122 112 final WQKms[] results = new WQKms[numResults];
123 WQKms [] results = new WQKms[numResults];
124 for (int i = 0; i < results.length; ++i) { 113 for (int i = 0; i < results.length; ++i) {
125 results[i] = new WQKms(); 114 results[i] = new WQKms();
126 } 115 }
127 116
128 if (Math.abs(step) < MINIMAL_STEP_WIDTH) { 117 if (Math.abs(this.step) < MINIMAL_STEP_WIDTH) {
129 step = MINIMAL_STEP_WIDTH; 118 this.step = MINIMAL_STEP_WIDTH;
130 } 119 }
131 120
132 if (from > to) { 121 if (this.from > this.to) {
133 step = -step; 122 this.step = -this.step;
134 } 123 }
135 124
136 QPosition [] qPositions = new QPosition[numResults]; 125 final QPosition[] qPositions = new QPosition[numResults];
137 126
138 Function [] functions = new Function[numResults]; 127 final Function[] functions = new Function[numResults];
139 128
140 double [] out = new double[2]; 129 final double[] out = new double[2];
141 130
142 Segment sentinel = new Segment(Double.MAX_VALUE); 131 final Segment sentinel = new Segment(Double.MAX_VALUE);
143 Segment s1 = sentinel, s2 = sentinel; 132 Segment s1 = sentinel, s2 = sentinel;
144 133
145 for (double pos = from; 134 for (double pos = this.from; this.from < this.to ? pos <= this.to : pos >= this.to; pos = DoubleUtil.round(pos + this.step)) {
146 from < to ? pos <= to : pos >= to;
147 pos = DoubleUtil.round(pos + step)
148 ) {
149 if (pos < s1.referencePoint || pos > s2.referencePoint) { 135 if (pos < s1.referencePoint || pos > s2.referencePoint) {
150 if (debug) { 136 if (debug) {
151 log.debug("need to find new interval for " + pos); 137 log.debug("need to find new interval for " + pos);
152 } 138 }
153 // find new interval 139 // find new interval
154 if (pos <= segments.get(0).referencePoint) { 140 if (pos <= this.segments.get(0).referencePoint) {
155 // before first segment -> "gleichwertig" 141 // before first segment -> "gleichwertig"
156 if (debug) { 142 if (debug) {
157 log.debug("before first segment -> gleichwertig"); 143 log.debug("before first segment -> gleichwertig");
158 } 144 }
159 Segment first = segments.get(0); 145 final Segment first = this.segments.get(0);
160 double [] values = first.values; 146 final double[] values = first.values;
161 double refPos = first.referencePoint; 147 final double refPos = first.referencePoint;
162 for (int i = 0; i < qPositions.length; ++i) { 148 for (int i = 0; i < qPositions.length; ++i) {
163 qPositions[i] = table.getQPosition( 149 qPositions[i] = table.getQPosition(refPos, values[i]);
164 refPos, values[i]);
165 } 150 }
166 sentinel.setReferencePoint(-Double.MAX_VALUE); 151 sentinel.setReferencePoint(-Double.MAX_VALUE);
167 s1 = sentinel; 152 s1 = sentinel;
168 s2 = segments.get(0); 153 s2 = this.segments.get(0);
169 Arrays.fill(functions, Identity.IDENTITY); 154 Arrays.fill(functions, Identity.IDENTITY);
170 } 155 } else if (pos >= this.segments.get(this.segments.size() - 1).referencePoint) {
171 else if (
172 pos >= segments.get(segments.size()-1).referencePoint
173 ) {
174 // after last segment -> "gleichwertig" 156 // after last segment -> "gleichwertig"
175 if (debug) { 157 if (debug) {
176 log.debug("after last segment -> gleichwertig"); 158 log.debug("after last segment -> gleichwertig");
177 } 159 }
178 Segment last = segments.get(segments.size()-1); 160 final Segment last = this.segments.get(this.segments.size() - 1);
179 double [] values = last.values; 161 final double[] values = last.values;
180 double refPos = last.referencePoint; 162 final double refPos = last.referencePoint;
181 for (int i = 0; i < qPositions.length; ++i) { 163 for (int i = 0; i < qPositions.length; ++i) {
182 qPositions[i] = table.getQPosition( 164 qPositions[i] = table.getQPosition(refPos, values[i]);
183 refPos, values[i]);
184 } 165 }
185 sentinel.setReferencePoint(Double.MAX_VALUE); 166 sentinel.setReferencePoint(Double.MAX_VALUE);
186 s1 = last; 167 s1 = last;
187 s2 = sentinel; 168 s2 = sentinel;
188 Arrays.fill(functions, Identity.IDENTITY); 169 Arrays.fill(functions, Identity.IDENTITY);
189 } 170 } else { // "ungleichwertig"
190 else { // "ungleichwertig" 171 // find matching interval
191 // find matching interval
192 if (debug) { 172 if (debug) {
193 log.debug("in segments -> ungleichwertig"); 173 log.debug("in segments -> ungleichwertig");
194 } 174 }
195 s1 = s2 = null; 175 s1 = s2 = null;
196 for (int i = 1, N = segments.size(); i < N; ++i) { 176 for (int i = 1, N = this.segments.size(); i < N; ++i) {
197 Segment si1 = segments.get(i-1); 177 final Segment si1 = this.segments.get(i - 1);
198 Segment si = segments.get(i); 178 final Segment si = this.segments.get(i);
199 if (debug) { 179 if (debug) {
200 log.debug("check " + pos + " in " 180 log.debug("check " + pos + " in " + si1.referencePoint + " - " + si.referencePoint);
201 + si1.referencePoint + " - "
202 + si.referencePoint);
203 } 181 }
204 if (pos >= si1.referencePoint 182 if (pos >= si1.referencePoint && pos <= si.referencePoint) {
205 && pos <= si. referencePoint) {
206 s1 = si1; 183 s1 = si1;
207 s2 = si; 184 s2 = si;
208 break; 185 break;
209 } 186 }
210 } 187 }
213 throw new IllegalStateException("no interval found"); 190 throw new IllegalStateException("no interval found");
214 } 191 }
215 192
216 Segment anchor, free; 193 Segment anchor, free;
217 194
218 if (from > to) { anchor = s1; free = s2; } 195 if (this.from > this.to) {
219 else { anchor = s2; free = s1; } 196 anchor = s1;
197 free = s2;
198 } else {
199 anchor = s2;
200 free = s1;
201 }
220 202
221 // build transforms based on "gleichwertiger" phase 203 // build transforms based on "gleichwertiger" phase
222 for (int i = 0; i < qPositions.length; ++i) { 204 for (int i = 0; i < qPositions.length; ++i) {
223 QPosition qi = table.getQPosition( 205 final QPosition qi = table.getQPosition(anchor.referencePoint, anchor.values[i]);
224 anchor.referencePoint,
225 anchor.values[i]);
226 206
227 if ((qPositions[i] = qi) == null) { 207 if ((qPositions[i] = qi) == null) {
228 addProblem(pos, "cannot.find.q", anchor.values[i]); 208 addProblem(pos, "cannot.find.q", anchor.values[i]);
229 functions[i] = Identity.IDENTITY; 209 functions[i] = Identity.IDENTITY;
230 } 210 } else {
231 else { 211 final double qA = table.getQ(qi, anchor.referencePoint);
232 double qA = table.getQ(qi, anchor.referencePoint); 212 final double qF = table.getQ(qi, free.referencePoint);
233 double qF = table.getQ(qi, free .referencePoint); 213
234 214 functions[i] = Double.isNaN(qA) || Double.isNaN(qF) ? Identity.IDENTITY : new Linear(qA, qF, anchor.values[i], free.values[i]);
235 functions[i] = Double.isNaN(qA) || Double.isNaN(qF)
236 ? Identity.IDENTITY
237 : new Linear(
238 qA, qF,
239 anchor.values[i], free.values[i]);
240 215
241 if (debug) { 216 if (debug) {
242 log.debug( 217 log.debug(anchor.referencePoint + ": " + qA + " -> " + functions[i].value(qA) + " / " + free.referencePoint + ": " + qF + " -> "
243 anchor.referencePoint + ": " + 218 + functions[i].value(qF));
244 qA + " -> " + functions[i].value(qA) +
245 " / " + free.referencePoint + ": " +
246 qF + " -> " + functions[i].value(qF));
247 } 219 }
248 } 220 }
249 } // build transforms 221 } // build transforms
250 } // "ungleichwertiges" interval 222 } // "ungleichwertiges" interval
251 } // find matching interval 223 } // find matching interval
252 224
253 for (int i = 0; i < qPositions.length; ++i) { 225 for (int i = 0; i < qPositions.length; ++i) {
254 QPosition qPosition = qPositions[i]; 226 final QPosition qPosition = qPositions[i];
255 227
256 if (qPosition == null) { 228 if (qPosition == null) {
257 continue; 229 continue;
258 } 230 }
259 231
260 if (table.interpolate(pos, out, qPosition, functions[i])) { 232 if (table.interpolate(pos, out, qPosition, functions[i])) {
261 results[i].add(out[0], out[1], pos); 233 results[i].add(out[0], out[1], pos);
262 } 234 } else {
263 else {
264 addProblem(pos, "cannot.interpolate.w.q"); 235 addProblem(pos, "cannot.interpolate.w.q");
265 } 236 }
266 } 237 }
267 } 238 }
239 final String custom = Resources.format(meta, "common.custom");
268 240
269 // Backjump correction 241 // Backjump correction
270 for (int i = 0; i < results.length; ++i) { 242 for (int i = 0; i < results.length; ++i) {
271 BackJumpCorrector bjc = new BackJumpCorrector(); 243 final BackJumpCorrector bjc = new BackJumpCorrector();
272 244
273 double [] ws = results[i].getWs(); 245 final double[] ws = results[i].getWs();
274 double [] kms = results[i].getKms(); 246 final double[] kms = results[i].getKms();
275 247
276 if (bjc.doCorrection(kms, ws, this)) { 248 if (bjc.doCorrection(kms, ws, this)) {
277 results[i] = new WQCKms(results[i], bjc.getCorrected()); 249 results[i] = new WQCKms(results[i], bjc.getCorrected());
278 } 250 }
279 } 251 }
280 252
281 // Name the curves. 253 // Name the curves.
282 for (int i = 0; i < results.length; ++i) { 254 for (int i = 0; i < results.length; ++i) {
283 results[i].setName(createName(i)); 255 results[i].setName(createName(i, custom));
284 } 256 }
285 257
286 // Generate the "Umhuellende". 258 // Generate the "Umhuellende".
287 ConstantWQKms [] infoldings = 259 final ConstantWQKms[] infoldings = generateInfolding(table, results, this.from, this.to, this.step);
288 generateInfolding(table, results, from, to, step);
289 260
290 // TODO: Use qkms in a new result type. 261 // TODO: Use qkms in a new result type.
291 WQKms [] newResults = new WQKms[results.length + infoldings.length]; 262 final WQKms[] newResults = new WQKms[results.length + infoldings.length];
292 System.arraycopy( 263 System.arraycopy(results, 0, newResults, 0, results.length);
293 results, 0, newResults, 0, results.length); 264 System.arraycopy(infoldings, 0, newResults, results.length, infoldings.length);
294 System.arraycopy(
295 infoldings, 0, newResults, results.length, infoldings.length);
296 265
297 return new CalculationResult(newResults, this); 266 return new CalculationResult(newResults, this);
298 } 267 }
299 268
300 protected ConstantWQKms [] generateInfolding( 269 protected ConstantWQKms[] generateInfolding(final WstValueTable wst, final WQKms[] results, final double from, final double to, final double step) {
301 WstValueTable wst, 270 final WstValueTable.Column[] columns = wst.getColumns();
302 WQKms [] results, 271
303 double from, 272 final InfoldingColumns ic = new InfoldingColumns(columns);
304 double to,
305 double step
306 ) {
307 WstValueTable.Column [] columns = wst.getColumns();
308
309 InfoldingColumns ic = new InfoldingColumns(columns);
310 ic.markInfoldingColumns(results); 273 ic.markInfoldingColumns(results);
311 274
312 List<ConstantWQKms> infoldings = new ArrayList<ConstantWQKms>(); 275 final List<ConstantWQKms> infoldings = new ArrayList<>();
313 276
314 boolean [] infoldingColumns = ic.getInfoldingColumns(); 277 final boolean[] infoldingColumns = ic.getInfoldingColumns();
315 278
316 double [] kms = null; 279 double[] kms = null;
317 double [] ws = null; 280 double[] ws = null;
318 281
319 for (int i = 0; i < infoldingColumns.length; ++i) { 282 for (int i = 0; i < infoldingColumns.length; ++i) {
320 if (!infoldingColumns[i]) { 283 if (!infoldingColumns[i]) {
321 continue; 284 continue;
322 } 285 }
323 286
324 if (kms == null) { 287 if (kms == null) {
325 kms = DoubleUtil.explode(from, to, step); 288 kms = DoubleUtil.explode(from, to, step);
326 ws = new double[kms.length]; 289 ws = new double[kms.length];
327 } 290 }
328 291
329 QRangeTree.QuickQFinder qf = 292 final QRangeTree.QuickQFinder qf = columns[i].getQRangeTree().new QuickQFinder();
330 columns[i].getQRangeTree().new QuickQFinder(); 293
331 294 final int numProblemsBefore = numProblems();
332 int numProblemsBefore = numProblems(); 295 final double[] qs = qf.findQs(kms, this);
333 double [] qs = qf.findQs(kms, this); 296
334 297 final String name = columns[i].getName();
335 String name = columns[i].getName(); 298 final ConstantWQKms infolding = new ConstantWQKms(kms, qs, ws, name);
336 ConstantWQKms infolding = new ConstantWQKms(kms, qs, ws, name);
337 299
338 if (numProblems() > numProblemsBefore) { 300 if (numProblems() > numProblemsBefore) {
339 infolding.removeNaNs(); 301 infolding.removeNaNs();
340 } 302 }
341 303
342 infoldings.add(infolding); 304 infoldings.add(infolding);
343 } 305 }
344 306
345 for (int i = 0, I = infoldings.size(); i < I; i++) { 307 for (int i = 0, I = infoldings.size(); i < I; i++) {
346 ConstantWQKms infolding = infoldings.get(i); 308 final ConstantWQKms infolding = infoldings.get(i);
347 String name = infolding.getName(); 309 final String name = infolding.getName();
348 // TODO: i18n 310 // TODO: i18n
349 if (i == 0) { 311 if (i == 0) {
350 infolding.setName("untere Umh\u00fcllende " + name); 312 infolding.setName("untere Umh\u00fcllende " + name);
351 } 313 } else if (i == I - 1) {
352 else if (i == I-1) {
353 infolding.setName("obere Umh\u00fcllende " + name); 314 infolding.setName("obere Umh\u00fcllende " + name);
354 } 315 } else {
355 else {
356 infolding.setName("geschnitten " + name); 316 infolding.setName("geschnitten " + name);
357 } 317 }
358 } 318 }
359 319
360 return infoldings.toArray(new ConstantWQKms[infoldings.size()]); 320 return infoldings.toArray(new ConstantWQKms[infoldings.size()]);
361 } 321 }
362 322
363 // TODO: issue1109/2, merge with FixRealizingCalculation 323 // TODO: issue1109/2, merge with FixRealizingCalculation
364 protected String createName(int index) { 324 protected String createName(final int index, final String custom) {
365 // TODO: i18n 325
366 StringBuilder sb = new StringBuilder(isQ ? "Q" : "W"); 326 final StringBuilder sb = new StringBuilder(this.isQ ? "Q" : "W");
367 sb.append(" benutzerdefiniert ("); 327 sb.append(" ").append(custom).append(" (");
368 for (int i = 0, N = segments.size(); i < N; ++i) { 328 for (int i = 0, N = this.segments.size(); i < N; ++i) {
369 if (i > 0) { 329 if (i > 0) {
370 sb.append("; "); 330 sb.append("; ");
371 } 331 }
372 Segment segment = segments.get(i); 332 final Segment segment = this.segments.get(i);
373 sb.append((segment.backup != null 333 sb.append((segment.backup != null ? segment.backup : segment.values)[index]);
374 ? segment.backup
375 : segment.values)[index]);
376 } 334 }
377 sb.append(')'); 335 sb.append(')');
378 return sb.toString(); 336 return sb.toString();
379 } 337 }
380 } 338 }
381 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org