<commit_before>/**
 * Implementation for the "Fit All" button
 * Fits all spots in the selected stack
 * 
 * Part of Micro-Manager's Localization Plugin
 * 
 * <NAME>, copyright UCSF (2012)
 * 
 */

package edu.valelab.gaussianfit;

import edu.valelab.gaussianfit.algorithm.FindLocalMaxima;
import edu.valelab.gaussianfit.utils.ProgressThread;
import edu.valelab.gaussianfit.data.GaussianInfo;
import edu.valelab.gaussianfit.data.SpotData;
import edu.valelab.gaussianfit.fitting.ZCalibrator;
import edu.valelab.gaussianfit.utils.MMWindowAbstraction;
import ij.IJ;
import ij.ImagePlus;
import ij.gui.Roi;
import ij.plugin.frame.RoiManager;
import ij.process.ImageProcessor;
import java.awt.Polygon;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.LinkedBlockingQueue;
import edu.valelab.gaussianfit.utils.ReportingUtils;

/**
 *
 * @author nico
 */
public class FitAllThread extends GaussianInfo implements Runnable  {
   double[] params0_;
   double[] steps_ = new double[5];
   GaussianFitStackThread[] gfsThreads_;
   private volatile Thread t_ = null;
   private static boolean running_ = false;
   private final FindLocalMaxima.FilterType preFilterType_;
   private final String positionString_;

   public FitAllThread(int shape, int fitMode, 
           FindLocalMaxima.FilterType preFilterType, String positions) {
      shape_ = shape;
      fitMode_ = fitMode;
      preFilterType_ = preFilterType;
      positionString_ = positions;
   }

   public synchronized void  init() {
      if (running_)
         return;
      t_ = new Thread(this);
      running_ = true;
      t_.start();
   }

   public synchronized void stop() {
      if (gfsThreads_ != null) {
         for (GaussianFitStackThread gfsThread : gfsThreads_) {
            if (gfsThread != null) {
               gfsThread.stop();
            }
         }
      }
      t_ = null;
      running_ = false;
   }

   public boolean isRunning() {
      return running_;
   }

   @Override
   public void run() {

      // List with spot positions found through the Find Maxima command
      sourceList_ = new LinkedBlockingQueue<SpotData>();
      resultList_ = Collections.synchronizedList(new ArrayList<SpotData>());

      // take the active ImageJ image
      ImagePlus siPlus;
      try {
         siPlus = IJ.getImage();
      } catch (Exception ex) {
         stop();
         return;
      }

      int nrThreads = ij.Prefs.getThreads();
      if (nrThreads > 8) {
         nrThreads = 8;
      }

      Roi originalRoi = siPlus.getRoi();

      long startTime = System.nanoTime();
      int nrPositions = 1;
      int nrChannels = siPlus.getNChannels();
      int nrFrames = siPlus.getNFrames();
      int nrSlices = siPlus.getNSlices();
      int maxNrSpots = 0;

      boolean isMMWindow = MMWindowAbstraction.isMMWindow(siPlus);

      if (isMMWindow) {
         String[] parts = positionString_.split("-");
         nrPositions = MMWindowAbstraction.getNumberOfPositions(siPlus);
         int startPos = 1; int endPos = 1;
         if (parts.length > 0) {
            startPos = Integer.parseInt(parts[0]);
         }
         if (parts.length > 1) {
            endPos = Integer.parseInt(parts[1]);
         }
         if (endPos > nrPositions) {
            endPos = nrPositions;
         }
         if (endPos < startPos) {
            endPos = startPos;
         }
         for (int p = startPos; p <= endPos; p++) {
            MMWindowAbstraction.setPosition(siPlus, p);

            int nrSpots = analyzeImagePlus(siPlus, p, nrThreads, originalRoi);
            if (nrSpots > maxNrSpots) {
               maxNrSpots = nrSpots;
            }
         }
      }

      if (!isMMWindow) {
         int nrSpots = analyzeImagePlus(siPlus, 1, nrThreads, originalRoi);
         if (nrSpots > maxNrSpots) {
            maxNrSpots = nrSpots;
         }
      }

      long endTime = System.nanoTime();

      // Add data to data overview window
      if (resultList_.size() < 1) {
         ReportingUtils.showError("No spots found");
         running_ = false;
         return;
      }
      DataCollectionForm dcForm = DataCollectionForm.getInstance();

      double zMax = resultList_.get(0).getZCenter();
      if (zMax < 0.0) {
         zMax = 0.0;
      }
      double zMin = zMax;
      ZCalibrator zc = DataCollectionForm.zc_;
      if (zc != null) {
         for (SpotData spot : resultList_) {
            double zTmp = spot.getZCenter();
            if (zMax < zTmp) {
               zMax = zTmp;
            }
            if (zMin > zTmp && zTmp > 0.0) {
               zMin = zTmp;
            }
         }
      }


      ArrayList<Double> timePoints = new ArrayList<Double>();
      // ugly code to deal with 1-based frame numbers and their relation to timePoints
      timePoints.add(0.0);
      for (int i = 1; i <= nrFrames; i++) {
         timePoints.add((i - 1) * timeIntervalMs_);
      }

      String title = siPlus.getTitle();
      if (nrPositions > 1) {
         title += "_Pos" + positionString_;
      }
      dcForm.addSpotData(title, siPlus.getTitle(), "",
              siPlus.getWidth(), siPlus.getHeight(), pixelSize_,
              zStackStepSize_, shape_, halfSize_,
              nrChannels, nrFrames, nrSlices, nrPositions, resultList_.size(),
              resultList_, timePoints, false, DataCollectionForm.Coordinates.NM,
              DataCollectionForm.zc_.hasFitFunctions(),
              zMin, zMax);

      dcForm.setVisible(true);

      // report duration of analysis
      double took = (endTime - startTime) / 1E9;
      double rate = resultList_.size() / took;
      DecimalFormat df2 = new DecimalFormat("#.##");
      DecimalFormat df0 = new DecimalFormat("#");
      print("Analyzed " + resultList_.size() + " spots in " + df2.format(took)
              + " seconds (" + df0.format(rate) + " spots/sec.)");

      running_ = false;
   }

   @SuppressWarnings("unchecked")
   private int analyzeImagePlus(ImagePlus siPlus, int position, int nrThreads, Roi originalRoi) {

      int nrSpots = 0;
      // Start up IJ.Prefs.getThreads() threads for gaussian fitting
      gfsThreads_ = new GaussianFitStackThread[nrThreads];
      for (int i = 0; i < nrThreads; i++) {
         gfsThreads_[i] = new GaussianFitStackThread(sourceList_, resultList_, siPlus, halfSize_,
                 shape_, fitMode_);<commit_msg>Gaussian: added functions to FitAllThread for external use<commit_after>/**
 * Implementation for the "Fit All" button
 * Fits all spots in the selected stack
 * 
 * Part of Micro-Manager's Localization Plugin
 * 
 * <NAME>, copyright UCSF (2012)
 * 
 */

package edu.valelab.gaussianfit;

import edu.valelab.gaussianfit.algorithm.FindLocalMaxima;
import edu.valelab.gaussianfit.utils.ProgressThread;
import edu.valelab.gaussianfit.data.GaussianInfo;
import edu.valelab.gaussianfit.data.SpotData;
import edu.valelab.gaussianfit.fitting.ZCalibrator;
import edu.valelab.gaussianfit.utils.MMWindowAbstraction;
import ij.IJ;
import ij.ImagePlus;
import ij.gui.Roi;
import ij.plugin.frame.RoiManager;
import ij.process.ImageProcessor;
import java.awt.Polygon;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.LinkedBlockingQueue;
import edu.valelab.gaussianfit.utils.ReportingUtils;
import java.util.List;

/**
 *
 * @author nico
 */
public class FitAllThread extends GaussianInfo implements Runnable  {
   double[] params0_;
   double[] steps_ = new double[5];
   GaussianFitStackThread[] gfsThreads_;
   private volatile Thread t_ = null;
   private static boolean running_ = false;
   private final FindLocalMaxima.FilterType preFilterType_;
   private final String positionString_;
   private boolean showDataWindow_ = true;

   public FitAllThread(int shape, int fitMode, 
           FindLocalMaxima.FilterType preFilterType, String positions) {
      shape_ = shape;
      fitMode_ = fitMode;
      preFilterType_ = preFilterType;
      positionString_ = positions;
   }

   public synchronized void  init() {
      if (running_)
         return;
      t_ = new Thread(this);
      running_ = true;
      t_.start();
   }
   
   public synchronized void join(long millis) throws InterruptedException {
      if (!running_) {
         return;
      }
      t_.join(millis);
   } 

   public synchronized void stop() {
      if (gfsThreads_ != null) {
         for (GaussianFitStackThread gfsThread : gfsThreads_) {
            if (gfsThread != null) {
               gfsThread.stop();
            }
         }
      }
      t_ = null;
      running_ = false;
   }

   public boolean isRunning() {
      return running_;
   }

   public synchronized List<SpotData> getResults() {
      return resultList_;
   }
   
   public synchronized void showDataWindow(boolean flag) {
      showDataWindow_ = flag;
   }
   
   @Override
   public void run() {

      // List with spot positions found through the Find Maxima command
      sourceList_ = new LinkedBlockingQueue<SpotData>();
      resultList_ = Collections.synchronizedList(new ArrayList<SpotData>());

      // take the active ImageJ image
      ImagePlus siPlus;
      try {
         siPlus = IJ.getImage();
      } catch (Exception ex) {
         stop();
         return;
      }

      int nrThreads = ij.Prefs.getThreads();
      if (nrThreads > 8) {
         nrThreads = 8;
      }

      Roi originalRoi = siPlus.getRoi();

      long startTime = System.nanoTime();
      int nrPositions = 1;
      int nrChannels = siPlus.getNChannels();
      int nrFrames = siPlus.getNFrames();
      int nrSlices = siPlus.getNSlices();
      int maxNrSpots = 0;

      boolean isMMWindow = MMWindowAbstraction.isMMWindow(siPlus);

      if (isMMWindow) {
         String[] parts = positionString_.split("-");
         nrPositions = MMWindowAbstraction.getNumberOfPositions(siPlus);
         int startPos = 1; int endPos = 1;
         if (parts.length > 0) {
            startPos = Integer.parseInt(parts[0]);
         }
         if (parts.length > 1) {
            endPos = Integer.parseInt(parts[1]);
         }
         if (endPos > nrPositions) {
            endPos = nrPositions;
         }
         if (endPos < startPos) {
            endPos = startPos;
         }
         for (int p = startPos; p <= endPos; p++) {
            MMWindowAbstraction.setPosition(siPlus, p);

            int nrSpots = analyzeImagePlus(siPlus, p, nrThreads, originalRoi);
            if (nrSpots > maxNrSpots) {
               maxNrSpots = nrSpots;
            }
         }
      }

      if (!isMMWindow) {
         int nrSpots = analyzeImagePlus(siPlus, 1, nrThreads, originalRoi);
         if (nrSpots > maxNrSpots) {
            maxNrSpots = nrSpots;
         }
      }

      long endTime = System.nanoTime();

      // Add data to data overview window
      if (resultList_.size() < 1) {
         ReportingUtils.showError("No spots found");
         running_ = false;
         return;
      }
      
      DataCollectionForm dcForm = DataCollectionForm.getInstance();

      double zMax = resultList_.get(0).getZCenter();
      if (zMax < 0.0) {
         zMax = 0.0;
      }
      double zMin = zMax;
      ZCalibrator zc = DataCollectionForm.zc_;
      if (zc != null) {
         for (SpotData spot : resultList_) {
            double zTmp = spot.getZCenter();
            if (zMax < zTmp) {
               zMax = zTmp;
            }
            if (zMin > zTmp && zTmp > 0.0) {
               zMin = zTmp;
            }
         }
      }


      ArrayList<Double> timePoints = new ArrayList<Double>();
      // ugly code to deal with 1-based frame numbers and their relation to timePoints
      timePoints.add(0.0);
      for (int i = 1; i <= nrFrames; i++) {
         timePoints.add((i - 1) * timeIntervalMs_);
      }

      String title = siPlus.getTitle();
      if (nrPositions > 1) {
         title += "_Pos" + positionString_;
      }
      dcForm.addSpotData(title, siPlus.getTitle(), "",
              siPlus.getWidth(), siPlus.getHeight(), pixelSize_,
              zStackStepSize_, shape_, halfSize_,
              nrChannels, nrFrames, nrSlices, nrPositions, resultList_.size(),
              resultList_, timePoints, false, DataCollectionForm.Coordinates.NM,
              DataCollectionForm.zc_.hasFitFunctions(),
              zMin, zMax);

      if (showDataWindow_) {
         dcForm.setVisible(true);
      }

      // report duration of analysis
      double took = (endTime - startTime) / 1E9;
      double rate = resultList_.size() / took;
      DecimalFormat df2 = new DecimalFormat("#.##");
      DecimalFormat df0 = new DecimalFormat("#");
      print("Analyzed " + resultList_.size() + " spots in " + df2.format(took)
              + " seconds (" + df0.format(rate) + " spots/sec.)");

      running_ = false;
   }

   @SuppressWarnings("unchecked")
   private int analyzeImagePlus(ImagePlus siPlus, int position, int nrThreads, Roi originalRoi) {

      int nrSpots = 0;
      // Start up IJ.Prefs.getThreads() threads for gaussian fitting
      gfsThreads_ = new GaussianFitStackThread[nrThreads];
      for (int i = 0; i < nrThreads; i++) {
         gfsThreads_[i] = new GaussianFitStackThread(sourceList_, resultList_, siPlus, halfSize_,
                 shape_, fitMode_);
{'fraction_non_alphanumeric': 0.10427986602158541, 'fraction_numerical': 0.005805731298846297, 'mean_word_length': 2.29475232957332, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6202437', 'n_tokens_mistral': 4199, 'n_tokens_neox': 4030, 'n_words': 978}