# HG changeset patch # User Sascha L. Teichmann # Date 1375978478 -7200 # Node ID 51eb6491c537b9be0f3a2ebeb1065433ff9f160f # Parent 70b440dc53170d804e8f892be43f8ef45421b8d9 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. diff -r 70b440dc5317 -r 51eb6491c537 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java Thu Aug 08 16:19:59 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java Thu Aug 08 18:14:38 2013 +0200 @@ -8,6 +8,7 @@ package org.dive4elements.river.artifacts.model.sq; +import org.dive4elements.artifacts.common.utils.StringUtils; import org.dive4elements.river.artifacts.math.fitting.Function; import java.util.ArrayList; @@ -83,7 +84,7 @@ public void initialize(List sqs) throws MathException { if (USE_NON_LINEAR_FITTING - || function.getInitialGuess().length != 2) { + || function.getParameterNames().length != 2) { nonLinearFitting(sqs); } else { @@ -92,43 +93,48 @@ } protected void linearFitting(List sqs) { - - coeffs = linearRegression(sqs); - + coeffs = linearRegression(sqs); instance = function.instantiate(coeffs); } protected double [] linearRegression(List sqs) { + String [] pns = function.getParameterNames(); + double [] result = new double[pns.length]; + + if (sqs.size() < 2) { + log.debug("not enough points"); + return result; + } + SimpleRegression reg = new SimpleRegression(); - int invalidPoints = 0; for (SQ sq: sqs) { - double s = sq.getS(); - double q = sq.getQ(); - if (s <= 0d || q <= 0d) { - ++invalidPoints; - continue; - } - reg.addData(Math.log(q), Math.log(s)); + double s = sqView.getS(sq); + double q = sqView.getQ(sq); + reg.addData(q, s); } - if (sqs.size() - invalidPoints < 2) { - log.debug("not enough points"); - return new double [] { 0, 0 }; - } - - double a = Math.exp(reg.getIntercept()); + double m = reg.getIntercept(); double b = reg.getSlope(); if (log.isDebugEnabled()) { - log.debug("invalid points: " + - invalidPoints + " (" + sqs.size() + ")"); - log.debug("a: " + a + " (" + Math.log(a) + ")"); + log.debug("m: " + m); log.debug("b: " + b); } - return new double [] { a, b }; + int mIdx = StringUtils.indexOf("m", pns); + int bIdx = StringUtils.indexOf("b", pns); + + if (mIdx == -1 || bIdx == -1) { + log.error("index not found: " + mIdx + " " + bIdx); + return result; + } + + result[bIdx] = m; + result[mIdx] = b; + + return result; } @@ -140,7 +146,7 @@ CurveFitter cf = new CurveFitter(optimizer); for (SQ sq: sqs) { - cf.addObservedPoint(sq.getS(), sq.getQ()); + cf.addObservedPoint(sqView.getQ(sq), sqView.getS(sq)); } coeffs = cf.fit( @@ -179,7 +185,7 @@ chiSqr); } - public boolean fit(List sqs, String method, Callback callback) { + public boolean fit(List sqs, String method, Callback callback) { if (sqs.size() < 2) { log.warn("Too less points for fitting."); diff -r 70b440dc5317 -r 51eb6491c537 artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java Thu Aug 08 16:19:59 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java Thu Aug 08 18:14:38 2013 +0200 @@ -8,6 +8,7 @@ package org.dive4elements.river.artifacts.model.sq; +import org.dive4elements.artifacts.common.utils.StringUtils; import org.dive4elements.river.artifacts.access.SQRelationAccess; import org.dive4elements.river.artifacts.math.fitting.Function; @@ -21,6 +22,7 @@ import org.dive4elements.river.backend.SedDBSessionHolder; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; @@ -30,7 +32,11 @@ private static final Logger log = Logger.getLogger(SQRelationCalculation.class); - public static final String SQ_FUNCTION_NAME = "sq-pow"; + public static final boolean NON_LINEAR_FITTING = + Boolean.getBoolean("minfo.sq.calcution.non.linear.fitting"); + + public static final String SQ_POW_FUNCTION_NAME = "sq-pow"; + public static final String SQ_LIN_FUNCTION_NAME = "linear"; protected String river; protected double location; @@ -49,8 +55,6 @@ Double outliers = access.getOutliers(); String method = access.getOutlierMethod(); - //river = "Rhein"; - if (river == null) { // TODO: i18n addProblem("sq.missing.river"); @@ -102,20 +106,76 @@ } } + public interface TransformCoeffs { + double [] transform(double [] coeffs); + } + + public static final TransformCoeffs IDENTITY_TRANS = + new TransformCoeffs() { + @Override + public double [] transform(double [] coeffs) { + return coeffs; + } + }; + + public static final TransformCoeffs LINEAR_TRANS = + new TransformCoeffs() { + @Override + public double [] transform(double [] coeffs) { + log.debug("before transform: " + Arrays.toString(coeffs)); + if (coeffs.length == 2) { + coeffs = new double [] { Math.exp(coeffs[1]), coeffs[0] }; + } + log.debug("after transform: " + Arrays.toString(coeffs)); + return coeffs; + } + }; + protected CalculationResult internalCalculate() { - Function function = FunctionFactory + Function powFunction = FunctionFactory .getInstance() - .getFunction(SQ_FUNCTION_NAME); + .getFunction(SQ_POW_FUNCTION_NAME); - if (function == null) { - log.error("No '" + SQ_FUNCTION_NAME + "' function found."); + if (powFunction == null) { + log.error("No '" + SQ_POW_FUNCTION_NAME + "' function found."); // TODO: i18n addProblem("sq.missing.sq.function"); + return new CalculationResult(new SQResult[0], this); } - SQ.View sqView = SQ.SQ_VIEW; - SQ.Factory sqFactory = SQ.SQ_FACTORY; + Function function; + SQ.View sqView; + SQ.Factory sqFactory; + ParameterCreator pc; + + + if (NON_LINEAR_FITTING) { + log.debug("Use non linear fitting."); + sqView = SQ.SQ_VIEW; + sqFactory = SQ.SQ_FACTORY; + function = powFunction; + pc = new ParameterCreator( + powFunction.getParameterNames(), + powFunction.getParameterNames()); + } + else { + log.debug("Use linear fitting."); + sqView = LogSQ.LOG_SQ_VIEW; + sqFactory = LogSQ.LOG_SQ_FACTORY; + function = FunctionFactory + .getInstance() + .getFunction(SQ_LIN_FUNCTION_NAME); + if (function == null) { + log.error("No '" + SQ_LIN_FUNCTION_NAME + "' function found."); + // TODO: i18n + addProblem("sq.missing.sq.function"); + return new CalculationResult(new SQResult[0], this); + } + pc = new LinearParameterCreator( + powFunction.getParameterNames(), + function.getParameterNames()); + } Measurements measurements = MeasurementFactory.getMeasurements( @@ -124,13 +184,14 @@ SQFractionResult [] fractionResults = new SQFractionResult[SQResult.NUMBER_FRACTIONS]; + for (int i = 0; i < fractionResults.length; ++i) { List sqs = measurements.getSQs(i); SQFractionResult fractionResult; List iterations = - doFitting(function, sqs, sqView); + doFitting(function, sqs, sqView, pc); if (iterations == null) { // TODO: i18n @@ -152,9 +213,10 @@ } protected List doFitting( - final Function function, - List sqs, - SQ.View sqView + final Function function, + List sqs, + SQ.View sqView, + final ParameterCreator pc ) { final List iterations = new ArrayList(); @@ -171,8 +233,7 @@ double standardDeviation, double chiSqr ) { - Parameters parameters = createParameters( - function.getParameterNames(), + Parameters parameters = pc.createParameters( coeffs, standardDeviation, chiSqr); @@ -186,22 +247,75 @@ return success ? iterations : null; } - public static final Parameters createParameters( - String [] names, - double [] values, - double standardDeviation, - double chiSqr - ) { - String [] columns = new String[names.length + 2]; - columns[0] = "chi_sqr"; - columns[1] = "std_dev"; - System.arraycopy(names, 0, columns, 2, names.length); - Parameters parameters = new Parameters(columns); - int row = parameters.newRow(); - parameters.set(row, names, values); - parameters.set(row, "chi_sqr", chiSqr); - parameters.set(row, "std_dev", standardDeviation); - return parameters; + public static class ParameterCreator { + + protected String [] origNames; + protected String [] proxyNames; + + public ParameterCreator(String [] origNames, String [] proxyNames) { + this.origNames = origNames; + this.proxyNames = proxyNames; + } + + protected double [] transformCoeffs(double [] coeffs) { + return coeffs; + } + + public Parameters createParameters( + double [] coeffs, + double standardDeviation, + double chiSqr + ) { + String [] columns = new String[origNames.length + 2]; + columns[0] = "chi_sqr"; + columns[1] = "std_dev"; + System.arraycopy(origNames, 0, columns, 2, origNames.length); + Parameters parameters = new Parameters(columns); + int row = parameters.newRow(); + parameters.set(row, origNames, transformCoeffs(coeffs)); + parameters.set(row, "chi_sqr", chiSqr); + parameters.set(row, "std_dev", standardDeviation); + return parameters; + } + } + + /** We need to transform the coeffs back to the original function. */ + public static class LinearParameterCreator extends ParameterCreator { + + public LinearParameterCreator( + String [] origNames, + String [] proxyNames + ) { + super(origNames, proxyNames); + } + + @Override + protected double [] transformCoeffs(double [] coeffs) { + + int bP = StringUtils.indexOf("m", proxyNames); + int mP = StringUtils.indexOf("b", proxyNames); + + int aO = StringUtils.indexOf("a", origNames); + int bO = StringUtils.indexOf("b", origNames); + + if (bP == -1 || mP == -1 || aO == -1 || bO == -1) { + log.error("index not found: " + + bP + " " + mP + " " + + aO + " " + bO); + return coeffs; + } + + double [] ncoeffs = (double [])coeffs.clone(); + ncoeffs[aO] = Math.exp(coeffs[mP]); + ncoeffs[bO] = coeffs[bP]; + + if (log.isDebugEnabled()) { + log.debug("before transform: " + Arrays.toString(coeffs)); + log.debug("after transform: " + Arrays.toString(ncoeffs)); + } + + return ncoeffs; + } } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :