changeset 6761:9479cb7c8cd5

flys/issue748: Force linear curve fitting. This is a real hack! Set the system property "minfo.sq.fitting.nonlinear" to re-enable the old behavior.
author Sascha L. Teichmann <teichmann@intevation.de>
date Tue, 06 Aug 2013 17:00:49 +0200 (2013-08-06)
parents ae419fc225b4
children 34c15927f9d9 dd5355775ce1
files artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java
diffstat 1 files changed, 43 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java	Tue Aug 06 16:57:47 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java	Tue Aug 06 17:00:49 2013 +0200
@@ -9,6 +9,7 @@
 package org.dive4elements.river.artifacts.model.sq;
 
 import org.dive4elements.river.artifacts.math.fitting.Function;
+import org.dive4elements.river.artifacts.math.fitting.Linear;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -17,6 +18,8 @@
 
 import org.apache.commons.math.optimization.fitting.CurveFitter;
 
+import org.apache.commons.math.optimization.general.AbstractLeastSquaresOptimizer;
+import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;
 import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
 
 import org.apache.log4j.Logger;
@@ -24,6 +27,10 @@
 public class Fitting
 implements   Outlier.Callback
 {
+    // XXX: Hack to force linear fitting!
+    private static final boolean USE_NON_LINEAR_FITTING =
+        Boolean.getBoolean("minfo.sq.fitting.nonlinear");
+
     private static Logger log = Logger.getLogger(Fitting.class);
 
     public interface Callback {
@@ -75,20 +82,51 @@
     @Override
     public void initialize(List<SQ> sqs) throws MathException {
 
-        LevenbergMarquardtOptimizer lmo =
-            new LevenbergMarquardtOptimizer();
+        AbstractLeastSquaresOptimizer optimizer = getOptimizer();
 
-        CurveFitter cf = new CurveFitter(lmo);
+        CurveFitter cf = new CurveFitter(optimizer);
+        double [] values = new double[2];
         for (SQ sq: sqs) {
-            cf.addObservedPoint(sq.getQ(), sq.getS());
+            values[0] = sq.getQ();
+            values[1] = sq.getS();
+            transformInputValues(values);
+            cf.addObservedPoint(values[0], values[1]);
         }
 
         coeffs = cf.fit(
             function, function.getInitialGuess());
 
+        transformCoeffsBack(coeffs);
+
         instance = function.instantiate(coeffs);
 
-        chiSqr = lmo.getChiSquare();
+        chiSqr = optimizer.getChiSquare();
+    }
+
+    protected Function getFunction(Function function) {
+        return USE_NON_LINEAR_FITTING
+            ? function
+            : Linear.INSTANCE;
+    }
+
+    protected void transformInputValues(double [] values) {
+        if (!USE_NON_LINEAR_FITTING) {
+            for (int i = 0; i < values.length; ++i) {
+                values[i] = Math.log(values[i]);
+            }
+        }
+    }
+
+    protected AbstractLeastSquaresOptimizer getOptimizer() {
+        return USE_NON_LINEAR_FITTING
+            ? new LevenbergMarquardtOptimizer()
+            : new GaussNewtonOptimizer(false);
+    }
+
+    protected void transformCoeffsBack(double [] coeffs) {
+        if (!USE_NON_LINEAR_FITTING && coeffs.length > 0) {
+            coeffs[0] = Math.exp(coeffs[0]);
+        }
     }
 
     @Override

http://dive4elements.wald.intevation.org