Search in sources :

Example 1 with ComputationException

use of uk.ac.sussex.gdsc.core.data.ComputationException in project GDSC-SMLM by aherbert.

the class AiryPsfModel method createAiryDistribution.

private static synchronized void createAiryDistribution() {
    if (spline != null) {
        return;
    }
    final double relativeAccuracy = 1e-4;
    final double absoluteAccuracy = 1e-8;
    final int minimalIterationCount = 3;
    final int maximalIterationCount = 32;
    final UnivariateIntegrator integrator = new CustomSimpsonIntegrator(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
    // The pattern profile is in one dimension.
    // Multiply by the perimeter of a circle to convert to 2D volume then normalise by 4 pi
    // return AiryPattern.intensity(x) * 2 * Math.PI * x / (4 * Math.PI)
    final UnivariateFunction f = x -> AiryPattern.intensity(x) * 0.5 * x;
    // Integrate up to a set number of dark rings
    final int samples = 1000;
    final double step = RINGS[SAMPLE_RINGS] / samples;
    double to = 0;
    double from = 0;
    final double[] radius = new double[samples + 1];
    final double[] sum = new double[samples + 1];
    for (int i = 1; i < sum.length; i++) {
        from = to;
        radius[i] = to = step * i;
        sum[i] = integrator.integrate(2000, f, from, to) + sum[i - 1];
    }
    if (DoubleEquality.relativeError(sum[samples], POWER[SAMPLE_RINGS]) > 1e-3) {
        throw new ComputationException("Failed to create the Airy distribution");
    }
    final SplineInterpolator si = new SplineInterpolator();
    spline = si.interpolate(sum, radius);
}
Also used : SplineInterpolator(org.apache.commons.math3.analysis.interpolation.SplineInterpolator) Arrays(java.util.Arrays) ComputationException(uk.ac.sussex.gdsc.core.data.ComputationException) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) UnivariateIntegrator(org.apache.commons.math3.analysis.integration.UnivariateIntegrator) UnitSphereSampler(org.apache.commons.rng.sampling.UnitSphereSampler) CustomSimpsonIntegrator(uk.ac.sussex.gdsc.smlm.math3.analysis.integration.CustomSimpsonIntegrator) PolynomialSplineFunction(org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction) UnivariateFunction(org.apache.commons.math3.analysis.UnivariateFunction) ValidationUtils(uk.ac.sussex.gdsc.core.utils.ValidationUtils) MathUtils(uk.ac.sussex.gdsc.core.utils.MathUtils) DoubleEquality(uk.ac.sussex.gdsc.core.utils.DoubleEquality) UnivariateIntegrator(org.apache.commons.math3.analysis.integration.UnivariateIntegrator) UnivariateFunction(org.apache.commons.math3.analysis.UnivariateFunction) ComputationException(uk.ac.sussex.gdsc.core.data.ComputationException) SplineInterpolator(org.apache.commons.math3.analysis.interpolation.SplineInterpolator) CustomSimpsonIntegrator(uk.ac.sussex.gdsc.smlm.math3.analysis.integration.CustomSimpsonIntegrator)

Example 2 with ComputationException

use of uk.ac.sussex.gdsc.core.data.ComputationException in project GDSC-SMLM by aherbert.

the class EmGainAnalysis method fit.

/**
 * Fit the EM-gain distribution (Gaussian * Gamma).
 *
 * @param histogram The distribution
 */
private void fit(int[] histogram) {
    final int[] limits = limits(histogram);
    final double[] x = getX(limits);
    final double[] y = getY(histogram, limits);
    Plot plot = new Plot(TITLE, "ADU", "Frequency");
    double yMax = MathUtils.max(y);
    plot.setLimits(limits[0], limits[1], 0, yMax);
    plot.setColor(Color.black);
    plot.addPoints(x, y, Plot.DOT);
    ImageJUtils.display(TITLE, plot);
    // Estimate remaining parameters.
    // Assuming a gamma_distribution(shape,scale) then mean = shape * scale
    // scale = gain
    // shape = Photons = mean / gain
    double mean = getMean(histogram) - settings.bias;
    // Note: if the bias is too high then the mean will be negative. Just move the bias.
    while (mean < 0) {
        settings.bias -= 1;
        mean += 1;
    }
    double photons = mean / settings.gain;
    if (settings.settingSimulate) {
        ImageJUtils.log("Simulated bias=%d, gain=%s, noise=%s, photons=%s", (int) settings.settingBias, MathUtils.rounded(settings.settingGain), MathUtils.rounded(settings.settingNoise), MathUtils.rounded(settings.settingPhotons));
    }
    ImageJUtils.log("Estimate bias=%d, gain=%s, noise=%s, photons=%s", (int) settings.bias, MathUtils.rounded(settings.gain), MathUtils.rounded(settings.noise), MathUtils.rounded(photons));
    final int max = (int) x[x.length - 1];
    double[] pg = pdf(max, photons, settings.gain, settings.noise, (int) settings.bias);
    plot.setColor(Color.blue);
    plot.addPoints(x, pg, Plot.LINE);
    ImageJUtils.display(TITLE, plot);
    // Perform a fit
    final CustomPowellOptimizer o = new CustomPowellOptimizer(1e-6, 1e-16, 1e-6, 1e-16);
    final double[] startPoint = new double[] { photons, settings.gain, settings.noise, settings.bias };
    int maxEval = 3000;
    final String[] paramNames = { "Photons", "Gain", "Noise", "Bias" };
    // Set bounds
    final double[] lower = new double[] { 0, 0.5 * settings.gain, 0, settings.bias - settings.noise };
    final double[] upper = new double[] { 2 * photons, 2 * settings.gain, settings.gain, settings.bias + settings.noise };
    // Restart until converged.
    // TODO - Maybe fix this with a better optimiser. This needs to be tested on real data.
    PointValuePair solution = null;
    for (int iter = 0; iter < 3; iter++) {
        IJ.showStatus("Fitting histogram ... Iteration " + iter);
        try {
            // Basic Powell optimiser
            final MultivariateFunction fun = getFunction(limits, y, max, maxEval);
            final PointValuePair optimum = o.optimize(new MaxEval(maxEval), new ObjectiveFunction(fun), GoalType.MINIMIZE, new InitialGuess((solution == null) ? startPoint : solution.getPointRef()));
            if (solution == null || optimum.getValue() < solution.getValue()) {
                final double[] point = optimum.getPointRef();
                // Check the bounds
                for (int i = 0; i < point.length; i++) {
                    if (point[i] < lower[i] || point[i] > upper[i]) {
                        throw new ComputationException(String.format("Fit out of of estimated range: %s %f", paramNames[i], point[i]));
                    }
                }
                solution = optimum;
            }
        } catch (final Exception ex) {
            IJ.log("Powell error: " + ex.getMessage());
            if (ex instanceof TooManyEvaluationsException) {
                maxEval = (int) (maxEval * 1.5);
            }
        }
        try {
            // Bounded Powell optimiser
            final MultivariateFunction fun = getFunction(limits, y, max, maxEval);
            final MultivariateFunctionMappingAdapter adapter = new MultivariateFunctionMappingAdapter(fun, lower, upper);
            PointValuePair optimum = o.optimize(new MaxEval(maxEval), new ObjectiveFunction(adapter), GoalType.MINIMIZE, new InitialGuess(adapter.boundedToUnbounded((solution == null) ? startPoint : solution.getPointRef())));
            final double[] point = adapter.unboundedToBounded(optimum.getPointRef());
            optimum = new PointValuePair(point, optimum.getValue());
            if (solution == null || optimum.getValue() < solution.getValue()) {
                solution = optimum;
            }
        } catch (final Exception ex) {
            IJ.log("Bounded Powell error: " + ex.getMessage());
            if (ex instanceof TooManyEvaluationsException) {
                maxEval = (int) (maxEval * 1.5);
            }
        }
    }
    ImageJUtils.finished();
    if (solution == null) {
        ImageJUtils.log("Failed to fit the distribution");
        return;
    }
    final double[] point = solution.getPointRef();
    photons = point[0];
    settings.gain = point[1];
    settings.noise = point[2];
    settings.bias = (int) Math.round(point[3]);
    final String label = String.format("Fitted bias=%d, gain=%s, noise=%s, photons=%s", (int) settings.bias, MathUtils.rounded(settings.gain), MathUtils.rounded(settings.noise), MathUtils.rounded(photons));
    ImageJUtils.log(label);
    if (settings.settingSimulate) {
        ImageJUtils.log("Relative Error bias=%s, gain=%s, noise=%s, photons=%s", MathUtils.rounded(relativeError(settings.bias, settings.settingBias)), MathUtils.rounded(relativeError(settings.gain, settings.settingGain)), MathUtils.rounded(relativeError(settings.noise, settings.settingNoise)), MathUtils.rounded(relativeError(photons, settings.settingPhotons)));
    }
    // Show the PoissonGammaGaussian approximation
    double[] approxValues = null;
    if (settings.showApproximation) {
        approxValues = new double[x.length];
        final PoissonGammaGaussianFunction fun = new PoissonGammaGaussianFunction(1.0 / settings.gain, settings.noise);
        final double expected = photons * settings.gain;
        for (int i = 0; i < approxValues.length; i++) {
            approxValues[i] = fun.likelihood(x[i] - settings.bias, expected);
        }
        yMax = MathUtils.maxDefault(yMax, approxValues);
    }
    // Replot
    pg = pdf(max, photons, settings.gain, settings.noise, (int) settings.bias);
    plot = new Plot(TITLE, "ADU", "Frequency");
    plot.setLimits(limits[0], limits[1], 0, yMax * 1.05);
    plot.setColor(Color.black);
    plot.addPoints(x, y, Plot.DOT);
    plot.setColor(Color.red);
    plot.addPoints(x, pg, Plot.LINE);
    plot.addLabel(0, 0, label);
    if (settings.showApproximation) {
        plot.setColor(Color.blue);
        plot.addPoints(x, approxValues, Plot.LINE);
    }
    ImageJUtils.display(TITLE, plot);
}
Also used : MaxEval(org.apache.commons.math3.optim.MaxEval) InitialGuess(org.apache.commons.math3.optim.InitialGuess) Plot(ij.gui.Plot) ObjectiveFunction(org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction) Point(java.awt.Point) ComputationException(uk.ac.sussex.gdsc.core.data.ComputationException) TooManyEvaluationsException(org.apache.commons.math3.exception.TooManyEvaluationsException) PointValuePair(org.apache.commons.math3.optim.PointValuePair) MultivariateFunction(org.apache.commons.math3.analysis.MultivariateFunction) MultivariateFunctionMappingAdapter(org.apache.commons.math3.optim.nonlinear.scalar.MultivariateFunctionMappingAdapter) TooManyEvaluationsException(org.apache.commons.math3.exception.TooManyEvaluationsException) ComputationException(uk.ac.sussex.gdsc.core.data.ComputationException) CustomPowellOptimizer(uk.ac.sussex.gdsc.smlm.math3.optim.nonlinear.scalar.noderiv.CustomPowellOptimizer) PoissonGammaGaussianFunction(uk.ac.sussex.gdsc.smlm.function.PoissonGammaGaussianFunction)

Aggregations

ComputationException (uk.ac.sussex.gdsc.core.data.ComputationException)2 Plot (ij.gui.Plot)1 Point (java.awt.Point)1 Arrays (java.util.Arrays)1 MultivariateFunction (org.apache.commons.math3.analysis.MultivariateFunction)1 UnivariateFunction (org.apache.commons.math3.analysis.UnivariateFunction)1 UnivariateIntegrator (org.apache.commons.math3.analysis.integration.UnivariateIntegrator)1 SplineInterpolator (org.apache.commons.math3.analysis.interpolation.SplineInterpolator)1 PolynomialSplineFunction (org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction)1 TooManyEvaluationsException (org.apache.commons.math3.exception.TooManyEvaluationsException)1 InitialGuess (org.apache.commons.math3.optim.InitialGuess)1 MaxEval (org.apache.commons.math3.optim.MaxEval)1 PointValuePair (org.apache.commons.math3.optim.PointValuePair)1 MultivariateFunctionMappingAdapter (org.apache.commons.math3.optim.nonlinear.scalar.MultivariateFunctionMappingAdapter)1 ObjectiveFunction (org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction)1 UniformRandomProvider (org.apache.commons.rng.UniformRandomProvider)1 UnitSphereSampler (org.apache.commons.rng.sampling.UnitSphereSampler)1 DoubleEquality (uk.ac.sussex.gdsc.core.utils.DoubleEquality)1 MathUtils (uk.ac.sussex.gdsc.core.utils.MathUtils)1 ValidationUtils (uk.ac.sussex.gdsc.core.utils.ValidationUtils)1