Skip to content

Commit ad1a163

Browse files
Further CLEM fixes (#308)
* Corrected CLEM context logic to ignore non-image series files and better discern between image series. --------- Co-authored-by: Daniel Hatton <[email protected]>
1 parent 6c04539 commit ad1a163

File tree

6 files changed

+60
-28
lines changed

6 files changed

+60
-28
lines changed

src/murfey/client/analyser.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ def _find_extension(self, file_path: Path):
113113
def _find_context(self, file_path: Path) -> bool:
114114
"""
115115
Using various conditionals, identifies what workflow the file is part of, and
116-
assigns the necessary context class to it for subsequent stages of processing
116+
assigns the correct context class to that batch of rsync files for subsequent
117+
stages of processing. Actions to take for individual files will be determined
118+
in the Context classes themselves.
117119
"""
118120

119121
# CLEM workflow checks
@@ -155,7 +157,7 @@ def _find_context(self, file_path: Path) -> bool:
155157
demo=self._environment.demo,
156158
)
157159
except Exception as e:
158-
logger.warning(f"exception encountered: {e}")
160+
logger.error(f"Exception encountered: {e}")
159161
cfg = {}
160162
else:
161163
cfg = {}
@@ -300,7 +302,7 @@ def _analyse(self):
300302
environment=self._environment,
301303
)
302304
except Exception as e:
303-
logger.warning(f"exception encountered {e}")
305+
logger.error(f"Exception encountered: {e}")
304306
if self._role == "detector":
305307
if not dc_metadata:
306308
try:
@@ -347,7 +349,7 @@ def _analyse(self):
347349

348350
# If a file with a CLEM context is identified, immediately post it
349351
elif isinstance(self._context, CLEMContext):
350-
logger.info(
352+
logger.debug(
351353
f"File {transferred_file.name!r} will be processed as part of CLEM workflow"
352354
)
353355
self.post_transfer(transferred_file)
@@ -366,7 +368,7 @@ def _analyse(self):
366368
environment=self._environment,
367369
)
368370
except Exception as e:
369-
logger.info(f"exception encountered {e}")
371+
logger.error(f"Exception encountered: {e}")
370372
if self._role == "detector":
371373
if not dc_metadata:
372374
try:
@@ -452,5 +454,5 @@ def stop(self):
452454
self.queue.put(None)
453455
self.thread.join()
454456
except Exception as e:
455-
logger.debug(f"Exception encountered while stopping analyser: {e}")
457+
logger.error(f"Exception encountered while stopping analyser: {e}")
456458
logger.debug("Analyser thread stop completed")

src/murfey/client/contexts/clem.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ def post_transfer(
116116

117117
# Process TIF/TIFF files
118118
if transferred_file.suffix in (".tif", ".tiff"):
119-
logger.debug("Detected a TIFF file")
120119

121120
# Files should be named "PositionX--ZXX--CXX.tif" by default
122121
# If Position is repeated, it will add an additional --00X to the end
@@ -126,6 +125,8 @@ def post_transfer(
126125
)
127126
return False
128127

128+
logger.debug(f"File {transferred_file.name!r} is part of a TIFF image series")
129+
129130
# Create a unique name for the series
130131
# For standard file name
131132
if len(transferred_file.stem.split("--")) == 3:
@@ -149,7 +150,7 @@ def post_transfer(
149150
)
150151
return False
151152
logger.debug(
152-
f"File {transferred_file.name!r} given the series identifier {series_name!r}"
153+
f"File {transferred_file.name!r} given the series name {series_name!r}"
153154
)
154155

155156
# Create key-value pairs containing empty list if not already present
@@ -171,21 +172,31 @@ def post_transfer(
171172

172173
# Process XLIF files
173174
if transferred_file.suffix == ".xlif":
174-
logger.debug("Detected an XLIF file")
175175

176176
# Skip processing of "_histo" histogram XLIF files
177177
if transferred_file.stem.endswith("_histo"):
178178
logger.debug(
179179
f"File {transferred_file.name!r} contains histogram metadata; skipping processing"
180180
)
181+
return True
182+
183+
# Skip processing of "IOManagerConfiguation.xlif" files (yes, the typo IS part of the file name)
184+
if "IOManagerConfiguation" in transferred_file.stem:
185+
logger.debug(
186+
f"File {transferred_file.name!r} is a Leica configuration file; skipping processing"
187+
)
188+
return True
181189

190+
logger.debug(f"File {transferred_file.name!r} contains metadata for an image series")
191+
192+
# Create series name for XLIF file
182193
# XLIF files don't have the "--ZXX--CXX" additions in the file name
183194
# But they have "/Metadata/" as the immediate parent
184195
series_name = "/".join(
185196
[*file_path.parent.parent.parts[-2:], file_path.stem]
186197
) # The previous 2 parent directories should be unique enough
187198
logger.debug(
188-
f"File {transferred_file.name!r} given the series identifier {series_name!r}"
199+
f"File {transferred_file.name!r} given the series name {series_name!r}"
189200
)
190201

191202
# Extract metadata to get the expected size of the series
@@ -221,17 +232,21 @@ def post_transfer(
221232

222233
# Post message if all files for the associated series have been collected
223234
# .get(series_name, 0) returns 0 if no associated key is found
224-
if len(self._tiff_series[series_name]) == 0:
235+
if not len(self._tiff_series.get(series_name, [])):
225236
logger.debug(f"TIFF series {series_name!r} not yet loaded")
226237
return True
227238
elif self._files_in_series.get(series_name, 0) == 0:
228239
logger.debug(
229240
f"Metadata for TIFF series {series_name!r} not yet processed"
230241
)
231242
return True
232-
elif len(self._tiff_series[series_name]) == self._files_in_series.get(
233-
series_name, 0
234-
):
243+
elif len(
244+
self._tiff_series.get(series_name, [])
245+
) == self._files_in_series.get(series_name, 0):
246+
logger.debug(
247+
f"Collected expected number of TIFF files for series {series_name!r}; posting job to server"
248+
)
249+
235250
# Construct URL for Murfey server to communicate with
236251
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/tiff_to_stack"
237252
if not url:
@@ -270,6 +285,8 @@ def post_transfer(
270285
logger.warning(f"No source found for file {transferred_file}")
271286
return True
272287

288+
logger.debug(f"File {transferred_file.name!r} is a valid LIF file; posting job to server")
289+
273290
# Construct the URL for the Murfey server to communicate with
274291
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/lif_to_tiff"
275292
# Type checking to satisfy MyPy

src/murfey/client/contexts/tomo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ def gather_metadata(
10001000
metadata_file.parent / data_file
10011001
)
10021002
except Exception as e:
1003-
logger.warning(f"Exception encountered in metadata gathering: {str(e)}")
1003+
logger.error(f"Exception encountered in metadata gathering: {str(e)}")
10041004
return OrderedDict({})
10051005

10061006
return mdoc_metadata

src/murfey/util/clem/tiff.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,18 @@ def process_tiff_files(
9999
f
100100
for f in tiff_list
101101
if (f"C{str(c).zfill(2)}" in f.stem or f"C{str(c).zfill(3)}" in f.stem)
102-
and (img_name in f.stem)
102+
and (img_name == f.stem.split("--")[0])
103103
]
104104
tiff_sublist.sort(
105105
key=lambda f: (int(f.stem.split("--")[1].replace("Z", "")),)
106-
) # Increasing order of Z
106+
) # Sort by Z as an int, not str
107+
108+
# Return error message if the list of TIFFs is empty for some reason
109+
if not tiff_sublist:
110+
logger.error(
111+
f"Error processing {color} channel for {img_name}; no TIFF files found"
112+
)
113+
return False
107114

108115
# Load image stack
109116
logger.info("Loading image stack")
@@ -216,7 +223,7 @@ def convert_tiff_to_stack(
216223
part.lower() == root_folder.lower() and counter < 1
217224
): # Remove case-sensitivity
218225
path_parts[p] = new_root_folder
219-
counter += 0 # Do for first instance only
226+
counter += 1 # Do for first instance only
220227
# Remove last level in path if same as previous one (redundancy)
221228
if p == len(path_parts) - 1:
222229
if part.replace(" ", "_") == path_parts[p - 1].replace(" ", "_"):

src/murfey/workflows/lif_to_tiff.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212

1313

1414
def zocalo_cluster_request(
15-
file: Path, root_folder: str, messenger: TransportManager | None = None
15+
file: Path,
16+
root_folder: str,
17+
messenger: TransportManager | None = None,
1618
):
1719
if messenger:
18-
# Set working directory to be the parent of the designated root folder
20+
# Construct path to session directory
1921
path_parts = list(file.parts)
2022
new_path = []
2123
for p in range(len(path_parts)):
@@ -27,16 +29,16 @@ def zocalo_cluster_request(
2729
if part.lower() == root_folder.lower():
2830
break
2931
new_path.append(part)
30-
working_dir = Path("/".join(new_path))
32+
session_dir = Path("/".join(new_path))
3133

3234
messenger.send(
3335
"processing_recipe",
3436
{
3537
"recipes": ["lif-to-tiff"],
3638
"parameters": {
37-
# Where the cluster generates and saves log files
38-
"working_dir": str(working_dir),
39-
"lif_path": str(file),
39+
# Represent file paths canonically
40+
"session_dir": repr(str(session_dir)),
41+
"lif_path": repr(str(file)),
4042
"root_dir": root_folder,
4143
},
4244
},

src/murfey/workflows/tiff_to_stack.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ def zocalo_cluster_request(
1919
messenger: TransportManager | None = None,
2020
):
2121
if messenger:
22-
23-
# Set working directory to be the parent of the designated root folder
22+
# Construct path to session directory
2423
path_parts = list(file.parts)
2524
new_path = []
2625
for p in range(len(path_parts)):
@@ -32,14 +31,19 @@ def zocalo_cluster_request(
3231
if part.lower() == root_folder.lower():
3332
break
3433
new_path.append(part)
35-
working_dir = Path("/".join(new_path))
34+
session_dir = Path("/".join(new_path))
35+
36+
# If no metadata file provided, generate path to one
37+
if metadata is None:
38+
series_name = file.stem.split("--")[0]
39+
metadata = file.parent / "Metadata" / (series_name + ".xlif")
3640

3741
messenger.send(
3842
"processing_recipe",
3943
{
4044
"recipes": ["tiff-to-stack"],
4145
"parameters": {
42-
"working_dir": str(working_dir),
46+
"session_dir": str(session_dir),
4347
"tiff_path": str(file),
4448
"root_dir": root_folder,
4549
"metadata": str(metadata),

0 commit comments

Comments
 (0)