Skip to content

Commit

Permalink
Add format class for I19-2 Eiger with DAC shadow (#481)
Browse files Browse the repository at this point in the history
Also, Remove redundant file mode "r". This has been the default since
h5py 3.0 and DIALS/DXTBX ship with >=3.1.
  • Loading branch information
benjaminhwilliams authored Feb 10, 2022
1 parent 6fdca14 commit 5cf1b92
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
1 change: 1 addition & 0 deletions newsfragments/481.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``FormatNXmxI19_2``: Allow data from beamline I19-2 at Diamond Light Source to be processed with optional masking of the beamline's standard diamond anvil pressure cell with a 76° aperture.
54 changes: 50 additions & 4 deletions src/dxtbx/format/FormatNXmx.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
from __future__ import annotations

import math

import h5py

from libtbx import Auto

import dxtbx.nexus
from dxtbx.format.FormatNexus import FormatNexus
from dxtbx.masking import GoniometerMaskerFactory


class FormatNXmx(FormatNexus):
"""Read NXmx-flavour NeXus-format HDF5 data."""

_cached_file_handle = None

@staticmethod
def understand(image_file):
with h5py.File(image_file, "r", swmr=True) as handle:
"""This format class currently only applies to beamline I19-2 at DLS."""
with h5py.File(image_file, swmr=True) as handle:
name = dxtbx.nexus.nxmx.h5str(FormatNXmx.get_instrument_name(handle))
# Temporarily restrict this to I19-2 while developing
if name and "I19-2" in name:
return True
return False
Expand All @@ -26,7 +32,7 @@ def __init__(self, image_file, **kwargs):
def _start(self):
self._static_mask = None

with h5py.File(self._image_file, "r", swmr=True) as fh:
with h5py.File(self._image_file, swmr=True) as fh:
nxmx = dxtbx.nexus.nxmx.NXmx(fh)
nxsample = nxmx.entries[0].samples[0]
nxinstrument = nxmx.entries[0].instruments[0]
Expand Down Expand Up @@ -61,7 +67,7 @@ def get_static_mask(self, index=None, goniometer=None):

def get_raw_data(self, index):
if self._cached_file_handle is None:
self._cached_file_handle = h5py.File(self._image_file, "r", swmr=True)
self._cached_file_handle = h5py.File(self._image_file, swmr=True)

nxmx = dxtbx.nexus.nxmx.NXmx(self._cached_file_handle)
nxdata = nxmx.entries[0].data[0]
Expand All @@ -79,3 +85,43 @@ def get_raw_data(self, index):
d1d.set_selected(d1d == top - 1, -1)
d1d.set_selected(d1d == top - 2, -2)
return raw_data


class FormatNXmxI19_2(FormatNXmx):
"""
Read NXmx-flavour data from beamline I19-2 at Diamond Light Source.
Include the option of dynamic shadowing of the standard I19-2 diamond anvil
pressure cell with a 76° conical aperture.
"""

@staticmethod
def understand(image_file):
"""This format class applies if the instrument name contains 'I19-2'."""
with h5py.File(image_file, swmr=True) as handle:
name = dxtbx.nexus.nxmx.h5str(FormatNXmx.get_instrument_name(handle))
if name and "I19-2" in name:
return True
return False

@staticmethod
def has_dynamic_shadowing(**kwargs):
"""Check if dynamic shadowing should be applied for a diamond anvil cell."""
dynamic_shadowing = kwargs.get("dynamic_shadowing", False)
if dynamic_shadowing in (Auto, "Auto"):
return False
return dynamic_shadowing

def __init__(self, image_file, **kwargs):
"""Initialise the image structure from the given file."""
self._dynamic_shadowing = self.has_dynamic_shadowing(**kwargs)
super().__init__(image_file, **kwargs)

def get_goniometer_shadow_masker(self, goniometer=None):
"""Apply the dynamic mask for a diamond anvil cell with a 76° aperture."""
if goniometer is None:
goniometer = self.get_goniometer()

return GoniometerMaskerFactory.diamond_anvil_cell(
goniometer, cone_opening_angle=math.radians(76)
)

0 comments on commit 5cf1b92

Please sign in to comment.