Skip to content

Commit 51a324e

Browse files
Register all grid squares from atlases (#780)
Currently we only register EPU grid squares when data collection is started. This sets up a method to register them in all atlases as during screening. The problem comes on conversion of screening sessions to EPU sessions. Here this loops through all grid squares and changes the tag when the data collection experiment type id is changed.
1 parent 1dca9b5 commit 51a324e

6 files changed

Lines changed: 152 additions & 13 deletions

File tree

src/murfey/client/contexts/atlas.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from murfey.client.context import Context, _atlas_destination, _get_source
88
from murfey.client.instance_environment import MurfeyInstanceEnvironment
99
from murfey.util.client import capture_post
10+
from murfey.util.spa_metadata import get_grid_square_atlas_positions
1011

1112
logger = logging.getLogger("murfey.client.contexts.atlas")
1213

@@ -158,3 +159,52 @@ def post_transfer_epu(
158159
logger.info(
159160
f"Registered data collection group for atlas {str(transferred_atlas_jpg)!r}"
160161
)
162+
163+
elif environment and transferred_file.name == "Atlas.dm":
164+
# Register all grid squares on this atlas
165+
gs_pix_positions = get_grid_square_atlas_positions(transferred_file)
166+
for gs, pos_data in gs_pix_positions.items():
167+
if pos_data:
168+
capture_post(
169+
base_url=str(environment.url.geturl()),
170+
router_name="session_control.spa_router",
171+
function_name="register_grid_square",
172+
token=self._token,
173+
instrument_name=environment.instrument_name,
174+
session_id=environment.murfey_session,
175+
gsid=int(gs),
176+
data={
177+
"tag": str(transferred_file.parent),
178+
"x_location": pos_data[0],
179+
"y_location": pos_data[1],
180+
"x_stage_position": pos_data[2],
181+
"y_stage_position": pos_data[3],
182+
"width": pos_data[4],
183+
"height": pos_data[5],
184+
"angle": pos_data[6],
185+
},
186+
)
187+
if gs_pix_positions:
188+
for p in transferred_file.parts:
189+
if p.startswith("Sample"):
190+
sample = int(p.replace("Sample", ""))
191+
break
192+
else:
193+
logger.warning(
194+
f"Sample could not be identified for {transferred_file}"
195+
)
196+
return
197+
capture_post(
198+
base_url=str(environment.url.geturl()),
199+
router_name="session_control.spa_router",
200+
function_name="register_atlas",
201+
token=self._token,
202+
instrument_name=environment.instrument_name,
203+
session_id=environment.murfey_session,
204+
data={
205+
"name": f"{environment.visit}-sample-{sample}",
206+
"acquisition_uuid": environment.acquisition_uuid,
207+
"register_grid": True,
208+
"tag": str(transferred_file.parent),
209+
},
210+
)

src/murfey/client/contexts/spa_metadata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def post_transfer(
152152
"angle": pos_data[6],
153153
},
154154
)
155-
if pos_data:
155+
if gs_pix_positions:
156156
capture_post(
157157
base_url=str(environment.url.geturl()),
158158
router_name="session_control.spa_router",

src/murfey/server/api/session_control.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ def get_foil_hole(
359359

360360
class AtlasRegistration(BaseModel):
361361
name: str
362-
acquisition_uuid: str
362+
acquisition_uuid: str | None
363363
storage_folder: str = ""
364364
register_grid: bool = False
365365
tag: str = ""
@@ -371,7 +371,7 @@ def register_atlas(
371371
atlas_registration_data: AtlasRegistration,
372372
db=murfey_db,
373373
):
374-
if SMARTEM_ACTIVE:
374+
if SMARTEM_ACTIVE and atlas_registration_data.acquisition_uuid is not None:
375375
session = db.exec(select(Session).where(Session.id == session_id)).one()
376376
machine_config = get_machine_config(session.instrument_name)[
377377
session.instrument_name
@@ -382,7 +382,7 @@ def register_atlas(
382382
)
383383
grid_uuid = None
384384
if atlas_registration_data.tag:
385-
dcg = murfey_db.exec(
385+
dcg = db.exec(
386386
select(DataCollectionGroup)
387387
.where(DataCollectionGroup.session_id == session_id)
388388
.where(DataCollectionGroup.tag == atlas_registration_data.tag)
@@ -410,7 +410,9 @@ def register_atlas(
410410
if atlas_registration_data.register_grid:
411411
smartem_client.grid_registered(grid_uuid)
412412
else:
413-
logger.info("smartem deactivated so did not register atlas")
413+
logger.info(
414+
f"smartem deactivated so did not register atlas for {sanitise(str(atlas_registration_data.acquisition_uuid))}"
415+
)
414416

415417

416418
class SquareRegistration(BaseModel):

src/murfey/server/api/workflow.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ def register_dc_group(
232232
)
233233
).all():
234234
# Case where we switch from atlas to processing
235+
original_tag = dcg_murfey[0].tag
235236
dcg_murfey[0].tag = dcg_params.tag or dcg_murfey[0].tag
236237
if _transport_object:
237238
_transport_object.send(
@@ -243,6 +244,13 @@ def register_dc_group(
243244
},
244245
)
245246
db.add(dcg_murfey[0])
247+
for grid_square in db.exec(
248+
select(GridSquare)
249+
.where(GridSquare.tag == original_tag)
250+
.where(GridSquare.session_id == session_id)
251+
).all():
252+
grid_square.tag = dcg_params.tag or original_tag
253+
db.add(grid_square)
246254
db.commit()
247255
else:
248256
dcg_parameters = {

src/murfey/workflows/spa/flush_spa_preprocess.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ def register_foil_hole(
297297
)
298298
fh_data = SmartEMFoilHoleData(
299299
id=str(foil_hole_params.name),
300+
gridsquare_id=str(gs.name),
300301
gridsquare_uuid=gs.smartem_uuid,
301302
x_location=(
302303
int(foil_hole_params.x_location)

tests/client/contexts/test_atlas.py

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ def test_atlas_context_mrc(mock_capture_post, tmp_path):
3333
atlas_mrc.parent.mkdir(parents=True)
3434
atlas_mrc.touch()
3535

36-
context.post_transfer(
37-
atlas_mrc,
38-
environment=env,
39-
)
36+
context.post_transfer(atlas_mrc, environment=env)
4037
mock_capture_post.assert_called_once_with(
4138
base_url="http://localhost:8000",
4239
router_name="session_control.spa_router",
@@ -72,10 +69,7 @@ def test_atlas_context_xml(mock_capture_post, tmp_path):
7269
"</numericValue></x></pixelSize></SpatialScale></MicroscopeImage>"
7370
)
7471

75-
context.post_transfer(
76-
atlas_xml,
77-
environment=env,
78-
)
72+
context.post_transfer(atlas_xml, environment=env)
7973
dcg_data = {
8074
"experiment_type_id": 44, # Atlas
8175
"tag": str(atlas_xml.parent),
@@ -95,3 +89,87 @@ def test_atlas_context_xml(mock_capture_post, tmp_path):
9589
session_id=1,
9690
data=dcg_data,
9791
)
92+
93+
94+
@patch("murfey.client.contexts.atlas.capture_post")
95+
def test_atlas_context_dm(mock_capture_post, tmp_path):
96+
env = MurfeyInstanceEnvironment(
97+
url=urlparse("http://localhost:8000"),
98+
client_id=0,
99+
sources=[tmp_path / "cm12345-6"],
100+
default_destinations={
101+
tmp_path / "cm12345-6": f"{tmp_path}/destination/cm12345-6"
102+
},
103+
instrument_name="m01",
104+
visit="cm12345-6",
105+
murfey_session=1,
106+
acquisition_uuid="uuid1",
107+
)
108+
109+
# Write sample dm file
110+
atlas_dm = tmp_path / "cm12345-6/Supervisor_atlas/Sample2/Atlas/Atlas.dm"
111+
atlas_dm.parent.mkdir(parents=True)
112+
grid_square_values = (
113+
"<value><b:PositionOnTheAtlas>"
114+
"<c:Center><d:x>1200</d:x><d:y>1500</d:y></c:Center>"
115+
"<c:Physical><d:x>2</d:x><d:y>3</d:y></c:Physical>"
116+
"<c:Size><d:width>130</d:width><d:height>560</d:height></c:Size>"
117+
"<c:Rotation>0.14</c:Rotation>"
118+
"</b:PositionOnTheAtlas></value>"
119+
)
120+
with open(atlas_dm, "w") as new_xml:
121+
new_xml.write(
122+
"<AtlasSessionXml><Atlas><TilesEfficient><_items>"
123+
# First tile with two grid squares
124+
"<TileXml><Nodes><KeyValuePairs><KeyValuePairOfintNodeXml1>"
125+
f"<key>101</key>{grid_square_values}"
126+
"</KeyValuePairOfintNodeXml1><KeyValuePairOfintNodeXml1>"
127+
f"<key>102</key>{grid_square_values}"
128+
"</KeyValuePairOfintNodeXml1></KeyValuePairs></Nodes></TileXml>"
129+
# Second tile with two grid squares
130+
"<TileXml><Nodes><KeyValuePairs><KeyValuePairOfintNodeXml1>"
131+
f"<key>103</key>{grid_square_values}"
132+
"</KeyValuePairOfintNodeXml1><KeyValuePairOfintNodeXml1>"
133+
f"<key>104</key>{grid_square_values}"
134+
"</KeyValuePairOfintNodeXml1></KeyValuePairs></Nodes></TileXml>"
135+
# Close all
136+
"</_items></TilesEfficient></Atlas></AtlasSessionXml>"
137+
)
138+
139+
context = AtlasContext("tomo", tmp_path, {}, "token")
140+
context.post_transfer(atlas_dm, environment=env)
141+
142+
assert mock_capture_post.call_count == 5
143+
mock_capture_post.assert_any_call(
144+
base_url="http://localhost:8000",
145+
router_name="session_control.spa_router",
146+
function_name="register_grid_square",
147+
token="token",
148+
instrument_name="m01",
149+
session_id=1,
150+
gsid=101,
151+
data={
152+
"tag": str(atlas_dm.parent),
153+
"x_location": 1200,
154+
"y_location": 1500,
155+
"x_stage_position": 2e9,
156+
"y_stage_position": 3e9,
157+
"width": 130,
158+
"height": 560,
159+
"angle": 0.14,
160+
},
161+
)
162+
mock_capture_post.assert_any_call(
163+
base_url="http://localhost:8000",
164+
router_name="session_control.spa_router",
165+
function_name="register_atlas",
166+
token="token",
167+
instrument_name="m01",
168+
session_id=1,
169+
data={
170+
"name": "cm12345-6-sample-2",
171+
"acquisition_uuid": "uuid1",
172+
"register_grid": True,
173+
"tag": str(atlas_dm.parent),
174+
},
175+
)

0 commit comments

Comments
 (0)