1111import time
1212from datetime import datetime
1313from pathlib import Path
14- from typing import Iterator , Optional
14+ from typing import Iterator , Optional , Union , Literal
1515import pydantic
1616
1717import gemmi
1818import numpy as np
1919import workflows .recipe
20- from pydantic import BaseModel , ValidationError
20+ from pydantic import BaseModel , ValidationError , Field
2121from rich .logging import RichHandler
2222from workflows .services .common_service import CommonService
2323
@@ -45,13 +45,15 @@ class PiaRequest(BaseModel):
4545 d_min : float | None = None
4646 d_max : float | None = None
4747 unit_cell : tuple [float , float , float , float , float , float ] | None = None
48+ detector : str = "Eiger16M"
4849
4950 @pydantic .validator ("unit_cell" , pre = True )
5051 def check_unit_cell (cls , v ):
5152 if not v :
5253 return None
5354 orig_v = v
5455 if isinstance (v , str ):
56+
5557 v = v .replace ("," , " " ).split ()
5658 v = [float (v ) for v in v ]
5759 try :
@@ -61,19 +63,58 @@ def check_unit_cell(cls, v):
6163 return v
6264
6365
64- class DetectorGeometry (BaseModel ):
66+ class DetectorParameters (BaseModel ):
67+ type : str
68+ thickness : float
69+ material : str
70+ pixel_size_x : float
71+ pixel_size_y : float
72+ image_size_x : int
73+ image_size_y : int
74+ _mu_cache : dict = {}
75+
76+ class Config :
77+ extra = "forbid" # Don't allow instantiation of this base class
78+
79+ def calculate_mu (self , wavelength : float ) -> float :
80+ if wavelength not in self ._mu_cache :
81+ self ._mu_cache [wavelength ] = calculate_mu_from_parameters (
82+ self .thickness , self .material , wavelength
83+ )
84+ return self ._mu_cache [wavelength ]
85+
86+
87+ class Eiger16M (DetectorParameters ):
88+ type : Literal ["Eiger16M" ]
89+ thickness : float = 0.45
90+ material : str = "Si" # atomic no 14
6591 pixel_size_x : float = 0.075 # Default value for Eiger
6692 pixel_size_y : float = 0.075 # Default value for Eiger
6793 image_size_x : int = 2068 # Default value for Eiger
6894 image_size_y : int = 2162 # Default value for Eiger
95+ mu : float = 3.9220781 # Default value for Eiger (Silicon) #FIXME replace with mu calculation
96+
97+
98+ class Eiger9M (DetectorParameters ):
99+ type : Literal ["Eiger9M" ]
100+ thickness : float = 0.45
101+ material : str = "Si"
102+ pixel_size_x : float = 0.075 # Default value for Eiger
103+ pixel_size_y : float = 0.075 # Default value for Eiger
104+ image_size_x : int = 1000 # Default value for Eiger9M #FIXME
105+ image_size_y : int = 1000 # Default value for Eiger9M #FIXME
106+ mu : float = 3.9220781 # Default value for Eiger (Silicon) #FIXME replace with mu calculation
107+
108+ class DetectorGeometry (BaseModel ):
69109 distance : float
70110 beam_center_x : float
71111 beam_center_y : float
72- thickness : float = 0.45 # Default value for Eiger (Silicon)
73- mu : float = 3.9220781 # Default value for Eiger (Silicon)
112+ detector : Union [Eiger9M , Eiger16M ] = Field (..., discriminator = "type" )
74113
75114 def to_json (self ):
76- return json .dumps (self .dict (), indent = 4 )
115+ d = self .dict ()
116+ d .update (self .detector .dict ())
117+ return json .dumps (d , indent = 4 )
77118
78119
79120def _setup_rich_logging (level = logging .DEBUG ):
@@ -231,6 +272,7 @@ def gpu_per_image_analysis(
231272 distance = parameters .detector_distance ,
232273 beam_center_x = parameters .xBeam ,
233274 beam_center_y = parameters .yBeam ,
275+ detector = {"type" :parameters .detector },
234276 )
235277 self .log .debug ("{detector_geometry.to_json()=}" )
236278 except ValidationError as e :
@@ -245,16 +287,18 @@ def gpu_per_image_analysis(
245287 np .array (cell .orth .mat , dtype = "float32" ), (3 , 3 )
246288 ) ## Cell as an orthogonalisation matrix
247289 ## convert beam centre to correct units (given in mm, want in px).
290+ px_size_x = detector_geometry .detector .pixel_size_x
291+ px_size_y = detector_geometry .detector .pixel_size_y
248292 self .indexer .panel = ffs .index .make_panel (
249293 detector_geometry .distance ,
250- detector_geometry .beam_center_x / detector_geometry . pixel_size_x ,
251- detector_geometry .beam_center_y / detector_geometry . pixel_size_y ,
252- detector_geometry . pixel_size_x ,
253- detector_geometry . pixel_size_y ,
254- detector_geometry .image_size_x ,
255- detector_geometry .image_size_y ,
256- detector_geometry .thickness ,
257- detector_geometry .mu ,
294+ detector_geometry .beam_center_x / px_size_x ,
295+ detector_geometry .beam_center_y / px_size_y ,
296+ px_size_x ,
297+ px_size_y ,
298+ detector_geometry .detector . image_size_x ,
299+ detector_geometry .detector . image_size_y ,
300+ detector_geometry .detector . thickness ,
301+ detector_geometry .detector . mu ,
258302 )
259303 self .indexer .wavelength = parameters .wavelength
260304 self .output_for_index = (
0 commit comments