88import unittest
99import logging
1010import numpy as np
11+ import odemis
1112
1213from concurrent .futures ._base import CancelledError
13-
1414from odemis import model
1515from odemis .util import testing , 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 )
@@ -115,6 +114,94 @@ def test_cancel(self):
115114 except :
116115 pass
117116 self .assertTrue (f .done ())
117+
118+
119+
120+ class TestAutoAlignGratingDetectorOffsets (unittest .TestCase ):
121+
122+ @classmethod
123+ def setUpClass (cls ):
124+ cls .spgr = model .getComponent (role = "spectrograph" )
125+ cls .ccd = model .getComponent (role = "ccd" )
126+ #cls.spccd = model.getComponent(role="sp-ccd")
127+ cls .selector = model .getComponent (role = "spec-det-selector" )
128+
129+ def setUp (self ):
130+ # Speed up acquisition
131+ self .ccd .exposureTime .value = self .ccd .exposureTime .range [0 ]
132+
133+ @timeout (1000 )
134+ def test_single_detector_iteration (self ):
135+ f = auto_align_grating_detector_offsets (spectrograph = self .spgr , detectors = [self .ccd ], selector = self .selector )
136+ res = f .result (timeout = 900 )
137+
138+ n_gratings = len (self .spgr .axes ["grating" ].choices )
139+ n_detectors = 1
140+ expected = n_detectors + (n_gratings - 1 )
141+
142+ self .assertEqual (len (res ), expected )
143+
144+ first_grating = list (self .spgr .axes ["grating" ].choices .keys ())[0 ]
145+ dets_first = [d for (g , d ) in res .keys () if g == first_grating ]
146+
147+ self .assertEqual (len (dets_first ), n_detectors )
148+
149+ def test_multi_detector_iteration (self ):
150+ spccd = model .getComponent (role = "sp-ccd" )
151+ spccd .exposureTime .value = spccd .exposureTime .range [0 ]
152+
153+ detectors = [self .ccd , spccd ]
154+
155+ # run alignment
156+ f = auto_align_grating_detector_offsets (spectrograph = self .spgr , detectors = detectors , selector = self .selector )
157+ res = f .result (timeout = 900 )
158+
159+ # calculate expected results
160+ n_gratings = len (self .spgr .axes ["grating" ].choices )
161+ n_detectors = len (detectors )
162+ expected_count = n_detectors + (n_gratings - 1 )
163+
164+ self .assertEqual (len (res ), expected_count , f"Expected { expected_count } results, got { len (res )} " )
165+
166+ # verify that every detector was used for the first grating
167+ gratings_list = list (self .spgr .axes ["grating" ].choices .keys ())
168+ first_grating = gratings_list [0 ]
169+
170+ dets_for_first_grating = [d for (g , d ) in res .keys () if g == first_grating ]
171+ self .assertEqual (len (dets_for_first_grating ), n_detectors )
172+ self .assertIn (self .ccd .name , dets_for_first_grating )
173+ self .assertIn (spccd .name , dets_for_first_grating )
174+
175+ # verify that only first detector is used for remaining gratings
176+ for g in gratings_list [1 :]:
177+ # Ensure only the first detector (index 0) is present for these gratings
178+ dets_for_this_grating = [d for (grating , d ) in res .keys () if grating == g ]
179+ self .assertEqual (len (dets_for_this_grating ), 1 )
180+ self .assertEqual (dets_for_this_grating [0 ], detectors [0 ].name )
181+
182+ # move to spectral camera
183+ self .selector .moveAbsSync ({"rx" : 1.5707963267948966 })
184+ data = spccd .data .get (asap = False )
185+
186+ # check data is not flat
187+ if data .max () == data .min ():
188+ print ("WARNING: sp-ccd is returning a flat image!" )
189+ else :
190+ print (f"sp-ccd signal range: { data .min ()} to { data .max ()} " )
191+
192+ @timeout (100 )
193+ def test_cancel (self ):
194+ f = auto_align_grating_detector_offsets (spectrograph = self .spgr , detectors = [self .ccd ],)
195+
196+ time .sleep (1 )
197+
198+ cancelled = f .cancel ()
199+ self .assertTrue (cancelled )
200+ self .assertTrue (f .cancelled ())
201+
202+ with self .assertRaises (CancelledError ):
203+ f .result (timeout = 900 )
204+
118205
119206if __name__ == "__main__" :
120- unittest .main ()
207+ unittest .main ()
0 commit comments