Skip to content

Commit fc8355f

Browse files
authored
Simplify FIB milling GIF creation workflow (#904)
* Let 'feedback_callback' handle database closure and any raised exceptions
1 parent 7bf5682 commit fc8355f

1 file changed

Lines changed: 53 additions & 65 deletions

File tree

‎src/murfey/workflows/fib/make_milling_gif.py‎

Lines changed: 53 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -15,72 +15,60 @@
1515

1616

1717
def run(message: dict[str, Any], murfey_db: SQLModelSession):
18-
# Outer try-finally block to close Murfey DB with
19-
try:
20-
try:
21-
# Parse and unpack incoming message
22-
session_id = int(message["session_id"])
23-
gif_params = FIBGIFParameters(**message["gif_params"])
24-
except Exception:
25-
logger.error("Error parsing contents of message", exc_info=True)
26-
return {"success": False, "requeue": False}
18+
# Parse and unpack incoming message
19+
session_id = int(message["session_id"])
20+
gif_params = FIBGIFParameters(**message["gif_params"])
2721

28-
# Load machine config and session info
29-
session_entry = murfey_db.exec(
30-
select(MurfeyDB.Session).where(MurfeyDB.Session.id == session_id)
31-
).one()
32-
instrument_name = session_entry.instrument_name
33-
visit_name = session_entry.visit
34-
machine_config = get_machine_config(instrument_name=instrument_name)[
35-
instrument_name
36-
]
37-
rsync_basepath = machine_config.rsync_basepath or Path(".").resolve()
22+
# Load machine config and session info
23+
session_entry = murfey_db.exec(
24+
select(MurfeyDB.Session).where(MurfeyDB.Session.id == session_id)
25+
).one()
26+
instrument_name = session_entry.instrument_name
27+
visit_name = session_entry.visit
28+
machine_config = get_machine_config(instrument_name=instrument_name)[
29+
instrument_name
30+
]
31+
rsync_basepath = machine_config.rsync_basepath or Path(".").resolve()
3832

39-
# Sanitise and verify that the output directory is relative to rsync basepath
40-
output_file = sanitise_path(gif_params.output_file)
41-
if not output_file.is_relative_to(rsync_basepath):
42-
raise ValueError("Output file path is not permitted")
33+
# Sanitise and verify that the output directory is relative to rsync basepath
34+
output_file = sanitise_path(gif_params.output_file)
35+
if not output_file.is_relative_to(rsync_basepath):
36+
raise ValueError("Output file path is not permitted")
4337

44-
# Create folders in the visit directory and onwards and change permissions
45-
visit_index = output_file.parts.index(visit_name)
46-
for current_path in list(reversed(output_file.parents))[visit_index + 1 :]:
47-
if not current_path.exists():
48-
current_path.mkdir(parents=True)
49-
logger.debug(f"Created output directory {current_path}")
50-
safe_chmod(current_path, mode=machine_config.mkdir_chmod)
38+
# Create folders in the visit directory and onwards and change permissions
39+
visit_index = output_file.parts.index(visit_name)
40+
for current_path in list(reversed(output_file.parents))[visit_index + 1 :]:
41+
if not current_path.exists():
42+
current_path.mkdir(parents=True)
43+
logger.debug(f"Created output directory {current_path}")
44+
safe_chmod(current_path, mode=machine_config.mkdir_chmod)
5145

52-
# Load the images as PIL Image objects
53-
converted: list[PIL.Image.Image] = []
54-
for f in gif_params.images:
55-
with PIL.Image.open(f) as im:
56-
im.thumbnail((512, 512))
57-
frame = np.array(im, dtype=np.float32)
58-
# Normalise to 8-bit
59-
vmin, vmax = np.percentile(frame, (0.5, 99.5))
60-
scale = 255 / ((vmax - vmin) or 1)
61-
np.clip(frame, a_min=vmin, a_max=vmax, out=frame)
62-
np.subtract(frame, vmin, out=frame)
63-
np.multiply(frame, scale, out=frame)
64-
# Convert back to PIL Image
65-
converted.append(
66-
PIL.Image.fromarray(frame.astype(np.uint8), mode="L").copy()
67-
)
68-
del frame # Explicitly remove frame from memory
69-
# Save stack as a GIF
70-
if not converted:
71-
raise ValueError("No images were provided or loaded")
72-
converted[0].save(
73-
output_file,
74-
format="GIF",
75-
append_images=converted[1:],
76-
save_all=True,
77-
duration=30,
78-
loop=0,
79-
)
80-
logger.info(f"Created GIF file {output_file}")
81-
return {"success": True}
82-
except Exception:
83-
logger.error("Error creating FIB milling GIF", exc_info=True)
84-
return {"success": False, "requeue": False}
85-
finally:
86-
murfey_db.close()
46+
# Load the images as PIL Image objects
47+
converted: list[PIL.Image.Image] = []
48+
for f in gif_params.images:
49+
with PIL.Image.open(f) as im:
50+
im.thumbnail((512, 512))
51+
frame = np.array(im, dtype=np.float32)
52+
# Normalise to 8-bit
53+
vmin, vmax = np.percentile(frame, (0.5, 99.5))
54+
scale = 255 / ((vmax - vmin) or 1)
55+
np.clip(frame, a_min=vmin, a_max=vmax, out=frame)
56+
np.subtract(frame, vmin, out=frame)
57+
np.multiply(frame, scale, out=frame)
58+
# Convert back to PIL Image
59+
converted.append(PIL.Image.fromarray(frame.astype(np.uint8), mode="L").copy())
60+
del frame # Explicitly remove frame from memory
61+
62+
# Save stack as a GIF
63+
if not converted:
64+
raise ValueError("No images were provided or loaded")
65+
converted[0].save(
66+
output_file,
67+
format="GIF",
68+
append_images=converted[1:],
69+
save_all=True,
70+
duration=30,
71+
loop=0,
72+
)
73+
logger.info(f"Created GIF file {output_file}")
74+
return {"success": True}

0 commit comments

Comments
 (0)