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

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3 

4from __future__ import annotations 

5 

6import gevent 

7import logging 

8from marshmallow import fields, validate 

9 

10from tomo.fulltomo import FullFieldTomo 

11from . import tomo_helper 

12from bliss.common.standard import mv 

13 

14from daiquiri.core.schema.validators import OneOf 

15from daiquiri.core.components import ( 

16 ComponentActor, 

17 ComponentActorSchema, 

18 ComponentActorKilled, 

19) 

20 

21 

22_logger = logging.getLogger(__name__) 

23 

24 

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 ) 

110 

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 } 

164 

165 @tomo_helper.patch_actor_validator 

166 def calculated(self, expo_time: float | None = None, **kwargs): 

167 """Returns the calculated values 

168 

169 Arguments: 

170 data: Dictionary containing the actual parameters of the form 

171 """ 

172 result = {} 

173 

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 

184 

185 return result 

186 

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 

194 

195 

196class TomoscanwithroiActor(ComponentActor): 

197 schema = TomoscanwithroiSchema 

198 name = "[tomo] full tomo scan" 

199 

200 metatype = "tomo" 

201 saving_args = {"dataset": "{dataset_name}"} 

202 

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: 

217 

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 

229 

230 tomo_config = tomo_helper.get_active_tomo_config() 

231 if tomo_config is None: 

232 raise RuntimeError("No ACTIVE_TOMOCONFIG selected") 

233 

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 ) 

240 

241 fulltomo = tomo_helper.get_sequence_from_name( 

242 tomo_config, fullfield_object_names, FullFieldTomo 

243 ) 

244 

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 ) 

254 

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 

263 

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) 

286 

287 tomo_config = tomo_helper.get_active_tomo_config() 

288 if tomo_config is None: 

289 raise RuntimeError("No ACTIVE_TOMOCONFIG selected") 

290 

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 ) 

297 

298 fulltomo = tomo_helper.get_sequence_from_name( 

299 tomo_config, fullfield_object_names, FullFieldTomo 

300 ) 

301 

302 mg = tomo_helper.create_mg(tomo_config) 

303 mg.set_active() 

304 

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 ) 

314 

315 scan_info = tomo_helper.create_daiquiri_scan_info( 

316 self, share_data_collection=True 

317 ) 

318 

319 before_scan_starts(self) 

320 

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 ) 

336 

337 greenlet = gevent.spawn(run) 

338 try: 

339 greenlet.join() 

340 except ComponentActorKilled: 

341 greenlet.kill() 

342 raise 

343 

344 greenlet.get()