Skip to content

Commit

Permalink
Merge pull request #774 from henrypinkard/main
Browse files Browse the repository at this point in the history
Working Python acquisiton engine/backend + tests + RAM Storage for Python and Java
  • Loading branch information
henrypinkard authored Jun 15, 2024
2 parents 7bbf5b4 + 4714cb7 commit 6a5f9fc
Show file tree
Hide file tree
Showing 30 changed files with 665 additions and 714 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/Java_dependency_update.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# When NDTiff, AcqEngJ, or NDViewer update, a automatic push
# When NDStorage, AcqEngJ, or NDViewer update, a automatic push
# to the dependency-update branch of pycro-manager will be generated
# that updates the version in their POM.xml files
# This script should then:
Expand Down
4 changes: 2 additions & 2 deletions build_automation/update_PycroManagerJava.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
def read_versions(root):
versions = {}
versions['PycroManagerJava'] = Version(root.find("version").text)
# iterate through the dependencies and get NDTiff, NDViewer, and AcqEngJ
# iterate through the dependencies and get NDStorage, NDViewer, and AcqEngJ
dependencies = root.findall(".//dependency")
for dependency in dependencies:
artifactId = dependency.find("artifactId").text
version = dependency.find("version").text
if artifactId in ["NDTiffStorage", "NDViewer", "AcqEngJ"]:
if artifactId in ["NDStorage", "NDViewer", "AcqEngJ"]:
versions[artifactId] = Version(version)
return versions

Expand Down
4 changes: 2 additions & 2 deletions build_automation/update_dependency.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
Script for updating NDTiff/AcqEngJ/NDViewer to latest version
It runs on the *-update branch and is called by an action in NDTiff/AcqEngJ/NDViewer repo
Script for updating NDStorage/AcqEngJ/NDViewer to latest version
It runs on the *-update branch and is called by an action in NDStorage/AcqEngJ/NDViewer repo
"""

import xml.etree.ElementTree as ET
Expand Down
2 changes: 1 addition & 1 deletion build_automation/update_mm_ivy.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
def read_versions(root):
versions = {}
versions['PycroManagerJava'] = Version(root.find("version").text)
# iterate through the dependencies and get NDTiff, NDViewer, and AcqEngJ
# iterate through the dependencies and get NDStorage, NDViewer, and AcqEngJ
dependencies = root.findall(".//dependency")
for dependency in dependencies:
artifactId = dependency.find("artifactId").text
Expand Down
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.46.8</version>
<version>0.46.9</version>
<packaging>jar</packaging>
<name>Pycro-Manager Java</name>
<description>The Java components of Pycro-Manager</description>
Expand Down Expand Up @@ -65,7 +65,7 @@
<dependency>
<groupId>org.micro-manager.ndtiffstorage</groupId>
<artifactId>NDTiffStorage</artifactId>
<version>2.17.0</version>
<version>2.18.0</version>
</dependency>
</dependencies>

Expand Down Expand Up @@ -154,4 +154,4 @@
</repository>
</distributionManagement>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public void start() {
ex.printStackTrace();
throw new RuntimeException(ex);
}

pushSocket_.push(e);
if (e.isAcquisitionEventsFinishedNotification()) {
eventsFinished = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,11 @@ public String getDiskLocation() {

public void close() {
try {
storage_.closeAndWait();
if (!(storage_ instanceof NDRAMStorage)) {
// If its RAM storage, the python side may want to hang onto it
storage_.closeAndWait();
storage_ = null;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Expand Down
2 changes: 1 addition & 1 deletion pycromanager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
from pycromanager.core import Core
from pyjavaz import JavaObject, JavaClass, PullSocket, PushSocket
from pycromanager.acquisition.acq_eng_py.main.acq_notification import AcqNotification
from ndtiff import Dataset
from ndstorage import Dataset
from ._version import __version__, version_info
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, 33, 0)
version_info = (0, 34, 0)
__version__ = ".".join(map(str, version_info))
138 changes: 0 additions & 138 deletions pycromanager/acquisition/RAMStorage.py

This file was deleted.

75 changes: 75 additions & 0 deletions pycromanager/acquisition/RAMStorage_java.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from pyjavaz.wrappers import JavaObject
from ndstorage.ndstorage_base import NDStorageBase

class NDRAMDatasetJava(NDStorageBase):
"""
A python class that wraps a Java-backend RAM data storage.
This class maintains an index of which images have been saved, but otherwise routes all calls to the Java
implementation of the RAM data storage.
"""

def __init__(self, java_RAM_data_storage):
super().__init__()
self._java_RAM_data_storage = java_RAM_data_storage
self._index_keys = set()

def __del__(self):
self.close()

def close(self):
self._java_RAM_data_storage = None # allow the Java side to be garbage collected

def add_available_axes(self, image_coordinates):
"""
The Java RAM storage has received a new image with the given axes. Add these axes to the index.
"""
self._index_keys.add(frozenset(image_coordinates.items()))
# update information about the available images
self._update_axes(image_coordinates)
self._new_image_event.set()
if self.dtype is None:
image = self.read_image(**image_coordinates)
self._infer_image_properties(image)

def get_image_coordinates_list(self):
"""
Return a list of every combination of axes that has an image in this dataset
"""
frozen_set_list = list(self._index_keys)
# convert to dict
return [{axis_name: position for axis_name, position in key} for key in frozen_set_list]

def is_finished(self) -> bool:
return self._java_RAM_data_storage.is_finished()

def has_image(self, channel=None, z=None, time=None, position=None, row=None, column=None, **kwargs):
axes = self._consolidate_axes(channel, z, position, time, row, column, **kwargs)
key = frozenset(axes.items())
return key in self._index_keys

def read_image(self, channel=None, z=None, time=None, position=None, row=None, column=None, **kwargs):
axes = self._consolidate_axes(channel, z, position, time, row, column, **kwargs)
key = frozenset(axes.items())
if key not in self._index_keys:
return None
java_hashmap = JavaObject('java.util.HashMap')
for k, v in axes.items():
java_hashmap.put(k, v)
tagged_image = self._java_RAM_data_storage.get_image(java_hashmap)
pixels = tagged_image.pix
metadata = tagged_image.tags
return pixels.reshape(metadata['Height'], metadata['Width'])

def read_metadata(self, channel=None, z=None, time=None, position=None, row=None, column=None, **kwargs):
axes = self._consolidate_axes(channel, z, position, time, row, column, **kwargs)
key = frozenset(axes.items())
if key not in self._index_keys:
return None
java_hashmap = JavaObject('java.util.HashMap')
for k, v in axes.items():
java_hashmap.put(k, v)
tagged_image = self._java_RAM_data_storage.get_image(java_hashmap)
return tagged_image.tags


2 changes: 1 addition & 1 deletion pycromanager/acquisition/acq_constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __new__(cls,

if _PYMMCORES:
# Python backend detected, so create a python backend acquisition
specific_arg_names = [k for k in signature(JavaBackendAcquisition.__init__).parameters.keys() if k != 'self']
specific_arg_names = [k for k in signature(PythonBackendAcquisition.__init__).parameters.keys() if k != 'self']
for name in specific_arg_names:
if name in kwargs:
named_args[name] = kwargs[name]
Expand Down
Loading

0 comments on commit 6a5f9fc

Please sign in to comment.