Search in sources :

Example 1 with PoissonSampler

use of org.apache.commons.rng.sampling.distribution.PoissonSampler 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 2 with PoissonSampler

use of org.apache.commons.rng.sampling.distribution.PoissonSampler in project GDSC-SMLM by aherbert.

the class CreateData method createBackground.

private float[] createBackground(UniformRandomProvider rng) {
    float[] pixels2 = null;
    if (settings.getBackground() > 0) {
        if (rng == null) {
            rng = createRandomGenerator();
        }
        pixels2 = new float[backgroundPixels.length];
        // Add Poisson noise.
        if (uniformBackground) {
            final double mean = backgroundPixels[0];
            // Simulate N photons hitting the image. The total photons (N) is
            // the mean for each pixel multiplied by the number of pixels.
            // Note: The number of samples (N) must be Poisson distributed, i.e.
            // the total amount of photons per frame is Poisson noise.
            // The alternative is to sample each pixel from a Poisson distribution. This is slow!
            int samples = new PoissonSampler(rng, mean * backgroundPixels.length).sample();
            final int upper = pixels2.length;
            while (samples-- > 0) {
                pixels2[rng.nextInt(upper)] += 1;
            }
        } else {
            for (int i = 0; i < pixels2.length; i++) {
                pixels2[i] = PoissonSamplerUtils.nextPoissonSample(rng, backgroundPixels[i]);
            }
        }
    } else {
        pixels2 = backgroundPixels.clone();
    }
    return pixels2;
}
Also used : PoissonSampler(org.apache.commons.rng.sampling.distribution.PoissonSampler) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint)

Example 3 with PoissonSampler

use of org.apache.commons.rng.sampling.distribution.PoissonSampler in project GDSC-SMLM by aherbert.

the class GradientCalculatorSpeedTest method mleCalculatorComputesLogLikelihoodRatio.

@SeededTest
void mleCalculatorComputesLogLikelihoodRatio(RandomSeed seed) {
    final EllipticalGaussian2DFunction func = new EllipticalGaussian2DFunction(1, blockWidth, blockWidth);
    final int n = blockWidth * blockWidth;
    final double[] a = new double[1 + Gaussian2DFunction.PARAMETERS_PER_PEAK];
    final UniformRandomProvider rng = RngUtils.create(seed.getSeed());
    final DoubleDoubleBiPredicate predicate = TestHelper.doublesAreClose(1e-10, 0);
    for (int run = 5; run-- > 0; ) {
        a[Gaussian2DFunction.BACKGROUND] = random(rng, background);
        a[Gaussian2DFunction.SIGNAL] = random(rng, amplitude);
        a[Gaussian2DFunction.ANGLE] = random(rng, angle);
        a[Gaussian2DFunction.X_POSITION] = random(rng, xpos);
        a[Gaussian2DFunction.Y_POSITION] = random(rng, ypos);
        a[Gaussian2DFunction.X_SD] = random(rng, xwidth);
        a[Gaussian2DFunction.Y_SD] = random(rng, ywidth);
        // Simulate Poisson process
        func.initialise(a);
        final double[] u = new double[n];
        final double[] x = new double[n];
        for (int i = 0; i < n; i++) {
            final double value = func.eval(i);
            u[i] = value;
            // Add random Poisson noise
            if (value > 0) {
                x[i] = new PoissonSampler(rng, value).sample();
            }
        }
        final int ng = func.getNumberOfGradients();
        final double[][] alpha = new double[ng][ng];
        final double[] beta = new double[ng];
        final GradientCalculator calc = GradientCalculatorUtils.newCalculator(ng, true);
        final double llr = PoissonCalculator.logLikelihoodRatio(u, x);
        final double llr2 = calc.findLinearised(n, x, a, alpha, beta, func);
        // logger.fine(FunctionUtils.getSupplier("llr=%f, llr2=%f", llr, llr2));
        TestAssertions.assertTest(llr, llr2, predicate, "Log-likelihood ratio");
    }
}
Also used : DoubleDoubleBiPredicate(uk.ac.sussex.gdsc.test.api.function.DoubleDoubleBiPredicate) SingleEllipticalGaussian2DFunction(uk.ac.sussex.gdsc.smlm.function.gaussian.SingleEllipticalGaussian2DFunction) EllipticalGaussian2DFunction(uk.ac.sussex.gdsc.smlm.function.gaussian.EllipticalGaussian2DFunction) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) PoissonSampler(org.apache.commons.rng.sampling.distribution.PoissonSampler) SeededTest(uk.ac.sussex.gdsc.test.junit5.SeededTest)

Example 4 with PoissonSampler

use of org.apache.commons.rng.sampling.distribution.PoissonSampler in project GDSC-SMLM by aherbert.

the class EmGainAnalysis method simulateFromPoissonGammaGaussian.

/**
 * Randomly generate a histogram from poisson-gamma-gaussian samples.
 *
 * @return The histogram
 */
private int[] simulateFromPoissonGammaGaussian() {
    // Randomly sample
    final UniformRandomProvider rng = UniformRandomProviders.create();
    final PoissonSampler poisson = new PoissonSampler(rng, settings.settingPhotons);
    final MarsagliaTsangGammaSampler gamma = new MarsagliaTsangGammaSampler(rng, settings.settingPhotons, settings.settingGain);
    final NormalizedGaussianSampler gauss = SamplerUtils.createNormalizedGaussianSampler(rng);
    final int steps = settings.simulationSize;
    final int[] samples = new int[steps];
    for (int n = 0; n < steps; n++) {
        if (n % 64 == 0) {
            IJ.showProgress(n, steps);
        }
        // Poisson
        double sample = poisson.sample();
        // Gamma
        if (sample > 0) {
            gamma.setAlpha(sample);
            sample = gamma.sample();
        }
        // Gaussian
        sample += settings.settingNoise * gauss.sample();
        // Convert the sample to a count
        samples[n] = (int) Math.round(sample + settings.settingBias);
    }
    final int max = MathUtils.max(samples);
    final int[] histogram = new int[max + 1];
    for (final int s : samples) {
        histogram[s]++;
    }
    return histogram;
}
Also used : UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) PoissonSampler(org.apache.commons.rng.sampling.distribution.PoissonSampler) NormalizedGaussianSampler(org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler) Point(java.awt.Point) MarsagliaTsangGammaSampler(uk.ac.sussex.gdsc.core.utils.rng.MarsagliaTsangGammaSampler)

Aggregations

PoissonSampler (org.apache.commons.rng.sampling.distribution.PoissonSampler)4 UniformRandomProvider (org.apache.commons.rng.UniformRandomProvider)3 ReadHint (uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint)2 TIntIntHashMap (gnu.trove.map.hash.TIntIntHashMap)1 GenericDialog (ij.gui.GenericDialog)1 Point (java.awt.Point)1 IOException (java.io.IOException)1 NullArgumentException (org.apache.commons.math3.exception.NullArgumentException)1 NormalizedGaussianSampler (org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler)1 DataException (uk.ac.sussex.gdsc.core.data.DataException)1 ConversionException (uk.ac.sussex.gdsc.core.data.utils.ConversionException)1 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)1 StoredDataStatistics (uk.ac.sussex.gdsc.core.utils.StoredDataStatistics)1 MarsagliaTsangGammaSampler (uk.ac.sussex.gdsc.core.utils.rng.MarsagliaTsangGammaSampler)1 ConfigurationException (uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException)1 EllipticalGaussian2DFunction (uk.ac.sussex.gdsc.smlm.function.gaussian.EllipticalGaussian2DFunction)1 SingleEllipticalGaussian2DFunction (uk.ac.sussex.gdsc.smlm.function.gaussian.SingleEllipticalGaussian2DFunction)1 ActivationEnergyImageModel (uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel)1 CompoundMoleculeModel (uk.ac.sussex.gdsc.smlm.model.CompoundMoleculeModel)1 FixedLifetimeImageModel (uk.ac.sussex.gdsc.smlm.model.FixedLifetimeImageModel)1