Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

Commit

Permalink
Move the basic parameter model components to MXB (#1537)
Browse files Browse the repository at this point in the history
* add mxb workspace

* move parameter components to mx-bluesky

* remove dependency on semver

* update mxb pin
  • Loading branch information
dperl-dls committed Aug 20, 2024
1 parent 2d47e50 commit 942706a
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 210 deletions.
23 changes: 23 additions & 0 deletions .vscode/hyperion-mx-bluesky.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"folders": [
{
"path": ".."
},
{
"path": "../../dodal"
},
{
"path": "../../mx-bluesky"
}
],
"settings": {
"python.languageServer": "Pylance",
"terminal.integrated.gpuAcceleration": "off",
"esbonio.sphinx.confDir": "",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.formatting.provider": "none",
"python.analysis.enablePytestExtra": false
}
}
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ install_requires =
pyzmq
scanspec
scipy
semver
#
# These dependencies may be issued as pre-release versions and should have a pin constraint
# as by default pip-install will not upgrade to a pre-release.
Expand All @@ -41,6 +40,7 @@ install_requires =
ophyd-async >= 0.3a5
bluesky >= 1.13.0a4
blueapi >= 0.4.3-rc1
mx-bluesky @ git+https://github.com/DiamondLightSource/mx-bluesky.git@0492e92f75eefa8885be59dde3eff323c1ea81c2
dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git

[options.entry_points]
Expand Down
2 changes: 1 addition & 1 deletion src/hyperion/experiment_plans/oav_snapshot_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from dodal.devices.oav.oav_detector import OAV
from dodal.devices.oav.oav_parameters import OAVParameters
from dodal.devices.smargon import Smargon
from mx_bluesky.parameters import WithSnapshot

from hyperion.device_setup_plans.setup_oav import setup_general_oav_params
from hyperion.parameters.components import WithSnapshot
from hyperion.parameters.constants import DocDescriptorNames

OAV_SNAPSHOT_SETUP_GROUP = "oav_snapshot_setup"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any, Callable, Optional

from mx_bluesky.parameters import IspybExperimentType

from hyperion.external_interaction.callbacks.common.ispyb_mapping import (
populate_data_collection_group,
populate_remaining_data_collection_info,
Expand All @@ -23,7 +25,6 @@
StoreInIspyb,
)
from hyperion.log import ISPYB_LOGGER, set_dcgid_tag
from hyperion.parameters.components import IspybExperimentType
from hyperion.parameters.constants import CONST
from hyperion.parameters.rotation import RotationScan

Expand Down
190 changes: 7 additions & 183 deletions src/hyperion/parameters/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
import datetime
import json
from abc import abstractmethod
from enum import StrEnum
from pathlib import Path
from typing import Sequence, SupportsInt, TypeVar
from typing import TypeVar

from dodal.devices.aperturescatterguard import AperturePositionGDANames
from dodal.devices.detector import (
DetectorParams,
TriggerMode,
)
from mx_bluesky.parameters import DiffractionExperiment, ParameterVersion, WithSample
from numpy.typing import NDArray
from pydantic import BaseModel, Extra, Field, root_validator, validator
from scanspec.core import AxesPoints
from semver import Version
from pydantic import BaseModel, Extra, Field, validator

from hyperion.external_interaction.config_server import FeatureFlags
from hyperion.external_interaction.ispyb.ispyb_dataclass import (
Expand All @@ -26,85 +22,9 @@
T = TypeVar("T")


class ParameterVersion(Version):
@classmethod
def _parse(cls, version):
if isinstance(version, cls):
return version
return cls.parse(version)

@classmethod
def __get_validators__(cls):
"""Return a list of validator methods for pydantic models."""
yield cls._parse

@classmethod
def __modify_schema__(cls, field_schema):
"""Inject/mutate the pydantic field schema in-place."""
field_schema.update(examples=["1.0.2", "2.15.3-alpha", "21.3.15-beta+12345"])


PARAMETER_VERSION = ParameterVersion.parse("5.0.0")


class RotationAxis(StrEnum):
OMEGA = "omega"
PHI = "phi"
CHI = "chi"
KAPPA = "kappa"


class XyzAxis(StrEnum):
X = "sam_x"
Y = "sam_y"
Z = "sam_z"


class IspybExperimentType(StrEnum):
# Enum values from ispyb column data type
SAD = "SAD" # at or slightly above the peak
SAD_INVERSE_BEAM = "SAD - Inverse Beam"
OSC = "OSC" # "native" (in the absence of a heavy atom)
COLLECT_MULTIWEDGE = (
"Collect - Multiwedge" # "poorly determined" ~ EDNA complex strategy???
)
MAD = "MAD"
HELICAL = "Helical"
MULTI_POSITIONAL = "Multi-positional"
MESH = "Mesh"
BURN = "Burn"
MAD_INVERSE_BEAM = "MAD - Inverse Beam"
CHARACTERIZATION = "Characterization"
DEHYDRATION = "Dehydration"
TOMO = "tomo"
EXPERIMENT = "experiment"
EM = "EM"
PDF = "PDF"
PDF_BRAGG = "PDF+Bragg"
BRAGG = "Bragg"
SINGLE_PARTICLE = "single particle"
SERIAL_FIXED = "Serial Fixed"
SERIAL_JET = "Serial Jet"
STANDARD = "Standard" # Routine structure determination experiment
TIME_RESOLVED = "Time Resolved" # Investigate the change of a system over time
DLS_ANVIL_HP = "Diamond Anvil High Pressure" # HP sample environment pressure cell
CUSTOM = "Custom" # Special or non-standard data collection
XRF_MAP = "XRF map"
ENERGY_SCAN = "Energy scan"
XRF_SPECTRUM = "XRF spectrum"
XRF_MAP_XAS = "XRF map xas"
MESH_3D = "Mesh3D"
SCREENING = "Screening"
STILL = "Still"
SSX_CHIP = "SSX-Chip"
SSX_JET = "SSX-Jet"

# Aliases for historic hyperion experiment type mapping
ROTATION = "SAD"
GRIDSCAN_2D = "mesh"
GRIDSCAN_3D = "Mesh3D"


class HyperionParameters(BaseModel):
class Config:
arbitrary_types_allowed = True
Expand Down Expand Up @@ -140,128 +60,32 @@ def from_json(cls, input: str | None, *, allow_extras: bool = False):
return params


class WithSnapshot(BaseModel):
snapshot_directory: Path
snapshot_omegas_deg: list[float] | None

@property
def take_snapshots(self) -> bool:
return bool(self.snapshot_omegas_deg)


class DiffractionExperiment(HyperionParameters, WithSnapshot):
class HyperionDiffractionExperiment(DiffractionExperiment, HyperionParameters):
"""For all experiments which use beam"""

visit: str = Field(min_length=1)
file_name: str = Field(pattern=r"[\w]{2}[\d]+-[\d]+")
exposure_time_s: float = Field(gt=0)
comment: str = Field(default="")
beamline: str = Field(default=CONST.I03.BEAMLINE, pattern=r"BL\d{2}[BIJS]")
beamline: str = Field(default=CONST.I03.BEAMLINE, regex=r"BL\d{2}[BIJS]")
insertion_prefix: str = Field(
default=CONST.I03.INSERTION_PREFIX, pattern=r"SR\d{2}[BIJS]"
default=CONST.I03.INSERTION_PREFIX, regex=r"SR\d{2}[BIJS]"
)
det_dist_to_beam_converter_path: str = Field(
default=CONST.PARAM.DETECTOR.BEAM_XY_LUT_PATH
)
zocalo_environment: str = Field(default=CONST.ZOCALO_ENV)
trigger_mode: TriggerMode = Field(default=TriggerMode.FREE_RUN)
detector_distance_mm: float | None = Field(default=None, gt=0)
demand_energy_ev: float | None = Field(default=None, gt=0)
run_number: int | None = Field(default=None, ge=0)
selected_aperture: AperturePositionGDANames | None = Field(default=None)
transmission_frac: float = Field(default=0.1)
ispyb_experiment_type: IspybExperimentType
storage_directory: str

@root_validator(pre=True)
def validate_snapshot_directory(cls, values):
snapshot_dir = values.get(
"snapshot_directory", Path(values["storage_directory"], "snapshots")
)
values["snapshot_directory"] = (
snapshot_dir if isinstance(snapshot_dir, Path) else Path(snapshot_dir)
)
return values

@property
def visit_directory(self) -> Path:
return (
Path(CONST.I03.BASE_DATA_DIR) / str(datetime.date.today().year) / self.visit
)

@property
def num_images(self) -> int:
return 0

@property
@abstractmethod
def detector_params(self) -> DetectorParams: ...

@property
@abstractmethod
def ispyb_params(self) -> IspybParams: # Soon to remove
...


class WithScan(BaseModel):
"""For experiments where the scan is known"""

@property
@abstractmethod
def scan_points(self) -> AxesPoints: ...

@property
@abstractmethod
def num_images(self) -> int: ...


class SplitScan(BaseModel):
@property
@abstractmethod
def scan_indices(self) -> Sequence[SupportsInt]:
"""Should return the first index of each scan (i.e. for each nexus file)"""
...


class WithSample(BaseModel):
sample_id: int
sample_puck: int | None = None
sample_pin: int | None = None


class DiffractionExperimentWithSample(DiffractionExperiment, WithSample): ...


class WithOavCentring(BaseModel):
oav_centring_file: str = Field(default=CONST.I03.OAV_CENTRING_FILE)


class OptionalXyzStarts(BaseModel):
x_start_um: float | None = None
y_start_um: float | None = None
z_start_um: float | None = None


class XyzStarts(BaseModel):
x_start_um: float
y_start_um: float
z_start_um: float

def _start_for_axis(self, axis: XyzAxis) -> float:
match axis:
case XyzAxis.X:
return self.x_start_um
case XyzAxis.Y:
return self.y_start_um
case XyzAxis.Z:
return self.z_start_um


class OptionalGonioAngleStarts(BaseModel):
omega_start_deg: float | None = None
phi_start_deg: float | None = None
chi_start_deg: float | None = None
kappa_start_deg: float | None = None
class DiffractionExperimentWithSample(HyperionDiffractionExperiment, WithSample): ...


class TemporaryIspybExtras(BaseModel):
Expand Down
19 changes: 10 additions & 9 deletions src/hyperion/parameters/gridscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,29 @@
PandAGridScanParams,
ZebraGridScanParams,
)
from pydantic import Field, PrivateAttr
from scanspec.core import Path as ScanPath
from scanspec.specs import Line, Static

from hyperion.external_interaction.ispyb.ispyb_dataclass import (
GridscanIspybParams,
)
from hyperion.parameters.components import (
DiffractionExperimentWithSample,
from mx_bluesky.parameters import (
IspybExperimentType,
OptionalGonioAngleStarts,
SplitScan,
WithOavCentring,
WithScan,
XyzStarts,
)
from pydantic import Field, PrivateAttr
from scanspec.core import Path as ScanPath
from scanspec.specs import Line, Static

from hyperion.external_interaction.ispyb.ispyb_dataclass import (
GridscanIspybParams,
)
from hyperion.parameters.components import DiffractionExperimentWithSample
from hyperion.parameters.constants import CONST, I03Constants


class GridCommon(
DiffractionExperimentWithSample, OptionalGonioAngleStarts, WithOavCentring
):
oav_centring_file: str = Field(default=CONST.I03.OAV_CENTRING_FILE)
grid_width_um: float = Field(default=CONST.PARAM.GRIDSCAN.WIDTH_UM)
exposure_time_s: float = Field(default=CONST.PARAM.GRIDSCAN.EXPOSURE_TIME_S)
use_roi_mode: bool = Field(default=CONST.PARAM.GRIDSCAN.USE_ROI)
Expand Down
14 changes: 8 additions & 6 deletions src/hyperion/parameters/rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
from dodal.devices.zebra import (
RotationDirection,
)
from mx_bluesky.parameters import (
IspybExperimentType,
OptionalGonioAngleStarts,
OptionalXyzStarts,
RotationAxis,
SplitScan,
WithScan,
)
from pydantic import Field, root_validator
from scanspec.core import AxesPoints
from scanspec.core import Path as ScanPath
Expand All @@ -21,13 +29,7 @@
from hyperion.external_interaction.ispyb.ispyb_dataclass import RotationIspybParams
from hyperion.parameters.components import (
DiffractionExperimentWithSample,
IspybExperimentType,
OptionalGonioAngleStarts,
OptionalXyzStarts,
RotationAxis,
SplitScan,
TemporaryIspybExtras,
WithScan,
)
from hyperion.parameters.constants import CONST, I03Constants

Expand Down
Loading

0 comments on commit 942706a

Please sign in to comment.