Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class LightSheetManagerPlugin implements MenuPlugin, SciJavaPlugin {
public static final String copyright = "Applied Scientific Instrumentation (ASI), 2022-2026";
public static final String description = "A plugin to control various types of light sheet microscopes.";
public static final String menuName = "Light Sheet Manager";
public static final String version = "0.6.1";
public static final String version = "0.6.3";

private Studio studio_;
private LightSheetManager model_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,11 @@ private void createUserInterface() {
settings.acquisitionMode(),
180, 24);

final boolean isUsingAdvancedTiming = settings.isUsingAdvancedTiming();
cbxUseAdvancedTiming_ = new CheckBox("Use advanced timing settings",
12, settings.isUsingAdvancedTiming(), CheckBox.RIGHT);
12, isUsingAdvancedTiming, CheckBox.RIGHT);
// initial enabled or disabled state
swapTimingSettingsPanels(isUsingAdvancedTiming);

btnRunOverviewAcq_.setEnabled(false); // TODO: re-enable when these features are put in
btnTestAcquisition_.setEnabled(false);
Expand Down Expand Up @@ -275,9 +278,11 @@ private void createEventHandlers() {
});

// select the acquisition mode
cmbAcquisitionModes_.registerListener(
() -> model_.acquisitions().settingsBuilder()
.acquisitionMode(cmbAcquisitionModes_.getSelected()));
cmbAcquisitionModes_.registerListener(() -> {
model_.acquisitions().settingsBuilder()
.acquisitionMode(cmbAcquisitionModes_.getSelected());
model_.acquisitions().updateDurationLabels();
});

// switches timing panels based on check box
cbxUseAdvancedTiming_.registerListener(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ private void createUserInterface() {

add(pnlScanSettings, "wrap");
if (isUsingPLogic_) {
add(pnlLightSheet, "growx");
add(pnlLightSheet, "growx, wrap");
}

add(btnCreateConfigGroup_, "gaptop 40");
add(btnCreateConfigGroup_, "");
}

private void createEventHandlers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ public void createUserInterface() {
btnLoadSettings_ = new Button("Load", 60, 20);
btnConvertSettings_ = new Button("Convert", 72, 20);

btnBrowse_.setToolTipText("Select the save directory with the file browser.");
btnOpen_.setToolTipText("Open the file explorer to the save directory.");
btnSaveSettings_.setToolTipText("Save the current acquisition settings to JSON.");
btnLoadSettings_.setToolTipText("Load acquisitions settings from a JSON file.");
btnConvertSettings_.setToolTipText("Convert \"AcqSettings.txt\" from the " +
"Micro-Manager 1.4 plugin into Light Sheet Manager settings.");

add(lblSaveDirectory, "");
add(txtSaveDirectory_, "");
add(btnBrowse_, "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ private void createEventHandlers() {
.sliceCalibrationBuilder().offset(newOffset);
model_.studio().logs().logMessage("updated offset for view " + pathNum_ + "; new value is " +
newOffset + " (with channel offset of " + channelOffset + ")");
} else {
model_.studio().logs().showError("The beam must be enabled to update the offset.", btnUpdate_);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

import java.util.Objects;

// Note: changes based on camera trigger mode

/**
* A setup panel for diSPIM.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import mmcorej.Configuration;
import org.micromanager.Studio;
import org.micromanager.lightsheetmanager.LightSheetManager;
import org.micromanager.lightsheetmanager.api.TimingSettings;
import org.micromanager.lightsheetmanager.api.data.AcquisitionMode;
import org.micromanager.lightsheetmanager.api.data.CameraMode;
import org.micromanager.lightsheetmanager.api.data.GeometryType;
Expand Down Expand Up @@ -193,7 +192,7 @@ public boolean prepareControllerForAcquisition(
final boolean isInterleaved = (settings.acquisitionMode() == AcquisitionMode.STAGE_SCAN_INTERLEAVED);

// figure out the speed we should be going according to slice period, slice spacing, geometry, etc.
final double requestedMotorSpeed = computeScanSpeed(settings, scanner_.getSPIMNumScansPerSlice()); // in mm/sec
final double requestedMotorSpeed = computeScanSpeed(settings); // in mm/sec

final double maxSpeed = xyStage_.getMaxSpeedX();
if (requestedMotorSpeed > (maxSpeed * 0.8)) {
Expand Down Expand Up @@ -265,10 +264,8 @@ public boolean prepareControllerForAcquisition(
}

// Compute appropriate motor speed in mm/s for the given stage scanning settings
public double computeScanSpeed(ScapeAcquisitionSettings settings, final int numScansPerSlice) {
//double sliceDuration = settings.timingSettings().sliceDuration();
// TODO: getSliceDuration only used here, but maybe should be computed elsewhere, and get with method above?
double sliceDuration = getSliceDuration(settings.timing(), numScansPerSlice);
public double computeScanSpeed(final ScapeAcquisitionSettings settings) {
double sliceDuration = settings.timing().sliceDuration();
if (settings.acquisitionMode() == AcquisitionMode.STAGE_SCAN_INTERLEAVED) {
// pretend like our slice takes twice as long so that we move the correct speed
// this has the effect of halving the motor speed, but keeping the scan distance the same
Expand All @@ -291,25 +288,10 @@ private int computeScanChannelsPerPass(ScapeAcquisitionSettings settings) {
* @param motorSpeed
* @return
*/
public double computeScanAcceleration(final double motorSpeed, ScapeAcquisitionSettings settings) {
public double computeScanAcceleration(final double motorSpeed, final ScapeAcquisitionSettings settings) {
return (10 + 100 * (motorSpeed / xyStage_.getMaxSpeedX())) * settings.stageScan().accelerationFactor();
}

// TODO: scanNum was part of SliceSettings (now TimingSettings)
// scanNum was populated from numScansPerSlice_ which is the scanner SPIM_NUM_SCANSPERSLICE("SPIMNumScansPerSlice")
// labeled "Lines scans per slice:" in advanced timing tab
// * gets the correct value for the slice timing's sliceDuration field based on other values of slice timing

// slice duration is the max out of the scan time, laser time, and camera time
public double getSliceDuration(final TimingSettings s, final int scanNum) {
return Math.max(Math.max(
s.delayBeforeScan() + (s.scanDuration() * scanNum), // scan time
s.delayBeforeLaser() + s.laserTriggerDuration() // laser time
),
s.delayBeforeCamera() + s.cameraTriggerDuration() // camera time
);
}

/**
* Compute appropriate acceleration time in ms for the specified motor speed.
* Set to be 10ms + 0-100ms depending on relative speed to max, all scaled by factor specified on the settings panel
Expand Down Expand Up @@ -487,7 +469,8 @@ public boolean prepareControllerForAcquisitionSide(
//final double slope2 = settings.sliceCalibration(2).sliceSlope();
double sliceRate = settings.sliceCalibration().slope();//(view == 1) ? slope1 : slope2;
if (NumberUtils.doublesEqual(sliceRate, 0.0)) {
studio_.logs().showError("Calibration slope for view " + view + " cannot be zero. Re-do calibration on Setup tab.");
studio_.logs().showError("The \"Galvo constant\" is not set, it must not be 0.\n" +
"Please update the value on the setup tab.");
return false;
}
//final double offset1 = settings.sliceCalibration(1).sliceOffset() + channelOffset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -885,17 +885,6 @@ public double getSliceDuration(
);
}

private double getSliceDuration(DefaultTimingSettings.Builder tsb) {
DefaultTimingSettings s = tsb.build();
// slice duration is the max out of the scan time, laser time, and camera time
return Math.max(Math.max(
s.delayBeforeScan() + (s.scanDuration() * s.scansPerSlice()), // scan time
s.delayBeforeLaser() + s.laserTriggerDuration() // laser time
),
s.delayBeforeCamera() + s.cameraTriggerDuration() // camera time
);
}

private double computeTimePointDuration() {
final double volumeDuration = computeActualVolumeDuration(acqSettings_);
if (acqSettings_.isUsingMultiplePositions()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.micromanager.lightsheetmanager.api.data.CameraMode;
import org.micromanager.lightsheetmanager.api.data.ChannelMode;
import org.micromanager.lightsheetmanager.api.internal.DefaultTimingSettings;
import org.micromanager.lightsheetmanager.api.internal.ScapeAcquisitionSettings;
import org.micromanager.lightsheetmanager.gui.utils.DialogUtils;
import org.micromanager.lightsheetmanager.model.DataStorage;
import org.micromanager.lightsheetmanager.LightSheetManager;
Expand All @@ -36,6 +37,7 @@
import org.micromanager.lightsheetmanager.model.devices.vendor.ASIScanner;
import org.micromanager.lightsheetmanager.model.devices.vendor.ASIXYStage;
import org.micromanager.lightsheetmanager.model.utils.FileUtils;
import org.micromanager.lightsheetmanager.model.utils.GeometryUtils;
import org.micromanager.lightsheetmanager.model.utils.NumberUtils;

import javax.swing.JLabel;
Expand Down Expand Up @@ -754,11 +756,14 @@ boolean finish() {
studio_.logs().logError("Couldn't restore shutter to original state");
}

// Check if acquisition ended due to an exception and show error to user if it did
try {
currentAcquisition_.checkForExceptions();
} catch (Exception e) {
studio_.logs().logError(e);
// check if acquisition ended due to an exception and show error
// currentAcquisition_ can be null if an error occurred during setup
if (currentAcquisition_ != null) {
try {
currentAcquisition_.checkForExceptions();
} catch (Exception e) {
studio_.logs().logError(e);
}
}

// TODO: execute any end-acquisition runnables
Expand Down Expand Up @@ -992,8 +997,7 @@ private boolean doHardwareCalculations(PLogicScape plc) {
}

double extraChannelOffset = 0.0;
plc.prepareControllerForAcquisition(acqSettings_, extraChannelOffset);
return true;
return plc.prepareControllerForAcquisition(acqSettings_, extraChannelOffset);
}

private void doHardwareCalculationsNIDAQ() {
Expand Down Expand Up @@ -1125,7 +1129,7 @@ public DefaultTimingSettings.Builder getTimingFromExposure() {
// only true when user has specified period that is unattainable
if (globalDelay < 0) {
globalDelay = 0;
studio_.logs().showError("Increasing slice period to meet laser exposure constraint\n"
studio_.logs().logDebugMessage("Increasing slice period to meet laser exposure constraint\n"
+ "(time required for camera readout; readout time depends on ROI).");
}
delayBeforeCamera += globalDelay;
Expand Down Expand Up @@ -1310,7 +1314,7 @@ public DefaultTimingSettings.Builder getTimingFromPeriodAndLightExposure() {
// only true when user has specified period that is unattainable
if (globalDelay < 0) {
globalDelay = 0;
studio_.logs().showError("Increasing slice period to meet laser exposure constraint\n"
studio_.logs().logDebugMessage("Increasing slice period to meet laser exposure constraint\n"
+ "(time required for camera readout; readout time depends on ROI).");
}
delayBeforeCamera += globalDelay;
Expand Down Expand Up @@ -1432,8 +1436,8 @@ public double computeVolumeDuration() {
final double stackDuration = numCameraTriggers * acqSettings_.timing().sliceDuration();

if (acqSettings_.stageScan().enabled()) {
final double rampDuration = 1; //getStageRampDuration(acqSettings);
final double retraceTime = 1; //getStageRetraceDuration(acqSettings);
final double rampDuration = getStageRampDuration(acqSettings_);
final double retraceTime = getStageRetraceDuration(acqSettings_);
// TODO(Jon): double-check these calculations below, at least they are better than before ;-)
if (acqSettings_.acquisitionMode() == AcquisitionMode.STAGE_SCAN) {
if (channelMode == ChannelMode.SLICE_HW) {
Expand Down Expand Up @@ -1468,4 +1472,42 @@ public double computeVolumeDuration() {
}
}

private double getStageRampDuration(final ScapeAcquisitionSettings settings) {
final double rampDuration = settings.volume().delayBeforeView() + getScanStageAcceleration(settings);
model_.studio().logs().logDebugMessage("stage ramp duration is " + rampDuration + " milliseconds");
return rampDuration;
}

private double getScanStageAcceleration(final ScapeAcquisitionSettings settings) {
// TODO: remove this and find a better way
if (controller_ == null) {
controller_ = new PLogicScape(model_);
}
// extra 1 for rounding up that often happens in controller
return controller_.computeScanAcceleration(controller_.computeScanSpeed(settings), settings) + 1;
}

private double getStageRetraceDuration(final ScapeAcquisitionSettings settings) {
final ASIXYStage stage = model_.devices().device("SampleXY");
if (stage == null) {
studio_.logs().showError("could not find XY stage!");
return 0.0; // early exit => error
}
final double retraceRelativeSpeedPercent;
if (stage.hasProperty(ASIXYStage.Properties.SCAN_RETRACE_SPEED)) {
// this added in firmware v3.30; if not present then we set to firmware default hardcoded previously
retraceRelativeSpeedPercent = stage.getScanRetraceSpeed();
} else {
retraceRelativeSpeedPercent = 67.0;
}
final double retraceSpeed = retraceRelativeSpeedPercent / 100 * stage.getMaxSpeedX();
final double speedFactor = GeometryUtils.getStageGeometricSpeedFactor(
settings.stageScan().firstViewAngle(), settings.volume().firstView() == 1);
final double scanDistance = settings.volume().slicesPerView() * settings.volume().sliceStepSize() * speedFactor;
final double accelerationX = getScanStageAcceleration(settings);
final double retraceDuration = scanDistance / retraceSpeed + accelerationX * 2;
studio_.logs().logDebugMessage("stage retrace duration is " + retraceDuration + " milliseconds");
return retraceDuration;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ public double getScanSettlingTime() {
return getPropertyFloat(Properties.SCAN_SETTLING_TIME);
}

// TODO: should this be an int?
public double getScanRetraceSpeed() {
return getPropertyFloat(Properties.SCAN_RETRACE_SPEED);
}

public static class Properties {
public static final String AXIS_POLARITY_X = "AxisPolarityX";
public static final String AXIS_POLARITY_Y = "AxisPolarityY";
Expand All @@ -182,7 +187,7 @@ public static class Properties {
public static final String SCAN_PATTERN = "ScanPattern";
public static final String SCAN_STATE = "ScanState";
public static final String SCAN_SETTLING_TIME = "ScanSettlingTime(ms)";

public static final String SCAN_RETRACE_SPEED = "ScanRetraceSpeedPercent(%)";
public static final String SCAN_FAST_AXIS_START_POSITION = "ScanFastAxisStartPosition(mm)";
public static final String SCAN_FAST_AXIS_STOP_POSITION = "ScanFastAxisStopPosition(mm)";
public static final String SCAN_SLOW_AXIS_START_POSITION = "ScanSlowAxisStartPosition(mm)";
Expand Down
Loading