Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java @ 3435:262e7d7e58fe
FixA: Made curve fitting over the given calculation range reusable. Removed dead code.
flys-artifacts/trunk@5098 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Sun, 22 Jul 2012 10:38:30 +0000 |
parents | 1a636be7612b |
children | e111902834d3 |
comparison
equal
deleted
inserted
replaced
3434:1a636be7612b | 3435:262e7d7e58fe |
---|---|
1 package de.intevation.flys.artifacts.model.fixings; | 1 package de.intevation.flys.artifacts.model.fixings; |
2 | |
3 import de.intevation.artifacts.common.utils.StringUtils; | |
4 | 2 |
5 import de.intevation.flys.artifacts.access.FixAnalysisAccess; | 3 import de.intevation.flys.artifacts.access.FixAnalysisAccess; |
6 | 4 |
7 import de.intevation.flys.artifacts.math.fitting.Function; | 5 import de.intevation.flys.artifacts.math.fitting.Function; |
8 import de.intevation.flys.artifacts.math.fitting.FunctionFactory; | 6 import de.intevation.flys.artifacts.math.fitting.FunctionFactory; |
9 | 7 |
10 import de.intevation.flys.artifacts.model.CalculationResult; | 8 import de.intevation.flys.artifacts.model.CalculationResult; |
11 import de.intevation.flys.artifacts.model.DateRange; | 9 import de.intevation.flys.artifacts.model.DateRange; |
12 import de.intevation.flys.artifacts.model.FixingsColumn; | |
13 import de.intevation.flys.artifacts.model.FixingsColumnFactory; | |
14 | 10 |
15 import de.intevation.flys.artifacts.model.FixingsOverview.AndFilter; | 11 import de.intevation.flys.artifacts.model.FixingsOverview.AndFilter; |
16 import de.intevation.flys.artifacts.model.FixingsOverview.DateRangeFilter; | 12 import de.intevation.flys.artifacts.model.FixingsOverview.DateRangeFilter; |
17 | 13 |
18 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter; | 14 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter; |
19 | 15 |
20 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; | 16 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; |
21 import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter; | 17 import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter; |
22 import de.intevation.flys.artifacts.model.FixingsOverview.KmFilter; | 18 import de.intevation.flys.artifacts.model.FixingsOverview.KmFilter; |
23 import de.intevation.flys.artifacts.model.FixingsOverview.SectorFilter; | 19 import de.intevation.flys.artifacts.model.FixingsOverview.SectorFilter; |
24 import de.intevation.flys.artifacts.model.FixingsOverview.SectorRangeFilter; | |
25 | 20 |
26 import de.intevation.flys.artifacts.model.FixingsOverview; | 21 import de.intevation.flys.artifacts.model.FixingsOverview; |
27 import de.intevation.flys.artifacts.model.FixingsOverviewFactory; | 22 import de.intevation.flys.artifacts.model.FixingsOverviewFactory; |
28 import de.intevation.flys.artifacts.model.Parameters; | 23 import de.intevation.flys.artifacts.model.Parameters; |
29 import de.intevation.flys.artifacts.model.Range; | 24 import de.intevation.flys.artifacts.model.Range; |
30 | 25 |
31 import de.intevation.flys.utils.DateAverager; | 26 import de.intevation.flys.utils.DateAverager; |
32 import de.intevation.flys.utils.DoubleUtil; | |
33 import de.intevation.flys.utils.KMIndex; | 27 import de.intevation.flys.utils.KMIndex; |
34 | 28 |
35 import java.util.ArrayList; | 29 import java.util.ArrayList; |
36 import java.util.Date; | 30 import java.util.Date; |
37 import java.util.List; | 31 import java.util.List; |
43 public class FixAnalysisCalculation | 37 public class FixAnalysisCalculation |
44 extends FixCalculation | 38 extends FixCalculation |
45 { | 39 { |
46 private static Logger log = Logger.getLogger(FixAnalysisCalculation.class); | 40 private static Logger log = Logger.getLogger(FixAnalysisCalculation.class); |
47 | 41 |
48 public static final double EPSILON = 1e-4; | |
49 | |
50 // TODO: Move to base class? | |
51 public static final String [] STANDARD_COLUMNS = { | |
52 "km", "chi_sqr", "max_q", "std-dev" | |
53 }; | |
54 | |
55 protected DateRange referencePeriod; | 42 protected DateRange referencePeriod; |
56 protected DateRange [] analysisPeriods; | 43 protected DateRange [] analysisPeriods; |
57 | 44 |
58 public FixAnalysisCalculation() { | 45 public FixAnalysisCalculation() { |
59 } | 46 } |
78 } | 65 } |
79 } | 66 } |
80 | 67 |
81 public CalculationResult calculate() { | 68 public CalculationResult calculate() { |
82 | 69 |
83 boolean debug = log.isDebugEnabled(); | |
84 | |
85 FixingsOverview overview = | 70 FixingsOverview overview = |
86 FixingsOverviewFactory.getOverview(river); | 71 FixingsOverviewFactory.getOverview(river); |
87 | 72 |
88 if (overview == null) { | 73 if (overview == null) { |
89 addProblem("fix.no.overview.available"); | 74 addProblem("fix.no.overview.available"); |
98 | 83 |
99 if (hasProblems()) { | 84 if (hasProblems()) { |
100 return new CalculationResult(this); | 85 return new CalculationResult(this); |
101 } | 86 } |
102 | 87 |
103 final List<Column> eventColumns = getEventColumns(overview); | 88 FitResult fitResult = doFitting(overview, func); |
104 | 89 |
105 if (eventColumns.size() < 2) { | 90 if (fitResult == null) { |
106 addProblem("fix.too.less.data.columns"); | |
107 return new CalculationResult(this); | 91 return new CalculationResult(this); |
108 } | 92 } |
109 | 93 |
110 final double [] qs = new double[eventColumns.size()]; | |
111 final double [] ws = new double[qs.length]; | |
112 final boolean [] interpolated = new boolean[ws.length]; | |
113 | |
114 Fitting.QWDFactory qwdFactory = new Fitting.QWDFactory() { | |
115 @Override | |
116 public QWD create(double q, double w) { | |
117 // Check all the event columns for close match | |
118 // and take the description and the date from meta. | |
119 for (int i = 0; i < qs.length; ++i) { | |
120 if (Math.abs(qs[i]-q) < EPSILON | |
121 && Math.abs(ws[i]-w) < EPSILON) { | |
122 Column column = eventColumns.get(i); | |
123 return new QWD( | |
124 qs[i], ws[i], | |
125 column.getDescription(), | |
126 column.getDate(), | |
127 interpolated[i], | |
128 0d); | |
129 } | |
130 } | |
131 log.warn("cannot find column for (" + q + ", " + w + ")"); | |
132 return new QWD(q, w); | |
133 } | |
134 }; | |
135 | |
136 Fitting fitting = new Fitting(func, qwdFactory, preprocessing); | |
137 | |
138 String [] parameterNames = func.getParameterNames(); | |
139 | |
140 Parameters results = | |
141 new Parameters( | |
142 StringUtils.join(STANDARD_COLUMNS, parameterNames)); | |
143 | |
144 boolean invalid = false; | |
145 | |
146 double [] kms = DoubleUtil.explode(from, to, step / 1000.0); | |
147 | |
148 if (debug) { | |
149 log.debug("number of kms: " + kms.length); | |
150 } | |
151 | |
152 KMIndex<QW []> outliers = new KMIndex<QW []>(); | |
153 KMIndex<QWD []> referenced = new KMIndex<QWD []>(kms.length); | |
154 | |
155 int kmIndex = results.columnIndex("km"); | |
156 int chiSqrIndex = results.columnIndex("chi_sqr"); | |
157 int maxQIndex = results.columnIndex("max_q"); | |
158 int stdDevIndex = results.columnIndex("std-dev"); | |
159 int [] parameterIndices = results.columnIndices(parameterNames); | |
160 | |
161 int numFailed = 0; | |
162 | |
163 for (int i = 0; i < kms.length; ++i) { | |
164 double km = kms[i]; | |
165 | |
166 // Fill Qs and Ws from event columns. | |
167 for (int j = 0; j < ws.length; ++j) { | |
168 interpolated[j] = !eventColumns.get(j).getQW(km, qs, ws, j); | |
169 } | |
170 | |
171 fitting.reset(); | |
172 | |
173 if (!fitting.fit(qs, ws)) { | |
174 ++numFailed; | |
175 addProblem(km, "fix.fitting.failed"); | |
176 continue; | |
177 } | |
178 | |
179 referenced.add(km, fitting.referencedToArray()); | |
180 | |
181 if (fitting.hasOutliers()) { | |
182 outliers.add(km, fitting.outliersToArray()); | |
183 } | |
184 | |
185 int row = results.newRow(); | |
186 double [] values = fitting.getParameters(); | |
187 | |
188 results.set(row, kmIndex, km); | |
189 results.set(row, chiSqrIndex, fitting.getChiSquare()); | |
190 results.set(row, stdDevIndex, fitting.getStandardDeviation()); | |
191 results.set(row, maxQIndex, fitting.getMaxQ()); | |
192 invalid |= results.set(row, parameterIndices, values); | |
193 | |
194 if (debug) { | |
195 log.debug("km: "+km+" " + toString(parameterNames, values)); | |
196 } | |
197 } | |
198 | |
199 if (debug) { | |
200 log.debug("success: " + (kms.length - numFailed)); | |
201 log.debug("failed: " + numFailed); | |
202 } | |
203 | |
204 if (invalid) { | |
205 addProblem("fix.invalid.values"); | |
206 results.removeNaNs(); | |
207 } | |
208 | |
209 KMIndex<AnalysisPeriod []> analysisPeriods = | 94 KMIndex<AnalysisPeriod []> analysisPeriods = |
210 calculateAnalysisPeriods(func, results, overview); | 95 calculateAnalysisPeriods( |
211 | 96 func, |
212 outliers.sort(); | 97 fitResult.getParameters(), |
213 referenced.sort(); | 98 overview); |
99 | |
214 analysisPeriods.sort(); | 100 analysisPeriods.sort(); |
215 | 101 |
216 FixAnalysisResult fr = new FixAnalysisResult( | 102 FixAnalysisResult far = new FixAnalysisResult( |
217 results, | 103 fitResult.getParameters(), |
218 referenced, outliers, | 104 fitResult.getReferenced(), |
105 fitResult.getOutliers(), | |
219 analysisPeriods); | 106 analysisPeriods); |
220 | 107 |
221 return new CalculationResult(fr, this); | 108 return new CalculationResult(far, this); |
222 } | 109 } |
223 | 110 |
224 @Override | 111 @Override |
225 protected Filter createFilter() { | 112 protected Filter createFilter() { |
226 Filter ids = super.createFilter(); | 113 Filter ids = super.createFilter(); |
391 new AnalysisPeriod[periodResults.size()])); | 278 new AnalysisPeriod[periodResults.size()])); |
392 } | 279 } |
393 | 280 |
394 return results; | 281 return results; |
395 } | 282 } |
396 | |
397 /** Fetch meta and data columns for analysis periods. */ | |
398 protected Column [][] getAnalysisColumns(FixingsOverview overview) { | |
399 | |
400 boolean debug = log.isDebugEnabled(); | |
401 if (debug) { | |
402 log.debug("number analysis periods: " + analysisPeriods.length); | |
403 } | |
404 | |
405 Column columns [][] = new Column[analysisPeriods.length][]; | |
406 | |
407 Range range = new Range(from, to); | |
408 SectorRangeFilter sectorRangeFilter = | |
409 new SectorRangeFilter(qSectorStart, qSectorEnd); | |
410 | |
411 FixingsColumnFactory fcf = FixingsColumnFactory.getInstance(); | |
412 | |
413 for (int i = 0; i < columns.length; ++i) { | |
414 | |
415 // Construct filter for period. | |
416 DateRange period = analysisPeriods[i]; | |
417 | |
418 DateRangeFilter dateRangeFilter = | |
419 new DateRangeFilter(period.getFrom(), period.getTo()); | |
420 | |
421 Filter filter = new AndFilter() | |
422 .add(dateRangeFilter) | |
423 .add(sectorRangeFilter); | |
424 | |
425 List<Fixing.Column> metaCols = overview.filter(range, filter); | |
426 | |
427 if (debug) { | |
428 log.debug("number of filtered columns: " + metaCols.size()); | |
429 } | |
430 | |
431 ArrayList<Column> cols = new ArrayList<Column>(metaCols.size()); | |
432 | |
433 // Only use columns which have data. | |
434 for (Fixing.Column meta: metaCols) { | |
435 FixingsColumn data = fcf.getColumnData(meta); | |
436 if (data != null) { | |
437 cols.add(new Column(meta, data)); | |
438 } | |
439 } | |
440 | |
441 if (debug) { | |
442 log.debug("failed loading: " + (metaCols.size()-cols.size())); | |
443 } | |
444 columns[i] = cols.toArray(new Column[cols.size()]); | |
445 } | |
446 | |
447 return columns; | |
448 } | |
449 } | 283 } |
450 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : | 284 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |