Skip to content

Commit

Permalink
Ability to Cancel Data Reduction Process
Browse files Browse the repository at this point in the history
  • Loading branch information
AvocadoMoon committed Nov 15, 2024
1 parent 585926d commit 609cebe
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.vcell.N5.reduction;

import com.amazonaws.AbortedException;
import com.google.gson.internal.LinkedTreeMap;
import com.opencsv.CSVWriter;
import ij.ImagePlus;
import ij.WindowManager;
import ij.gui.Roi;
import org.vcell.N5.ExportDataRepresentation;
import org.vcell.N5.N5ImageHandler;
import org.vcell.N5.UI.ControlButtonsPanel;
import org.vcell.N5.UI.MainPanel;
import org.vcell.N5.UI.N5ExportTable;
import org.vcell.N5.reduction.DTO.RangeOfImage;
Expand All @@ -17,6 +20,8 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

public class DataReductionWriter implements SimLoadingListener {
private final ArrayList<Roi> arrayOfSimRois;
Expand All @@ -34,6 +39,9 @@ public class DataReductionWriter implements SimLoadingListener {
private final ArrayList<ArrayList<String>> standardDivMatrix = new ArrayList<>();
private final ArrayList<ArrayList<String>> metaDataSheet = new ArrayList<>();

private final ConcurrentHashMap<String, ThreadStruct> threadPool = new ConcurrentHashMap<>();
private final Object threadPoolLock = new Object();

private final HashMap<SelectMeasurements.AvailableMeasurements, ArrayList<ArrayList<String>>> sheetsAvailable = new HashMap<SelectMeasurements.AvailableMeasurements, ArrayList<ArrayList<String>>>(){{
put(SelectMeasurements.AvailableMeasurements.AVERAGE, averageMatrix);
put(SelectMeasurements.AvailableMeasurements.STD_DEV, standardDivMatrix);
Expand Down Expand Up @@ -61,10 +69,6 @@ public ReducedData(int rowLen, int colLen, SelectMeasurements.AvailableMeasureme
// Initialize Sheet and Lab results //
/////////////////////////////////////

public static void createDataReductionProcess(DataReductionGUI.DataReductionSubmission submission){
new DataReductionWriter(submission);
}

public DataReductionWriter(DataReductionGUI.DataReductionSubmission submission){
N5ImageHandler.loadingManager.addSimLoadingListener(this);
this.submission = submission;
Expand All @@ -83,8 +87,15 @@ public DataReductionWriter(DataReductionGUI.DataReductionSubmission submission){

Thread processLabResults = new Thread(() -> {
calculateAndAddResults(submission.labResults, submission.experiementNormRange, submission.experimentImageRange,
submission.arrayOfLabRois, null);
submission.arrayOfLabRois, null, "Lab");
synchronized (threadPoolLock){
threadPool.remove("Lab");
}
}, "Processing Lab Image");
ThreadStruct threadStruct = new ThreadStruct(null, new AtomicBoolean(true), processLabResults);
synchronized (threadPoolLock){
threadPool.put("Lab", threadStruct);
}
processLabResults.start();
}

Expand Down Expand Up @@ -137,7 +148,8 @@ private void initializeDataSheets(){

private void calculateAndAddResults(ImagePlus imagePlus, RangeOfImage normRange,
RangeOfImage imageRange, ArrayList<Roi> rois,
LinkedTreeMap<String, LinkedTreeMap<String, String>> channelInfo){
LinkedTreeMap<String, LinkedTreeMap<String, String>> channelInfo,
String threadName){
HashMap<String, Double> normValue = null;
if (submission.normalizeMeasurementsBool){
normValue = calculations.calculateNormalValue(imagePlus, normRange, rois, imageRange);
Expand All @@ -153,9 +165,12 @@ private void calculateAndAddResults(ImagePlus imagePlus, RangeOfImage normRange,
reducedDataArrayList.add(reducedData);
calculations.addAppropriateHeaders(imagePlus, rois, imageRange, reducedData, channelInfo);
}
calculations.calculateStatistics(imagePlus, rois, normValue, reducedDataArrayList, imageRange);
AtomicBoolean continueOperation = threadPool.get(threadName).continueOperation;
calculations.calculateStatistics(imagePlus, rois, normValue, reducedDataArrayList, imageRange, continueOperation);
for (ReducedData reducedData: reducedDataArrayList){
addValuesToCSVMatrix(reducedData);
if (continueOperation.get()){
addValuesToCSVMatrix(reducedData);
}
}
}

Expand Down Expand Up @@ -248,8 +263,26 @@ private void writeCSVMatrix(){
throw new RuntimeException(e);
} finally {
N5ImageHandler.loadingManager.removeFromSimLoadingListener(this);
MainPanel.controlButtonsPanel.enableCriticalButtons(true);
MainPanel.controlButtonsPanel.updateButtonsToMatchState(false, ControlButtonsPanel.PanelState.NOTHING_OR_LOADING_IMAGE);
}
}

public void stopAllThreads(){
synchronized (threadPoolLock){
for (String threadName: threadPool.keySet()){
ThreadStruct threadStruct = threadPool.get(threadName);
threadStruct.continueOperation.set(false);
// Experiment image is in thread pool, so trying to retrieve a results loader for it would not work
if (threadStruct.simResultsLoader != null){
SimResultsLoader loadedResults = threadStruct.simResultsLoader;
MainPanel.n5ExportTable.removeSpecificRowFromLoadingRows(loadedResults.rowNumber);
WindowManager.getImage(loadedResults.getImagePlus().getID()).close();
}
threadPool.remove(threadName);
}
}
N5ImageHandler.loadingManager.removeFromSimLoadingListener(this);
MainPanel.controlButtonsPanel.updateButtonsToMatchState(false, ControlButtonsPanel.PanelState.NOTHING_OR_LOADING_IMAGE);
}


Expand All @@ -266,14 +299,32 @@ public void simFinishedLoading(SimResultsLoader loadedResults) {
imagePlus.show();
addMetaData(loadedResults);
calculateAndAddResults(imagePlus, submission.simNormRange, submission.simImageRange,
submission.arrayOfSimRois, loadedResults.getChannelInfo());
submission.arrayOfSimRois, loadedResults.getChannelInfo(), loadedResults.exportID);
MainPanel.n5ExportTable.removeSpecificRowFromLoadingRows(loadedResults.rowNumber);
imagePlus.close();
synchronized (threadPoolLock){
threadPool.remove(loadedResults.exportID);
}
}, "Processing Image: " + loadedResults.userSetFileName);
ThreadStruct threadStruct = new ThreadStruct(loadedResults, new AtomicBoolean(true), imageProcessingThread);
synchronized (threadPoolLock){
threadPool.put(loadedResults.exportID, threadStruct);
}
imageProcessingThread.start();
}
}

static class ThreadStruct {
public final SimResultsLoader simResultsLoader;
public final AtomicBoolean continueOperation;
public final Thread thread;
public ThreadStruct(SimResultsLoader simResultsLoader, AtomicBoolean continueOperation, Thread thread){
this.simResultsLoader = simResultsLoader;
this.continueOperation = continueOperation;
this.thread = thread;
}
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;

class ReductionCalculations {
private final boolean normalize;
Expand Down Expand Up @@ -37,9 +38,9 @@ public void addAppropriateHeaders(ImagePlus imagePlus, ArrayList<Roi> roiList, R
* @param rangeOfImage
*/
void calculateStatistics(ImagePlus imagePlus, ArrayList<Roi> roiList,
HashMap<String, Double> normalizationValue,
ArrayList<DataReductionWriter.ReducedData> reducedDataArrayList,
RangeOfImage rangeOfImage){
HashMap<String, Double> normalizationValue,
ArrayList<DataReductionWriter.ReducedData> reducedDataArrayList,
RangeOfImage rangeOfImage, AtomicBoolean continueOperation){
int roiCounter = 0;
for (Roi roi: roiList) {
imagePlus.setRoi(roi);
Expand All @@ -48,6 +49,9 @@ void calculateStatistics(ImagePlus imagePlus, ArrayList<Roi> roiList,
for (int z = rangeOfImage.zStart; z <= rangeOfImage.zEnd; z++){
for (int c = rangeOfImage.channelStart; c <= rangeOfImage.channelEnd; c++){
int channelSize = rangeOfImage.channelEnd - rangeOfImage.channelStart + 1;
if (!continueOperation.get()){
return;
}
imagePlus.setPosition(c, z, t);
double calculatedValue;
for (DataReductionWriter.ReducedData reducedData : reducedDataArrayList){
Expand All @@ -61,7 +65,7 @@ void calculateStatistics(ImagePlus imagePlus, ArrayList<Roi> roiList,
default:
throw new RuntimeException("Unknown measurement type selected.");
}
if (normalize && reducedData.measurementType == SelectMeasurements.AvailableMeasurements.AVERAGE){
if (normalize){
calculatedValue = calculatedValue / normalizationValue.get(roi.getName() + c);
}
reducedData.data[tzCounter][c - 1 + (roiCounter * channelSize)] = calculatedValue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.vcell.N5.retrieving;

import com.amazonaws.AbortedException;
import com.amazonaws.http.timers.client.SdkInterruptedException;
import ij.ImagePlus;
import org.scijava.log.Logger;
import org.vcell.N5.N5ImageHandler;
Expand All @@ -26,6 +25,7 @@ public class LoadingManager implements SimLoadingEventCreator {

private final HashMap<String, Thread> openingSimulations = new HashMap<>();
private final Object openSimulationsLock = new Object();
private DataReductionWriter dataReductionWriter = null;

private static final Logger logger = N5ImageHandler.getLogger(RangeSelector.class);

Expand All @@ -38,13 +38,13 @@ public void openN5FileDataset(ArrayList<SimResultsLoader> filesToOpen, boolean o
ArrayList<Double> dimensions = firstSim.getN5Dimensions();
if (dataReduction){
dataReductionGUI = new DataReductionGUI(filesToOpen, dimensions.get(2), dimensions.get(3), dimensions.get(4));
dataReductionWriter = dataReductionGUI.shouldContinueWithProcess() ? new DataReductionWriter(dataReductionGUI.createSubmission()) : null;
} else {
rangeSelector.displayRangeMenu(dimensions.get(2), dimensions.get(3), dimensions.get(4));
}
}
boolean dataReductionOkay = dataReduction && dataReductionGUI.shouldContinueWithProcess();
if (dataReductionOkay || !dataReduction){
controlButtonsPanel.allowCancel(true);
MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR));
for (int i = 0; i < filesToOpen.size(); i++){
SimResultsLoader simResultsLoader = filesToOpen.get(i);
Expand All @@ -64,6 +64,7 @@ public void openN5FileDataset(ArrayList<SimResultsLoader> filesToOpen, boolean o
}
catch (RuntimeException e) {
simResultsLoader.setTagToCanceled();
MainPanel.n5ExportTable.removeSpecificRowFromLoadingRows(simResultsLoader.rowNumber);
if (e instanceof AbortedException){
logger.debug("Simulation stopped loading");
} else {
Expand All @@ -75,8 +76,6 @@ public void openN5FileDataset(ArrayList<SimResultsLoader> filesToOpen, boolean o
synchronized (openSimulationsLock){
openingSimulations.remove(simResultsLoader.exportID);
}
controlButtonsPanel.enableRowContextDependentButtons(true);
MainPanel.controlButtonsPanel.allowCancel(false);
}
});
openThread.setName("Opening sim number: " + i + ". With id: " + simResultsLoader.exportID);
Expand All @@ -88,18 +87,36 @@ public void openN5FileDataset(ArrayList<SimResultsLoader> filesToOpen, boolean o
}
}

public void stopOpeningSimulation(String exportID){
public void stopAllImagesAndAnalysis(){
Thread stopEverything = new Thread(() -> {
synchronized (openSimulationsLock){
for (String threadName : openingSimulations.keySet()){
openingSimulations.get(threadName).interrupt();
openingSimulations.remove(threadName);
}
}
if (dataReductionWriter != null){
dataReductionWriter.stopAllThreads();
}
});
stopEverything.start();
}


public void stopLoadingImage(String exportID){
Thread stopOtherThread = new Thread(() -> {
synchronized (openSimulationsLock){
openingSimulations.get(exportID).interrupt();
openingSimulations.remove(exportID);
if (openingSimulations.containsKey(exportID)){
openingSimulations.get(exportID).interrupt();
openingSimulations.remove(exportID);
}
}
});
stopOtherThread.start();
}

public void openLocalN5FS(ArrayList<SimResultsLoader> filesToOpen){
controlButtonsPanel.enableCriticalButtons(true);
controlButtonsPanel.enableAllButtons(true);
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setAcceptAllFileFilterUsed(false);
Expand All @@ -121,7 +138,7 @@ public void openLocalN5FS(ArrayList<SimResultsLoader> filesToOpen){
@Override
public void run() {
MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR));
controlButtonsPanel.enableCriticalButtons(true);
controlButtonsPanel.enableAllButtons(true);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;

public class ReductionCalculationsTest {
// First two are SimROI, last two are LabROI
Expand Down Expand Up @@ -55,7 +56,7 @@ private void compareExpectedCalculations(ImagePlus imagePlus, ArrayList<Roi> roi
reducedDataArrayList.add(reducedData);

HashMap<String, Double> norms = reductionCalculations.calculateNormalValue(imagePlus, normRange, roiList, entireRange);
reductionCalculations.calculateStatistics(imagePlus, roiList, norms, reducedDataArrayList, entireRange);
reductionCalculations.calculateStatistics(imagePlus, roiList, norms, reducedDataArrayList, entireRange, new AtomicBoolean(true));
for (int r = 0; r < expectedResults.length; r++){
for (int c = 0; c < expectedResults[r].length; c++){
Assert.assertEquals(expectedResults[r][c], reducedData.data[r][c], 0.0009);
Expand Down

0 comments on commit 609cebe

Please sign in to comment.