Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
927cc32
Read xrm files for metadata on the client
stephen-riggs Jun 23, 2026
d5db21e
Move around the sxt logic
stephen-riggs Jun 24, 2026
1b5c534
Add dummy router for xrm position info
stephen-riggs Jun 24, 2026
2ce7055
Change router name in main
stephen-riggs Jun 24, 2026
095195f
Ispyb insert function for sxt roi
stephen-riggs Jun 24, 2026
74e0c7d
Merge branch 'main' into sxt-atlas
stephen-riggs Jul 6, 2026
3b064fe
Add code to register metadata
stephen-riggs Jul 7, 2026
c67c870
Can just use searchmap
stephen-riggs Jul 7, 2026
d714c16
Fix naming
stephen-riggs Jul 7, 2026
da39351
Catch different tomo and sxt registrations
stephen-riggs Jul 7, 2026
e639893
Use imaging site to avoid db changes
stephen-riggs Jul 7, 2026
f20417f
Registration fixes from testing
stephen-riggs Jul 7, 2026
a74ab7e
Add a test
stephen-riggs Jul 8, 2026
597b011
Fix some tests
stephen-riggs Jul 8, 2026
730ab98
More test fixes
stephen-riggs Jul 8, 2026
c9f2bfd
More test fixes
stephen-riggs Jul 8, 2026
f0c30b5
Maybe mocking wrong thing
stephen-riggs Jul 9, 2026
ada1f85
search map ids diff
stephen-riggs Jul 9, 2026
8695966
Do rounding as int
stephen-riggs Jul 9, 2026
e602621
typo
stephen-riggs Jul 9, 2026
9a876db
Test for im site insert
stephen-riggs Jul 9, 2026
f312d92
typo
stephen-riggs Jul 9, 2026
02704b3
typo
stephen-riggs Jul 9, 2026
42c232b
change software name
stephen-riggs Jul 9, 2026
c9fc226
sanitise string
stephen-riggs Jul 9, 2026
b26a956
Typo
stephen-riggs Jul 13, 2026
45bba8d
Switch from all to one_or_none
stephen-riggs Jul 13, 2026
97cee9f
Log missing transport objects
stephen-riggs Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ TomographyMetadataContext = "murfey.client.contexts.tomo_metadata:TomographyMeta
"spa.flush_spa_preprocess" = "murfey.workflows.spa.flush_spa_preprocess:flush_spa_preprocess"
"spa.motion_corrected" = "murfey.workflows.spa.motion_correction:motion_corrected"
"sxt.process_tilt_series" = "murfey.workflows.sxt.process_sxt_tilt_series:run"
"sxt.register_roi" = "murfey.workflows.sxt.sxt_metadata:run"

[tool.setuptools]
package-dir = {"" = "src"}
Expand Down
14 changes: 8 additions & 6 deletions src/murfey/client/contexts/sxt.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,14 +246,17 @@ def post_transfer(
/ environment.visit
)
destination_extra = ""
converted_file_path = (
converted_tiff_path = (
Path(self._machine_config.get("rsync_basepath", ""))
/ destination_base
/ self._machine_config.get("processed_directory_name", "")
/ self._machine_config.get("processed_extra_directory", "")
/ destination_extra
/ f"{transferred_file.relative_to(source).stem}_Annotated.tiff"
)
thumbnail_path = converted_tiff_path.parent / (
converted_tiff_path.stem + "_thumbnail.jpg"
)
capture_post(
base_url=str(environment.url.geturl()),
router_name="workflow_sxt.router",
Expand All @@ -262,7 +265,7 @@ def post_transfer(
instrument_name=environment.instrument_name,
data={
"xrm_path": str(image_path),
"tiff_path": str(converted_file_path),
"tiff_path": str(converted_tiff_path),
},
)

Expand All @@ -274,7 +277,7 @@ def post_transfer(
dcg_data = {
"experiment_type_id": 44, # Atlas
"tag": dcg_tag,
"atlas": str(converted_file_path),
"atlas": str(thumbnail_path),
"atlas_pixel_size": round(metadata.get("pixel_size", 0), 2),
Comment thread
tieneupin marked this conversation as resolved.
"atlas_x_stage_position": metadata.get("x_position", None),
"atlas_y_stage_position": metadata.get("y_position", None),
Expand Down Expand Up @@ -303,11 +306,10 @@ def post_transfer(
function_name="register_sxt_roi",
token=self._token,
instrument_name=environment.instrument_name,
visit_name=environment.visit,
session_id=environment.murfey_session,
roi_name=transferred_file.stem,
data={
"tag": dcg_tag,
"name": transferred_file.stem,
"x_stage_position": metadata.get("x_position", None),
"y_stage_position": metadata.get("y_position", None),
"pixel_size": round(metadata.get("pixel_size", 0), 2),
Expand All @@ -317,7 +319,7 @@ def post_transfer(
"width": int(
metadata.get("width", 0) * metadata["mosaic_columns"]
),
"image": str(converted_file_path),
"image": str(thumbnail_path),
},
)

Expand Down
63 changes: 57 additions & 6 deletions src/murfey/server/api/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
DataCollectionGroup,
FoilHole,
GridSquare,
ImagingSite,
Movie,
PreprocessStash,
ProcessingJob,
Expand Down Expand Up @@ -121,15 +122,15 @@ def register_dc_group(
db.exec(select(Session).where(Session.id == session_id)).one().instrument_name
)
logger.info(f"Registering data collection group on microscope {instrument_name}")
machine_config = get_machine_config(instrument_name=instrument_name)[
instrument_name
]
smartem_grid_uuid = None
if (
dcg_params.create_smartem_grid
and SMARTEM_ACTIVE
and dcg_params.acquisition_uuid
):
machine_config = get_machine_config(instrument_name=instrument_name)[
instrument_name
]
if machine_config.smartem_api_url:
try:
smartem_client = SmartEMAPIClient(
Expand Down Expand Up @@ -178,6 +179,40 @@ def register_dc_group(
if smartem_grid_uuid:
dcg_instance.smartem_grid_uuid = smartem_grid_uuid

# Update any atlases which are registered as imaging sites
if atlas_instance := db.exec(
select(ImagingSite).where(ImagingSite.dcg_id == dcg_instance.id)
).one_or_none():
atlas_instance.pos_x = (
dcg_params.atlas_x_stage_position or atlas_instance.pos_x
)
atlas_instance.pos_y = (
dcg_params.atlas_y_stage_position or atlas_instance.pos_y
)
atlas_instance.image_pixels_x = (
dcg_params.atlas_width or atlas_instance.image_pixels_x
)
atlas_instance.image_pixels_y = (
dcg_params.atlas_height or atlas_instance.image_pixels_y
)
atlas_instance.image_pixel_size = (
dcg_params.atlas_pixel_size or atlas_instance.image_pixel_size
)
db.add(atlas_instance)
elif dcg_params.atlas_x_stage_position:
atlas_instance = ImagingSite(
dcg_id=dcg_instance.id,
session_id=session_id,
site_name=dcg_instance.tag,
data_type="atlas",
pos_x=dcg_params.atlas_x_stage_position,
pos_y=dcg_params.atlas_y_stage_position,
image_pixels_x=dcg_params.atlas_width,
image_pixels_y=dcg_params.atlas_height,
image_pixel_size=dcg_params.atlas_pixel_size,
)
db.add(atlas_instance)

if _transport_object:
if dcg_instance.atlas_id is not None:
_transport_object.send(
Expand Down Expand Up @@ -213,9 +248,21 @@ def register_dc_group(
).all()
search_map_params = SearchMapParameters(tag=dcg_params.tag)
for sm in search_maps:
register_search_map_in_database(
session_id, sm.name, search_map_params, db, close_db=False
)
# Different behaviour for tomo and SXT
if "tomo" in machine_config.acquisition_software:
register_search_map_in_database(
session_id, sm.name, search_map_params, db, close_db=False
)
elif _transport_object:
_transport_object.send(
_transport_object.feedback_queue,
{
"register": "sxt.register_roi",
"session_id": session_id,
"roi_name": sm.name,
"roi_info": search_map_params.model_dump(mode="json"),
},
)
db.close()
elif dcg_murfey := db.exec(
select(DataCollectionGroup)
Expand Down Expand Up @@ -255,6 +302,10 @@ def register_dc_group(
"atlas": dcg_params.atlas,
"sample": dcg_params.sample,
"atlas_pixel_size": dcg_params.atlas_pixel_size,
"atlas_x_stage_position": dcg_params.atlas_x_stage_position,
"atlas_y_stage_position": dcg_params.atlas_y_stage_position,
"atlas_width": dcg_params.atlas_width,
"atlas_height": dcg_params.atlas_height,
}

if _transport_object:
Expand Down
35 changes: 19 additions & 16 deletions src/murfey/server/api/workflow_sxt.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
validate_instrument_token,
)
from murfey.server.murfey_db import murfey_db
from murfey.util import sanitise
from murfey.util.models import SearchMapParameters
from murfey.workflows.sxt.process_sxt_tilt_series import SXTTiltSeriesInfo

logger = getLogger("murfey.server.api.workflow_sxt")
Expand Down Expand Up @@ -62,23 +64,24 @@ def convert_xrm_to_tiff(xrm_file: XrmFile, db=murfey_db):
)


class SxtRoiInfo(BaseModel):
tag: str
name: str
x_stage_position: float
y_stage_position: float
pixel_size: float
height: int
width: int
image: Path


@router.post("/visits/{visit_name}/sessions/{session_id}/register_sxt_roi")
@router.post("/sessions/{session_id}/sxt_roi/{roi_name}")
def register_sxt_roi(
visit_name: str,
session_id: MurfeySessionID,
tilt_series_info: SXTTiltSeriesInfo,
roi_name: str,
roi_info: SearchMapParameters,
db=murfey_db,
):
# TODO
return
if _transport_object:
Comment thread
stephen-riggs marked this conversation as resolved.
logger.info(f"Registering SXT region {sanitise(roi_name)}")
_transport_object.send(
_transport_object.feedback_queue,
{
"register": "sxt.register_roi",
"session_id": session_id,
"roi_name": roi_name,
"roi_info": roi_info.model_dump(mode="json"),
},
new_connection=True,
)
else:
logger.warning("No transport object for register_sxt_roi")
90 changes: 90 additions & 0 deletions src/murfey/server/ispyb.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,96 @@ def do_update_search_map(
)
return {"success": False, "return_value": None}

def do_insert_sxt_roi(
self,
atlas_id: int,
roi_parameters: SearchMapParameters,
):
if (
roi_parameters.pixel_size
and roi_parameters.height
and roi_parameters.height_on_atlas
):
roi_parameters.pixel_size *= (
roi_parameters.height / roi_parameters.height_on_atlas
)
roi_parameters.x_location = (
int(roi_parameters.x_location) if roi_parameters.x_location else None
)
roi_parameters.y_location = (
int(roi_parameters.y_location) if roi_parameters.y_location else None
)
record = GridSquare(
atlasId=atlas_id,
gridSquareImage=roi_parameters.image,
pixelLocationX=roi_parameters.x_location,
pixelLocationY=roi_parameters.y_location,
height=roi_parameters.height_on_atlas,
width=roi_parameters.width_on_atlas,
angle=0,
stageLocationX=roi_parameters.x_stage_position,
stageLocationY=roi_parameters.y_stage_position,
pixelSize=roi_parameters.pixel_size,
)
try:
with ISPyBSession() as db:
db.add(record)
db.commit()
log.info(f"Created SXT ROI (GridSquare) {record.gridSquareId}")
return {"success": True, "return_value": record.gridSquareId}
except ispyb.ISPyBException as e:
log.error(
"Inserting SXT ROI (GridSquare) entry caused exception '%s'.",
e,
exc_info=True,
)
return {"success": False, "return_value": None}

def do_update_sxt_roi(self, roi_id, roi_parameters: SearchMapParameters):
try:
with ISPyBSession() as db:
grid_square = (
db.query(GridSquare).filter(GridSquare.gridSquareId == roi_id).one()
)
if (
roi_parameters.pixel_size
and roi_parameters.height
and roi_parameters.height_on_atlas
):
roi_parameters.pixel_size *= (
roi_parameters.height / roi_parameters.height_on_atlas
)
grid_square.gridSquareImage = (
roi_parameters.image or grid_square.gridSquareImage
)
if roi_parameters.x_location:
grid_square.pixelLocationX = int(roi_parameters.x_location)
if roi_parameters.y_location:
grid_square.pixelLocationY = int(roi_parameters.y_location)
if roi_parameters.height_on_atlas:
grid_square.height = int(roi_parameters.height_on_atlas)
if roi_parameters.width_on_atlas:
grid_square.width = int(roi_parameters.width_on_atlas)
grid_square.stageLocationX = (
roi_parameters.x_stage_position or grid_square.stageLocationX
)
grid_square.stageLocationY = (
roi_parameters.y_stage_position or grid_square.stageLocationY
)
grid_square.pixelSize = (
roi_parameters.pixel_size or grid_square.pixelSize
)
db.add(grid_square)
db.commit()
return {"success": True, "return_value": grid_square.gridSquareId}
except ispyb.ISPyBException as e:
log.error(
"Updating SXT ROI (GridSquare) entry caused exception '%s'.",
e,
exc_info=True,
)
return {"success": False, "return_value": None}

def send(self, queue: str, message: dict, new_connection: bool = False):
if self.transport:
if not self.transport.is_connected():
Expand Down
4 changes: 2 additions & 2 deletions src/murfey/util/route_manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1460,10 +1460,10 @@ murfey.server.api.workflow_sxt.router:
path_params: []
methods:
- POST
- path: /workflow/sxt/visits/{visit_name}/sessions/{session_id}/register_sxt_roi
- path: /workflow/sxt/sessions/{session_id}/sxt_roi/{roi_name}
function: register_sxt_roi
path_params:
- name: visit_name
- name: roi_name
type: str
- name: session_id
type: int
Expand Down
15 changes: 14 additions & 1 deletion src/murfey/workflows/register_data_collection_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from murfey.server import _transport_object
from murfey.server.ispyb import ISPyBSession, get_session_id
from murfey.util.db import DataCollectionGroup
from murfey.util.db import DataCollectionGroup, ImagingSite

logger = logging.getLogger("murfey.workflows.register_data_collection_group")

Expand Down Expand Up @@ -90,6 +90,19 @@ def run(message: dict, murfey_db: SQLModelSession) -> dict[str, bool]:
smartem_grid_uuid=message.get("smartem_grid_uuid"),
)
murfey_db.add(murfey_dcg)
if dcgid is not None and message.get("atlas_x_stage_position"):
atlas_site = ImagingSite(
dcg_id=dcgid,
session_id=message["session_id"],
site_name=message.get("tag"),
data_type="atlas",
pos_x=message.get("atlas_x_stage_position"),
pos_y=message.get("atlas_y_stage_position"),
image_pixels_x=message.get("atlas_width"),
image_pixels_y=message.get("atlas_height"),
image_pixel_size=message.get("atlas_pixel_size"),
)
murfey_db.add(atlas_site)
murfey_db.commit()
murfey_db.close()

Expand Down
Loading