Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java @ 6787:51eb6491c537
S/Q: Excel compat completed: Now the data is linearized before fitting. This can be prevented by setting the system property S/Q: Excel compat completed: Now the data is linearized before fitting. This can be prevented by setting the system property "minfo.sq.calcution.non.linear.fitting" to true.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 08 Aug 2013 18:14:38 +0200 |
parents | b8f94e865875 |
children | 978ab716a15e |
comparison
equal
deleted
inserted
replaced
6786:70b440dc5317 | 6787:51eb6491c537 |
---|---|
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.sq; | 9 package org.dive4elements.river.artifacts.model.sq; |
10 | 10 |
11 import org.dive4elements.artifacts.common.utils.StringUtils; | |
11 import org.dive4elements.river.artifacts.access.SQRelationAccess; | 12 import org.dive4elements.river.artifacts.access.SQRelationAccess; |
12 | 13 |
13 import org.dive4elements.river.artifacts.math.fitting.Function; | 14 import org.dive4elements.river.artifacts.math.fitting.Function; |
14 import org.dive4elements.river.artifacts.math.fitting.FunctionFactory; | 15 import org.dive4elements.river.artifacts.math.fitting.FunctionFactory; |
15 | 16 |
19 import org.dive4elements.river.artifacts.model.Parameters; | 20 import org.dive4elements.river.artifacts.model.Parameters; |
20 | 21 |
21 import org.dive4elements.river.backend.SedDBSessionHolder; | 22 import org.dive4elements.river.backend.SedDBSessionHolder; |
22 | 23 |
23 import java.util.ArrayList; | 24 import java.util.ArrayList; |
25 import java.util.Arrays; | |
24 import java.util.List; | 26 import java.util.List; |
25 | 27 |
26 import org.apache.log4j.Logger; | 28 import org.apache.log4j.Logger; |
27 | 29 |
28 public class SQRelationCalculation extends Calculation { | 30 public class SQRelationCalculation extends Calculation { |
29 | 31 |
30 private static final Logger log = | 32 private static final Logger log = |
31 Logger.getLogger(SQRelationCalculation.class); | 33 Logger.getLogger(SQRelationCalculation.class); |
32 | 34 |
33 public static final String SQ_FUNCTION_NAME = "sq-pow"; | 35 public static final boolean NON_LINEAR_FITTING = |
36 Boolean.getBoolean("minfo.sq.calcution.non.linear.fitting"); | |
37 | |
38 public static final String SQ_POW_FUNCTION_NAME = "sq-pow"; | |
39 public static final String SQ_LIN_FUNCTION_NAME = "linear"; | |
34 | 40 |
35 protected String river; | 41 protected String river; |
36 protected double location; | 42 protected double location; |
37 protected DateRange period; | 43 protected DateRange period; |
38 protected double outliers; | 44 protected double outliers; |
46 String river = access.getRiver(); | 52 String river = access.getRiver(); |
47 Double location = access.getLocation(); | 53 Double location = access.getLocation(); |
48 DateRange period = access.getPeriod(); | 54 DateRange period = access.getPeriod(); |
49 Double outliers = access.getOutliers(); | 55 Double outliers = access.getOutliers(); |
50 String method = access.getOutlierMethod(); | 56 String method = access.getOutlierMethod(); |
51 | |
52 //river = "Rhein"; | |
53 | 57 |
54 if (river == null) { | 58 if (river == null) { |
55 // TODO: i18n | 59 // TODO: i18n |
56 addProblem("sq.missing.river"); | 60 addProblem("sq.missing.river"); |
57 } | 61 } |
100 finally { | 104 finally { |
101 SedDBSessionHolder.release(); | 105 SedDBSessionHolder.release(); |
102 } | 106 } |
103 } | 107 } |
104 | 108 |
109 public interface TransformCoeffs { | |
110 double [] transform(double [] coeffs); | |
111 } | |
112 | |
113 public static final TransformCoeffs IDENTITY_TRANS = | |
114 new TransformCoeffs() { | |
115 @Override | |
116 public double [] transform(double [] coeffs) { | |
117 return coeffs; | |
118 } | |
119 }; | |
120 | |
121 public static final TransformCoeffs LINEAR_TRANS = | |
122 new TransformCoeffs() { | |
123 @Override | |
124 public double [] transform(double [] coeffs) { | |
125 log.debug("before transform: " + Arrays.toString(coeffs)); | |
126 if (coeffs.length == 2) { | |
127 coeffs = new double [] { Math.exp(coeffs[1]), coeffs[0] }; | |
128 } | |
129 log.debug("after transform: " + Arrays.toString(coeffs)); | |
130 return coeffs; | |
131 } | |
132 }; | |
133 | |
105 protected CalculationResult internalCalculate() { | 134 protected CalculationResult internalCalculate() { |
106 | 135 |
107 Function function = FunctionFactory | 136 Function powFunction = FunctionFactory |
108 .getInstance() | 137 .getInstance() |
109 .getFunction(SQ_FUNCTION_NAME); | 138 .getFunction(SQ_POW_FUNCTION_NAME); |
110 | 139 |
111 if (function == null) { | 140 if (powFunction == null) { |
112 log.error("No '" + SQ_FUNCTION_NAME + "' function found."); | 141 log.error("No '" + SQ_POW_FUNCTION_NAME + "' function found."); |
113 // TODO: i18n | 142 // TODO: i18n |
114 addProblem("sq.missing.sq.function"); | 143 addProblem("sq.missing.sq.function"); |
115 } | 144 return new CalculationResult(new SQResult[0], this); |
116 | 145 } |
117 SQ.View sqView = SQ.SQ_VIEW; | 146 |
118 SQ.Factory sqFactory = SQ.SQ_FACTORY; | 147 Function function; |
148 SQ.View sqView; | |
149 SQ.Factory sqFactory; | |
150 ParameterCreator pc; | |
151 | |
152 | |
153 if (NON_LINEAR_FITTING) { | |
154 log.debug("Use non linear fitting."); | |
155 sqView = SQ.SQ_VIEW; | |
156 sqFactory = SQ.SQ_FACTORY; | |
157 function = powFunction; | |
158 pc = new ParameterCreator( | |
159 powFunction.getParameterNames(), | |
160 powFunction.getParameterNames()); | |
161 } | |
162 else { | |
163 log.debug("Use linear fitting."); | |
164 sqView = LogSQ.LOG_SQ_VIEW; | |
165 sqFactory = LogSQ.LOG_SQ_FACTORY; | |
166 function = FunctionFactory | |
167 .getInstance() | |
168 .getFunction(SQ_LIN_FUNCTION_NAME); | |
169 if (function == null) { | |
170 log.error("No '" + SQ_LIN_FUNCTION_NAME + "' function found."); | |
171 // TODO: i18n | |
172 addProblem("sq.missing.sq.function"); | |
173 return new CalculationResult(new SQResult[0], this); | |
174 } | |
175 pc = new LinearParameterCreator( | |
176 powFunction.getParameterNames(), | |
177 function.getParameterNames()); | |
178 } | |
119 | 179 |
120 Measurements measurements = | 180 Measurements measurements = |
121 MeasurementFactory.getMeasurements( | 181 MeasurementFactory.getMeasurements( |
122 river, location, period, sqFactory); | 182 river, location, period, sqFactory); |
123 | 183 |
124 SQFractionResult [] fractionResults = | 184 SQFractionResult [] fractionResults = |
125 new SQFractionResult[SQResult.NUMBER_FRACTIONS]; | 185 new SQFractionResult[SQResult.NUMBER_FRACTIONS]; |
126 | 186 |
187 | |
127 for (int i = 0; i < fractionResults.length; ++i) { | 188 for (int i = 0; i < fractionResults.length; ++i) { |
128 List<SQ> sqs = measurements.getSQs(i); | 189 List<SQ> sqs = measurements.getSQs(i); |
129 | 190 |
130 SQFractionResult fractionResult; | 191 SQFractionResult fractionResult; |
131 | 192 |
132 List<SQFractionResult.Iteration> iterations = | 193 List<SQFractionResult.Iteration> iterations = |
133 doFitting(function, sqs, sqView); | 194 doFitting(function, sqs, sqView, pc); |
134 | 195 |
135 if (iterations == null) { | 196 if (iterations == null) { |
136 // TODO: i18n | 197 // TODO: i18n |
137 addProblem("sq.fitting.failed." + i); | 198 addProblem("sq.fitting.failed." + i); |
138 fractionResult = new SQFractionResult(); | 199 fractionResult = new SQFractionResult(); |
150 new SQResult[] { new SQResult(location, fractionResults) }, | 211 new SQResult[] { new SQResult(location, fractionResults) }, |
151 this); | 212 this); |
152 } | 213 } |
153 | 214 |
154 protected List<SQFractionResult.Iteration> doFitting( | 215 protected List<SQFractionResult.Iteration> doFitting( |
155 final Function function, | 216 final Function function, |
156 List<SQ> sqs, | 217 List<SQ> sqs, |
157 SQ.View sqView | 218 SQ.View sqView, |
219 final ParameterCreator pc | |
158 ) { | 220 ) { |
159 final List<SQFractionResult.Iteration> iterations = | 221 final List<SQFractionResult.Iteration> iterations = |
160 new ArrayList<SQFractionResult.Iteration>(); | 222 new ArrayList<SQFractionResult.Iteration>(); |
161 | 223 |
162 boolean success = new Fitting(function, outliers, sqView).fit( | 224 boolean success = new Fitting(function, outliers, sqView).fit( |
169 SQ [] measurements, | 231 SQ [] measurements, |
170 SQ [] outliers, | 232 SQ [] outliers, |
171 double standardDeviation, | 233 double standardDeviation, |
172 double chiSqr | 234 double chiSqr |
173 ) { | 235 ) { |
174 Parameters parameters = createParameters( | 236 Parameters parameters = pc.createParameters( |
175 function.getParameterNames(), | |
176 coeffs, | 237 coeffs, |
177 standardDeviation, | 238 standardDeviation, |
178 chiSqr); | 239 chiSqr); |
179 iterations.add(new SQFractionResult.Iteration( | 240 iterations.add(new SQFractionResult.Iteration( |
180 parameters, | 241 parameters, |
184 }); | 245 }); |
185 | 246 |
186 return success ? iterations : null; | 247 return success ? iterations : null; |
187 } | 248 } |
188 | 249 |
189 public static final Parameters createParameters( | 250 public static class ParameterCreator { |
190 String [] names, | 251 |
191 double [] values, | 252 protected String [] origNames; |
192 double standardDeviation, | 253 protected String [] proxyNames; |
193 double chiSqr | 254 |
194 ) { | 255 public ParameterCreator(String [] origNames, String [] proxyNames) { |
195 String [] columns = new String[names.length + 2]; | 256 this.origNames = origNames; |
196 columns[0] = "chi_sqr"; | 257 this.proxyNames = proxyNames; |
197 columns[1] = "std_dev"; | 258 } |
198 System.arraycopy(names, 0, columns, 2, names.length); | 259 |
199 Parameters parameters = new Parameters(columns); | 260 protected double [] transformCoeffs(double [] coeffs) { |
200 int row = parameters.newRow(); | 261 return coeffs; |
201 parameters.set(row, names, values); | 262 } |
202 parameters.set(row, "chi_sqr", chiSqr); | 263 |
203 parameters.set(row, "std_dev", standardDeviation); | 264 public Parameters createParameters( |
204 return parameters; | 265 double [] coeffs, |
266 double standardDeviation, | |
267 double chiSqr | |
268 ) { | |
269 String [] columns = new String[origNames.length + 2]; | |
270 columns[0] = "chi_sqr"; | |
271 columns[1] = "std_dev"; | |
272 System.arraycopy(origNames, 0, columns, 2, origNames.length); | |
273 Parameters parameters = new Parameters(columns); | |
274 int row = parameters.newRow(); | |
275 parameters.set(row, origNames, transformCoeffs(coeffs)); | |
276 parameters.set(row, "chi_sqr", chiSqr); | |
277 parameters.set(row, "std_dev", standardDeviation); | |
278 return parameters; | |
279 } | |
280 } | |
281 | |
282 /** We need to transform the coeffs back to the original function. */ | |
283 public static class LinearParameterCreator extends ParameterCreator { | |
284 | |
285 public LinearParameterCreator( | |
286 String [] origNames, | |
287 String [] proxyNames | |
288 ) { | |
289 super(origNames, proxyNames); | |
290 } | |
291 | |
292 @Override | |
293 protected double [] transformCoeffs(double [] coeffs) { | |
294 | |
295 int bP = StringUtils.indexOf("m", proxyNames); | |
296 int mP = StringUtils.indexOf("b", proxyNames); | |
297 | |
298 int aO = StringUtils.indexOf("a", origNames); | |
299 int bO = StringUtils.indexOf("b", origNames); | |
300 | |
301 if (bP == -1 || mP == -1 || aO == -1 || bO == -1) { | |
302 log.error("index not found: " | |
303 + bP + " " + mP + " " | |
304 + aO + " " + bO); | |
305 return coeffs; | |
306 } | |
307 | |
308 double [] ncoeffs = (double [])coeffs.clone(); | |
309 ncoeffs[aO] = Math.exp(coeffs[mP]); | |
310 ncoeffs[bO] = coeffs[bP]; | |
311 | |
312 if (log.isDebugEnabled()) { | |
313 log.debug("before transform: " + Arrays.toString(coeffs)); | |
314 log.debug("after transform: " + Arrays.toString(ncoeffs)); | |
315 } | |
316 | |
317 return ncoeffs; | |
318 } | |
205 } | 319 } |
206 } | 320 } |
207 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : | 321 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : |