Skip to content

Commit cbd894c

Browse files
authored
Search for user provided initial model (#312)
Appropriately rescale if found
1 parent 08654e7 commit cbd894c

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

src/murfey/server/__init__.py

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import argparse
44
import logging
5+
import math
56
import os
7+
import subprocess
68
import time
79
from datetime import datetime
810
from functools import partial, singledispatch, wraps
@@ -39,7 +41,12 @@
3941
import murfey.server.prometheus as prom
4042
import murfey.server.websocket
4143
from murfey.client.contexts.tomo import _midpoint
42-
from murfey.server.config import get_hostname, get_machine_config, get_microscope
44+
from murfey.server.config import (
45+
MachineConfig,
46+
get_hostname,
47+
get_machine_config,
48+
get_microscope,
49+
)
4350
from murfey.server.murfey_db import url # murfey_db
4451

4552
try:
@@ -1547,6 +1554,95 @@ def _register_class_selection(message: dict, _db=murfey_db, demo: bool = False):
15471554
_db.close()
15481555

15491556

1557+
def _find_initial_model(visit: str, machine_config: MachineConfig) -> Path | None:
1558+
if machine_config.initial_model_search_directory:
1559+
visit_directory = (
1560+
machine_config.rsync_basepath
1561+
/ (machine_config.rsync_module or "data")
1562+
/ str(datetime.now().year)
1563+
/ visit
1564+
)
1565+
possible_models = list(
1566+
(visit_directory / machine_config.initial_model_search_directory).glob(
1567+
"*.mrc"
1568+
)
1569+
)
1570+
if possible_models:
1571+
return sorted(possible_models, key=lambda x: x.stat().st_ctime)[-1]
1572+
return None
1573+
1574+
1575+
def _downscaled_box_size(
1576+
particle_diameter: int, pixel_size: float
1577+
) -> Tuple[int, float]:
1578+
box_size = int(math.ceil(1.2 * particle_diameter))
1579+
box_size = box_size + box_size % 2
1580+
for small_box_pix in (
1581+
48,
1582+
64,
1583+
96,
1584+
128,
1585+
160,
1586+
192,
1587+
256,
1588+
288,
1589+
300,
1590+
320,
1591+
360,
1592+
384,
1593+
400,
1594+
420,
1595+
450,
1596+
480,
1597+
512,
1598+
640,
1599+
768,
1600+
896,
1601+
1024,
1602+
):
1603+
# Don't go larger than the original box
1604+
if small_box_pix > box_size:
1605+
return box_size, pixel_size
1606+
# If Nyquist freq. is better than 8.5 A, use this downscaled box, else step size
1607+
small_box_angpix = pixel_size * box_size / small_box_pix
1608+
if small_box_angpix < 4.25:
1609+
return small_box_pix, small_box_angpix
1610+
raise ValueError(f"Box size is too large: {box_size}")
1611+
1612+
1613+
def _resize_intial_model(
1614+
downscaled_box_size: int,
1615+
downscaled_pixel_size: float,
1616+
input_path: Path,
1617+
output_path: Path,
1618+
executables: Dict[str, str],
1619+
env: Dict[str, str],
1620+
) -> None:
1621+
if executables.get("relion_image_handler"):
1622+
comp_proc = subprocess.run(
1623+
[
1624+
f"{executables['relion_image_handler']}",
1625+
"--i",
1626+
str(input_path),
1627+
"--new_box",
1628+
str(downscaled_box_size),
1629+
"--rescale_angpix",
1630+
str(downscaled_pixel_size),
1631+
"--force_header_angpix",
1632+
"--o",
1633+
str(output_path),
1634+
],
1635+
capture_output=True,
1636+
text=True,
1637+
env=env,
1638+
)
1639+
if comp_proc.returncode:
1640+
logger.error(
1641+
f"Resizing initial model {input_path} failed \n {comp_proc.stdout}"
1642+
)
1643+
return None
1644+
1645+
15501646
def _register_3d_batch(message: dict, _db=murfey_db, demo: bool = False):
15511647
"""Received 3d batch from class selection service"""
15521648
class3d_message = message.get("class3d_message")
@@ -1567,6 +1663,36 @@ def _register_3d_batch(message: dict, _db=murfey_db, demo: bool = False):
15671663
).one()
15681664
other_options = dict(feedback_params)
15691665

1666+
visit_name = (
1667+
_db.exec(
1668+
select(db.ClientEnvironment).where(
1669+
db.ClientEnvironment.session_id == message["session_id"]
1670+
)
1671+
)
1672+
.one()
1673+
.visit
1674+
)
1675+
1676+
provided_initial_model = _find_initial_model(visit_name, machine_config)
1677+
if provided_initial_model:
1678+
rescaled_initial_model_path = (
1679+
provided_initial_model.parent
1680+
/ f"{provided_initial_model.stem}_rescaled{provided_initial_model.suffix}"
1681+
)
1682+
_resize_intial_model(
1683+
*_downscaled_box_size(
1684+
message["particle_diameter"],
1685+
relion_options["angpix"],
1686+
),
1687+
provided_initial_model,
1688+
rescaled_initial_model_path,
1689+
machine_config.external_executables,
1690+
machine_config.external_environment,
1691+
)
1692+
feedback_params.initial_model = str(rescaled_initial_model_path)
1693+
_db.add(feedback_params)
1694+
_db.commit()
1695+
15701696
if feedback_params.hold_class3d:
15711697
# If waiting then save the message
15721698
class3d_params = _db.exec(

src/murfey/server/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class MachineConfig(BaseModel):
5858
upstream_data_tiff_locations: List[str] = ["processed"] # Location of CLEM TIFFs
5959

6060
model_search_directory: str = "processing"
61+
initial_model_search_directory: str = "processing/initial_model"
6162

6263
failure_queue: str = ""
6364
auth_key: str = ""

0 commit comments

Comments
 (0)