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