view flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java @ 3552:1df6984628c3

S/Q: Extented the result data model of the S/Q calculation to store the curve coefficients for each iteration step of the outlier elimination. flys-artifacts/trunk@5146 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 27 Jul 2012 12:36:09 +0000
parents 49fe2ed03c12
children 8d0f06b76e09
line wrap: on
line source
package de.intevation.flys.artifacts.model.sq;

import de.intevation.flys.artifacts.math.fitting.Function;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.math.MathException;

import org.apache.commons.math.optimization.fitting.CurveFitter;

import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;

import org.apache.log4j.Logger;

public class Fitting
implements   Outlier.Callback
{
    private static Logger log = Logger.getLogger(Fitting.class);

    public interface Callback {

        void afterIteration(
            double [] parameters,
            SQ []     measurements,
            SQ []     outliers,
            double    standardDeviation,
            double    chiSqr);
    } // interfacte

    protected Function function;

    protected double [] coeffs;

    protected de.intevation.flys.artifacts.math.Function instance;

    protected List<SQ> remainings;
    protected List<SQ> outliers;

    protected double standardDeviation;
    protected double stdDevFactor;
    protected double chiSqr;

    protected Callback callback;

    public Fitting() {
        remainings = new ArrayList<SQ>();
        outliers   = new ArrayList<SQ>();
    }

    public Fitting(Function function, double stdDevFactor) {
        this();
        this.function     = function;
        this.stdDevFactor = stdDevFactor;
    }

    public Function getFunction() {
        return function;
    }

    public void setFunction(Function function) {
        this.function = function;
    }

    public double getStdDevFactor() {
        return stdDevFactor;
    }

    public void setStdDevFactor(double stdDevFactor) {
        this.stdDevFactor = stdDevFactor;
    }

    @Override
    public void initialize(Iterator<SQ> good) throws MathException {

        LevenbergMarquardtOptimizer lmo =
            new LevenbergMarquardtOptimizer();

        CurveFitter cf = new CurveFitter(lmo);
        while (good.hasNext()) {
            SQ sq = good.next();
            cf.addObservedPoint(sq.getQ(), sq.getS());
        }

        coeffs = cf.fit(
            function, function.getInitialGuess());

        instance = function.instantiate(coeffs);

        chiSqr = lmo.getChiSquare();

    }

    @Override
    public double eval(SQ sq) {
        double s = instance.value(sq.q);
        return sq.s - s;
    }

    @Override
    public void outlier(SQ sq) {
        outliers.add(sq);
    }

    @Override
    public void remaining(SQ sq) {
        remainings.add(sq);
    }

    @Override
    public void standardDeviation(double standardDeviation) {
        this.standardDeviation = standardDeviation;
    }

    @Override
    public void iterationFinished() {
        if (log.isDebugEnabled()) {
            log.debug("iterationFinished ----");
            log.debug(" num remainings: " + remainings.size());
            log.debug(" num outliers: " + outliers.size());
            log.debug(" standardDeviation: " + standardDeviation);
            log.debug(" Chi^2: " + chiSqr);
            log.debug("---- iterationFinished");
        }
        callback.afterIteration(
            coeffs,
            remainings.toArray(new SQ[remainings.size()]),
            outliers.toArray(new SQ[outliers.size()]),
            standardDeviation,
            chiSqr);
        remainings.clear();
        outliers.clear();
    }

    protected static final List<SQ> onlyValid(List<SQ> sqs) {

        List<SQ> good = new ArrayList<SQ>(sqs.size());

        for (SQ sq: sqs) {
            if (sq.isValid()) {
                good.add(sq);
            }
        }

        return good;
    }

    public boolean fit(List<SQ> sqs, Callback callback) {

        sqs = onlyValid(sqs);

        if (sqs.size() < 2) {
            log.warn("Too less points for fitting.");
            return false;
        }

        this.callback = callback;

        try {
            Outlier.detectOutliers(this, sqs, stdDevFactor);
        }
        catch (MathException me) {
            log.warn(me);
            return false;
        }

        return true;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org