Skip to content

Commit 4464f75

Browse files
committed
Merged recent changes from 'main' branch
2 parents 404b989 + 8b4803a commit 4464f75

File tree

19 files changed

+1296
-534
lines changed

19 files changed

+1296
-534
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ GitHub = "https://github.com/DiamondLightSource/python-murfey"
108108
"clem.register_preprocessing_result" = "murfey.workflows.clem.register_preprocessing_results:run"
109109
"data_collection" = "murfey.workflows.register_data_collection:run"
110110
"data_collection_group" = "murfey.workflows.register_data_collection_group:run"
111+
"experiment_type_update" = "murfey.workflows.register_experiment_type_update:run"
111112
"pato" = "murfey.workflows.notifications:notification_setup"
112113
"picked_particles" = "murfey.workflows.spa.picking:particles_picked"
113114
"picked_tomogram" = "murfey.workflows.tomo.picking:picked_tomogram"

src/murfey/client/context.py

Lines changed: 145 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,156 @@
33
import logging
44
from importlib.metadata import entry_points
55
from pathlib import Path
6-
from typing import Any, Dict, List, NamedTuple
6+
from typing import Any, List, NamedTuple
77

8-
from murfey.client.instance_environment import MurfeyInstanceEnvironment
8+
import xmltodict
9+
10+
from murfey.client.instance_environment import MurfeyInstanceEnvironment, SampleInfo
11+
from murfey.util.client import capture_post, get_machine_config_client
912

1013
logger = logging.getLogger("murfey.client.context")
1114

1215

13-
class FutureRequest(NamedTuple):
14-
url: str
15-
message: Dict[str, Any]
16+
def _atlas_destination(
17+
environment: MurfeyInstanceEnvironment, source: Path, token: str
18+
) -> Path:
19+
machine_config = get_machine_config_client(
20+
str(environment.url.geturl()),
21+
token,
22+
instrument_name=environment.instrument_name,
23+
demo=environment.demo,
24+
)
25+
for i, destination_part in enumerate(
26+
Path(environment.default_destinations[source]).parts
27+
):
28+
if destination_part == environment.visit:
29+
return Path(machine_config.get("rsync_basepath", "")) / "/".join(
30+
Path(environment.default_destinations[source]).parent.parts[: i + 1]
31+
)
32+
return (
33+
Path(machine_config.get("rsync_basepath", ""))
34+
/ Path(environment.default_destinations[source]).parent
35+
/ environment.visit
36+
)
37+
38+
39+
def ensure_dcg_exists(
40+
collection_type: str,
41+
metadata_source: Path,
42+
environment: MurfeyInstanceEnvironment,
43+
token: str,
44+
) -> str | None:
45+
"""Create a data collection group"""
46+
if collection_type == "tomo":
47+
experiment_type_id = 36
48+
session_file = metadata_source / "Session.dm"
49+
elif collection_type == "spa":
50+
experiment_type_id = 37
51+
session_file = metadata_source / "EpuSession.dm"
52+
for h in entry_points(group="murfey.hooks"):
53+
try:
54+
if h.name == "get_epu_session_metadata":
55+
h.load()(session_file, environment=environment)
56+
except Exception as e:
57+
logger.warning(f"Get EPU session hook failed: {e}")
58+
else:
59+
logger.error(f"Unknown collection type {collection_type}")
60+
return None
61+
62+
if not session_file.is_file():
63+
logger.warning(f"Cannot find session file {str(session_file)}")
64+
dcg_tag = (
65+
str(metadata_source).replace(f"/{environment.visit}", "").replace("//", "/")
66+
)
67+
dcg_data = {
68+
"experiment_type_id": experiment_type_id,
69+
"tag": dcg_tag,
70+
}
71+
else:
72+
with open(session_file, "r") as session_xml:
73+
session_data = xmltodict.parse(session_xml.read())
74+
75+
if collection_type == "tomo":
76+
windows_path = session_data["TomographySession"]["AtlasId"]
77+
else:
78+
windows_path = session_data["EpuSessionXml"]["Samples"]["_items"][
79+
"SampleXml"
80+
][0]["AtlasId"]["#text"]
81+
82+
logger.info(f"Windows path to atlas metadata found: {windows_path}")
83+
if not windows_path:
84+
logger.warning("No atlas metadata path found")
85+
return None
86+
visit_index = windows_path.split("\\").index(environment.visit)
87+
partial_path = "/".join(windows_path.split("\\")[visit_index + 1 :])
88+
logger.info("Partial Linux path successfully constructed from Windows path")
89+
90+
source_visit_dir = metadata_source.parent
91+
logger.info(
92+
f"Looking for atlas XML file in metadata directory {str((source_visit_dir / partial_path).parent)}"
93+
)
94+
atlas_xml_path = list(
95+
(source_visit_dir / partial_path).parent.glob("Atlas_*.xml")
96+
)[0]
97+
logger.info(f"Atlas XML path {str(atlas_xml_path)} found")
98+
with open(atlas_xml_path, "rb") as atlas_xml:
99+
atlas_xml_data = xmltodict.parse(atlas_xml)
100+
atlas_original_pixel_size = float(
101+
atlas_xml_data["MicroscopeImage"]["SpatialScale"]["pixelSize"]["x"][
102+
"numericValue"
103+
]
104+
)
105+
# need to calculate the pixel size of the downscaled image
106+
atlas_pixel_size = atlas_original_pixel_size * 7.8
107+
logger.info(f"Atlas image pixel size determined to be {atlas_pixel_size}")
108+
109+
for p in partial_path.split("/"):
110+
if p.startswith("Sample"):
111+
sample = int(p.replace("Sample", ""))
112+
break
113+
else:
114+
logger.warning(f"Sample could not be identified for {metadata_source}")
115+
return None
116+
environment.samples[metadata_source] = SampleInfo(
117+
atlas=Path(partial_path), sample=sample
118+
)
119+
120+
dcg_search_dir = (
121+
str(metadata_source).replace(f"/{environment.visit}", "").replace("//", "/")
122+
)
123+
if collection_type == "tomo":
124+
dcg_tag = dcg_search_dir
125+
else:
126+
dcg_images_dirs = sorted(
127+
Path(dcg_search_dir).glob("Images-Disc*"),
128+
key=lambda x: x.stat().st_ctime,
129+
)
130+
if not dcg_images_dirs:
131+
logger.warning(f"Cannot find Images-Disc* in {dcg_search_dir}")
132+
return None
133+
dcg_tag = str(dcg_images_dirs[-1])
134+
135+
dcg_data = {
136+
"experiment_type_id": experiment_type_id,
137+
"tag": dcg_tag,
138+
"atlas": str(
139+
_atlas_destination(environment, metadata_source, token)
140+
/ environment.samples[metadata_source].atlas.parent
141+
/ atlas_xml_path.with_suffix(".jpg").name
142+
).replace("//", "/"),
143+
"sample": environment.samples[metadata_source].sample,
144+
"atlas_pixel_size": atlas_pixel_size,
145+
}
146+
capture_post(
147+
base_url=str(environment.url.geturl()),
148+
router_name="workflow.router",
149+
function_name="register_dc_group",
150+
token=token,
151+
visit_name=environment.visit,
152+
session_id=environment.murfey_session,
153+
data=dcg_data,
154+
)
155+
return dcg_tag
16156

17157

18158
class ProcessingParameter(NamedTuple):

src/murfey/client/contexts/atlas.py

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
from pathlib import Path
33
from typing import Optional
44

5-
from murfey.client.context import Context
5+
import xmltodict
6+
7+
from murfey.client.context import Context, _atlas_destination
68
from murfey.client.contexts.spa import _get_source
7-
from murfey.client.contexts.spa_metadata import _atlas_destination
89
from murfey.client.instance_environment import MurfeyInstanceEnvironment
910
from murfey.util.client import capture_post
1011

@@ -36,16 +37,68 @@ def post_transfer(
3637
source = _get_source(transferred_file, environment)
3738
if source:
3839
transferred_atlas_name = _atlas_destination(
39-
environment, source, transferred_file, self._token
40+
environment, source, self._token
4041
) / transferred_file.relative_to(source.parent)
4142
capture_post(
4243
base_url=str(environment.url.geturl()),
4344
router_name="session_control.spa_router",
4445
function_name="make_atlas_jpg",
4546
token=self._token,
4647
session_id=environment.murfey_session,
47-
data={"path": str(transferred_atlas_name)},
48+
data={"path": str(transferred_atlas_name).replace("//", "/")},
4849
)
4950
logger.info(
5051
f"Submitted request to create JPG image of atlas {str(transferred_atlas_name)!r}"
5152
)
53+
elif (
54+
environment
55+
and "Atlas_" in transferred_file.stem
56+
and transferred_file.suffix == ".xml"
57+
):
58+
source = _get_source(transferred_file, environment)
59+
if source:
60+
atlas_mrc = transferred_file.with_suffix(".mrc")
61+
transferred_atlas_jpg = _atlas_destination(
62+
environment, source, self._token
63+
) / atlas_mrc.relative_to(source.parent).with_suffix(".jpg")
64+
65+
with open(transferred_file, "rb") as atlas_xml:
66+
atlas_xml_data = xmltodict.parse(atlas_xml)
67+
atlas_original_pixel_size = float(
68+
atlas_xml_data["MicroscopeImage"]["SpatialScale"]["pixelSize"][
69+
"x"
70+
]["numericValue"]
71+
)
72+
73+
# need to calculate the pixel size of the downscaled image
74+
atlas_pixel_size = atlas_original_pixel_size * 7.8
75+
76+
for p in transferred_file.parts:
77+
if p.startswith("Sample"):
78+
sample = int(p.replace("Sample", ""))
79+
break
80+
else:
81+
logger.warning(
82+
f"Sample could not be identified for {transferred_file}"
83+
)
84+
return
85+
86+
dcg_data = {
87+
"experiment_type_id": 44, # Atlas
88+
"tag": str(transferred_file.parent),
89+
"atlas": str(transferred_atlas_jpg).replace("//", "/"),
90+
"sample": sample,
91+
"atlas_pixel_size": atlas_pixel_size,
92+
}
93+
capture_post(
94+
base_url=str(environment.url.geturl()),
95+
router_name="workflow.router",
96+
function_name="register_dc_group",
97+
token=self._token,
98+
visit_name=environment.visit,
99+
session_id=environment.murfey_session,
100+
data=dcg_data,
101+
)
102+
logger.info(
103+
f"Registered data collection group for atlas {str(transferred_atlas_jpg)!r}"
104+
)

0 commit comments

Comments
 (0)