diff --git a/src/murfey/cli/inject_spa_processing.py b/src/murfey/cli/inject_spa_processing.py index 2b14df9d9..2294835a5 100644 --- a/src/murfey/cli/inject_spa_processing.py +++ b/src/murfey/cli/inject_spa_processing.py @@ -21,7 +21,7 @@ SPAFeedbackParameters, SPARelionParameters, ) -from murfey.util.spa_params import default_spa_parameters +from murfey.util.processing_params import default_spa_parameters def run(): diff --git a/src/murfey/server/__init__.py b/src/murfey/server/__init__.py index 0c795ac6c..07c50fade 100644 --- a/src/murfey/server/__init__.py +++ b/src/murfey/server/__init__.py @@ -56,7 +56,7 @@ get_microscope, get_security_config, ) -from murfey.util.spa_params import default_spa_parameters +from murfey.util.processing_params import default_spa_parameters from murfey.util.state import global_state try: diff --git a/src/murfey/server/api/__init__.py b/src/murfey/server/api/__init__.py index 86e140998..70cdbe716 100644 --- a/src/murfey/server/api/__init__.py +++ b/src/murfey/server/api/__init__.py @@ -105,7 +105,7 @@ TiltSeriesInfo, Visit, ) -from murfey.util.spa_params import default_spa_parameters +from murfey.util.processing_params import default_spa_parameters from murfey.util.state import global_state log = logging.getLogger("murfey.server.api") diff --git a/src/murfey/server/api/clem.py b/src/murfey/server/api/clem.py index 17cdd6f1d..606e18496 100644 --- a/src/murfey/server/api/clem.py +++ b/src/murfey/server/api/clem.py @@ -2,13 +2,15 @@ import re import traceback +from ast import literal_eval from importlib.metadata import EntryPoint # type hinting only from logging import getLogger from pathlib import Path -from typing import Optional, Type, Union +from typing import Literal, Optional, Type, Union from backports.entry_points_selectable import entry_points from fastapi import APIRouter +from pydantic import BaseModel, validator from sqlalchemy.exc import NoResultFound from sqlmodel import Session, select @@ -23,7 +25,6 @@ CLEMTIFFFile, ) from murfey.util.db import Session as MurfeySession -from murfey.util.models import TIFFSeriesInfo # Set up logger logger = getLogger("murfey.server.api.clem") @@ -622,7 +623,7 @@ def register_image_stack( "/sessions/{session_id}/clem/preprocessing/process_raw_lifs" ) # API posts to this URL def process_raw_lifs( - session_id: int, # Used by the decorator + session_id: int, lif_file: Path, db: Session = murfey_db, ): @@ -654,9 +655,15 @@ def process_raw_lifs( return True +class TIFFSeriesInfo(BaseModel): + series_name: str + tiff_files: list[Path] + series_metadata: Path + + @router.post("/sessions/{session_id}/clem/preprocessing/process_raw_tiffs") def process_raw_tiffs( - session_id: int, # Used by the decorator + session_id: int, tiff_info: TIFFSeriesInfo, db: Session = murfey_db, ): @@ -687,3 +694,72 @@ def process_raw_tiffs( messenger=_transport_object, ) return True + + +class AlignAndMergeParams(BaseModel): + # Processing parameters + series_name: str + images: list[Path] + metadata: Path + # Optional processing parameters + crop_to_n_frames: Optional[int] = None + align_self: Literal["enabled", ""] = "" + flatten: Literal["mean", "min", "max", ""] = "" + align_across: Literal["enabled", ""] = "" + + @validator( + "images", + pre=True, + ) + def parse_stringified_list(cls, value): + if isinstance(value, str): + try: + eval_result = literal_eval(value) + if isinstance(eval_result, list): + parent_tiffs = [Path(p) for p in eval_result] + return parent_tiffs + except (SyntaxError, ValueError): + raise ValueError("Unable to parse input") + # Return value as-is; if it fails, it fails + return value + + +@router.post("/sessions/{session_id}/clem/processing/align_and_merge_stacks") +def align_and_merge_stacks( + session_id: int, + align_and_merge_params: AlignAndMergeParams, + db: Session = murfey_db, +): + try: + # Try and load relevant Murfey workflow + workflow: EntryPoint = list( + entry_points().select(group="murfey.workflows", name="clem.align_and_merge") + )[0] + except IndexError: + raise RuntimeError("The relevant Murfey workflow was not found") + + # Get instrument name from the database to load the correct config file + session_row: MurfeySession = db.exec( + select(MurfeySession).where(MurfeySession.id == session_id) + ).one() + instrument_name = session_row.instrument_name + + # Pass arguments to correct workflow + workflow.load()( + # Match the arguments found in murfey.workflows.clem.align_and_merge + # Session parameters + session_id=session_id, + instrument_name=instrument_name, + # Processing parameters + series_name=align_and_merge_params.series_name, + images=align_and_merge_params.images, + metadata=align_and_merge_params.metadata, + # Optional processing parameters + crop_to_n_frames=align_and_merge_params.crop_to_n_frames, + align_self=align_and_merge_params.align_self, + flatten=align_and_merge_params.flatten, + align_across=align_and_merge_params.align_across, + # Optional session parameters + messenger=_transport_object, + ) + return True diff --git a/src/murfey/server/demo_api.py b/src/murfey/server/demo_api.py index eab41858a..7f1221e3c 100644 --- a/src/murfey/server/demo_api.py +++ b/src/murfey/server/demo_api.py @@ -90,7 +90,7 @@ TiltSeriesInfo, Visit, ) -from murfey.util.spa_params import default_spa_parameters +from murfey.util.processing_params import default_spa_parameters from murfey.util.state import global_state log = logging.getLogger("murfey.server.demo_api") diff --git a/src/murfey/util/models.py b/src/murfey/util/models.py index 97fedb610..911eae8e5 100644 --- a/src/murfey/util/models.py +++ b/src/murfey/util/models.py @@ -147,19 +147,6 @@ class FractionationParameters(BaseModel): fractionation_file_name: str = "eer_fractionation.txt" -""" -Cryo-CLEM -========= -Models related to the cryo-CLEM workflow. -""" - - -class TIFFSeriesInfo(BaseModel): - series_name: str - tiff_files: List[Path] - series_metadata: Path - - """ FIB === diff --git a/src/murfey/util/spa_params.py b/src/murfey/util/processing_params.py similarity index 56% rename from src/murfey/util/spa_params.py rename to src/murfey/util/processing_params.py index 3cc130be8..66ea481c0 100644 --- a/src/murfey/util/spa_params.py +++ b/src/murfey/util/processing_params.py @@ -1,6 +1,18 @@ +from typing import Literal, Optional + from pydantic import BaseModel +class CLEMAlignAndMergeParameters(BaseModel): + crop_to_n_frames: Optional[int] = 50 + align_self: Literal["enabled", ""] = "enabled" + flatten: Literal["mean", "min", "max", ""] = "mean" + align_across: Literal["enabled", ""] = "enabled" + + +default_clem_align_and_merge_parameters = CLEMAlignAndMergeParameters() + + class SPAParameters(BaseModel): nr_iter_2d: int = 25 nr_iter_3d: int = 25 diff --git a/src/murfey/workflows/clem/align_and_merge.py b/src/murfey/workflows/clem/align_and_merge.py index 5c02e6e0f..c5df9fecf 100644 --- a/src/murfey/workflows/clem/align_and_merge.py +++ b/src/murfey/workflows/clem/align_and_merge.py @@ -25,9 +25,10 @@ def submit_cluster_request( images: list[Path], metadata: Path, # Optional processing parameters - align_self: Optional[str] = None, - flatten: Optional[Literal["min", "max", "mean"]] = "mean", - align_across: Optional[str] = None, + crop_to_n_frames: Optional[int] = None, + align_self: Literal["enabled", ""] = "", + flatten: Literal["mean", "min", "max", ""] = "mean", + align_across: Literal["enabled", ""] = "", # Optional session parameters messenger: Optional[TransportManager] = None, ): @@ -64,6 +65,7 @@ def submit_cluster_request( "series_name": series_name, "images": [str(file) for file in images], "metadata": str(metadata), + "crop_to_n_frames": crop_to_n_frames, "align_self": align_self, "flatten": flatten, "align_across": align_across, diff --git a/src/murfey/workflows/clem/register_preprocessing_results.py b/src/murfey/workflows/clem/register_preprocessing_results.py index 35d4b7d9e..202cc740a 100644 --- a/src/murfey/workflows/clem/register_preprocessing_results.py +++ b/src/murfey/workflows/clem/register_preprocessing_results.py @@ -25,6 +25,9 @@ CLEMTIFFFile, ) from murfey.util.db import Session as MurfeySession +from murfey.util.processing_params import ( + default_clem_align_and_merge_parameters as processing_params, +) from murfey.workflows.clem import get_db_entry from murfey.workflows.clem.align_and_merge import submit_cluster_request @@ -187,9 +190,10 @@ def register_lif_preprocessing_result( series_name=result.series_name, images=image_stacks, metadata=result.metadata, - align_self=None, - flatten="mean", - align_across=None, + crop_to_n_frames=processing_params.crop_to_n_frames, + align_self=processing_params.align_self, + flatten=processing_params.flatten, + align_across=processing_params.align_across, messenger=_transport_object, ) if cluster_response is False: @@ -369,9 +373,10 @@ def register_tiff_preprocessing_result( series_name=result.series_name, images=image_stacks, metadata=result.metadata, - align_self=None, - flatten="mean", - align_across=None, + crop_to_n_frames=processing_params.crop_to_n_frames, + align_self=processing_params.align_self, + flatten=processing_params.flatten, + align_across=processing_params.align_across, messenger=_transport_object, ) if cluster_response is False: