Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/implementors/tomo/tomoscanwithroi.py: 0%
103 statements
« prev ^ index » next coverage.py v7.6.5, created at 2024-11-15 02:12 +0000
« prev ^ index » next coverage.py v7.6.5, created at 2024-11-15 02:12 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
4from __future__ import annotations
6import gevent
7import logging
8from marshmallow import fields, validate
10from tomo.fulltomo import FullFieldTomo
11from . import tomo_helper
12from bliss.common.standard import mv
14from daiquiri.core.schema.validators import OneOf
15from daiquiri.core.components import (
16 ComponentActor,
17 ComponentActorSchema,
18 ComponentActorKilled,
19)
22_logger = logging.getLogger(__name__)
25class TomoscanwithroiSchema(ComponentActorSchema):
26 sampleid = fields.Int(
27 required=True,
28 metadata={"title": "Collection"},
29 )
30 dataset_name = fields.Str(
31 required=True,
32 metadata={"title": "Dataset"},
33 )
34 scan_type = OneOf(
35 ["Continuous", "Step"],
36 dump_default="Continuous",
37 metadata={"title": "Scan type"},
38 )
39 start_pos = fields.Float(
40 dump_default=0,
41 metadata={"title": "Start angle", "unit": "deg"},
42 )
43 range = fields.Float(
44 dump_default=360,
45 metadata={"title": "Range angle", "unit": "deg"},
46 )
47 tomo_n = fields.Int(
48 dump_default=360,
49 validate=validate.Range(min=1, max=999999),
50 metadata={"title": "Nb steps"},
51 )
52 n_dark = fields.Int(
53 dump_default=1,
54 validate=validate.Range(min=0, max=999999),
55 metadata={"title": "Nb darks"},
56 )
57 n_flat = fields.Int(
58 dump_default=1,
59 validate=validate.Range(min=0, max=999999),
60 metadata={"title": "Nb flats"},
61 )
62 expo_time = fields.Float(
63 validate=validate.Range(min=0.001, max=10),
64 dump_default=None,
65 metadata={"title": "Exposure time", "unit": "s"},
66 )
67 use_sinogram = fields.Bool(
68 dump_default=True,
69 metadata={
70 "title": "Sinogram",
71 "description": "Generate or not a sinogram during the scan",
72 },
73 )
74 axis_displacement = fields.Int(
75 dump_default=0,
76 validate=validate.Range(min=-300, max=300),
77 metadata={
78 "title": "Axis displacement",
79 "unit": "%",
80 "description": "0% = centered, 100% = half detector width",
81 },
82 )
83 comment = fields.Str(
84 dump_default="",
85 metadata={
86 "title": "Comment",
87 },
88 )
89 x = fields.Float(
90 dump_default=0,
91 allow_none=True,
92 metadata={"title": "X", "unit": "mm", "readOnly": True},
93 )
94 y = fields.Float(
95 dump_default=0,
96 allow_none=True,
97 metadata={"title": "Y", "unit": "mm", "readOnly": True},
98 )
99 z = fields.Float(
100 dump_default=0,
101 allow_none=True,
102 metadata={"title": "Z", "unit": "mm", "readOnly": True},
103 )
104 enqueue = fields.Bool(
105 dump_default=True,
106 metadata={
107 "title": "Queue Scan",
108 },
109 )
111 class Meta:
112 uiorder = [
113 "sampleid",
114 "dataset_name",
115 "scan_type",
116 "expo_time",
117 "start_pos",
118 "range",
119 "tomo_n",
120 "use_sinogram",
121 "n_dark",
122 "n_flat",
123 "axis_displacement",
124 "comment",
125 "x",
126 "y",
127 "z",
128 "enqueue",
129 ]
130 uigroups = [
131 {
132 "Data policy": [
133 "sampleid",
134 "dataset_name",
135 ],
136 "ui:minwidth": 12,
137 },
138 "scan_type",
139 {
140 "Main": ["expo_time", "start_pos", "range", "tomo_n"],
141 "ui:minwidth": 12,
142 },
143 {
144 "Options": ["use_sinogram", "n_dark", "n_flat"],
145 "ui:minwidth": 12,
146 },
147 {
148 "Half acquisition": ["axis_displacement"],
149 "ui:minwidth": 12,
150 },
151 "comment",
152 {
153 "Positioning": ["x", "y", "z"],
154 "ui:minwidth": 6,
155 },
156 "enqueue",
157 ]
158 uischema = {
159 "sampleid": {"ui:widget": "SampleId"},
160 "dataset_name": {"ui:widget": "DatasetName"},
161 "comment": {"ui:widget": "textarea", "ui:options": {"rows": 3}},
162 "enqueue": {"classNames": "hidden-row", "ui:widget": "hidden"},
163 }
165 @tomo_helper.patch_actor_validator
166 def calculated(self, expo_time: float | None = None, **kwargs):
167 """Returns the calculated values
169 Arguments:
170 data: Dictionary containing the actual parameters of the form
171 """
172 result = {}
174 if expo_time is None:
175 # Trick to feed the initial expo time based on the tomo imaging device
176 tomo_config = tomo_helper.get_active_tomo_config()
177 if tomo_config is None:
178 raise RuntimeError("No ACTIVE_TOMOCONFIG selected")
179 imaging = tomo_config.tomo_imaging
180 if imaging is not None:
181 result["expo_time"] = imaging.exposure_time
182 else:
183 result["expo_time"] = 1.0
185 return result
187 def time_estimate(self, data):
188 try:
189 actor = self.get_actor()
190 return actor.time_estimate(**data)
191 except Exception:
192 _logger.error("Error while reading time estimate", exc_info=True)
193 return None
196class TomoscanwithroiActor(ComponentActor):
197 schema = TomoscanwithroiSchema
198 name = "[tomo] full tomo scan"
200 metatype = "tomo"
201 saving_args = {"dataset": "{dataset_name}"}
203 def time_estimate(
204 self,
205 scan_type: str | None = None,
206 start_pos: float | None = None,
207 range: float | None = None,
208 tomo_n: int | None = None,
209 expo_time: float | None = None,
210 use_sinogram: bool | None = None,
211 n_dark: int | None = None,
212 n_flat: int | None = None,
213 axis_displacement: float | None = None,
214 comment: str | None = None,
215 **kwargs,
216 ) -> float | None:
218 if (
219 scan_type is None
220 or start_pos is None
221 or range is None
222 or tomo_n is None
223 or expo_time is None
224 or use_sinogram is None
225 or n_dark is None
226 or n_flat is None
227 ):
228 return None
230 tomo_config = tomo_helper.get_active_tomo_config()
231 if tomo_config is None:
232 raise RuntimeError("No ACTIVE_TOMOCONFIG selected")
234 actor_config = self.get_config()
235 fullfield_object_names = actor_config.get("fullfield_object")
236 if fullfield_object_names is None:
237 raise RuntimeError(
238 "'fullfield_name' config field was not setup in this samplescan actor description"
239 )
241 fulltomo = tomo_helper.get_sequence_from_name(
242 tomo_config, fullfield_object_names, FullFieldTomo
243 )
245 tomo_helper.setup_main_pars(
246 fulltomo,
247 scan_type=scan_type,
248 use_sinogram=use_sinogram,
249 n_dark=n_dark,
250 n_flat=n_flat,
251 axis_displacement=axis_displacement,
252 comment=comment,
253 )
255 fulltomo.pars.start_pos = start_pos
256 fulltomo.pars.range = range
257 fulltomo.pars.tomo_n = tomo_n
258 fulltomo.pars.exposure_time = expo_time
259 fulltomo.prepare()
260 # Else it will be considered as already prepared next time
261 fulltomo._prepare_done = False
262 return fulltomo._inpars.scan_time
264 def method(
265 self,
266 scan_type: str,
267 dataset_name: str,
268 start_pos: float,
269 range: float,
270 x: float,
271 y: float,
272 z: float,
273 tomo_n: int,
274 expo_time: float,
275 use_sinogram: bool,
276 n_dark: int,
277 n_flat: int,
278 axis_displacement: float,
279 comment: str,
280 before_scan_starts,
281 update_datacollection,
282 **kwargs,
283 ):
284 if len(kwargs):
285 print("Unused params", kwargs)
287 tomo_config = tomo_helper.get_active_tomo_config()
288 if tomo_config is None:
289 raise RuntimeError("No ACTIVE_TOMOCONFIG selected")
291 actor_config = self.get_config()
292 fullfield_object_names = actor_config.get("fullfield_object")
293 if fullfield_object_names is None:
294 raise RuntimeError(
295 "'fullfield_name' config field was not setup in this samplescan actor description"
296 )
298 fulltomo = tomo_helper.get_sequence_from_name(
299 tomo_config, fullfield_object_names, FullFieldTomo
300 )
302 mg = tomo_helper.create_mg(tomo_config)
303 mg.set_active()
305 tomo_helper.setup_main_pars(
306 fulltomo,
307 scan_type=scan_type,
308 use_sinogram=use_sinogram,
309 n_dark=n_dark,
310 n_flat=n_flat,
311 axis_displacement=axis_displacement,
312 comment=comment,
313 )
315 scan_info = tomo_helper.create_daiquiri_scan_info(
316 self, share_data_collection=True
317 )
319 before_scan_starts(self)
321 def run():
322 with tomo_config.auto_projection.inhibit():
323 sample_stage = tomo_config.sample_stage
324 yrot = sample_stage.y_axis.position
325 mv(
326 sample_stage.z_axis,
327 z,
328 sample_stage.sample_x_axis,
329 x - yrot,
330 sample_stage.sample_y_axis,
331 y - yrot,
332 )
333 fulltomo.basic_scan(
334 start_pos, start_pos + range, tomo_n, expo_time, scan_info=scan_info
335 )
337 greenlet = gevent.spawn(run)
338 try:
339 greenlet.join()
340 except ComponentActorKilled:
341 greenlet.kill()
342 raise
344 greenlet.get()