|
3 | 3 | import logging |
4 | 4 | from importlib.metadata import entry_points |
5 | 5 | from pathlib import Path |
6 | | -from typing import Any, Dict, List, NamedTuple |
| 6 | +from typing import Any, List, NamedTuple |
7 | 7 |
|
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 |
9 | 12 |
|
10 | 13 | logger = logging.getLogger("murfey.client.context") |
11 | 14 |
|
12 | 15 |
|
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 |
16 | 156 |
|
17 | 157 |
|
18 | 158 | class ProcessingParameter(NamedTuple): |
|
0 commit comments