1111import logging
1212import re
1313import traceback
14+ from collections .abc import Collection
1415from importlib .metadata import entry_points
1516from pathlib import Path
1617from typing import Literal , Optional
@@ -66,6 +67,27 @@ def _is_clem_atlas(result: CLEMPreprocessingResult):
6667 )
6768
6869
70+ COLOR_FLAGS_MURFEY = {
71+ "gray" : "has_grey" ,
72+ "red" : "has_red" ,
73+ "green" : "has_green" ,
74+ "blue" : "has_blue" ,
75+ "cyan" : "has_cyan" ,
76+ "magenta" : "has_magenta" ,
77+ "yellow" : "has_yellow" ,
78+ }
79+
80+
81+ def _get_color_flags (
82+ colors : Collection [str ] | None = None ,
83+ ):
84+ colors = colors or []
85+ color_flags = dict .fromkeys (COLOR_FLAGS_MURFEY .values (), False )
86+ for color in colors :
87+ color_flags [COLOR_FLAGS_MURFEY [color ]] = True
88+ return color_flags
89+
90+
6991def _register_clem_image_series (
7092 session_id : int ,
7193 result : CLEMPreprocessingResult ,
@@ -159,6 +181,11 @@ def _register_clem_image_series(
159181 clem_img_series .image_search_string = str (output_file .parent / "*tiff" )
160182 clem_img_series .data_type = "atlas" if _is_clem_atlas (result ) else "grid_square"
161183 clem_img_series .number_of_members = result .number_of_members
184+ for col_name , value in _get_color_flags (result .output_files .keys ()).items ():
185+ setattr (clem_img_series , col_name , value )
186+ clem_img_series .collection_mode = _determine_collection_mode (
187+ result .output_files .keys ()
188+ )
162189 clem_img_series .image_pixels_x = result .pixels_x
163190 clem_img_series .image_pixels_y = result .pixels_y
164191 clem_img_series .image_pixel_size = result .pixel_size
@@ -186,6 +213,31 @@ def _register_clem_image_series(
186213 logger .info (f"CLEM preprocessing results registered for { result .series_name !r} " )
187214
188215
216+ def _determine_collection_mode (
217+ colors : Collection [str ] | None = None ,
218+ ):
219+ if not colors :
220+ logger .warning ("No colours were present in returned result" )
221+ return None
222+ if "gray" in colors :
223+ if len (colors ) == 1 :
224+ return "Bright Field"
225+ else :
226+ return "Bright Field and Fluorescent"
227+ else :
228+ return "Fluorescent"
229+
230+
231+ def _snake_to_camel_case (string : str ):
232+ parts = string .split ("_" )
233+ return parts [0 ] + "" .join (part .capitalize () for part in parts [1 :])
234+
235+
236+ COLOR_FLAGS_MURFEY_TO_ISPYB = {
237+ value : _snake_to_camel_case (value ) for value in COLOR_FLAGS_MURFEY .values ()
238+ }
239+
240+
189241def _register_dcg_and_atlas (
190242 session_id : int ,
191243 instrument_name : str ,
@@ -225,9 +277,17 @@ def _register_dcg_and_atlas(
225277 else :
226278 atlas_name = str (output_file .parent / "*.tiff" )
227279 atlas_pixel_size = result .pixel_size
280+ # Translate colour flags into ISPyB convention
281+ color_flags = {
282+ COLOR_FLAGS_MURFEY_TO_ISPYB [key ]: int (value )
283+ for key , value in _get_color_flags (result .output_files .keys ()).items ()
284+ }
285+ collection_mode = _determine_collection_mode (result .output_files .keys ())
228286 else :
229287 atlas_name = ""
230288 atlas_pixel_size = 0.0
289+ color_flags = None
290+ collection_mode = None
231291
232292 if dcg_search := murfey_db .exec (
233293 select (MurfeyDB .DataCollectionGroup )
@@ -245,6 +305,8 @@ def _register_dcg_and_atlas(
245305 "atlas" : atlas_name ,
246306 "atlas_pixel_size" : atlas_pixel_size ,
247307 "sample" : dcg_entry .sample ,
308+ "color_flags" : color_flags ,
309+ "collection_mode" : collection_mode ,
248310 }
249311 if entry_point_result := entry_points (
250312 group = "murfey.workflows" , name = "atlas_update"
@@ -269,6 +331,8 @@ def _register_dcg_and_atlas(
269331 "atlas" : atlas_name ,
270332 "atlas_pixel_size" : atlas_pixel_size ,
271333 "sample" : None ,
334+ "color_flags" : color_flags ,
335+ "collection_mode" : collection_mode ,
272336 }
273337 if entry_point_result := entry_points (
274338 group = "murfey.workflows" , name = "data_collection_group"
@@ -342,6 +406,8 @@ def _register_grid_square(
342406 and atlas_entry .x1 is not None
343407 and atlas_entry .y0 is not None
344408 and atlas_entry .y1 is not None
409+ and atlas_entry .thumbnail_pixels_x is not None
410+ and atlas_entry .thumbnail_pixels_y is not None
345411 ):
346412 atlas_width_real = atlas_entry .x1 - atlas_entry .x0
347413 atlas_height_real = atlas_entry .y1 - atlas_entry .y0
@@ -356,34 +422,31 @@ def _register_grid_square(
356422 and clem_img_series .x1 is not None
357423 and clem_img_series .y0 is not None
358424 and clem_img_series .y1 is not None
359- and clem_img_series .thumbnail_pixels_x is not None
360- and clem_img_series .thumbnail_pixels_y is not None
361- and clem_img_series .thumbnail_pixel_size is not None
362425 ):
363426 # Find pixel corresponding to image midpoint on atlas
364427 x_mid_real = (
365428 0.5 * (clem_img_series .x0 + clem_img_series .x1 ) - atlas_entry .x0
366429 )
367430 x_mid_px = int (
368- x_mid_real / atlas_width_real * clem_img_series .thumbnail_pixels_x
431+ x_mid_real / atlas_width_real * atlas_entry .thumbnail_pixels_x
369432 )
370433 y_mid_real = (
371434 0.5 * (clem_img_series .y0 + clem_img_series .y1 ) - atlas_entry .y0
372435 )
373436 y_mid_px = int (
374- y_mid_real / atlas_height_real * clem_img_series .thumbnail_pixels_y
437+ y_mid_real / atlas_height_real * atlas_entry .thumbnail_pixels_y
375438 )
376439
377- # Find the size of the image, in pixels, when overlaid the atlas
440+ # Find the size of the image, in pixels, when overlaid on the atlas
378441 width_scaled = int (
379442 (clem_img_series .x1 - clem_img_series .x0 )
380443 / atlas_width_real
381- * clem_img_series .thumbnail_pixels_x
444+ * atlas_entry .thumbnail_pixels_x
382445 )
383446 height_scaled = int (
384447 (clem_img_series .y1 - clem_img_series .y0 )
385448 / atlas_height_real
386- * clem_img_series .thumbnail_pixels_y
449+ * atlas_entry .thumbnail_pixels_y
387450 )
388451 else :
389452 logger .warning (
@@ -410,7 +473,13 @@ def _register_grid_square(
410473 y_stage_position = 0.5 * (clem_img_series .y0 + clem_img_series .y1 ),
411474 pixel_size = clem_img_series .image_pixel_size ,
412475 image = clem_img_series .thumbnail_search_string ,
476+ collection_mode = clem_img_series .collection_mode ,
413477 )
478+ # Construct colour flags for ISPyB
479+ color_flags = {
480+ ispyb_color_flags : int (getattr (clem_img_series , murfey_color_flags , 0 ))
481+ for murfey_color_flags , ispyb_color_flags in COLOR_FLAGS_MURFEY_TO_ISPYB .items ()
482+ }
414483 # Register or update the grid square entry as required
415484 if grid_square_result := murfey_db .exec (
416485 select (MurfeyDB .GridSquare )
@@ -435,6 +504,7 @@ def _register_grid_square(
435504 _transport_object .do_update_grid_square (
436505 grid_square_id = grid_square_entry .id ,
437506 grid_square_parameters = grid_square_params ,
507+ color_flags = color_flags ,
438508 )
439509 else :
440510 # Look up data collection group for current series
@@ -448,6 +518,7 @@ def _register_grid_square(
448518 atlas_id = dcg_entry .atlas_id ,
449519 grid_square_id = clem_img_series .id ,
450520 grid_square_parameters = grid_square_params ,
521+ color_flags = color_flags ,
451522 )
452523 # Register to Murfey
453524 grid_square_entry = MurfeyDB .GridSquare (
0 commit comments