Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java @ 2729:a441be7f1589
Added Fix calculation.
flys-artifacts/trunk@4462 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 22 May 2012 17:09:27 +0000 |
parents | |
children | c1f2e792704a |
comparison
equal
deleted
inserted
replaced
2728:306b9d0f0fb3 | 2729:a441be7f1589 |
---|---|
1 package de.intevation.flys.artifacts.model.fixings; | |
2 | |
3 import de.intevation.flys.artifacts.FixationArtifactAccess; | |
4 | |
5 import de.intevation.flys.artifacts.math.fitting.Function; | |
6 import de.intevation.flys.artifacts.math.fitting.FunctionFactory; | |
7 | |
8 import de.intevation.flys.artifacts.model.Calculation; | |
9 import de.intevation.flys.artifacts.model.CalculationResult; | |
10 import de.intevation.flys.artifacts.model.FixingsColumn; | |
11 import de.intevation.flys.artifacts.model.FixingsColumnFactory; | |
12 import de.intevation.flys.artifacts.model.FixingsOverview; | |
13 import de.intevation.flys.artifacts.model.FixingsOverviewFactory; | |
14 import de.intevation.flys.artifacts.model.Parameters; | |
15 | |
16 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing; | |
17 import de.intevation.flys.artifacts.model.FixingsOverview.IdFilter; | |
18 | |
19 import de.intevation.flys.utils.DoubleUtil; | |
20 | |
21 import java.util.ArrayList; | |
22 import java.util.List; | |
23 | |
24 import org.apache.commons.math.MathException; | |
25 | |
26 import org.apache.commons.math.optimization.fitting.CurveFitter; | |
27 | |
28 import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer; | |
29 | |
30 import org.apache.log4j.Logger; | |
31 | |
32 public class FixCalculation | |
33 extends Calculation | |
34 { | |
35 private static Logger logger = Logger.getLogger(FixCalculation.class); | |
36 | |
37 protected String river; | |
38 protected double from; | |
39 protected double to; | |
40 protected double step; | |
41 protected boolean preprocessing; | |
42 protected String function; | |
43 protected int [] events; | |
44 | |
45 public FixCalculation() { | |
46 } | |
47 | |
48 public FixCalculation(FixationArtifactAccess access) { | |
49 | |
50 String river = access.getRiver(); | |
51 Double from = access.getFrom(); | |
52 Double to = access.getTo(); | |
53 Double step = access.getStep(); | |
54 String function = access.getFunction(); | |
55 int [] events = access.getEvents(); | |
56 | |
57 if (river == null) { | |
58 // TODO: i18n | |
59 addProblem("fix.missing.river"); | |
60 } | |
61 | |
62 if (from == null) { | |
63 // TODO: i18n | |
64 addProblem("fix.missing.from"); | |
65 } | |
66 | |
67 if (to == null) { | |
68 // TODO: i18n | |
69 addProblem("fix.missing.to"); | |
70 } | |
71 | |
72 if (step == null) { | |
73 // TODO: i18n | |
74 addProblem("fix.missing.step"); | |
75 } | |
76 | |
77 if (function == null) { | |
78 // TODO: i18n | |
79 addProblem("fix.missing.function"); | |
80 } | |
81 | |
82 if (events == null || events.length < 1) { | |
83 // TODO: i18n | |
84 addProblem("fix.missing.events"); | |
85 } | |
86 | |
87 if (!hasProblems()) { | |
88 this.river = river; | |
89 this.from = from; | |
90 this.to = to; | |
91 this.step = step; | |
92 this.function = function; | |
93 this.events = events; | |
94 } | |
95 } | |
96 | |
97 public CalculationResult calculate() { | |
98 | |
99 FixingsOverview overview = | |
100 FixingsOverviewFactory.getOverview(river); | |
101 | |
102 if (overview == null) { | |
103 addProblem("fix.no.overview.available"); | |
104 } | |
105 | |
106 Function func = FunctionFactory.getInstance() | |
107 .getFunction(function); | |
108 | |
109 if (func == null) { | |
110 // TODO: i18n | |
111 addProblem("fix.invalid.function.name"); | |
112 } | |
113 | |
114 if (hasProblems()) { | |
115 return new CalculationResult(this); | |
116 } | |
117 | |
118 FixingsColumnFactory fcf = FixingsColumnFactory.getInstance(); | |
119 | |
120 List<FixingsColumn> dataColumns = | |
121 new ArrayList<FixingsColumn>(events.length); | |
122 | |
123 for (int eventId: events) { | |
124 IdFilter idFilter = new IdFilter(eventId); | |
125 | |
126 List<Fixing.Column> columns = overview.filter(null, idFilter); | |
127 if (columns.isEmpty()) { | |
128 // TODO: i18n | |
129 addProblem("fix.missing.column", eventId); | |
130 continue; | |
131 } | |
132 FixingsColumn dataColumn = fcf.getColumnData(columns.get(0)); | |
133 if (dataColumn == null) { | |
134 // TODO: i18n | |
135 addProblem("fix.cannot.load.data", eventId); | |
136 continue; | |
137 } | |
138 dataColumns.add(dataColumn); | |
139 } | |
140 | |
141 if (dataColumns.size() < 2) { | |
142 // TODO: i18n | |
143 addProblem("fix.too.less.data.columns"); | |
144 return new CalculationResult(this); | |
145 } | |
146 | |
147 double [] kms = DoubleUtil.explode(from, to, step); | |
148 | |
149 double [] ws = new double[dataColumns.size()]; | |
150 double [] qs = new double[ws.length]; | |
151 | |
152 String [] parameterNames = func.getParameterNames(); | |
153 | |
154 Parameters results = | |
155 new Parameters(createColumnNames(parameterNames)); | |
156 | |
157 boolean invalid = false; | |
158 | |
159 for (int i = 0; i < kms.length; ++i) { | |
160 double km = kms[i]; | |
161 | |
162 for (int j = 0; j < ws.length; ++j) { | |
163 FixingsColumn column = dataColumns.get(j); | |
164 qs[j] = column.getQ(km); | |
165 boolean interpolated = column.getW(km, ws, j); | |
166 // TODO: mark as interpolated. | |
167 } | |
168 | |
169 // TODO: Do preprocessing here! | |
170 double [] parameters = fit(func, km, ws, qs); | |
171 if (parameters == null) { // Problems are reported already. | |
172 continue; | |
173 } | |
174 | |
175 int row = results.newRow(); | |
176 | |
177 results.set(row, "km", km); | |
178 for (int j = 0; j < parameters.length; ++j) { | |
179 if (Double.isNaN(parameters[j])) { | |
180 invalid = true; | |
181 } | |
182 else { | |
183 results.set(row, parameterNames[j], parameters[j]); | |
184 } | |
185 } | |
186 // TODO: Calculate statistics, too! | |
187 } | |
188 | |
189 if (invalid) { | |
190 // TODO: i18n | |
191 addProblem("fix.invalid.values"); | |
192 results.removeNaNs(); | |
193 } | |
194 | |
195 // TODO: Calculate Delta W/t, too. | |
196 return new CalculationResult(results, this); | |
197 } | |
198 | |
199 protected static String [] createColumnNames(String [] parameters) { | |
200 String [] result = new String[parameters.length + 1]; | |
201 result[0] = "km"; | |
202 // TODO: Add statistic columns, too. | |
203 System.arraycopy(parameters, 0, result, 1, parameters.length); | |
204 return result; | |
205 } | |
206 | |
207 protected double [] fit( | |
208 Function function, | |
209 double km, | |
210 double [] ws, | |
211 double [] qs | |
212 ) { | |
213 LevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer(); | |
214 CurveFitter cf = new CurveFitter(lmo); | |
215 | |
216 boolean missingWs = false; | |
217 boolean missingQs = false; | |
218 | |
219 for (int i = 0; i < ws.length; ++i) { | |
220 boolean ignore = false; | |
221 if (Double.isNaN(ws[i])) { | |
222 ignore = true; | |
223 if (!missingWs) { | |
224 missingWs = true; | |
225 // TODO: i18n | |
226 addProblem(km, "fix.missing.w"); | |
227 } | |
228 } | |
229 if (Double.isNaN(qs[i])) { | |
230 ignore = true; | |
231 if (!missingQs) { | |
232 missingQs = true; | |
233 // TODO: i18n | |
234 addProblem(km, "fix.missing.q"); | |
235 } | |
236 } | |
237 if (!ignore) { | |
238 cf.addObservedPoint(ws[i], qs[i]); | |
239 } | |
240 } | |
241 | |
242 try { | |
243 return cf.fit(function, function.getInitialGuess()); | |
244 } | |
245 catch (MathException me) { | |
246 addProblem(km, "fix.fitting.failed"); | |
247 } | |
248 | |
249 return null; | |
250 } | |
251 } | |
252 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |