Skip to content

Commit

Permalink
Merge branch 'main' into lightSheetFixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Nico Stuurman committed Aug 9, 2023
2 parents daba733 + b826b66 commit 560b018
Show file tree
Hide file tree
Showing 13 changed files with 331 additions and 124 deletions.
6 changes: 3 additions & 3 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.micro-manager.pycro-manager</groupId>
<artifactId>PycroManagerJava</artifactId>
<version>0.41.2</version>
<version>0.41.6</version>
<packaging>jar</packaging>
<name>Pycro-Manager Java</name>
<description>The Java components of Pycro-Manager</description>
Expand Down Expand Up @@ -54,7 +54,7 @@
<dependency>
<groupId>org.micro-manager.acqengj</groupId>
<artifactId>AcqEngJ</artifactId>
<version>0.29.1</version>
<version>0.30.0</version>
</dependency>
<dependency>
<groupId>org.micro-manager.ndviewer</groupId>
Expand All @@ -64,7 +64,7 @@
<dependency>
<groupId>org.micro-manager.ndtiffstorage</groupId>
<artifactId>NDTiffStorage</artifactId>
<version>2.13.1</version>
<version>2.14.0</version>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,15 @@ public void finish() {
storage_.setDisplaySettings(displaySettings);
storage_.finishedWriting();
}
display_.setWindowTitle(getUniqueAcqName() + " (Finished)");
displayCommunicationExecutor_.shutdown();

try {
storage_.checkForWritingException();
display_.setWindowTitle(name_ + " (Finished)");
} catch (Exception e) {
display_.setWindowTitle(name_ + " (Finished with saving error)");
} finally {
displayCommunicationExecutor_.shutdown();
}
displayCommunicationExecutor_ = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public RemoteEventSource() {
System.out.println("pull socket started");
while (true) {
List<AcquisitionEvent> eList = pullSocket_.next();
System.out.println("got something from pull socket");
boolean finished = eList.get(eList.size() - 1).isAcquisitionFinishedEvent();
Future result = acq_.submitEventIterator(eList.iterator());
result.get(); //propogate any exceptions
Expand All @@ -65,14 +64,12 @@ public RemoteEventSource() {
}
} catch (InterruptedException e) {
// it was aborted
System.out.println("pull socket interrupted");
} catch (Exception e) {
e.printStackTrace();
if (!executor_.isShutdown()) {
acq_.abort(e);
}
} finally {
System.out.println("pull socket closed");
pullSocket_.close();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,14 @@ public void finish() {
}

if (showViewer_) {
viewer_.setWindowTitle(name_ + " (Finished)");
displayCommunicationExecutor_.shutdown();
try {
storage_.checkForWritingException();
viewer_.setWindowTitle(name_ + " (Finished)");
} catch (Exception e) {
viewer_.setWindowTitle(name_ + " (Finished with saving error)");
} finally {
displayCommunicationExecutor_.shutdown();
}
}
finished_ = true;
}
Expand Down
2 changes: 1 addition & 1 deletion pycromanager/_version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version_info = (0, 27, 5)
version_info = (0, 28, 1)
__version__ = ".".join(map(str, version_info))
52 changes: 34 additions & 18 deletions pycromanager/acq_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import copy
import types
import numpy as np
from typing import Union, List
from typing import Union, List, Iterable

SUBPROCESSES = []

Expand Down Expand Up @@ -107,8 +107,9 @@ def multi_d_acquisition_events(
channel_group: str=None,
channels: list=None,
channel_exposures_ms: list=None,
xy_positions=None,
xyz_positions=None,
xy_positions: Iterable=None,
xyz_positions: Iterable=None,
position_labels: List[str]=None,
order: str="tpcz",
keep_shutter_open_between_channels: bool=False,
keep_shutter_open_between_z_steps: bool=False,
Expand Down Expand Up @@ -142,17 +143,13 @@ def multi_d_acquisition_events(
channel_exposures_ms : list of floats or ints
list of camera exposure times corresponding to each channel. The length of this list
should be the same as the the length of the list of channels (Default value = None)
xy_positions : arraylike
N by 2 array where N is the number of XY stage positions, and the 2 are the X and Y
coordinates (Default value = None)
xyz_positions : arraylike
N by 3 array where N is the number of XY stage positions, and the 3 are the X, Y and Z coordinates.
xy_positions : iterable
An array of shape (N, 2) containing N (X, Y) stage coordinates. (Default value = None)
xyz_positions : iterable
An array of shape (N, 3) containing N (X, Y, Z) stage coordinates. (Default value = None).
If passed then z_start, z_end, and z_step will be relative to the z_position in xyz_positions. (Default value = None)
z_positions : arraylike
The z_positions for each xy point. Either 1D (shape: (N,) ) to specify the center z position for each xy point,
or 2D (shape: (N, n_z) ) to fully specify the xyz points.
If z_positions is 1D and z_start, z_end and z_step are not None then relative
z_positions will be created using np.arange(z_position + z_start, z_position + z_end, z_step)
position_labels : iterable
An array of length N containing position labels for each of the XY stage positions. (Default value = None)
order : str
string that specifies the order of different dimensions. Must have some ordering of the letters
c, t, p, and z. For example, 'tcz' would run a timelapse where z stacks would be acquired at each channel in
Expand All @@ -174,14 +171,29 @@ def multi_d_acquisition_events(
order = order.lower()
if "p" in order and "z" in order and order.index("p") > order.index("z"):
raise ValueError(
"This function requres that the xy position come earlier in the order than z"
"This function requires that the xy position come earlier in the order than z"
)
if isinstance(time_interval_s, list):
if len(time_interval_s) != num_time_points:
raise ValueError(
"Length of time interval list should be equal to num_time_points"
)
has_zsteps = z_start is not None and z_step is not None and z_end is not None
if position_labels is not None:
if xy_positions is not None and len(xy_positions) != len(position_labels):
raise ValueError("xy_positions and position_labels must be of equal length")
if xyz_positions is not None and len(xyz_positions) != len(position_labels):
raise ValueError("xyz_positions and position_labels must be of equal length")

# If any of z_start, z_step, z_end are provided, then they should all be provided
# Here we can't use `all` as some of the values of z_start, z_step, z_end
# may be zero and all((0,)) = False
has_zsteps = False
if any([z_start, z_step, z_end]):
if not None in [z_start, z_step, z_end]:
has_zsteps = True
else:
raise ValueError('All of z_start, z_step, and z_end must be provided')

z_positions = None
if xy_positions is not None:
xy_positions = np.asarray(xy_positions)
Expand All @@ -205,6 +217,9 @@ def multi_d_acquisition_events(
pos.append(z + z_rel)
z_positions = np.asarray(pos)

if position_labels is None and xy_positions is not None:
position_labels = list(range(len(xy_positions)))

def generate_events(event, order):
if len(order) == 0:
yield event
Expand All @@ -224,7 +239,8 @@ def generate_events(event, order):
yield generate_events(new_event, order[1:])
elif order[0] == "z" and z_positions is not None:
if "axes" in event and "position" in event["axes"]:
zs = z_positions[event["axes"]["position"]]
pos_idx = position_labels.index(event["axes"]["position"])
zs = z_positions[pos_idx]
else:
zs = z_positions

Expand All @@ -236,9 +252,9 @@ def generate_events(event, order):
new_event["keep_shutter_open"] = True
yield generate_events(new_event, order[1:])
elif order[0] == "p" and xy_positions is not None:
for p_index, xy in enumerate(xy_positions):
for p_label, xy in zip(position_labels, xy_positions):
new_event = copy.deepcopy(event)
new_event["axes"]["position"] = p_index
new_event["axes"]["position"] = p_label
new_event["x"] = xy[0]
new_event["y"] = xy[1]
yield generate_events(new_event, order[1:])
Expand Down
1 change: 0 additions & 1 deletion pycromanager/acquisitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ def __init__(self, message):
# prevent problems with pickling when running them in differnet process

def _run_acq_event_source(acquisition, event_port, event_queue, debug=False):
print('running event source')
event_socket = PushSocket(event_port, debug=debug)
try:
while True:
Expand Down
122 changes: 61 additions & 61 deletions pycromanager/test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,72 +78,72 @@ def download_mm_nightly():

@pytest.fixture(scope="session")
def install_mm(download_mm_nightly):
# make sure MM is not already running (used for local testing)
mm_installed = False
mm_running = False
mm_install_dir = os.path.join(os.path.expanduser('~'), "Micro-Manager-nightly")

# check if there is currently a Micro-manager instance running (used for local testing)
if is_port_in_use(4827):
mm_running = True
print('Using Micro-manager running on port 4827 for testing')
yield
else:
mm_app_found = False
mm_install_dir = os.path.join(os.path.expanduser('~'), "Micro-Manager-nightly")

# check if there is currently a Micro-manager instance running (used for local testing)
if is_port_in_use(4827):
yield
if os.path.isdir(mm_install_dir):
# Check if Micro-manager installation is present in mm_install_dir.
# If so, the latest Micro-manager nightly build will not be installed.
print(f'Existing Micro-manager installation found at {mm_install_dir}')
else:
if os.path.isdir(mm_install_dir):
# Check if Micro-manager installation is present in mm_install_dir.
# If so, the latest Micro-manager nightly build will not be installed.
mm_app_found = True
print(f'Existing Micro-manager installation found at {mm_install_dir}')
# Install Micro-manager nightly build. Currently only supported on Windows platforms
# To run tests on other platform, please place a working Micro-manager installation in "~/Micro-Manager-nightly"
mm_installed = True

if sys.platform.startswith('win'):
mm_installer = download_mm_nightly
mm_install_log_path = os.path.join(os.path.dirname(mm_installer), "mm_install.log")
else:
raise RuntimeError(
'''Micro-manager nightly build installation is currently only supported on Windows platforms.
To run tests on other platform, please place a working Micro-manager installation in
"~/Micro-Manager-nightly"'''
)

os.mkdir(mm_install_dir)

print(f'Installing Micro-manager nightly build at: {mm_install_dir}')
cmd = f"{mm_installer} /SP /VERYSILENT /SUPRESSMSGBOXES /CURRENTUSER /DIR={mm_install_dir} /LOG={mm_install_log_path}"
subprocess.run(cmd, shell=True)

# find pycro-manager/java path
if os.path.isdir('java'):
java_path = os.path.abspath('java')
# in case cwd is '/pycromanager/test'
elif os.path.isdir('../../java'):
java_path = os.path.abspath('../../java')
else:
# Install Micro-manager nightly build. Currently only supported on Windows platforms
# To run tests on other platform, please place a working Micro-manager installation in "~/Micro-Manager-nightly"
if sys.platform.startswith('win'):
mm_installer = download_mm_nightly
mm_install_log_path = os.path.join(os.path.dirname(mm_installer), "mm_install.log")
else:
raise RuntimeError(
'''Micro-manager nightly build installation is currently only supported on Windows platforms.
To run tests on other platform, please place a working Micro-manager installation in
"~/Micro-Manager-nightly"'''
)

os.mkdir(mm_install_dir)

print(f'Installing Micro-manager nightly build at: {mm_install_dir}')
cmd = f"{mm_installer} /SP /VERYSILENT /SUPRESSMSGBOXES /CURRENTUSER /DIR={mm_install_dir} /LOG={mm_install_log_path}"
subprocess.run(cmd, shell=True)

# find pycro-manager/java path
if os.path.isdir('java'):
java_path = os.path.abspath('java')
# in case cwd is '/pycromanager/test'
elif os.path.isdir('../../java'):
java_path = os.path.abspath('../../java')
else:
raise RuntimeError('Could not find pycro-manager/java path')

# Update pycromanager jar files packaged with the Micro-manager nightly build
# Files are updated only if they are larger version
if os.path.isdir(os.path.join(java_path, 'target')):
replace_jars(os.path.join(java_path, 'target'), os.path.join(mm_install_dir, 'plugins', 'Micro-Manager'),
['PycroManagerJava'])
# Copy dependency jar files if present in target/dependency
if os.path.isdir(os.path.join(java_path, 'target/dependency')):
replace_jars(os.path.join(java_path, 'target/dependency'), os.path.join(mm_install_dir, 'plugins', 'Micro-Manager'),
['AcqEngJ', 'NDTiffStorage', 'NDViewer'])
# Copy dependency jar files if present in ../../REPO_NAME/target
for repo_name in ['AcqEngJ', 'NDTiffStorage', 'NDViewer']:
if os.path.isdir(os.path.join(java_path, f'../../{repo_name}/target')):
replace_jars(os.path.join(java_path, f'../../{repo_name}/target'),
os.path.join(mm_install_dir, 'plugins', 'Micro-Manager'), [repo_name])

yield mm_install_dir

# cleanup only if Micro-manager was installed in this session
if not mm_app_found:
os.remove(mm_install_log_path)
# fails, because MM is still running, I think
# shutil.rmtree(mm_install_dir)
raise RuntimeError('Could not find pycro-manager/java path')

# Update pycromanager jar files packaged with the Micro-manager nightly build
# Files are updated only if they are larger version
if os.path.isdir(os.path.join(java_path, 'target')):
replace_jars(os.path.join(java_path, 'target'), os.path.join(mm_install_dir, 'plugins', 'Micro-Manager'),
['PycroManagerJava'])
# Copy dependency jar files if present in target/dependency
if os.path.isdir(os.path.join(java_path, 'target/dependency')):
replace_jars(os.path.join(java_path, 'target/dependency'), os.path.join(mm_install_dir, 'plugins', 'Micro-Manager'),
['AcqEngJ', 'NDTiffStorage', 'NDViewer'])
# Copy dependency jar files if present in ../../REPO_NAME/target
for repo_name in ['AcqEngJ', 'NDTiffStorage', 'NDViewer']:
if os.path.isdir(os.path.join(java_path, f'../../{repo_name}/target')):
replace_jars(os.path.join(java_path, f'../../{repo_name}/target'),
os.path.join(mm_install_dir, 'plugins', 'Micro-Manager'), [repo_name])

yield mm_install_dir

# cleanup only if Micro-manager was installed in this session
if not mm_running and mm_installed:
os.remove(mm_install_log_path)
# fails, because MM is still running, I think
# shutil.rmtree(mm_install_dir)


@pytest.fixture(scope="session")
Expand Down
Loading

0 comments on commit 560b018

Please sign in to comment.