88import unittest
99import logging
1010import numpy as np
11+ import odemis
1112
1213from concurrent .futures ._base import CancelledError
13-
1414from odemis import model
15- from odemis .util import testing , timeout
15+ from odemis .util import timeout
1616
1717from odemis .acq .align .goffset import (find_peak_position ,
1818 estimate_goffset_scale ,
19- sparc_auto_grating_offset )
20-
21- import odemis
19+ sparc_auto_grating_offset ,
20+ auto_align_grating_detector_offsets )
2221
2322logging .getLogger ().setLevel (logging .DEBUG )
2423
@@ -59,7 +58,7 @@ def test_find_peak_position_synthetic(self):
5958 """
6059 x = np .arange (200 )
6160 true_center = 83.4
62- spectrum = np .exp (- 0.5 * ((x - true_center )/ 3.0 )** 2 )
61+ spectrum = np .exp (- 0.5 * ((x - true_center ) / 3.0 )** 2 )
6362
6463 peak = find_peak_position (spectrum )
6564 self .assertAlmostEqual (peak , true_center , places = 1 )
@@ -70,7 +69,7 @@ def test_find_peak_position_2d(self):
7069 """
7170 x = np .arange (200 )
7271 true_center = 120.0
73- line = np .exp (- 0.5 * ((x - true_center )/ 4.0 )** 2 )
72+ line = np .exp (- 0.5 * ((x - true_center ) / 4.0 )** 2 )
7473 image = np .tile (line , (50 , 1 ))
7574
7675 peak = find_peak_position (image )
@@ -116,5 +115,90 @@ def test_cancel(self):
116115 pass
117116 self .assertTrue (f .done ())
118117
118+ class TestAutoAlignGratingDetectorOffsets (unittest .TestCase ):
119+
120+ @classmethod
121+ def setUpClass (cls ):
122+ cls .spgr = model .getComponent (role = "spectrograph" )
123+ cls .ccd = model .getComponent (role = "ccd" )
124+ #cls.spccd = model.getComponent(role="sp-ccd")
125+ cls .selector = model .getComponent (role = "spec-det-selector" )
126+
127+ def setUp (self ):
128+ # Speed up acquisition
129+ self .ccd .exposureTime .value = self .ccd .exposureTime .range [0 ]
130+
131+ @timeout (1000 )
132+ def test_single_detector_iteration (self ):
133+ f = auto_align_grating_detector_offsets (spectrograph = self .spgr , detectors = [self .ccd ], selector = self .selector )
134+ res = f .result (timeout = 900 )
135+
136+ n_gratings = len (self .spgr .axes ["grating" ].choices )
137+ n_detectors = 1
138+ expected = n_detectors + (n_gratings - 1 )
139+
140+ self .assertEqual (len (res ), expected )
141+
142+ first_grating = list (self .spgr .axes ["grating" ].choices .keys ())[0 ]
143+ dets_first = [d for (g , d ) in res .keys () if g == first_grating ]
144+
145+ self .assertEqual (len (dets_first ), n_detectors )
146+
147+ def test_multi_detector_iteration (self ):
148+ spccd = model .getComponent (role = "sp-ccd" )
149+ spccd .exposureTime .value = spccd .exposureTime .range [0 ]
150+
151+ detectors = [self .ccd , spccd ]
152+
153+ # run alignment
154+ f = auto_align_grating_detector_offsets (spectrograph = self .spgr , detectors = detectors , selector = self .selector )
155+ res = f .result (timeout = 900 )
156+
157+ # calculate expected results
158+ n_gratings = len (self .spgr .axes ["grating" ].choices )
159+ n_detectors = len (detectors )
160+ expected_count = n_detectors + (n_gratings - 1 )
161+
162+ self .assertEqual (len (res ), expected_count , f"Expected { expected_count } results, got { len (res )} " )
163+
164+ # verify that every detector was used for the first grating
165+ gratings_list = list (self .spgr .axes ["grating" ].choices .keys ())
166+ first_grating = gratings_list [0 ]
167+
168+ dets_for_first_grating = [d for (g , d ) in res .keys () if g == first_grating ]
169+ self .assertEqual (len (dets_for_first_grating ), n_detectors )
170+ self .assertIn (self .ccd .name , dets_for_first_grating )
171+ self .assertIn (spccd .name , dets_for_first_grating )
172+
173+ # verify that only first detector is used for remaining gratings
174+ for g in gratings_list [1 :]:
175+ # Ensure only the first detector (index 0) is present for these gratings
176+ dets_for_this_grating = [d for (grating , d ) in res .keys () if grating == g ]
177+ self .assertEqual (len (dets_for_this_grating ), 1 )
178+ self .assertEqual (dets_for_this_grating [0 ], detectors [0 ].name )
179+
180+ # move to spectral camera
181+ self .selector .moveAbsSync ({"rx" : 1.5707963267948966 })
182+ data = spccd .data .get (asap = False )
183+
184+ # check data is not flat
185+ if data .max () == data .min ():
186+ print ("WARNING: sp-ccd is returning a flat image!" )
187+ else :
188+ print (f"sp-ccd signal range: { data .min ()} to { data .max ()} " )
189+
190+ @timeout (100 )
191+ def test_cancel (self ):
192+ f = auto_align_grating_detector_offsets (spectrograph = self .spgr , detectors = [self .ccd ],)
193+
194+ time .sleep (1 )
195+
196+ cancelled = f .cancel ()
197+ self .assertTrue (cancelled )
198+ self .assertTrue (f .cancelled ())
199+
200+ with self .assertRaises (CancelledError ):
201+ f .result (timeout = 900 )
202+
119203if __name__ == "__main__" :
120- unittest .main ()
204+ unittest .main ()
0 commit comments