Skip to content

Commit

Permalink
Add FormatADSCSMVCetaD to dxtbx. Users persist in converting MicroED
Browse files Browse the repository at this point in the history
data from Ceta-D to SMV format. This helps them out so they don't need
to install the plugin FormatSMVCetaD_TUI.py. Unless they have "CETAD"
in an appropriate place in the header though, they will have to set an
environment variable, FORCE_SMV_AS_CETAD, to activate the class
  • Loading branch information
dagewa committed Nov 7, 2024
1 parent 834cb48 commit 2624a43
Showing 1 changed file with 74 additions and 0 deletions.
74 changes: 74 additions & 0 deletions src/dxtbx/format/FormatADSCSMVCetaD.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Format class to recognise images from a ThermoFisher Ceta D detector that
have been converted to an ADSC-like SMV with useful metadata. We
want to override the beam model to produce an unpolarised beam and to set the
detector gain to something sensible."""

from __future__ import annotations

import os

from dxtbx.format.FormatSMVADSC import FormatSMVADSC
from dxtbx.model.beam import Probe


# We have to inherit from FormatSMVADSC rather than FormatSMV, so that we can
# activate this class with an enivronment variable in cases where the
# BEAMLINE or DETECTOR_SN are not set to anything specific (for example files
# that lie and set BEAMLINE=ALS831).
class FormatSMVADSCCetaD(FormatSMVADSC):
@staticmethod
def understand(image_file):
# Allow this class to override FormatSMVADSC with an environment variable
if "FORCE_SMV_AS_CETAD" in os.environ:
return True

# Otherwise recognise specific instruments from the header
size, header = FormatSMVADSC.get_smv_header(image_file)
check = header.get("BEAMLINE", "") + header.get("DETECTOR_SN", "")
if "CETAD" in check:
return True

return False

def _detector(self):
distance = float(self._header_dictionary["DISTANCE"])
beam_x = float(self._header_dictionary["BEAM_CENTER_X"])
beam_y = float(self._header_dictionary["BEAM_CENTER_Y"])
pixel_size = float(self._header_dictionary["PIXEL_SIZE"])
image_size = (
float(self._header_dictionary["SIZE1"]),
float(self._header_dictionary["SIZE2"]),
)
# Ceta has gain of > 26 and saturates at about 8000.0 for binning=1
# according to Thermo Fisher
binning = {"1x1": 1, "2x2": 2}.get(self._header_dictionary.get("BIN"), 1)
gain = float(self._header_dictionary.get("GAIN", 26.0))
saturation = 8000 * binning**2
trusted_range = (-1000, saturation)
pedestal = float(self._header_dictionary.get("IMAGE_PEDESTAL", 0))

return self._detector_factory.simple(
"PAD",
distance,
(beam_y, beam_x),
"+x",
"-y",
(pixel_size, pixel_size),
image_size,
trusted_range,
[],
gain=gain,
pedestal=pedestal,
)

def _beam(self):
"""Return a simple model for an unpolarised beam."""

wavelength = float(self._header_dictionary["WAVELENGTH"])
return self._beam_factory.make_polarized_beam(
sample_to_source=(0.0, 0.0, 1.0),
wavelength=wavelength,
polarization=(0, 1, 0),
polarization_fraction=0.5,
probe=Probe.electron,
)

0 comments on commit 2624a43

Please sign in to comment.