package gdsc.smlm.function.gaussian.erf; import gdsc.smlm.function.ValueProcedure; /*----------------------------------------------------------------------------- * GDSC SMLM Software * * Copyright (C) 2017 Alex Herbert * Genome Damage and Stability Centre * University of Sussex, UK * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. *---------------------------------------------------------------------------*/ /** * Abstract base class for an 2-dimensional Gaussian function for a configured number of peaks. * <p> * The function will calculate the value of the Gaussian and evaluate the gradient of a set of parameters. The class can * specify which of the following parameters the function will evaluate:<br/> * background, signal, z-depth, position0, position1, sd0, sd1 * <p> * The class provides an index of the position in the parameter array where the parameter is expected. */ public abstract class MultiErfGaussian2DFunction extends ErfGaussian2DFunction { protected final int nPeaks; protected final int[] gradientIndices; // Required for the PSF protected final double[] tI; /** * Instantiates a new multi-peak erf gaussian 2D function. * * @param nPeaks * The number of peaks * @param maxx * The maximum x value of the 2-dimensional data (used to unpack a linear index into coordinates) * @param maxy * The maximum y value of the 2-dimensional data (used to unpack a linear index into coordinates) */ public MultiErfGaussian2DFunction(int nPeaks, int maxx, int maxy) { super(nPeaks, maxx, maxy); this.nPeaks = nPeaks; this.gradientIndices = createGradientIndices(); tI = new double[nPeaks]; } /* * (non-Javadoc) * * @see gdsc.fitting.function.GaussianFunction#getNPeaks() */ @Override public int getNPeaks() { return nPeaks; } /** * Creates the gradient indices. * * @return the the gradient indices */ abstract protected int[] createGradientIndices(); /** * Replicate the gradient indices from a single peak for the configured number of peaks. * * @param singleGradientIndices * the single gradient indices */ protected int[] replicateGradientIndices(int[] singleGradientIndices) { final int start = (evaluatesBackground() ? 1 : 0); final int m = singleGradientIndices.length; final int[] indices = new int[start + nPeaks * (m - start)]; int p = 0; if (evaluatesBackground()) indices[p++] = 0; for (int n = 0, i = 0; n < nPeaks; n++, i += 6) { for (int j = start; j < m; j++) indices[p++] = i + singleGradientIndices[j]; } return indices; } /* * (non-Javadoc) * * @see gdsc.smlm.fitting.function.NonLinearFunction#gradientIndices() */ public int[] gradientIndices() { return gradientIndices; } /* * (non-Javadoc) * * @see gdsc.smlm.function.GradientFunction#getNumberOfGradients() */ public int getNumberOfGradients() { return gradientIndices.length; } /** * Evaluates an 2-dimensional Gaussian function for a single peak. * * @param i * Input predictor * @return The Gaussian value * * @see gdsc.fitting.function.NonLinearFunction#eval(int) */ public double eval(final int i) { // Unpack the predictor into the dimensions int yy = i / maxx; int xx = i % maxx; double I = tB; for (int n = 0; n < nPeaks; n++, xx += maxx, yy += maxy) I += tI[n] * deltaEx[xx] * deltaEy[yy]; return I; } /* * (non-Javadoc) * * @see gdsc.smlm.function.GradientFunction#forEach(gdsc.smlm.function.GradientFunction.ValueProcedure) */ public void forEach(ValueProcedure procedure) { // Unroll for the number of peaks if (nPeaks == 2) { for (int y = 0; y < maxy; y++) { // Pre-compute final double tI_deltaEy0 = tI[0] * deltaEy[y]; final double tI_deltaEy1 = tI[1] * deltaEy[y + maxy]; for (int x = 0; x < maxx; x++) { procedure.execute(tB + tI_deltaEy0 * deltaEx[x] + tI_deltaEy1 * deltaEx[x + maxx]); } } } else { final double[] tI_deltaEy = new double[nPeaks]; for (int y = 0; y < maxy; y++) { // Pre-compute for (int n = 0, yy = y; n < nPeaks; n++, yy += maxy) tI_deltaEy[n] = tI[n] * deltaEy[yy]; for (int x = 0; x < maxx; x++) { double I = tB; for (int n = 0, xx = x; n < nPeaks; n++, xx += maxx) I += tI_deltaEy[n] * deltaEx[xx]; procedure.execute(I); } // No pre-compute // for (int x = 0; x < maxx; x++) // { // double I = tB; // for (int n = 0, xx = x, yy = y; n < nPeaks; n++, xx += maxx, yy += maxy) // I += tI[n] * deltaEx[xx] * deltaEy[yy]; // procedure.execute(I); // } } } } }