Skip to content

Commit

Permalink
Add ispyb.model.detector.Detector model (#100)
Browse files Browse the repository at this point in the history
Provide access from DataCollection model via detector attribute.

Co-authored-by: Markus Gerstel <markus.gerstel@diamond.ac.uk>
  • Loading branch information
rjgildea and Anthchirp committed May 19, 2020
1 parent 4bb6496 commit 06a5506
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 2 deletions.
10 changes: 8 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ object-like representations of database entries:
.. autoclass:: ispyb.model.interface.ObjectModelMixIn
:members:

DataCollection
==============
DataCollection and DataCollectionGroup
======================================

.. automodule:: ispyb.model.datacollection
:members:

Detector
========

.. automodule:: ispyb.model.detector
:members:

ProcessingJob
=============

Expand Down
18 changes: 18 additions & 0 deletions ispyb/model/__future__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ def __exit__(cm, *args):
_get_linked_image_quality_indicators_for_data_collection
)

import ispyb.model.detector

ispyb.model.detector.Detector.reload = _get_detector


def _get_autoprocprogram(self):
# https://jira.diamond.ac.uk/browse/SCI-7414
Expand Down Expand Up @@ -454,6 +458,20 @@ def _get_image_quality_indicators_for_dcid(self):
self._data = cursor.fetchall()


def _get_detector(self):
with _db_cc() as cursor:
cursor.run(
"SELECT detectorType, detectorManufacturer, detectorModel, "
"detectorPixelSizeHorizontal, detectorPixelSizeVertical, "
"detectorSerialNumber, detectorDistanceMin, detectorDistanceMax, "
"sensorThickness, numberOfPixelsX, numberOfPixelsY "
"FROM Detector "
"WHERE detectorId = %s",
self._detectorid,
)
self._data = cursor.fetchone()


def test_connection():
"""A test function to verify that the database connection is alive."""
with _db_cc() as cursor:
Expand Down
19 changes: 19 additions & 0 deletions ispyb/model/datacollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import ispyb.model
import ispyb.model.container
import ispyb.model.detector
import ispyb.model.gridinfo


Expand All @@ -23,6 +24,7 @@ def __init__(self, dcid, db_area, preload=None):
:return: A DataCollection object representing the database entry for
the specified DataCollectionID
"""
self._cache_detector = None
self._cache_group = None
self._db = db_area
self._dcid = int(dcid)
Expand Down Expand Up @@ -61,6 +63,17 @@ def image_quality(self):
this DC."""
raise NotImplementedError("TODO: Not implemented yet")

@property
def detector(self):
"""Returns the Detector object associated with this DC."""
if not self.detector_id:
return None
if self._cache_detector is None:
self._cache_detector = ispyb.model.detector.Detector(
self.detector_id, self._db.conn
)
return self._cache_detector

@property
def file_template_full(self):
"""Template for file names with full directory path. As with file_template
Expand Down Expand Up @@ -130,6 +143,12 @@ def __str__(self):
"detectorDistance",
"Distance from the sample to the detector in mm",
),
(
"detector_id",
"detectorId",
"A unique identifier for the detector used in this acquisition. You can access the "
"detector model object via .detector directly.",
),
(
"detector_2theta",
"detector2Theta",
Expand Down
100 changes: 100 additions & 0 deletions ispyb/model/detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# coding: utf-8
from __future__ import absolute_import, division, print_function

import ispyb
import ispyb.model


class Detector(ispyb.model.DBCache):
"""An object representing a Detector database entry. The object
lazily accesses the underlying database when necessary and exposes record
data as python attributes.
"""

def __init__(self, detectorid, db_conn, preload=None):
"""Create a Detector object for a defined detectorid. Requires
a database connection object exposing further data access methods.
:param detectorid: detectorId
:param db_conn: ISPyB database connection object
:return: A Detector object representing the database entry for
the specified detectorId
"""
self._db = db_conn
self._detectorid = int(detectorid)
if preload:
self._data = preload

def reload(self):
"""Load/update information from the database."""
raise NotImplementedError()

@property
def id(self):
"Returns the detectorId"
return self._detectorid

def __repr__(self):
"""Returns an object representation, including the DetectorID,
the database connection interface object, and the cache status."""
return "<Detector #%d (%s), %r>" % (
self._detectorid,
"cached" if self.cached else "uncached",
self._db,
)

def __str__(self):
"""Returns a pretty-printed object representation."""
if not self.cached:
return "Detector id: %d (not yet loaded from database)" % (self._detectorid)
return (
"\n".join(
(
"Detector",
" id : {0.id}",
" manufacturer : {0.manufacturer}",
" model : {0.model}",
" serial_number : {0.serial_number}",
" pixel_size_horizontal : {0.pixel_size_horizontal}",
" pixel_size_vertical : {0.pixel_size_vertical}",
" pixels_x : {0.pixels_x}",
" pixels_y : {0.pixels_y}",
" distance_min : {0.distance_min}",
" distance_max : {0.distance_max}",
)
)
).format(self)


ispyb.model.add_properties(
Detector,
(
("type", "detectorType", "The detector type, e.g. 'Photon Counting' or 'CCD'"),
("manufacturer", "detectorManufacturer", "The detector manufacturer"),
("model", "detectorModel", "The detector model"),
(
"pixel_size_horizontal",
"detectorPixelSizeHorizontal",
"The pixel size in the horizonal direction (µm)",
),
(
"pixel_size_vertical",
"detectorPixelSizeVertical",
"The pixel size in the vertical direction (µm)",
),
("serial_number", "detectorSerialNumber", "The detector serial number"),
(
"distance_min",
"detectorDistanceMin",
"The minimum sample-detector distance (mm)",
),
(
"distance_max",
"detectorDistanceMax",
"The maximum sample-detector distance (mm)",
),
("sensor_thickness", "sensorThickness", "The detector sensor thickness (µm)"),
("pixels_x", "numberOfPixelsX", "Detector number of pixels in x"),
("pixels_y", "numberOfPixelsY", "Detector number of pixels in y"),
),
)
5 changes: 5 additions & 0 deletions ispyb/model/interface.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import absolute_import, division, print_function

import ispyb.model.datacollection
import ispyb.model.detector
import ispyb.model.processingprogram
import ispyb.model.processingjob
import ispyb.model.screening
Expand Down Expand Up @@ -64,3 +65,7 @@ def get_screening_strategy_sub_wedge(self, screening_strategy_sub_wedge_id):
return ispyb.model.screening.ScreeningStrategySubWedge(
screening_strategy_sub_wedge_id, self
)

def get_detector(self, detectorid):
"""Return a Detector object representing a Detector database entry."""
return ispyb.model.detector.Detector(detectorid, self)
37 changes: 37 additions & 0 deletions tests/model/test_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import absolute_import, division, print_function
import ispyb.model.detector
import ispyb.model.__future__


def test_detector(testdb, testconfig):
ispyb.model.__future__.enable(testconfig)
detector = testdb.get_detector(4)
assert str(detector) == "Detector id: 4 (not yet loaded from database)"
detector.load()
assert detector.id == 4
assert detector.manufacturer == "In-house"
assert detector.model == "Excalibur"
assert detector.serial_number == "1109-434"
assert detector.distance_min == 100
assert detector.distance_max == 300
assert (
str(detector)
== """\
Detector
id : 4
manufacturer : In-house
model : Excalibur
serial_number : 1109-434
pixel_size_horizontal : None
pixel_size_vertical : None
pixels_x : None
pixels_y : None
distance_min : 100.0
distance_max : 300.0"""
)


def test_dc_detector(testdb, testconfig):
ispyb.model.__future__.enable(testconfig)
dc = testdb.get_data_collection(1066786)
assert dc.detector is None

0 comments on commit 06a5506

Please sign in to comment.