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 :

http://dive4elements.wald.intevation.org