Search in sources :

Example 1 with StoredDataStatistics

use of uk.ac.sussex.gdsc.core.utils.StoredDataStatistics in project GDSC-SMLM by aherbert.

the class CreateData method showSummary.

private double showSummary(List<? extends FluorophoreSequenceModel> fluorophores, List<LocalisationModel> localisations) {
    IJ.showStatus("Calculating statistics ...");
    final Statistics[] stats = new Statistics[NAMES.length];
    for (int i = 0; i < stats.length; i++) {
        stats[i] = (settings.getShowHistograms() || alwaysRemoveOutliers[i]) ? new StoredDataStatistics() : new Statistics();
    }
    // Find the largest timepoint
    final ImagePlus outputImp = WindowManager.getImage(benchmarkImageId);
    int frameCount;
    if (outputImp == null) {
        sortLocalisationsByTime(localisations);
        frameCount = localisations.get(localisations.size() - 1).getTime();
    } else {
        frameCount = outputImp.getStackSize();
    }
    final int[] countHistogram = new int[frameCount + 1];
    // Use the localisations that were drawn to create the sampled on/off times
    rebuildNeighbours(localisations);
    // Assume that there is at least one localisation
    final LocalisationModel first = localisations.get(0);
    // The current localisation
    int currentId = first.getId();
    // The last time this localisation was on
    int lastT = first.getTime();
    // Number of blinks
    int blinks = 0;
    // On-time of current pulse
    int currentT = 0;
    double signal = 0;
    final double centreOffset = settings.getSize() * 0.5;
    // Used to convert the sampled times in frames into seconds
    final double framesPerSecond = 1000.0 / settings.getExposureTime();
    // final double gain = new CreateDataSettingsHelper(settings).getTotalGainSafe();
    for (final LocalisationModel l : localisations) {
        final double[] data = l.getData();
        if (data == null) {
            throw new IllegalStateException("No localisation data. This should not happen!");
        }
        final double noise = data[1];
        final double sx = data[2];
        final double sy = data[3];
        final double intensityInPhotons = data[4];
        // Q. What if the noise is zero, i.e. no background photon / read noise?
        // Just ignore it at current. This is only an approximation to the SNR estimate
        // if this is not a Gaussian spot.
        final double snr = Gaussian2DPeakResultHelper.getMeanSignalUsingP05(intensityInPhotons, sx, sy) / noise;
        stats[SIGNAL].add(intensityInPhotons);
        stats[NOISE].add(noise);
        if (noise != 0) {
            stats[SNR].add(snr);
        }
        // if (l.isContinuous())
        if (l.getNext() != null && l.getPrevious() != null) {
            stats[SIGNAL_CONTINUOUS].add(intensityInPhotons);
            if (noise != 0) {
                stats[SNR_CONTINUOUS].add(snr);
            }
        }
        final int id = l.getId();
        // Check if this a new fluorophore
        if (currentId != id) {
            // Add previous fluorophore
            stats[SAMPLED_BLINKS].add(blinks);
            stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
            stats[TOTAL_SIGNAL].add(signal);
            // Reset
            blinks = 0;
            currentT = 1;
            currentId = id;
            signal = intensityInPhotons;
        } else {
            signal += intensityInPhotons;
            // Check if the current fluorophore pulse is broken (i.e. a blink)
            if (l.getTime() - 1 > lastT) {
                blinks++;
                stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
                currentT = 1;
                stats[SAMPLED_T_OFF].add(((l.getTime() - 1) - lastT) / framesPerSecond);
            } else {
                // Continuous on-time
                currentT++;
            }
        }
        lastT = l.getTime();
        countHistogram[lastT]++;
        stats[X].add((l.getX() - centreOffset) * settings.getPixelPitch());
        stats[Y].add((l.getY() - centreOffset) * settings.getPixelPitch());
        stats[Z].add(l.getZ() * settings.getPixelPitch());
    }
    // Final fluorophore
    stats[SAMPLED_BLINKS].add(blinks);
    stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
    stats[TOTAL_SIGNAL].add(signal);
    // Samples per frame
    for (int t = 1; t < countHistogram.length; t++) {
        stats[SAMPLES].add(countHistogram[t]);
    }
    if (fluorophores != null) {
        for (final FluorophoreSequenceModel f : fluorophores) {
            stats[BLINKS].add(f.getNumberOfBlinks());
            // On-time
            for (final double t : f.getOnTimes()) {
                stats[T_ON].add(t);
            }
            // Off-time
            for (final double t : f.getOffTimes()) {
                stats[T_OFF].add(t);
            }
        }
    } else {
        // show no blinks
        stats[BLINKS].add(0);
        stats[T_ON].add(1);
    }
    if (results != null) {
        // Convert depth-of-field to pixels
        final double depth = settings.getDepthOfField() / settings.getPixelPitch();
        try {
            // Get widths
            final WidthResultProcedure wp = new WidthResultProcedure(results, DistanceUnit.PIXEL);
            wp.getW();
            stats[WIDTH].add(wp.wx);
        } catch (final DataException ex) {
            ImageJUtils.log("Unable to compute width: " + ex.getMessage());
        }
        try {
            // Get z depth
            final StandardResultProcedure sp = new StandardResultProcedure(results, DistanceUnit.PIXEL);
            sp.getXyz();
            // Get precision
            final PrecisionResultProcedure pp = new PrecisionResultProcedure(results);
            pp.getPrecision();
            stats[PRECISION].add(pp.precisions);
            for (int i = 0; i < pp.size(); i++) {
                if (Math.abs(sp.z[i]) < depth) {
                    stats[PRECISION_IN_FOCUS].add(pp.precisions[i]);
                }
            }
        } catch (final DataException ex) {
            ImageJUtils.log("Unable to compute LSE precision: " + ex.getMessage());
        }
        // Compute density per frame. Multi-thread for speed
        if (settings.getDensityRadius() > 0) {
            final int threadCount = Prefs.getThreads();
            final Ticker ticker = ImageJUtils.createTicker(results.getLastFrame(), threadCount, "Calculating density ...");
            final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
            final List<Future<?>> futures = new LinkedList<>();
            final TFloatArrayList coordsX = new TFloatArrayList();
            final TFloatArrayList coordsY = new TFloatArrayList();
            final Statistics densityStats = stats[DENSITY];
            final float radius = (float) (settings.getDensityRadius() * getHwhm());
            final Rectangle bounds = results.getBounds();
            final double area = (double) bounds.width * bounds.height;
            // Store the density for each result.
            final int[] allDensity = new int[results.size()];
            final FrameCounter counter = results.newFrameCounter();
            results.forEach((PeakResultProcedure) result -> {
                if (counter.advance(result.getFrame())) {
                    counter.increment(runDensityCalculation(threadPool, futures, coordsX, coordsY, densityStats, radius, area, allDensity, counter.getCount(), ticker));
                }
                coordsX.add(result.getXPosition());
                coordsY.add(result.getYPosition());
            });
            runDensityCalculation(threadPool, futures, coordsX, coordsY, densityStats, radius, area, allDensity, counter.getCount(), ticker);
            ConcurrencyUtils.waitForCompletionUnchecked(futures);
            threadPool.shutdown();
            ImageJUtils.finished();
            // Split results into singles (density = 0) and clustered (density > 0)
            final MemoryPeakResults singles = copyMemoryPeakResults("No Density");
            final MemoryPeakResults clustered = copyMemoryPeakResults("Density");
            counter.reset();
            results.forEach((PeakResultProcedure) result -> {
                final int density = allDensity[counter.getAndIncrement()];
                result.setOrigValue(density);
                if (density == 0) {
                    singles.add(result);
                } else {
                    clustered.add(result);
                }
            });
        }
    }
    final StringBuilder sb = new StringBuilder();
    sb.append(datasetNumber).append('\t');
    if (settings.getCameraType() == CameraType.SCMOS) {
        sb.append("sCMOS (").append(settings.getCameraModelName()).append(") ");
        final Rectangle bounds = cameraModel.getBounds();
        sb.append(" ").append(bounds.x).append(",").append(bounds.y);
        final int size = settings.getSize();
        sb.append(" ").append(size).append("x").append(size);
    } else if (CalibrationProtosHelper.isCcdCameraType(settings.getCameraType())) {
        sb.append(CalibrationProtosHelper.getName(settings.getCameraType()));
        final int size = settings.getSize();
        sb.append(" ").append(size).append("x").append(size);
        if (settings.getCameraType() == CameraType.EMCCD) {
            sb.append(" EM=").append(settings.getEmGain());
        }
        sb.append(" CG=").append(settings.getCameraGain());
        sb.append(" RN=").append(settings.getReadNoise());
        sb.append(" B=").append(settings.getBias());
    } else {
        throw new IllegalStateException();
    }
    sb.append(" QE=").append(settings.getQuantumEfficiency()).append('\t');
    sb.append(settings.getPsfModel());
    if (psfModelType == PSF_MODEL_IMAGE) {
        sb.append(" Image").append(settings.getPsfImageName());
    } else if (psfModelType == PSF_MODEL_ASTIGMATISM) {
        sb.append(" model=").append(settings.getAstigmatismModel());
    } else {
        sb.append(" DoF=").append(MathUtils.rounded(settings.getDepthOfFocus()));
        if (settings.getEnterWidth()) {
            sb.append(" SD=").append(MathUtils.rounded(settings.getPsfSd()));
        } else {
            sb.append(" λ=").append(MathUtils.rounded(settings.getWavelength()));
            sb.append(" NA=").append(MathUtils.rounded(settings.getNumericalAperture()));
        }
    }
    sb.append('\t');
    sb.append((fluorophores == null) ? localisations.size() : fluorophores.size()).append('\t');
    sb.append(stats[SAMPLED_BLINKS].getN() + (int) stats[SAMPLED_BLINKS].getSum()).append('\t');
    sb.append(localisations.size()).append('\t');
    sb.append(frameCount).append('\t');
    sb.append(MathUtils.rounded(areaInUm)).append('\t');
    sb.append(MathUtils.rounded(localisations.size() / (areaInUm * frameCount), 4)).append('\t');
    sb.append(MathUtils.rounded(getHwhm(), 4)).append('\t');
    double sd = getPsfSd();
    sb.append(MathUtils.rounded(sd, 4)).append('\t');
    sd *= settings.getPixelPitch();
    final double sa = PsfCalculator.squarePixelAdjustment(sd, settings.getPixelPitch()) / settings.getPixelPitch();
    sb.append(MathUtils.rounded(sa, 4)).append('\t');
    // Width not valid for the Image PSF.
    // Q. Is this true? We can approximate the FHWM for a spot-like image PSF.
    final int nStats = (psfModelType == PSF_MODEL_IMAGE) ? stats.length - 1 : stats.length;
    for (int i = 0; i < nStats; i++) {
        final double centre = (alwaysRemoveOutliers[i]) ? ((StoredDataStatistics) stats[i]).getStatistics().getPercentile(50) : stats[i].getMean();
        sb.append(MathUtils.rounded(centre, 4)).append('\t');
    }
    createSummaryTable().accept(sb.toString());
    // Show histograms
    if (settings.getShowHistograms() && !java.awt.GraphicsEnvironment.isHeadless()) {
        IJ.showStatus("Calculating histograms ...");
        final boolean[] chosenHistograms = getChoosenHistograms();
        final WindowOrganiser wo = new WindowOrganiser();
        final HistogramPlotBuilder builder = new HistogramPlotBuilder(TITLE);
        for (int i = 0; i < NAMES.length; i++) {
            if (chosenHistograms[i]) {
                builder.setData((StoredDataStatistics) stats[i]).setName(NAMES[i]).setIntegerBins(integerDisplay[i]).setRemoveOutliersOption((settings.getRemoveOutliers() || alwaysRemoveOutliers[i]) ? 2 : 0).setNumberOfBins(settings.getHistogramBins()).show(wo);
            }
        }
        wo.tile();
    }
    IJ.showStatus("");
    return stats[SIGNAL].getMean();
}
Also used : RandomUtils(uk.ac.sussex.gdsc.core.utils.rng.RandomUtils) LoadLocalisations(uk.ac.sussex.gdsc.smlm.ij.plugins.LoadLocalisations) Arrays(java.util.Arrays) PoissonSamplerUtils(uk.ac.sussex.gdsc.core.utils.rng.PoissonSamplerUtils) Molecule(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.Molecule) IdPeakResult(uk.ac.sussex.gdsc.smlm.results.IdPeakResult) ImageProcessor(ij.process.ImageProcessor) HistogramPlotBuilder(uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder) ConfigurationException(uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException) AiryPsfModel(uk.ac.sussex.gdsc.smlm.model.AiryPsfModel) GaussianPsfModel(uk.ac.sussex.gdsc.smlm.model.GaussianPsfModel) MemoryUtils(uk.ac.sussex.gdsc.core.utils.MemoryUtils) PSFType(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFType) HelpUrls(uk.ac.sussex.gdsc.smlm.ij.plugins.HelpUrls) ResultsManager(uk.ac.sussex.gdsc.smlm.ij.plugins.ResultsManager) GammaDistribution(org.apache.commons.math3.distribution.GammaDistribution) Future(java.util.concurrent.Future) Vector(java.util.Vector) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) Map(java.util.Map) DensityManager(uk.ac.sussex.gdsc.core.clustering.DensityManager) UnicodeReader(uk.ac.sussex.gdsc.core.utils.UnicodeReader) RadialFalloffIllumination(uk.ac.sussex.gdsc.smlm.model.RadialFalloffIllumination) DistanceUnit(uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.DistanceUnit) RawResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.RawResultProcedure) ConcurrencyUtils(uk.ac.sussex.gdsc.core.utils.concurrent.ConcurrencyUtils) TextUtils(uk.ac.sussex.gdsc.core.utils.TextUtils) Gaussian2DFunction(uk.ac.sussex.gdsc.smlm.function.gaussian.Gaussian2DFunction) Executors(java.util.concurrent.Executors) PeakFit(uk.ac.sussex.gdsc.smlm.ij.plugins.PeakFit) TIntHashSet(gnu.trove.set.hash.TIntHashSet) ImagePlus(ij.ImagePlus) LocalisationList(uk.ac.sussex.gdsc.smlm.ij.plugins.LoadLocalisations.LocalisationList) UniformDistribution(uk.ac.sussex.gdsc.smlm.model.UniformDistribution) ShortProcessor(ij.process.ShortProcessor) FileUtils(uk.ac.sussex.gdsc.core.utils.FileUtils) CameraModelFisherInformationAnalysis(uk.ac.sussex.gdsc.smlm.ij.plugins.CameraModelFisherInformationAnalysis) CalibrationProtosHelper(uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtosHelper) PlugIn(ij.plugin.PlugIn) LocalisationModelSet(uk.ac.sussex.gdsc.smlm.model.LocalisationModelSet) AiryPattern(uk.ac.sussex.gdsc.smlm.model.AiryPattern) Prefs(ij.Prefs) FrameCounter(uk.ac.sussex.gdsc.smlm.results.count.FrameCounter) WindowManager(ij.WindowManager) PeakResult(uk.ac.sussex.gdsc.smlm.results.PeakResult) CreateDataSettings(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.CreateDataSettings) GridDistribution(uk.ac.sussex.gdsc.smlm.model.GridDistribution) ArrayList(java.util.ArrayList) Atom(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.Atom) AutoThreshold(uk.ac.sussex.gdsc.core.threshold.AutoThreshold) GenericDialog(ij.gui.GenericDialog) ImagePsfModel(uk.ac.sussex.gdsc.smlm.model.ImagePsfModel) PsfModel(uk.ac.sussex.gdsc.smlm.model.PsfModel) PeakResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.PeakResultProcedure) PoissonGaussianFisherInformation(uk.ac.sussex.gdsc.smlm.function.PoissonGaussianFisherInformation) ImagePsfHelper(uk.ac.sussex.gdsc.smlm.ij.settings.ImagePsfHelper) UnivariateLikelihoodFisherInformationCalculator(uk.ac.sussex.gdsc.smlm.fitting.UnivariateLikelihoodFisherInformationCalculator) SpatialIllumination(uk.ac.sussex.gdsc.smlm.model.SpatialIllumination) PeakResultsReader(uk.ac.sussex.gdsc.smlm.results.PeakResultsReader) PsfCombiner(uk.ac.sussex.gdsc.smlm.ij.plugins.PsfCombiner) DiffusionType(uk.ac.sussex.gdsc.smlm.model.DiffusionType) Files(java.nio.file.Files) BufferedWriter(java.io.BufferedWriter) FitWorker(uk.ac.sussex.gdsc.smlm.engine.FitWorker) RandomGeneratorAdapter(uk.ac.sussex.gdsc.core.utils.rng.RandomGeneratorAdapter) AtomOrBuilder(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.AtomOrBuilder) IOException(java.io.IOException) SamplerUtils(uk.ac.sussex.gdsc.core.utils.rng.SamplerUtils) DiscreteUniformSampler(org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler) File(java.io.File) SummaryStatistics(org.apache.commons.math3.stat.descriptive.SummaryStatistics) FloatProcessor(ij.process.FloatProcessor) BasePoissonFisherInformation(uk.ac.sussex.gdsc.smlm.function.BasePoissonFisherInformation) Paths(java.nio.file.Paths) AstigmatismZModel(uk.ac.sussex.gdsc.smlm.function.gaussian.AstigmatismZModel) TextFilePeakResults(uk.ac.sussex.gdsc.smlm.results.TextFilePeakResults) EmCcdCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.EmCcdCameraModel) ImageStack(ij.ImageStack) PoissonSampler(org.apache.commons.rng.sampling.distribution.PoissonSampler) CameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CameraModel) ExtendedPeakResult(uk.ac.sussex.gdsc.smlm.results.ExtendedPeakResult) PsfHelper(uk.ac.sussex.gdsc.smlm.data.config.PsfHelper) BufferedReader(java.io.BufferedReader) ImmutableMemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.ImmutableMemoryPeakResults) DoubleEquality(uk.ac.sussex.gdsc.core.utils.DoubleEquality) StandardResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.StandardResultProcedure) SphericalDistribution(uk.ac.sussex.gdsc.smlm.model.SphericalDistribution) TIntArrayList(gnu.trove.list.array.TIntArrayList) GaussianFilter(uk.ac.sussex.gdsc.smlm.filters.GaussianFilter) TextWindow(ij.text.TextWindow) StandardValueProcedure(uk.ac.sussex.gdsc.smlm.function.StandardValueProcedure) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) Formatter(java.util.Formatter) FixedLifetimeImageModel(uk.ac.sussex.gdsc.smlm.model.FixedLifetimeImageModel) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) PeakResults(uk.ac.sussex.gdsc.smlm.results.PeakResults) DataException(uk.ac.sussex.gdsc.core.data.DataException) PsfCalculator(uk.ac.sussex.gdsc.smlm.ij.plugins.PsfCalculator) EmpiricalDistribution(org.apache.commons.math3.random.EmpiricalDistribution) MathUtils(uk.ac.sussex.gdsc.core.utils.MathUtils) BinomialDiscreteInverseCumulativeProbabilityFunction(uk.ac.sussex.gdsc.core.utils.rng.BinomialDiscreteInverseCumulativeProbabilityFunction) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) Offset(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.Offset) TextFormat(com.google.protobuf.TextFormat) PsfProtosHelper(uk.ac.sussex.gdsc.smlm.data.config.PsfProtosHelper) SettingsManager(uk.ac.sussex.gdsc.smlm.ij.settings.SettingsManager) ItemEvent(java.awt.event.ItemEvent) CameraType(uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.CameraType) SpatialDistribution(uk.ac.sussex.gdsc.smlm.model.SpatialDistribution) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) AstigmatismModelManager(uk.ac.sussex.gdsc.smlm.ij.plugins.AstigmatismModelManager) UniformRealDistribution(org.apache.commons.math3.distribution.UniformRealDistribution) MoleculeModel(uk.ac.sussex.gdsc.smlm.model.MoleculeModel) TIntIntHashMap(gnu.trove.map.hash.TIntIntHashMap) MarsagliaTsangGammaSampler(uk.ac.sussex.gdsc.core.utils.rng.MarsagliaTsangGammaSampler) WidthResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.WidthResultProcedure) Gaussian2DPeakResultHelper(uk.ac.sussex.gdsc.smlm.results.Gaussian2DPeakResultHelper) List(java.util.List) FluorophoreSequenceModel(uk.ac.sussex.gdsc.smlm.model.FluorophoreSequenceModel) BirResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.BirResultProcedure) Entry(java.util.Map.Entry) CompoundMoleculeModel(uk.ac.sussex.gdsc.smlm.model.CompoundMoleculeModel) RealDistribution(org.apache.commons.math3.distribution.RealDistribution) HoltzerAstigmatismZModel(uk.ac.sussex.gdsc.smlm.function.gaussian.HoltzerAstigmatismZModel) ImageModel(uk.ac.sussex.gdsc.smlm.model.ImageModel) MaskDistribution3D(uk.ac.sussex.gdsc.smlm.model.MaskDistribution3D) TypeConverter(uk.ac.sussex.gdsc.core.data.utils.TypeConverter) PrecisionResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.PrecisionResultProcedure) Rectangle(java.awt.Rectangle) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) PSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSF) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) IntensityUnit(uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.IntensityUnit) Mixture(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.Mixture) AtomicReference(java.util.concurrent.atomic.AtomicReference) SobolSequenceGenerator(org.apache.commons.math3.random.SobolSequenceGenerator) MaskDistribution(uk.ac.sussex.gdsc.smlm.model.MaskDistribution) OptionListener(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog.OptionListener) OpenDialog(ij.io.OpenDialog) ParameterUtils(uk.ac.sussex.gdsc.smlm.ij.plugins.ParameterUtils) IJImageSource(uk.ac.sussex.gdsc.smlm.ij.IJImageSource) NoiseEstimatorMethod(uk.ac.sussex.gdsc.smlm.data.config.FitProtos.NoiseEstimatorMethod) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint) ExponentialDistribution(org.apache.commons.math3.distribution.ExponentialDistribution) FisherInformationMatrix(uk.ac.sussex.gdsc.smlm.fitting.FisherInformationMatrix) UnitHelper(uk.ac.sussex.gdsc.smlm.data.config.UnitHelper) LinkedList(java.util.LinkedList) CcdCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CcdCameraModel) FileSaver(ij.io.FileSaver) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) ExecutorService(java.util.concurrent.ExecutorService) CreateDataSettingsHelper(uk.ac.sussex.gdsc.smlm.ij.settings.CreateDataSettingsHelper) TFloatArrayList(gnu.trove.list.array.TFloatArrayList) FunctionHelper(uk.ac.sussex.gdsc.smlm.function.FunctionHelper) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) PoissonSamplerCache(org.apache.commons.rng.sampling.distribution.PoissonSamplerCache) AstigmatismModel(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.AstigmatismModel) ConversionException(uk.ac.sussex.gdsc.core.data.utils.ConversionException) SplitMix64(org.apache.commons.rng.core.source64.SplitMix64) Checkbox(java.awt.Checkbox) ActivationEnergyImageModel(uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel) LoadLocalisationsSettings(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.LoadLocalisationsSettings) FileInputStream(java.io.FileInputStream) Ticker(uk.ac.sussex.gdsc.core.logging.Ticker) PsfModelGradient1Function(uk.ac.sussex.gdsc.smlm.model.PsfModelGradient1Function) InterpolatedPoissonFisherInformation(uk.ac.sussex.gdsc.smlm.function.InterpolatedPoissonFisherInformation) Consumer(java.util.function.Consumer) CameraModelManager(uk.ac.sussex.gdsc.smlm.ij.plugins.CameraModelManager) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) ImageJUtils(uk.ac.sussex.gdsc.core.ij.ImageJUtils) UniformIllumination(uk.ac.sussex.gdsc.smlm.model.UniformIllumination) SynchronizedPeakResults(uk.ac.sussex.gdsc.smlm.results.SynchronizedPeakResults) IJ(ij.IJ) NullArgumentException(org.apache.commons.math3.exception.NullArgumentException) SmlmUsageTracker(uk.ac.sussex.gdsc.smlm.ij.plugins.SmlmUsageTracker) InverseTransformDiscreteSampler(org.apache.commons.rng.sampling.distribution.InverseTransformDiscreteSampler) Comparator(java.util.Comparator) Collections(java.util.Collections) NormalizedGaussianSampler(org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) UniformRandomProviders(uk.ac.sussex.gdsc.core.utils.rng.UniformRandomProviders) Rectangle(java.awt.Rectangle) HistogramPlotBuilder(uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) ImmutableMemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.ImmutableMemoryPeakResults) Ticker(uk.ac.sussex.gdsc.core.logging.Ticker) FrameCounter(uk.ac.sussex.gdsc.smlm.results.count.FrameCounter) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) WidthResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.WidthResultProcedure) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) PrecisionResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.PrecisionResultProcedure) SummaryStatistics(org.apache.commons.math3.stat.descriptive.SummaryStatistics) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) ImagePlus(ij.ImagePlus) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint) LinkedList(java.util.LinkedList) TFloatArrayList(gnu.trove.list.array.TFloatArrayList) DataException(uk.ac.sussex.gdsc.core.data.DataException) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) FluorophoreSequenceModel(uk.ac.sussex.gdsc.smlm.model.FluorophoreSequenceModel) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) StandardResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.StandardResultProcedure)

Example 2 with StoredDataStatistics

use of uk.ac.sussex.gdsc.core.utils.StoredDataStatistics in project GDSC-SMLM by aherbert.

the class CreateData method run.

@Override
public void run(String arg) {
    SmlmUsageTracker.recordPlugin(this.getClass(), arg);
    extraOptions = ImageJUtils.isExtraOptions();
    simpleMode = (arg != null && arg.contains("simple"));
    benchmarkMode = (arg != null && arg.contains("benchmark"));
    spotMode = (arg != null && arg.contains("spot"));
    trackMode = (arg != null && arg.contains("track"));
    if ("load".equals(arg)) {
        loadBenchmarkData();
        return;
    }
    // Each localisation set is a collection of localisations that represent all localisations
    // with the same ID that are on in the same image time frame (Note: the simulation
    // can create many localisations per fluorophore per time frame which is useful when
    // modelling moving particles)
    List<LocalisationModelSet> localisationSets = null;
    // Each fluorophore contains the on and off times when light was emitted
    List<? extends FluorophoreSequenceModel> fluorophores = null;
    if (simpleMode || benchmarkMode || spotMode) {
        if (!showSimpleDialog()) {
            return;
        }
        resetMemory();
        // 1 second frames
        settings.setExposureTime(1000);
        areaInUm = settings.getSize() * settings.getPixelPitch() * settings.getSize() * settings.getPixelPitch() / 1e6;
        // Number of spots per frame
        int count = 0;
        int[] nextN = null;
        SpatialDistribution dist;
        if (benchmarkMode) {
            // --------------------
            // BENCHMARK SIMULATION
            // --------------------
            // Draw the same point on the image repeatedly
            count = 1;
            dist = createFixedDistribution();
            try {
                reportAndSaveFittingLimits(dist);
            } catch (final Exception ex) {
                // This will be from the computation of the CRLB
                IJ.error(TITLE, ex.getMessage());
                return;
            }
        } else if (spotMode) {
            // ---------------
            // SPOT SIMULATION
            // ---------------
            // The spot simulation draws 0 or 1 random point per frame.
            // Ensure we have 50% of the frames with a spot.
            nextN = new int[settings.getParticles() * 2];
            Arrays.fill(nextN, 0, settings.getParticles(), 1);
            RandomUtils.shuffle(nextN, UniformRandomProviders.create());
            // Only put spots in the central part of the image
            final double border = settings.getSize() / 4.0;
            dist = createUniformDistribution(border);
        } else {
            // -----------------
            // SIMPLE SIMULATION
            // -----------------
            // The simple simulation draws n random points per frame to achieve a specified density.
            // No points will appear in multiple frames.
            // Each point has a random number of photons sampled from a range.
            // We can optionally use a mask. Create his first as it updates the areaInUm
            dist = createDistribution();
            // Randomly sample (i.e. not uniform density in all frames)
            if (settings.getSamplePerFrame()) {
                final double mean = areaInUm * settings.getDensity();
                ImageJUtils.log("Mean samples = %f", mean);
                if (mean < 0.5) {
                    final GenericDialog gd = new GenericDialog(TITLE);
                    gd.addMessage("The mean samples per frame is low: " + MathUtils.rounded(mean) + "\n \nContinue?");
                    gd.enableYesNoCancel();
                    gd.hideCancelButton();
                    gd.showDialog();
                    if (!gd.wasOKed()) {
                        return;
                    }
                }
                final PoissonSampler poisson = new PoissonSampler(createRandomGenerator(), mean);
                final StoredDataStatistics samples = new StoredDataStatistics(settings.getParticles());
                while (samples.getSum() < settings.getParticles()) {
                    samples.add(poisson.sample());
                }
                nextN = new int[samples.getN()];
                for (int i = 0; i < nextN.length; i++) {
                    nextN[i] = (int) samples.getValue(i);
                }
            } else {
                // Use the density to get the number per frame
                count = (int) Math.max(1, Math.round(areaInUm * settings.getDensity()));
            }
        }
        UniformRandomProvider rng = null;
        localisationSets = new ArrayList<>(settings.getParticles());
        final int minPhotons = (int) settings.getPhotonsPerSecond();
        final int range = (int) settings.getPhotonsPerSecondMaximum() - minPhotons + 1;
        if (range > 1) {
            rng = createRandomGenerator();
        }
        // Add frames at the specified density until the number of particles has been reached
        int id = 0;
        int time = 0;
        while (id < settings.getParticles()) {
            // Allow the number per frame to be specified
            if (nextN != null) {
                if (time >= nextN.length) {
                    break;
                }
                count = nextN[time];
            }
            // Simulate random positions in the frame for the specified density
            time++;
            for (int j = 0; j < count; j++) {
                final double[] xyz = dist.next();
                // Ignore within border. We do not want to draw things we cannot fit.
                // if (!distBorder.isWithinXy(xyz))
                // continue;
                // Simulate random photons
                final int intensity = minPhotons + ((rng != null) ? rng.nextInt(range) : 0);
                final LocalisationModel m = new LocalisationModel(id, time, xyz, intensity, LocalisationModel.CONTINUOUS);
                // Each localisation can be a separate localisation set
                final LocalisationModelSet set = new LocalisationModelSet(id, time);
                set.add(m);
                localisationSets.add(set);
                id++;
            }
        }
    } else {
        if (!showDialog()) {
            return;
        }
        resetMemory();
        areaInUm = settings.getSize() * settings.getPixelPitch() * settings.getSize() * settings.getPixelPitch() / 1e6;
        int totalSteps;
        double correlation = 0;
        ImageModel imageModel;
        if (trackMode) {
            // ----------------
            // TRACK SIMULATION
            // ----------------
            // In track mode we create fixed lifetime fluorophores that do not overlap in time.
            // This is the simplest simulation to test moving molecules.
            settings.setSeconds((int) Math.ceil(settings.getParticles() * (settings.getExposureTime() + settings.getTOn()) / 1000));
            totalSteps = 0;
            final double simulationStepsPerFrame = (settings.getStepsPerSecond() * settings.getExposureTime()) / 1000.0;
            imageModel = new FixedLifetimeImageModel(settings.getStepsPerSecond() * settings.getTOn() / 1000.0, simulationStepsPerFrame, createRandomGenerator());
        } else {
            // ---------------
            // FULL SIMULATION
            // ---------------
            // The full simulation draws n random points in space.
            // The same molecule may appear in multiple frames, move and blink.
            // 
            // Points are modelled as fluorophores that must be activated and then will
            // blink and photo-bleach. The molecules may diffuse and this can be simulated
            // with many steps per image frame. All steps from a frame are collected
            // into a localisation set which can be drawn on the output image.
            final SpatialIllumination activationIllumination = createIllumination(settings.getPulseRatio(), settings.getPulseInterval());
            // Generate additional frames so that each frame has the set number of simulation steps
            totalSteps = (int) Math.ceil(settings.getSeconds() * settings.getStepsPerSecond());
            // Since we have an exponential decay of activations
            // ensure half of the particles have activated by 30% of the frames.
            final double eAct = totalSteps * 0.3 * activationIllumination.getAveragePhotons();
            // Q. Does tOn/tOff change depending on the illumination strength?
            imageModel = new ActivationEnergyImageModel(eAct, activationIllumination, settings.getStepsPerSecond() * settings.getTOn() / 1000.0, settings.getStepsPerSecond() * settings.getTOffShort() / 1000.0, settings.getStepsPerSecond() * settings.getTOffLong() / 1000.0, settings.getNBlinksShort(), settings.getNBlinksLong(), createRandomGenerator());
            imageModel.setUseGeometricDistribution(settings.getNBlinksGeometricDistribution());
            // Only use the correlation if selected for the distribution
            if (PHOTON_DISTRIBUTION[PHOTON_CORRELATED].equals(settings.getPhotonDistribution())) {
                correlation = settings.getCorrelation();
            }
        }
        imageModel.setPhotonBudgetPerFrame(true);
        imageModel.setDiffusion2D(settings.getDiffuse2D());
        imageModel.setRotation2D(settings.getRotate2D());
        IJ.showStatus("Creating molecules ...");
        final SpatialDistribution distribution = createDistribution();
        final List<CompoundMoleculeModel> compounds = createCompoundMolecules();
        if (compounds == null) {
            return;
        }
        final List<CompoundMoleculeModel> molecules = imageModel.createMolecules(compounds, settings.getParticles(), distribution, settings.getRotateInitialOrientation());
        // Activate fluorophores
        IJ.showStatus("Creating fluorophores ...");
        // Note: molecules list will be converted to compounds containing fluorophores
        fluorophores = imageModel.createFluorophores(molecules, totalSteps);
        if (fluorophores.isEmpty()) {
            IJ.error(TITLE, "No fluorophores created");
            return;
        }
        // Map the fluorophore ID to the compound for mixtures
        if (compounds.size() > 1) {
            idToCompound = new TIntIntHashMap(fluorophores.size());
            for (final FluorophoreSequenceModel l : fluorophores) {
                idToCompound.put(l.getId(), l.getLabel());
            }
        }
        IJ.showStatus("Creating localisations ...");
        // TODO - Output a molecule Id for each fluorophore if using compound molecules. This allows
        // analysis
        // of the ratio of trimers, dimers, monomers, etc that could be detected.
        totalSteps = checkTotalSteps(totalSteps, fluorophores);
        if (totalSteps == 0) {
            return;
        }
        imageModel.setPhotonDistribution(createPhotonDistribution());
        try {
            imageModel.setConfinementDistribution(createConfinementDistribution());
        } catch (final ConfigurationException ex) {
            // We asked the user if it was OK to continue and they said no
            return;
        }
        // This should be optimised
        imageModel.setConfinementAttempts(10);
        final List<LocalisationModel> localisations = imageModel.createImage(molecules, settings.getFixedFraction(), totalSteps, settings.getPhotonsPerSecond() / settings.getStepsPerSecond(), correlation, settings.getRotateDuringSimulation());
        // Re-adjust the fluorophores to the correct time
        if (settings.getStepsPerSecond() != 1) {
            final double scale = 1.0 / settings.getStepsPerSecond();
            for (final FluorophoreSequenceModel f : fluorophores) {
                f.adjustTime(scale);
            }
        }
        // Integrate the frames
        localisationSets = combineSimulationSteps(localisations);
        localisationSets = filterToImageBounds(localisationSets);
    }
    datasetNumber.getAndIncrement();
    final List<LocalisationModel> localisations = drawImage(localisationSets);
    if (localisations == null || localisations.isEmpty()) {
        IJ.error(TITLE, "No localisations created");
        return;
    }
    fluorophores = removeFilteredFluorophores(fluorophores, localisations);
    final double signalPerFrame = showSummary(fluorophores, localisations);
    if (!benchmarkMode) {
        final boolean fullSimulation = (!(simpleMode || spotMode));
        saveSimulationParameters(localisations.size(), fullSimulation, signalPerFrame);
    }
    IJ.showStatus("Saving data ...");
    saveFluorophores(fluorophores);
    saveImageResults(results);
    saveLocalisations(localisations);
    // The settings for the filenames may have changed
    SettingsManager.writeSettings(settings.build());
    IJ.showStatus("Done");
}
Also used : ActivationEnergyImageModel(uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel) CompoundMoleculeModel(uk.ac.sussex.gdsc.smlm.model.CompoundMoleculeModel) ConfigurationException(uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException) GenericDialog(ij.gui.GenericDialog) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) SpatialIllumination(uk.ac.sussex.gdsc.smlm.model.SpatialIllumination) PoissonSampler(org.apache.commons.rng.sampling.distribution.PoissonSampler) TIntIntHashMap(gnu.trove.map.hash.TIntIntHashMap) SpatialDistribution(uk.ac.sussex.gdsc.smlm.model.SpatialDistribution) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint) ConfigurationException(uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException) IOException(java.io.IOException) DataException(uk.ac.sussex.gdsc.core.data.DataException) ConversionException(uk.ac.sussex.gdsc.core.data.utils.ConversionException) NullArgumentException(org.apache.commons.math3.exception.NullArgumentException) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) FluorophoreSequenceModel(uk.ac.sussex.gdsc.smlm.model.FluorophoreSequenceModel) FixedLifetimeImageModel(uk.ac.sussex.gdsc.smlm.model.FixedLifetimeImageModel) LocalisationModelSet(uk.ac.sussex.gdsc.smlm.model.LocalisationModelSet) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) FixedLifetimeImageModel(uk.ac.sussex.gdsc.smlm.model.FixedLifetimeImageModel) ImageModel(uk.ac.sussex.gdsc.smlm.model.ImageModel) ActivationEnergyImageModel(uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel)

Example 3 with StoredDataStatistics

use of uk.ac.sussex.gdsc.core.utils.StoredDataStatistics in project GDSC-SMLM by aherbert.

the class BenchmarkSpotFit method showDoubleHistogram.

private double[] showDoubleHistogram(StoredDataStatistics[][] stats, final int index, WindowOrganiser wo, double[][] matchScores) {
    final String xLabel = filterCriteria[index].name;
    LowerLimit lower = filterCriteria[index].lower;
    UpperLimit upper = filterCriteria[index].upper;
    double[] jaccard = null;
    double[] metric = null;
    double maxJaccard = 0;
    if (index <= FILTER_PRECISION && (settings.showFilterScoreHistograms || upper.requiresJaccard || lower.requiresJaccard)) {
        // Jaccard score verses the range of the metric
        for (final double[] d : matchScores) {
            if (!Double.isFinite(d[index])) {
                System.out.printf("Error in fit data [%d]: %s%n", index, d[index]);
            }
        }
        // Do not use Double.compare(double, double) so we get exceptions in the sort for inf/nan
        Arrays.sort(matchScores, (o1, o2) -> {
            if (o1[index] < o2[index]) {
                return -1;
            }
            if (o1[index] > o2[index]) {
                return 1;
            }
            return 0;
        });
        final int scoreIndex = FILTER_PRECISION + 1;
        final int n = results.size();
        double tp = 0;
        double fp = 0;
        jaccard = new double[matchScores.length + 1];
        metric = new double[jaccard.length];
        for (int k = 0; k < matchScores.length; k++) {
            final double score = matchScores[k][scoreIndex];
            tp += score;
            fp += (1 - score);
            jaccard[k + 1] = tp / (fp + n);
            metric[k + 1] = matchScores[k][index];
        }
        metric[0] = metric[1];
        maxJaccard = MathUtils.max(jaccard);
        if (settings.showFilterScoreHistograms) {
            final String title = TITLE + " Jaccard " + xLabel;
            final Plot plot = new Plot(title, xLabel, "Jaccard");
            plot.addPoints(metric, jaccard, Plot.LINE);
            // Remove outliers
            final double[] limitsx = MathUtils.limits(metric);
            final Percentile p = new Percentile();
            final double l = p.evaluate(metric, 25);
            final double u = p.evaluate(metric, 75);
            final double iqr = 1.5 * (u - l);
            limitsx[1] = Math.min(limitsx[1], u + iqr);
            plot.setLimits(limitsx[0], limitsx[1], 0, MathUtils.max(jaccard));
            ImageJUtils.display(title, plot, wo);
        }
    }
    // [0] is all
    // [1] is matches
    // [2] is no match
    final StoredDataStatistics s1 = stats[0][index];
    final StoredDataStatistics s2 = stats[1][index];
    final StoredDataStatistics s3 = stats[2][index];
    if (s1.getN() == 0) {
        return new double[4];
    }
    final DescriptiveStatistics d = s1.getStatistics();
    double median = 0;
    Plot plot = null;
    String title = null;
    if (settings.showFilterScoreHistograms) {
        median = d.getPercentile(50);
        final String label = String.format("n = %d. Median = %s nm", s1.getN(), MathUtils.rounded(median));
        final HistogramPlot histogramPlot = new HistogramPlotBuilder(TITLE, s1, xLabel).setMinBinWidth(filterCriteria[index].minBinWidth).setRemoveOutliersOption((filterCriteria[index].restrictRange) ? 1 : 0).setPlotLabel(label).build();
        final PlotWindow plotWindow = histogramPlot.show(wo);
        if (plotWindow == null) {
            IJ.log("Failed to show the histogram: " + xLabel);
            return new double[4];
        }
        title = plotWindow.getTitle();
        // Reverse engineer the histogram settings
        plot = histogramPlot.getPlot();
        final double[] xvalues = histogramPlot.getPlotXValues();
        final int bins = xvalues.length;
        final double yMin = xvalues[0];
        final double binSize = xvalues[1] - xvalues[0];
        final double yMax = xvalues[0] + (bins - 1) * binSize;
        if (s2.getN() > 0) {
            final double[] values = s2.getValues();
            final double[][] hist = HistogramPlot.calcHistogram(values, yMin, yMax, bins);
            if (hist[0].length > 0) {
                plot.setColor(Color.red);
                plot.addPoints(hist[0], hist[1], Plot.BAR);
                ImageJUtils.display(title, plot);
            }
        }
        if (s3.getN() > 0) {
            final double[] values = s3.getValues();
            final double[][] hist = HistogramPlot.calcHistogram(values, yMin, yMax, bins);
            if (hist[0].length > 0) {
                plot.setColor(Color.blue);
                plot.addPoints(hist[0], hist[1], Plot.BAR);
                ImageJUtils.display(title, plot);
            }
        }
    }
    // Do cumulative histogram
    final double[][] h1 = MathUtils.cumulativeHistogram(s1.getValues(), true);
    final double[][] h2 = MathUtils.cumulativeHistogram(s2.getValues(), true);
    final double[][] h3 = MathUtils.cumulativeHistogram(s3.getValues(), true);
    if (settings.showFilterScoreHistograms) {
        title = TITLE + " Cumul " + xLabel;
        plot = new Plot(title, xLabel, "Frequency");
        // Find limits
        double[] xlimit = MathUtils.limits(h1[0]);
        xlimit = MathUtils.limits(xlimit, h2[0]);
        xlimit = MathUtils.limits(xlimit, h3[0]);
        // Restrict using the inter-quartile range
        if (filterCriteria[index].restrictRange) {
            final double q1 = d.getPercentile(25);
            final double q2 = d.getPercentile(75);
            final double iqr = (q2 - q1) * 2.5;
            xlimit[0] = MathUtils.max(xlimit[0], median - iqr);
            xlimit[1] = MathUtils.min(xlimit[1], median + iqr);
        }
        plot.setLimits(xlimit[0], xlimit[1], 0, 1.05);
        plot.addPoints(h1[0], h1[1], Plot.LINE);
        plot.setColor(Color.red);
        plot.addPoints(h2[0], h2[1], Plot.LINE);
        plot.setColor(Color.blue);
        plot.addPoints(h3[0], h3[1], Plot.LINE);
    }
    // Determine the maximum difference between the TP and FP
    double maxx1 = 0;
    double maxx2 = 0;
    double max1 = 0;
    double max2 = 0;
    // We cannot compute the delta histogram, or use percentiles
    if (s2.getN() == 0) {
        upper = UpperLimit.ZERO;
        lower = LowerLimit.ZERO;
    }
    final boolean requireLabel = (settings.showFilterScoreHistograms && filterCriteria[index].requireLabel);
    if (requireLabel || upper.requiresDeltaHistogram() || lower.requiresDeltaHistogram()) {
        if (s2.getN() != 0 && s3.getN() != 0) {
            final LinearInterpolator li = new LinearInterpolator();
            final PolynomialSplineFunction f1 = li.interpolate(h2[0], h2[1]);
            final PolynomialSplineFunction f2 = li.interpolate(h3[0], h3[1]);
            for (final double x : h1[0]) {
                if (x < h2[0][0] || x < h3[0][0]) {
                    continue;
                }
                try {
                    final double v1 = f1.value(x);
                    final double v2 = f2.value(x);
                    final double diff = v2 - v1;
                    if (diff > 0) {
                        if (max1 < diff) {
                            max1 = diff;
                            maxx1 = x;
                        }
                    } else if (max2 > diff) {
                        max2 = diff;
                        maxx2 = x;
                    }
                } catch (final OutOfRangeException ex) {
                    // Because we reached the end
                    break;
                }
            }
        }
    }
    if (plot != null) {
        // We use bins=1 on charts where we do not need a label
        if (requireLabel) {
            final String label = String.format("Max+ %s @ %s, Max- %s @ %s", MathUtils.rounded(max1), MathUtils.rounded(maxx1), MathUtils.rounded(max2), MathUtils.rounded(maxx2));
            plot.setColor(Color.black);
            plot.addLabel(0, 0, label);
        }
        ImageJUtils.display(title, plot, wo);
    }
    // Now compute the bounds using the desired limit
    double lowerBound;
    double upperBound;
    switch(lower) {
        case MAX_NEGATIVE_CUMUL_DELTA:
            // Switch to percentiles if we have no delta histogram
            if (maxx2 < 0) {
                lowerBound = maxx2;
                break;
            }
        // fall-through
        case ONE_PERCENT:
            lowerBound = getPercentile(h2, 0.01);
            break;
        case MIN:
            lowerBound = getPercentile(h2, 0.0);
            break;
        case ZERO:
            lowerBound = 0;
            break;
        case HALF_MAX_JACCARD_VALUE:
            lowerBound = getXValue(metric, jaccard, maxJaccard * 0.5);
            break;
        default:
            throw new IllegalStateException("Missing lower limit method");
    }
    switch(upper) {
        case MAX_POSITIVE_CUMUL_DELTA:
            // Switch to percentiles if we have no delta histogram
            if (maxx1 > 0) {
                upperBound = maxx1;
                break;
            }
        // fall-through
        case NINETY_NINE_PERCENT:
            upperBound = getPercentile(h2, 0.99);
            break;
        case NINETY_NINE_NINE_PERCENT:
            upperBound = getPercentile(h2, 0.999);
            break;
        case ZERO:
            upperBound = 0;
            break;
        case MAX_JACCARD2:
            upperBound = getXValue(metric, jaccard, maxJaccard) * 2;
            // System.out.printf("MaxJ = %.4f @ %.3f\n", maxJ, u / 2);
            break;
        default:
            throw new IllegalStateException("Missing upper limit method");
    }
    final double min = getPercentile(h1, 0);
    final double max = getPercentile(h1, 1);
    return new double[] { lowerBound, upperBound, min, max };
}
Also used : DescriptiveStatistics(org.apache.commons.math3.stat.descriptive.DescriptiveStatistics) Percentile(org.apache.commons.math3.stat.descriptive.rank.Percentile) Plot(ij.gui.Plot) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) HistogramPlotBuilder(uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder) PlotWindow(ij.gui.PlotWindow) PolynomialSplineFunction(org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction) PeakResultPoint(uk.ac.sussex.gdsc.smlm.results.PeakResultPoint) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) LinearInterpolator(org.apache.commons.math3.analysis.interpolation.LinearInterpolator) OutOfRangeException(org.apache.commons.math3.exception.OutOfRangeException)

Example 4 with StoredDataStatistics

use of uk.ac.sussex.gdsc.core.utils.StoredDataStatistics in project GDSC-SMLM by aherbert.

the class DoubletAnalysis method summariseResults.

/**
 * Summarise results.
 *
 * @param results the results
 * @param density the density
 * @param runTime the run time
 */
private void summariseResults(ArrayList<DoubletResult> results, double density, long runTime) {
    // If we are only assessing results with no neighbour candidates
    // TODO - Count the number of actual results that have no neighbours
    final int numberOfMolecules = this.results.size() - ignored.get();
    final FitConfiguration fitConfig = config.getFitConfiguration();
    // Store details we want in the analysis table
    final StringBuilder sb = new StringBuilder();
    sb.append(MathUtils.rounded(density)).append('\t');
    sb.append(MathUtils.rounded(getSa())).append('\t');
    sb.append(config.getFittingWidth()).append('\t');
    sb.append(PsfProtosHelper.getName(fitConfig.getPsfType()));
    sb.append(":").append(PeakFit.getSolverName(fitConfig));
    if (fitConfig.isModelCameraMle()) {
        sb.append(":Camera\t");
        // Add details of the noise model for the MLE
        final CalibrationReader r = new CalibrationReader(fitConfig.getCalibration());
        sb.append("EM=").append(r.isEmCcd());
        sb.append(":A=").append(MathUtils.rounded(r.getCountPerElectron()));
        sb.append(":N=").append(MathUtils.rounded(r.getReadNoise()));
        sb.append('\t');
    } else {
        sb.append("\t\t");
    }
    final String analysisPrefix = sb.toString();
    // -=-=-=-=-
    showResults(results, settings.showResults);
    sb.setLength(0);
    final int n = countN(results);
    // Create the benchmark settings and the fitting settings
    sb.append(numberOfMolecules).append('\t');
    sb.append(n).append('\t');
    sb.append(MathUtils.rounded(density)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.minSignal)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.maxSignal)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.averageSignal)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.sd)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.pixelPitch)).append('\t');
    sb.append(MathUtils.rounded(getSa() * simulationParameters.pixelPitch)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.gain)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.readNoise)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.background)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.noise)).append('\t');
    sb.append(MathUtils.rounded(simulationParameters.averageSignal / simulationParameters.noise)).append('\t');
    sb.append(config.getFittingWidth()).append('\t');
    sb.append(PsfProtosHelper.getName(fitConfig.getPsfType()));
    sb.append(":").append(PeakFit.getSolverName(fitConfig));
    if (fitConfig.isModelCameraMle()) {
        sb.append(":Camera\t");
        // Add details of the noise model for the MLE
        final CalibrationReader r = new CalibrationReader(fitConfig.getCalibration());
        sb.append("EM=").append(r.isEmCcd());
        sb.append(":A=").append(MathUtils.rounded(r.getCountPerElectron()));
        sb.append(":N=").append(MathUtils.rounded(r.getReadNoise()));
        sb.append('\t');
    } else {
        sb.append("\t\t");
    }
    // Now output the actual results ...
    // Show histograms as cumulative to avoid problems with bin width
    // Residuals scores
    // Iterations and evaluations where fit was OK
    final StoredDataStatistics[] stats = new StoredDataStatistics[Settings.NAMES2.length];
    for (int i = 0; i < stats.length; i++) {
        stats[i] = new StoredDataStatistics();
    }
    // For Jaccard scoring we need to count the score with no residuals threshold,
    // i.e. Accumulate the score accepting all doublets that were fit
    double tp = 0;
    double fp = 0;
    double bestTp = 0;
    double bestFp = 0;
    final ArrayList<DoubletBonus> data = new ArrayList<>(results.size());
    for (final DoubletResult result : results) {
        final double score = result.getMaxScore();
        // Filter the singles that would be accepted
        if (result.good1) {
            // Filter the doublets that would be accepted
            if (result.good2) {
                final double tp2 = result.tp2a + result.tp2b;
                final double fp2 = result.fp2a + result.fp2b;
                tp += tp2;
                fp += fp2;
                if (result.tp2a > 0.5) {
                    bestTp += result.tp2a;
                    bestFp += result.fp2a;
                }
                if (result.tp2b > 0.5) {
                    bestTp += result.tp2b;
                    bestFp += result.fp2b;
                }
                // Store this as a doublet bonus
                data.add(new DoubletBonus(score, result.getAvScore(), tp2 - result.tp1, fp2 - result.fp1));
            } else {
                // No doublet fit so this will always be the single fit result
                tp += result.tp1;
                fp += result.fp1;
                if (result.tp1 > 0.5) {
                    bestTp += result.tp1;
                    bestFp += result.fp1;
                }
            }
        }
        // Build statistics
        final int c = result.matchClass;
        // True results, i.e. where there was a choice between single or doublet
        if (result.valid) {
            stats[c].add(score);
        }
        // Of those where the fit was good, summarise the iterations and evaluations
        if (result.good1) {
            stats[3].add(result.iter1);
            stats[4].add(result.eval1);
            // about the iteration increase for singles that are not doublets.
            if (c != 0 && result.good2) {
                stats[5].add(result.iter2);
                stats[6].add(result.eval2);
            }
        }
    }
    // Debug the counts
    // double tpSingle = 0;
    // double fpSingle = 0;
    // double tpDoublet = 0;
    // double fpDoublet = 0;
    // int nSingle = 0, nDoublet = 0;
    // for (DoubletResult result : results) {
    // if (result.good1) {
    // if (result.good2) {
    // tpDoublet += result.tp2a + result.tp2b;
    // fpDoublet += result.fp2a + result.fp2b;
    // nDoublet++;
    // }
    // tpSingle += result.tp1;
    // fpSingle += result.fp1;
    // nSingle++;
    // }
    // }
    // System.out.printf("Single %.1f,%.1f (%d) : Doublet %.1f,%.1f (%d)\n", tpSingle, fpSingle,
    // nSingle, tpDoublet, fpDoublet, nDoublet * 2);
    // Summarise score for true results
    final Percentile p = new Percentile(99);
    for (int c = 0; c < stats.length; c++) {
        final double[] values = stats[c].getValues();
        // Sorting is need for the percentile and the cumulative histogram so do it once
        Arrays.sort(values);
        sb.append(MathUtils.rounded(stats[c].getMean())).append("+/-").append(MathUtils.rounded(stats[c].getStandardDeviation())).append(" (").append(stats[c].getN()).append(") ").append(MathUtils.rounded(p.evaluate(values))).append('\t');
        if (settings.showHistograms && settings.displayHistograms[c + Settings.NAMES.length]) {
            showCumulativeHistogram(values, Settings.NAMES2[c]);
        }
    }
    sb.append(Settings.MATCHING_METHODS[settings.matchingMethod]).append('\t');
    // Plot a graph of the additional results we would fit at all score thresholds.
    // This assumes we just pick the the doublet if we fit it (NO FILTERING at all!)
    // Initialise the score for residuals 0
    // Store this as it serves as a baseline for the filtering analysis
    final ResidualsScore residualsScoreMax = computeScores(data, tp, fp, numberOfMolecules, true);
    final ResidualsScore residualsScoreAv = computeScores(data, tp, fp, numberOfMolecules, false);
    residualsScore = (settings.useMaxResiduals) ? residualsScoreMax : residualsScoreAv;
    if (settings.showJaccardPlot) {
        plotJaccard(residualsScore, null);
    }
    final String bestJaccard = MathUtils.rounded(bestTp / (bestFp + numberOfMolecules)) + '\t';
    final String analysisPrefix2 = analysisPrefix + bestJaccard;
    sb.append(bestJaccard);
    addJaccardScores(sb);
    sb.append('\t').append(TextUtils.nanosToString(runTime));
    createSummaryTable().append(sb.toString());
    // Store results in memory for later analysis
    referenceResults.set(new ReferenceResults(results, residualsScoreMax, residualsScoreAv, numberOfMolecules, analysisPrefix2));
}
Also used : Percentile(org.apache.commons.math3.stat.descriptive.rank.Percentile) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) ArrayList(java.util.ArrayList) CalibrationReader(uk.ac.sussex.gdsc.smlm.data.config.CalibrationReader) PeakResultPoint(uk.ac.sussex.gdsc.smlm.results.PeakResultPoint) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) FitConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitConfiguration)

Example 5 with StoredDataStatistics

use of uk.ac.sussex.gdsc.core.utils.StoredDataStatistics in project GDSC-SMLM by aherbert.

the class BlinkEstimatorTest method estimateBlinking.

private TIntHashSet estimateBlinking(UniformRandomProvider rg, double blinkingRate, double ton, double toff, int particles, double fixedFraction, boolean timeAtLowerBound, boolean doAssert) {
    Assumptions.assumeTrue(TestSettings.allow(TestComplexity.MAXIMUM));
    final SpatialIllumination activationIllumination = new UniformIllumination(100);
    int totalSteps = 100;
    final double eAct = totalSteps * 0.3 * activationIllumination.getAveragePhotons();
    final ImageModel imageModel = new ActivationEnergyImageModel(eAct, activationIllumination, ton, 0, toff, 0, blinkingRate, rg);
    final double[] max = new double[] { 256, 256, 32 };
    final double[] min = new double[3];
    final SpatialDistribution distribution = new UniformDistribution(min, max, rg.nextInt());
    final List<CompoundMoleculeModel> compounds = new ArrayList<>(1);
    final CompoundMoleculeModel c = new CompoundMoleculeModel(1, 0, 0, 0, Arrays.asList(new MoleculeModel(0, 0, 0, 0)));
    c.setDiffusionRate(diffusionRate);
    c.setDiffusionType(DiffusionType.RANDOM_WALK);
    compounds.add(c);
    final List<CompoundMoleculeModel> molecules = imageModel.createMolecules(compounds, particles, distribution, false);
    // Activate fluorophores
    final List<? extends FluorophoreSequenceModel> fluorophores = imageModel.createFluorophores(molecules, totalSteps);
    totalSteps = checkTotalSteps(totalSteps, fluorophores);
    final List<LocalisationModel> localisations = imageModel.createImage(molecules, fixedFraction, totalSteps, photons, 0.5, false);
    // // Remove localisations to simulate missed counts.
    // List<LocalisationModel> newLocalisations = new
    // ArrayList<LocalisationModel>(localisations.size());
    // boolean[] id = new boolean[fluorophores.size() + 1];
    // Statistics photonStats = new Statistics();
    // for (LocalisationModel l : localisations)
    // {
    // photonStats.add(l.getIntensity());
    // // Remove by intensity threshold and optionally at random.
    // if (l.getIntensity() < minPhotons || rand.nextDouble() < pDelete)
    // continue;
    // newLocalisations.add(l);
    // id[l.getId()] = true;
    // }
    // localisations = newLocalisations;
    // logger.info("Photons = %f", photonStats.getMean());
    // 
    // List<FluorophoreSequenceModel> newFluorophores = new
    // ArrayList<FluorophoreSequenceModel>(fluorophores.size());
    // for (FluorophoreSequenceModel f : fluorophores)
    // {
    // if (id[f.getId()])
    // newFluorophores.add(f);
    // }
    // fluorophores = newFluorophores;
    final MemoryPeakResults results = new MemoryPeakResults();
    final CalibrationWriter calibration = new CalibrationWriter();
    calibration.setNmPerPixel(pixelPitch);
    calibration.setExposureTime(msPerFrame);
    calibration.setCountPerPhoton(1);
    results.setCalibration(calibration.getCalibration());
    results.setPsf(PsfHelper.create(PSFType.ONE_AXIS_GAUSSIAN_2D));
    final float b = 0;
    float intensity;
    final float z = 0;
    for (final LocalisationModel l : localisations) {
        // Remove by intensity threshold and optionally at random.
        if (l.getIntensity() < minPhotons || rg.nextDouble() < probabilityDelete) {
            continue;
        }
        final int frame = l.getTime();
        intensity = (float) l.getIntensity();
        final float x = (float) l.getX();
        final float y = (float) l.getY();
        final float[] params = Gaussian2DPeakResultHelper.createParams(b, intensity, x, y, z, psfWidth);
        results.add(frame, 0, 0, 0, 0, 0, 0, params, null);
    }
    // Add random localisations
    // Intensity doesn't matter at the moment for tracing
    intensity = (float) photons;
    for (int i = (int) (localisations.size() * probabilityAdd); i-- > 0; ) {
        final int frame = 1 + rg.nextInt(totalSteps);
        final float x = (float) (rg.nextDouble() * max[0]);
        final float y = (float) (rg.nextDouble() * max[1]);
        final float[] params = Gaussian2DPeakResultHelper.createParams(b, intensity, x, y, z, psfWidth);
        results.add(frame, 0, 0, 0, 0, 0, 0, params, null);
    }
    // Get actual simulated stats ...
    final Statistics statsNBlinks = new Statistics();
    final Statistics statsTOn = new Statistics();
    final Statistics statsTOff = new Statistics();
    final Statistics statsSampledNBlinks = new Statistics();
    final Statistics statsSampledTOn = new Statistics();
    final StoredDataStatistics statsSampledTOff = new StoredDataStatistics();
    for (final FluorophoreSequenceModel f : fluorophores) {
        statsNBlinks.add(f.getNumberOfBlinks());
        statsTOn.add(f.getOnTimes());
        statsTOff.add(f.getOffTimes());
        final int[] on = f.getSampledOnTimes();
        statsSampledNBlinks.add(on.length);
        statsSampledTOn.add(on);
        statsSampledTOff.add(f.getSampledOffTimes());
    }
    logger.info(FunctionUtils.getSupplier("N = %d (%d), N-blinks = %f, tOn = %f, tOff = %f, Fixed = %f", fluorophores.size(), localisations.size(), blinkingRate, ton, toff, fixedFraction));
    logger.info(FunctionUtils.getSupplier("Actual N-blinks = %f (%f), tOn = %f (%f), tOff = %f (%f), 95%% = %f, max = %f", statsNBlinks.getMean(), statsSampledNBlinks.getMean(), statsTOn.getMean(), statsSampledTOn.getMean(), statsTOff.getMean(), statsSampledTOff.getMean(), statsSampledTOff.getStatistics().getPercentile(95), statsSampledTOff.getStatistics().getMax()));
    logger.info("-=-=--=-");
    final BlinkEstimator be = new BlinkEstimator();
    be.setMaxDarkTime((int) (toff * 10));
    be.setMsPerFrame(msPerFrame);
    be.setRelativeDistance(false);
    final double d = ImageModel.getRandomMoveDistance(diffusionRate);
    be.setSearchDistance((fixedFraction < 1) ? Math.sqrt(2 * d * d) * 3 : 0);
    be.setTimeAtLowerBound(timeAtLowerBound);
    // Assertions.assertTrue("Max dark time must exceed the dark time of the data (otherwise no
    // plateau)",
    // be.maxDarkTime > statsSampledTOff.getStatistics().getMax());
    final int nMolecules = fluorophores.size();
    if (usePopulationStatistics) {
        blinkingRate = statsNBlinks.getMean();
        toff = statsTOff.getMean();
    } else {
        blinkingRate = statsSampledNBlinks.getMean();
        toff = statsSampledTOff.getMean();
    }
    // See if any fitting regime gets a correct answer
    final TIntHashSet ok = new TIntHashSet();
    for (int numberOfFittedPoints = MIN_FITTED_POINTS; numberOfFittedPoints <= MAX_FITTED_POINTS; numberOfFittedPoints++) {
        be.setNumberOfFittedPoints(numberOfFittedPoints);
        be.computeBlinkingRate(results, true);
        final double moleculesError = DoubleEquality.relativeError(nMolecules, be.getNMolecules());
        final double blinksError = DoubleEquality.relativeError(blinkingRate, be.getNBlinks());
        final double offError = DoubleEquality.relativeError(toff * msPerFrame, be.getTOff());
        logger.info(FunctionUtils.getSupplier("Error %d: N = %f, blinks = %f, tOff = %f : %f", numberOfFittedPoints, moleculesError, blinksError, offError, (moleculesError + blinksError + offError) / 3));
        if (moleculesError < relativeError && blinksError < relativeError && offError < relativeError) {
            ok.add(numberOfFittedPoints);
            logger.info("-=-=--=-");
            logger.info(FunctionUtils.getSupplier("*** Correct at %d fitted points ***", numberOfFittedPoints));
            if (doAssert) {
                break;
            }
        }
    // if (!be.isIncreaseNFittedPoints())
    // break;
    }
    logger.info("-=-=--=-");
    if (doAssert) {
        Assertions.assertFalse(ok.isEmpty());
    }
    // relativeError);
    return ok;
}
Also used : ActivationEnergyImageModel(uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel) CompoundMoleculeModel(uk.ac.sussex.gdsc.smlm.model.CompoundMoleculeModel) ArrayList(java.util.ArrayList) TIntHashSet(gnu.trove.set.hash.TIntHashSet) MoleculeModel(uk.ac.sussex.gdsc.smlm.model.MoleculeModel) CompoundMoleculeModel(uk.ac.sussex.gdsc.smlm.model.CompoundMoleculeModel) SpatialIllumination(uk.ac.sussex.gdsc.smlm.model.SpatialIllumination) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) SpatialDistribution(uk.ac.sussex.gdsc.smlm.model.SpatialDistribution) UniformDistribution(uk.ac.sussex.gdsc.smlm.model.UniformDistribution) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) UniformIllumination(uk.ac.sussex.gdsc.smlm.model.UniformIllumination) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) FluorophoreSequenceModel(uk.ac.sussex.gdsc.smlm.model.FluorophoreSequenceModel) ActivationEnergyImageModel(uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel) ImageModel(uk.ac.sussex.gdsc.smlm.model.ImageModel)

Aggregations

StoredDataStatistics (uk.ac.sussex.gdsc.core.utils.StoredDataStatistics)29 Statistics (uk.ac.sussex.gdsc.core.utils.Statistics)11 ArrayList (java.util.ArrayList)10 UniformRandomProvider (org.apache.commons.rng.UniformRandomProvider)9 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)9 Plot (ij.gui.Plot)7 Rectangle (java.awt.Rectangle)6 ImagePlus (ij.ImagePlus)5 ImageStack (ij.ImageStack)5 DescriptiveStatistics (org.apache.commons.math3.stat.descriptive.DescriptiveStatistics)5 HistogramPlotBuilder (uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder)5 WindowOrganiser (uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser)5 GenericDialog (ij.gui.GenericDialog)4 PlotWindow (ij.gui.PlotWindow)4 LinkedList (java.util.LinkedList)4 TIntHashSet (gnu.trove.set.hash.TIntHashSet)3 IJ (ij.IJ)3 Prefs (ij.Prefs)3 PlugIn (ij.plugin.PlugIn)3 ConcurrentRuntimeException (org.apache.commons.lang3.concurrent.ConcurrentRuntimeException)3