hasyutils 2.0.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. HasyUtils/MgUtils.py +722 -0
  2. HasyUtils/MsUtils.py +1283 -0
  3. HasyUtils/OtherUtils.py +1097 -0
  4. HasyUtils/TgUtils.py +6712 -0
  5. HasyUtils/__init__.py +11 -0
  6. HasyUtils/fastscananalysis.py +476 -0
  7. HasyUtils/fioReader.py +714 -0
  8. HasyUtils/nxIO.py +309 -0
  9. HasyUtils/nxsReader.py +697 -0
  10. HasyUtils/nxsconftools.py +144 -0
  11. HasyUtils/pooltools.py +2648 -0
  12. HasyUtils/pyqtSelector.py +49 -0
  13. HasyUtils/spectraDoor.py +1549 -0
  14. HasyUtils/ssa.py +223 -0
  15. HasyUtils/tngMonitorAttrs.py +567 -0
  16. hasyutils-2.0.0.data/scripts/ECMonitor.py +85 -0
  17. hasyutils-2.0.0.data/scripts/HasyUtilsMain.py +44 -0
  18. hasyutils-2.0.0.data/scripts/MotorLogger.py +439 -0
  19. hasyutils-2.0.0.data/scripts/SardanaAIO.py +140 -0
  20. hasyutils-2.0.0.data/scripts/SardanaAdjustLimits.py +63 -0
  21. hasyutils-2.0.0.data/scripts/SardanaAlarmMonitor.py +129 -0
  22. hasyutils-2.0.0.data/scripts/SardanaChMg.py +289 -0
  23. hasyutils-2.0.0.data/scripts/SardanaChat.py +58 -0
  24. hasyutils-2.0.0.data/scripts/SardanaCheckOnlineXml.py +108 -0
  25. hasyutils-2.0.0.data/scripts/SardanaClearSCAs.py +22 -0
  26. hasyutils-2.0.0.data/scripts/SardanaConvert.py +1847 -0
  27. hasyutils-2.0.0.data/scripts/SardanaDeleteMotorGroups.py +32 -0
  28. hasyutils-2.0.0.data/scripts/SardanaDiag.py +149 -0
  29. hasyutils-2.0.0.data/scripts/SardanaIVP.py +767 -0
  30. hasyutils-2.0.0.data/scripts/SardanaInfoViewer.py +165 -0
  31. hasyutils-2.0.0.data/scripts/SardanaLimitsFromTS2Pool.py +31 -0
  32. hasyutils-2.0.0.data/scripts/SardanaMacroExecutor.py +51 -0
  33. hasyutils-2.0.0.data/scripts/SardanaMacroTester.py +256 -0
  34. hasyutils-2.0.0.data/scripts/SardanaMotorMonitor.py +318 -0
  35. hasyutils-2.0.0.data/scripts/SardanaRestartBoth.py +36 -0
  36. hasyutils-2.0.0.data/scripts/SardanaRestartMacroServer.py +51 -0
  37. hasyutils-2.0.0.data/scripts/SardanaRestartPool.py +40 -0
  38. hasyutils-2.0.0.data/scripts/SardanaShutdown.py +80 -0
  39. hasyutils-2.0.0.data/scripts/SardanaStartMacroServer.py +39 -0
  40. hasyutils-2.0.0.data/scripts/SardanaStartPool.py +40 -0
  41. hasyutils-2.0.0.data/scripts/SardanaStartup.py +245 -0
  42. hasyutils-2.0.0.data/scripts/SardanaStatus.py +63 -0
  43. hasyutils-2.0.0.data/scripts/SardanaStopBoth.py +28 -0
  44. hasyutils-2.0.0.data/scripts/SardanaStopMacro.py +57 -0
  45. hasyutils-2.0.0.data/scripts/SardanaStopMacroServer.py +36 -0
  46. hasyutils-2.0.0.data/scripts/SardanaStopPool.py +38 -0
  47. hasyutils-2.0.0.data/scripts/TngEigerCLI.py +277 -0
  48. hasyutils-2.0.0.data/scripts/TngMonitorAttrs.py +83 -0
  49. hasyutils-2.0.0.data/scripts/TngUtility.py +1445 -0
  50. hasyutils-2.0.0.data/scripts/alarm.ui +54 -0
  51. hasyutils-2.0.0.data/scripts/nxs_ifc.py +50 -0
  52. hasyutils-2.0.0.data/scripts/nxsclient.py +51 -0
  53. hasyutils-2.0.0.data/scripts/nxsreader.py +62 -0
  54. hasyutils-2.0.0.dist-info/AUTHORS +7 -0
  55. hasyutils-2.0.0.dist-info/LICENSE +34 -0
  56. hasyutils-2.0.0.dist-info/METADATA +9 -0
  57. hasyutils-2.0.0.dist-info/RECORD +59 -0
  58. hasyutils-2.0.0.dist-info/WHEEL +6 -0
  59. hasyutils-2.0.0.dist-info/top_level.txt +1 -0
HasyUtils/MsUtils.py ADDED
@@ -0,0 +1,1283 @@
1
+ #!/usr/bin/env python3
2
+ '''
3
+ this file contains the helper functions for the MacroServer
4
+ '''
5
+ #
6
+ # not fatal because pyspViewer.py might be called on a non-exp host
7
+ #
8
+ try:
9
+ import PyTango as _PyTango
10
+ except:
11
+ pass
12
+ from . import TgUtils
13
+ import os as _os
14
+ import imp as _imp
15
+ import sys as _sys
16
+ import math as _math
17
+
18
+ def _findTangoDevice( macro, poolDevice):
19
+ '''
20
+ return the TangoDevice belonging to a poolDevice
21
+ '''
22
+ try:
23
+ poolProxy = _PyTango.DeviceProxy( poolDevice)
24
+ temp = poolProxy.read_attribute( "TangoDevice").value
25
+ except Exception as e:
26
+ macro.output( "MsUtils._findTangoDevice: failed for %s, %s" %
27
+ ( poolDevice, str( e)))
28
+ macro.abort()
29
+ return None
30
+ #macro.output( "MsUtils._findTangoDevice: %s" % temp)
31
+ return temp
32
+
33
+ def _findFilewriter( macro, name):
34
+ '''
35
+ name is the Tango device name of an EigerDectris. This
36
+ function returns the name of the corresponding filewriter.
37
+ '''
38
+ #
39
+ # find an EigerFilewriter for the EigerDectris
40
+ #
41
+ deviceNameFw = None
42
+ TangoHost = None
43
+ if name.find( ":10000"):
44
+ lst = name.split( ':')
45
+ TangoHost = "%s:10000" % lst[0]
46
+
47
+ devsFw = TgUtils.getDeviceNamesByClass( "EigerFilewriter", tangoHost = TangoHost)
48
+ for devFw in devsFw:
49
+ prop = TgUtils.getDeviceProperty( devFw, 'EigerDevice', tangoHost = TangoHost)
50
+ #
51
+ # prop[0]: p62/eiger/e4m vs. hasnp62eh:10000/p62/eiger/e4m
52
+ #
53
+ if name.find( prop[0]) != -1:
54
+ deviceNameFw = devFw
55
+ break
56
+ if deviceNameFw is None:
57
+ macro.output( "MsUtils._findFilewriter: failed to find filewriter for %s" %
58
+ (name))
59
+ macro.abort()
60
+ return None
61
+ if TangoHost is not None:
62
+ deviceNameFw = "%s/%s" % (TangoHost, deviceNameFw)
63
+ return deviceNameFw
64
+
65
+ def prepareEigerDectrisAttrs( macro, name = None, NbImages = 1,
66
+ CountTime = None, TriggerMode = None, NbTriggers = 1,
67
+ ArmFlag = True, ImagesPerFile = 1000):
68
+ '''
69
+
70
+ called from MsUtils.prepareDetectorAttrs()
71
+
72
+ sets these detector attributes
73
+ CountTime
74
+ NbImages
75
+ NbTriggers
76
+ TriggerMode
77
+
78
+ the Filewriter FileNamePattern ist derived from ScanFile, ScanDir, ScanID
79
+ #
80
+ # ScanDir == "/gpfs/commissioning/raw"
81
+ #
82
+ if scan_dir.find( "commissioning/raw") != -1:
83
+ temp = "commissioning/raw/%s_%05d/%s/%s_%05d" % ( prefix, int( scan_id), detectorName, prefix, int( scan_id))
84
+ #
85
+ # ScanDir == "/gpfs/local"
86
+ #
87
+ elif scan_dir.find( "/gpfs/local") != -1:
88
+ temp = "local/%s_%05d/%s/%s_%05d" % ( prefix, int( scan_id), detectorName, prefix, int( scan_id))
89
+ #
90
+ # ScanDir == /gpfs/current/raw
91
+ #
92
+ else:
93
+ temp = "current/raw/%s_%05d/%s/%s_%05d" % ( prefix, int( scan_id), detectorName, prefix, int( scan_id))
94
+ eigerFw_proxy.FilenamePattern = temp
95
+
96
+ scanNameDir = "%s/%s_%05d" % ( scan_dir, prefix, int( scan_id))
97
+ fileDir = "%s/%s_%05d/%s" % ( scan_dir, prefix, int( scan_id), detectorName)
98
+ *** scanNameDir and fileDir are created with 0777
99
+ this feature has been added to avoid permission issues for beamlines
100
+ with two different users, e.g. p99user and p99femto
101
+
102
+ ImagesPerFile = 1000 by default
103
+
104
+ Eventually execute arm()
105
+ ArmFlag can be False, if users want to do some extra initialisations
106
+
107
+
108
+ Here is an example (PreScan Hook)
109
+
110
+ scanInfo = HasyUtils.createScanInfo( self.getParentMacro().getCommand())
111
+ if HasyUtils.isInMg( self, detectorName):
112
+ if not HasyUtils.prepareDetectorAttrs( self,
113
+ name = detectorName,
114
+ trig_mode = 'ints',
115
+ nbFrames = 1, # per trigger
116
+ acq_time = scanInfo[ 'sampleTime'],
117
+ NbTriggers = scanInfo[ 'intervals'] + 1,
118
+ ImagesPerFile = 1000):
119
+ self.output( "general_features.gh_pre_scan: prepareDetectors: returned error")
120
+ return False
121
+
122
+ '''
123
+
124
+ detectorName = name
125
+ if detectorName is None:
126
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: no detectorName")
127
+ macro.abort()
128
+ return False
129
+ #
130
+ # detectorName is a pool device name, find the Tango device
131
+ #
132
+ tangoDevice = _findTangoDevice( macro, detectorName)
133
+ if tangoDevice is None:
134
+ return
135
+ try:
136
+ eiger_proxy = _PyTango.DeviceProxy( tangoDevice)
137
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: Eiger %s" % tangoDevice)
138
+ macro.debug("MsUtils.prepareEigerDectrisAttrs: %s found in active MG" % detectorName)
139
+ except Exception as e:
140
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: failed to create proxy to %s, %s, %s" %
141
+ (detectorName, controllerProxy.TangoDevice, str( e)))
142
+ macro.abort()
143
+ return False
144
+
145
+ #
146
+ # disarm the detector before setting the attributes
147
+ #
148
+ eiger_proxy.disarm()
149
+
150
+ #
151
+ # CountTime (exposure time)
152
+ #
153
+ if CountTime is not None:
154
+ eiger_proxy.CountTime = float( CountTime)
155
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: CountTime to %g" % eiger_proxy.CountTime)
156
+ #eiger_proxy.FrameTime = float( CountTime)*1.001
157
+ #macro.output( "MsUtils.prepareEigerDectrisAttrs: FrameTime to %g" % eiger_proxy.CountTime)
158
+ #
159
+ # NbImages per Trigger
160
+ #
161
+ eiger_proxy.NbImages = int( NbImages)
162
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: NbImages to %d" % eiger_proxy.NbImages)
163
+
164
+ #
165
+ # TriggerMode, usually 'ints' for internal triggers
166
+ #
167
+ if TriggerMode is not None:
168
+ eiger_proxy.TriggerMode = TriggerMode
169
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: TriggerMode to %s" % eiger_proxy.TriggerMode)
170
+ #
171
+ # NbTriggers
172
+ #
173
+ eiger_proxy.NbTriggers = int( NbTriggers)
174
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: NbTrigger to %d" % eiger_proxy.NbTriggers)
175
+
176
+ #
177
+ # handle Filewriter
178
+ #
179
+ deviceNameFw = _findFilewriter( macro, tangoDevice)
180
+ if deviceNameFw is None:
181
+ return
182
+
183
+ try:
184
+ eigerFw_proxy = _PyTango.DeviceProxy( deviceNameFw)
185
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: FileWriter %s" % deviceNameFw)
186
+ except Exception as e:
187
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: failed to create proxy to %s, %s" %
188
+ ( deviceNameFw, str( e)))
189
+ macro.abort()
190
+ return False
191
+
192
+ #
193
+ # tst.fio -> tst
194
+ #
195
+ scan_file = macro.getEnv("ScanFile")
196
+ if type(scan_file).__name__ == 'list':
197
+ scan_file = scan_file[0]
198
+
199
+ prefix = scan_file.split( '.')[0]
200
+ scan_id = macro.getEnv("ScanID")
201
+ #
202
+ # use ScanDir to select
203
+ # current/raw/<prefix>_<ScanID>/<detectorName>/<prefix>_$id
204
+ # or
205
+ # commissioning/raw/<prefix>_<ScanID>/<detectorName>/<prefix>_$id
206
+ #
207
+ # $id is handled by Dectris
208
+ #
209
+ # on the DCU we will always have /data/current/raw
210
+ # the download job looks at ScanDir
211
+ #
212
+ scan_dir = macro.getEnv( "ScanDir")
213
+ scanNameDir = "%s/%s_%05d" % ( scan_dir, prefix, int( scan_id))
214
+ fileDir = "%s/%s_%05d/%s" % ( scan_dir, prefix, int( scan_id), detectorName)
215
+ try:
216
+ _os.makedirs( fileDir, exist_ok=True)
217
+ _os.chmod( fileDir, 0o777)
218
+ _os.chmod( scanNameDir, 0o777)
219
+ except Exception as e:
220
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to create %s, %s" % (fileDir, e))
221
+ return False
222
+ macro.output( "MsUtils.prepareEigerDetectorAttrs: creating %s" % (fileDir))
223
+ #+++
224
+ #
225
+ # 9.3.2021: taken out $id for Florian Bertram
226
+ #
227
+ if scan_dir.find( "commissioning/raw") != -1:
228
+ #temp = "commissioning/raw/%s_%05d/%s/%s_$id" % ( prefix, int( scan_id), detectorName, prefix)
229
+ temp = "commissioning/raw/%s_%05d/%s/%s_%05d" % ( prefix, int( scan_id), detectorName, prefix, int( scan_id))
230
+ #
231
+ # ScanDir == "/gpfs/local"
232
+ #
233
+ elif scan_dir.find( "/gpfs/local") != -1:
234
+ #temp = "local/%s_%05d/%s/%s_$id" % ( prefix, int( scan_id), detectorName, prefix)
235
+ temp = "local/%s_%05d/%s/%s_%05d" % ( prefix, int( scan_id), detectorName, prefix, int( scan_id))
236
+ else:
237
+ #temp = "current/raw/%s_%05d/%s/%s_$id" % ( prefix, int( scan_id), detectorName, prefix)
238
+ temp = "current/raw/%s_%05d/%s/%s_%05d" % ( prefix, int( scan_id), detectorName, prefix, int( scan_id))
239
+ eigerFw_proxy.FilenamePattern = temp
240
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: FilenamePattern to %s" % eigerFw_proxy.FilenamePattern)
241
+ #
242
+ # ImagesPerFile
243
+ #
244
+ # eigerFw_proxy.ImagesPerFile = NbImages*NbTriggers
245
+ # Florian like the 'fixed' 1000 better, to avoid large files
246
+ #
247
+ eigerFw_proxy.ImagesPerFile = ImagesPerFile
248
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: ImagesPerFile to %d" % eigerFw_proxy.ImagesPerFile)
249
+
250
+ #
251
+ # eventually arm() the detector
252
+ #
253
+ if ArmFlag:
254
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: calling arm()")
255
+ eiger_proxy.arm()
256
+ else:
257
+ macro.output( "MsUtils.prepareEigerDectrisAttrs: NOT calling arm()")
258
+
259
+ return True
260
+
261
+
262
+ def resetEigerDectrisAttrs( macro, name = None):
263
+ '''
264
+ make sure that:
265
+ - the detector is disarmed to close the file
266
+ - NbTriggers is set to 1 in order to allow for 'ct'
267
+ - ImagesPerFile is set to 1 in order to allow for 'ct'
268
+ '''
269
+
270
+ import time
271
+ detectorName = name
272
+ if detectorName is None:
273
+ macro.output( "MsUtils.resetEigerDectrisAttrs: no detectorName")
274
+ macro.abort()
275
+ return False
276
+
277
+ tangoDevice = _findTangoDevice( macro, detectorName)
278
+ if tangoDevice is None:
279
+ return
280
+ try:
281
+ eiger_proxy = _PyTango.DeviceProxy( tangoDevice)
282
+ except Exception as e:
283
+ macro.output( "MsUtils.resetEigerDectrisAttrs: failed to create proxy to %s, %s" %
284
+ ( tangoDevice, str( e)))
285
+ macro.abort()
286
+ return False
287
+
288
+
289
+ deviceNameFw = _findFilewriter( macro, tangoDevice)
290
+ if deviceNameFw is None:
291
+ return
292
+ try:
293
+ eigerFw_proxy = _PyTango.DeviceProxy( deviceNameFw)
294
+ except Exception as e:
295
+ macro.output( "MsUtils.resetEigerDectrisAttrs: failed to create proxy to %s, %s" %
296
+ ( deviceNameFw, str( e)))
297
+ macro.abort()
298
+ return False
299
+
300
+ if eigerFw_proxy.state() == _PyTango.DevState.MOVING:
301
+ macro.output( "MsUtils.resetEigerDectrisAttrs: FW (%s) is MOVING -> disarm detector" % deviceNameFw)
302
+ eiger_proxy.disarm()
303
+ startTime = time.time()
304
+ while eigerFw_proxy.state() != _PyTango.DevState.ON:
305
+ time.sleep( 0.1)
306
+ if (time.time() - startTime) > 2:
307
+ macro.output( "MsUtils.resetEigerDectrisAttrs: FW %s does not become ON" % deviceNameFw)
308
+ return False
309
+ while eigerFw_proxy.status() != 'ready':
310
+ time.sleep( 0.1)
311
+ if (time.time() - startTime) > 2:
312
+ macro.output( "MsUtils.resetEigerDectrisAttrs: FW %s does not become 'ready'" % deviceNameFw)
313
+ return False
314
+
315
+ scan_file = macro.getEnv("ScanFile")
316
+ if type(scan_file).__name__ == 'list':
317
+ scan_file = scan_file[0]
318
+ lst = scan_file.split( '.')
319
+ #
320
+ # this creates current/raw/SingleShots
321
+ #
322
+ eigerFw_proxy.FilenamePattern = "current/raw/SingleShots/%s_$id" % lst[0]
323
+ macro.output( "MsUtils.resetEigerDectrisAttrs: FilenamePattern to %s" % eigerFw_proxy.Filenamepattern)
324
+
325
+ eigerFw_proxy.ImagesPerFile = 1
326
+ macro.output( "MsUtils.resetEigerDectrisAttrs: ImagesPerFile to %d" % int( eigerFw_proxy.ImagesPerFile))
327
+ eiger_proxy.NbImages = 1
328
+ macro.output( "MsUtils.resetEigerDectrisAttrs: NbImages to %d" % int( eiger_proxy.NbImages))
329
+ eiger_proxy.NbTriggers = 1
330
+ macro.output( "MsUtils.resetEigerDectrisAttrs: NbTriggers to %d" % int( eiger_proxy.NbTriggers))
331
+ eiger_proxy.TriggerMode = 'ints'
332
+ macro.output( "MsUtils.resetEigerDectrisAttrs: TriggerMode to %s" % eiger_proxy.TriggerMode)
333
+
334
+ return True
335
+
336
+ def prepareDetectorAttrs( macro, name = "pilatus", rootDir = "/ramdisk",
337
+ nbFrames = 1, acq_time = None, trig_mode = None, NbTriggers = 1,
338
+ ArmFlag = True, ImagesPerFile = 1000, do_check_if_detector_in_mg=True):
339
+ '''
340
+ prepareDetectorAttrs() uses the input arguments and the MacroServer
341
+ environment variables ScanFile and ScanID to set these detector attributes:
342
+ FileDir|SaveFilePath|saving_directory: /<rootDir>/<scanName>/<detectorName>
343
+ /ramdisk/au_01390/pilatus
344
+ FilePrefix|saving_prefix: <scanName>
345
+ au_01390
346
+ NbFrames|FrameNumbers|acq_nb_frames: nbFrames
347
+
348
+ FileStartNum|saving_next_number: 0
349
+
350
+ This directory is created:
351
+ rootDir + "/" + scanName + "/" + detectorName
352
+ /gpfs/current/raw/au_00001/pilatus
353
+
354
+ As a safety measure, rootDir is compared with FileDir|SaveFilePath|saving_directory.
355
+ An error is thrown, if the values are incompatible. Both
356
+ strings are compatible, if FileDir starts with rootDir
357
+
358
+ So far Dalsa, Eiger, Pilatus, Lambda, Kromo and Lima (Andor) servers are supported
359
+
360
+ trig_mode: FreeRunning, ExtTrigger, Snapshot, TimedSnap, TrigSequence
361
+
362
+ for doku about the Eiger interface, see HasyUtils.prepareEigerDectrisAttrs? and
363
+ HasyUtils.resetEigerDectrisAttrs?
364
+
365
+ ArmFlag == True
366
+ Eiger: ArmFlag can be False, if users want to do some extra initialisations
367
+ ImagesPerFile, for the EigerFilewriter
368
+ '''
369
+ detectorName = name
370
+
371
+ if do_check_if_detector_in_mg and not isInMg( macro, detectorName):
372
+ macro.output( "MsUtils.prepareDetectorAttrs: MG does not contain %s " % detectorName)
373
+ return True
374
+
375
+ try:
376
+ clss = TgUtils.getClassNameByDevice( _findTangoDevice( macro, detectorName))
377
+ except Exception as e:
378
+ macro.output( "MsUtils.prepareDetectorAttrs: error finding class for %s" % detectorName)
379
+ macro.output( "MsUtils.prepareDetectorAttrs: %s" % repr( e))
380
+ return
381
+ if clss == "EigerDectris":
382
+ return prepareEigerDectrisAttrs( macro,
383
+ name = detectorName,
384
+ NbImages = nbFrames,
385
+ CountTime = acq_time,
386
+ TriggerMode = trig_mode,
387
+ NbTriggers = NbTriggers,
388
+ ArmFlag = ArmFlag,
389
+ ImagesPerFile = ImagesPerFile)
390
+
391
+ scan_file = macro.getEnv("ScanFile")
392
+ if type(scan_file).__name__ == 'list':
393
+ scan_file = scan_file[0]
394
+ scan_id = macro.getEnv("ScanID")
395
+
396
+ tangoDevice_proxy = None
397
+ count = 0
398
+ while True:
399
+ try:
400
+ controllerProxy = _PyTango.DeviceProxy(detectorName)
401
+ temp = controllerProxy.read_attribute( "TangoDevice").value
402
+ tangoDevice_proxy = _PyTango.DeviceProxy( temp)
403
+ macro.debug("MsUtils.prepareDetectorAttrs: %s found in active MG" % detectorName)
404
+ break
405
+ except Exception as e:
406
+ count += 1
407
+ if count > 5:
408
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to create proxy to %s, %s, %s" %
409
+ (detectorName, controllerProxy.TangoDevice, str( e)))
410
+ macro.abort()
411
+ return False
412
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to create proxy to %s, %s, retry" %
413
+ (detectorName, controllerProxy.TangoDevice))
414
+
415
+ #
416
+ # ScanName, e.g.: au_012345
417
+ #
418
+ scanName = "%s_%05d" % (scan_file.split('.')[0], int( scan_id))
419
+ fileDirName = None
420
+ lst = ["FileDir", "SaveFilePath", "saving_directory"]
421
+ for elm in lst:
422
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
423
+ fileDirName = elm
424
+ break
425
+ else:
426
+ macro.output( "MsUtils.prepareDetectorAttrs: attribute %s is missing on %s" %
427
+ (str(lst), tangoDevice_proxy.name()))
428
+ return False
429
+
430
+ try:
431
+ rootDirSrv = tangoDevice_proxy.read_attribute( fileDirName).value
432
+ except Exception as e:
433
+ macro.output( "MsUtils.prepareDetectorAttrs: caught exception during reading %s of %s, %s" %
434
+ (fileDirName, tangoDevice_proxy.name(), str(e)))
435
+ return
436
+
437
+ if rootDirSrv is None:
438
+ macro.output( "MsUtils.prepareDetectorAttrs: rootDirSrv is None, fileDirName %s" % (fileDirName))
439
+ return
440
+ #
441
+ # see, if rootDir is compatible with the FileDir on the server
442
+ #
443
+ if rootDirSrv.find( rootDir) != 0:
444
+ macro.output( "MsUtils.prepareDetectorAttrs:")
445
+ macro.output( " %s: %s which is an attr of %s " % (fileDirName, rootDirSrv, tangoDevice_proxy.name()))
446
+ macro.output( " and")
447
+ macro.output( " rootDir: %s found in general_features" % (rootDir))
448
+ macro.output( " are incompatible")
449
+ macro.output( " Please fix it, maybe by changing the %s attribute in the detector server" % fileDirName)
450
+ macro.abort()
451
+ return False
452
+
453
+ macro.output( "MsUtils.prepareDetectorAttrs: device %s" % ( tangoDevice_proxy.name()))
454
+ #
455
+ # it is important to create the directory before it is written to the server
456
+ #
457
+ if rootDir[-1] == '/':
458
+ fileDir = rootDir + scanName + "/" + detectorName
459
+ else:
460
+ fileDir = rootDir + "/" + scanName + "/" + detectorName
461
+ macro.output( "MsUtils.prepareDetectorAttrs: creating %s %s (0o777)" % (fileDirName, fileDir))
462
+ try:
463
+ _os.makedirs( fileDir)
464
+ _os.chmod( fileDir, 0o777)
465
+ except Exception as e:
466
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to create %s, %s" % (fileDir, e))
467
+ return False
468
+ macro.output( "MsUtils.prepareDetectorAttrs: setting %s to %s" % (fileDirName, fileDir))
469
+ try:
470
+ tangoDevice_proxy.write_attribute( fileDirName, fileDir)
471
+ except Exception as e:
472
+ macro.output( "MsUtils.prepareDetectorAttrs: caught exception writing %s to %s, %s " % \
473
+ (fileDir, fileDirName, tangoDevice_proxy.name()))
474
+ macro.output( "%s" % ( repr(e)))
475
+ return False
476
+ #
477
+ # FrameNumbers
478
+ #
479
+ set_nbframes = 1
480
+ nbFramesName = None
481
+ lst = ["NbFrames", "FrameNumbers", "acq_nb_frames"]
482
+ for elm in lst:
483
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
484
+ nbFramesName = elm
485
+ break
486
+ else:
487
+ set_nbframes = 0
488
+
489
+ if set_nbframes:
490
+ try:
491
+ tangoDevice_proxy.write_attribute( nbFramesName, nbFrames)
492
+ macro.output( "MsUtils.prepareDetectorAttrs: Number of frames set to 1")
493
+ except Exception as e:
494
+ macro.output( "MsUtils.prepareDetectorAttrs: caught exception writing to %s, %s, %s" % \
495
+ (nbFramesName, tangoDevice_proxy.name(), str(e)))
496
+ return False
497
+ #
498
+ # fileStartNum
499
+ #
500
+ fileStartNum = None
501
+ lst = ["FileStartNum", "saving_next_number", "FileIndex", "FileRefNumber"]
502
+ for elm in lst:
503
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
504
+ fileStartNum = elm
505
+ break
506
+ else:
507
+ macro.output( "MsUtils.prepareDetectorAttrs: attribute %s is missing on %s" %
508
+ (str(lst), tangoDevice_proxy.name()))
509
+ return False
510
+
511
+ try:
512
+ #
513
+ # P03, Jannik Woehnert: pscamera: FileRefNumber ist ein string
514
+ #
515
+ cfg = tangoDevice_proxy.get_attribute_config( fileStartNum)
516
+ if cfg.data_type == _PyTango.CmdArgType.DevString:
517
+ tangoDevice_proxy.write_attribute( fileStartNum, "0")
518
+ else:
519
+ tangoDevice_proxy.write_attribute( fileStartNum, 0)
520
+ except Exception as e:
521
+ macro.output( "MsUtils.prepareDetectorAttrs: caught exception writing to %s, %s, %s" %
522
+ (fileStartNum, tangoDevice_proxy.name(), str(e)))
523
+ return False
524
+ #
525
+ # FilePrefix
526
+ #
527
+ filePrefix = None
528
+ lst = ["FilePrefix", "saving_prefix"]
529
+ for elm in lst:
530
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
531
+ filePrefix = elm
532
+ #
533
+ # Lima does not provide the '_' between prefix and image number itself
534
+ #
535
+ if elm == "saving_prefix":
536
+ scanName += "_"
537
+ break
538
+ else:
539
+ macro.output( "MsUtils.prepareDetectorAttrs: attribute %s is missing on %s" %
540
+ ( str(lst), tangoDevice_proxy.name()))
541
+ return False
542
+
543
+ try:
544
+ tangoDevice_proxy.write_attribute( filePrefix, scanName)
545
+ except Exception as e:
546
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to set %s %s, %s, %s" %
547
+ (filePrefix, detectorName, scanName, str(e)))
548
+ return False
549
+ #
550
+ # ShutterTime
551
+ #
552
+ if acq_time is not None:
553
+ actTimeName = None
554
+ lst = ["ExtendedExposure", "ShutterTime"]
555
+ for elm in lst:
556
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
557
+ actTimeName = elm
558
+ break
559
+ if actTimeName is None:
560
+ macro.output( "MsUtils.prepareDetectorAttrs: device has no %s attributes" %
561
+ ( detectorName, str(lst)))
562
+ return False
563
+ return False
564
+
565
+ try:
566
+ tangoDevice_proxy.write_attribute( actTimeName, acq_time)
567
+ except Exception as e:
568
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to set %s %s to %s, %s" %
569
+ (detectorName, actTimeName, acq_time, repr( e)))
570
+ #
571
+ # TriggerMode: FreeRunning, ExtTrigger, Snapshot, TimedSnap, TrigSequence (Dalsa)
572
+ #
573
+ if trig_mode is not None:
574
+ lst = ["TriggerMode"]
575
+ trigModeName = None
576
+ for elm in lst:
577
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
578
+ trigModeName = elm
579
+ break
580
+ if trigModeName is None:
581
+ macro.output( "MsUtils.prepareDetectorAttrs: device has no %s attributes" %
582
+ ( detectorName, str(lst)))
583
+ return False
584
+ try:
585
+ tangoDevice_proxy.write_attribute( trigModeName, trig_mode)
586
+ except Exception as e:
587
+ macro.output( "MsUtils.prepareDetectorAttrs: failed to set %s %s to %s, %s" %
588
+ (detectorName, trigModeName, trig_mode, repr( e)))
589
+
590
+ return True
591
+
592
+ def resetDetectorAttrs( macro, name = "pilatus", rootDir = "/ramdisk", do_check_if_detector_in_mg=True):
593
+ '''
594
+ resetDetectorAttrs() is intended to be use in post-scan hooks to
595
+ store imgages created by the 'ct' command in rootDir
596
+
597
+ FileDir|SaveFilePath|saving_directory: to <rootDir>
598
+
599
+ So far Pilatus, Lambda and Eiger servers are supported
600
+ '''
601
+ detectorName = name
602
+
603
+ if do_check_if_detector_in_mg and not isInMg( macro, detectorName):
604
+ macro.output( "MsUtils.resetDetectorAttrs: MG does not contain %s" % detectorName)
605
+ return True
606
+
607
+ clss = TgUtils.getClassNameByDevice( _findTangoDevice( macro, detectorName))
608
+ if clss == "EigerDectris":
609
+ return resetEigerDectrisAttrs( macro, name = detectorName)
610
+
611
+ tangoDevice_proxy = None
612
+
613
+ count = 0
614
+ while True:
615
+ try:
616
+ controllerProxy = _PyTango.DeviceProxy(detectorName)
617
+ temp = controllerProxy.read_attribute( "TangoDevice").value
618
+ tangoDevice_proxy = _PyTango.DeviceProxy( temp)
619
+ macro.debug("MsUtils.resetDetectorAttrs: %s found in active MG" % detectorName)
620
+ break
621
+ except:
622
+ count += 1
623
+ if count > 5:
624
+ macro.output( "MsUtils.resetDetectorAttrs: failed to create proxy to %s, %s" %
625
+ (detectorName, controllerProxy.TangoDevice))
626
+ macro.abort()
627
+ return False
628
+ macro.output( "MsUtils.resetDetectorAttrs: failed to create proxy to %s, %s, retry" %
629
+ (detectorName, controllerProxy.TangoDevice))
630
+
631
+ fileDirName = None
632
+ lst = ["FileDir", "SaveFilePath", "saving_directory"]
633
+ for elm in lst:
634
+ if TgUtils.proxyHasAttribute( tangoDevice_proxy, elm):
635
+ fileDirName = elm
636
+ break
637
+ else:
638
+ macro.output( "MsUtils.resetDetectorAttrs: attribute %s is missing on %s" %
639
+ (str(lst), tangoDevice_proxy.name()))
640
+ return False
641
+
642
+ try:
643
+ rootDirSrv = tangoDevice_proxy.read_attribute( fileDirName).value
644
+ except Exception:
645
+ macro.output( "MsUtils.resetDetectorAttrs: caught exception during reading FileDir of %s" %
646
+ tangoDevice_proxy.name())
647
+
648
+ try:
649
+ tangoDevice_proxy.write_attribute( fileDirName, rootDir)
650
+ except Exception as e:
651
+ macro.output( "MsUtils.resetDetectorAttrs: caught exception writing %s to %s, %s " % \
652
+ (fileDir, fileDirName, tangoDevice_proxy.name()))
653
+ macro.output( "%s" % ( repr(e)))
654
+ return False
655
+
656
+ return True
657
+
658
+ def isInMg( macro, detectorName):
659
+ '''
660
+ getObj() disables Ctrl-Cs
661
+ '''
662
+ import sardana.macroserver.macro as _ms
663
+ _ms.Type = TgUtils.TypeNames()
664
+
665
+ active_mg = macro.getEnv("ActiveMntGrp")
666
+ try:
667
+ mg = macro.getObj(active_mg, type_class=_ms.Type.MeasurementGroup)
668
+ except Exception as e:
669
+ macro.output( "MsUtils.isInMg: getObj active_mg exception %s, aborting" % e)
670
+ macro.abort()
671
+ return False
672
+
673
+ channels = mg.getChannelLabels()
674
+ if detectorName in channels:
675
+ return True
676
+ return False
677
+
678
+ def isInMgWOgetObj( macro, detectorName):
679
+ '''
680
+ returns True, if detectorName in in the ActiveMntGrp
681
+ '''
682
+ active_mg = macro.getEnv("ActiveMntGrp")
683
+ try:
684
+ mg = _PyTango.DeviceProxy( active_mg)
685
+ except Exception as e:
686
+ macro.output( "MsUtils.isInMg: failed to create a proxy to %s, %s, aborting" % (active_mg, e))
687
+ macro.abort()
688
+ return False
689
+ channels = mg.read_attribute( "ElementList").value
690
+ if detectorName in channels:
691
+ return True
692
+ return False
693
+
694
+ def testImportOld( filename):
695
+ """
696
+ uses 'import importlib.util'
697
+ returns (True, ""), if filename can be imported
698
+ returns (False, "exception-string") otherwise
699
+ """
700
+ import importlib.util
701
+
702
+ status = True
703
+ msg = ""
704
+ try:
705
+ spec = importlib.util.spec_from_file_location( '', filename)
706
+ a = importlib.util.module_from_spec(spec)
707
+ spec.loader.exec_module(a)
708
+ except Exception as e:
709
+ status = False
710
+ msg = repr( e)
711
+ finally:
712
+ pass
713
+
714
+ return( status, msg)
715
+
716
+ def testImport( filename):
717
+ """
718
+ uses importlib.import_module to see whether a python
719
+ file can be importet
720
+
721
+ returns (True, ""), if filename can be imported
722
+ returns (False, "exception-string") otherwise
723
+
724
+ Works at least on Debian-11 and Debian-12
725
+ """
726
+ import importlib
727
+
728
+ dirName = _os.path.dirname( filename)
729
+ baseName = _os.path.basename( filename)
730
+
731
+ prefixName = baseName
732
+ if baseName.find( '.py') > 0:
733
+ prefixName = baseName.rpartition('.')[0]
734
+
735
+ if dirName not in _sys.path:
736
+ _sys.path.insert( 0, dirName)
737
+
738
+ status = True
739
+ msg = ""
740
+ try:
741
+ mod = importlib.import_module( prefixName)
742
+ except Exception as e:
743
+ msg = repr( e)
744
+ status = False
745
+
746
+ return (status, msg)
747
+
748
+ def getModule( filename):
749
+ """
750
+ returns the module or None
751
+ """
752
+ import importlib.util
753
+
754
+ status = True
755
+ msg = ""
756
+ try:
757
+ spec = importlib.util.spec_from_file_location( '', filename)
758
+ a = importlib.util.module_from_spec(spec)
759
+ spec.loader.exec_module(a)
760
+ except Exception as e:
761
+ a = None
762
+
763
+ return( a)
764
+ #
765
+ # ===
766
+ #
767
+ def _appendAbs( scanInfo, mot, start, stop, intervals = None):
768
+ '''
769
+ function to append absolute scans to the scanInfo
770
+ ascan exp_dmy01 0 10 10 0.1
771
+
772
+ extend the motor array of scanInfo by an entry of the kind
773
+ { name: someName,
774
+ start: the start of the scan
775
+ stop: the stop of the scan
776
+ }
777
+ '''
778
+ mDct = {}
779
+ mDct['name'] = mot
780
+ mDct['start'] = float( start)
781
+ mDct['stop'] = float( stop)
782
+ if intervals is not None:
783
+ mDct['intervals'] = int( intervals)
784
+ scanInfo[ 'motors'].append( mDct)
785
+ return
786
+ #
787
+ # ===
788
+ #
789
+ def _appendRel( scanInfo, mot, left, right, intervals = None):
790
+ '''
791
+ function to append relative scans to the scanInfo
792
+ dscan exp_dmy01 -1 1 10 0.1
793
+
794
+ extend the motor array of scanInfo by an entry of the kind
795
+ { name: someName,
796
+ start: the start of the scan
797
+ stop: the stop of the scan
798
+ }
799
+ '''
800
+ mDct = {}
801
+ mDct['name'] = mot
802
+ try:
803
+ p = _PyTango.DeviceProxy( mDct[ 'name'])
804
+ except Exception as e:
805
+ print( "MsUtils._appendRel: failed to create proxy to %s" % mDct['name'])
806
+ mDct['start'] = p.position + float( left)
807
+ mDct['stop'] = p.position + float( right)
808
+ if intervals is not None:
809
+ mDct['intervals'] = int( intervals)
810
+ scanInfo[ 'motors'].append( mDct)
811
+ return
812
+
813
+ def getScanFileName():
814
+ '''
815
+ returns the file name used by the last scan
816
+ returns None, if the file does not exist
817
+
818
+ uses the MacroServer environment variables: ScanDir, ScanFilem ScanID
819
+ '''
820
+ scanDir = TgUtils.getEnv( "ScanDir")
821
+ scanFile = TgUtils.getEnv( "ScanFile")
822
+ scanID = TgUtils.getEnv( "ScanID")
823
+
824
+ if type( scanFile) is list:
825
+ scanFileTemp = scanFile[0]
826
+ else:
827
+ scanFileTemp = scanFile
828
+ #
829
+ # ['tst.fio'] -> ['tst', 'fio']
830
+ #
831
+ lst = scanFileTemp.split( ".")
832
+
833
+ fileName = "%s/%s_%05d.%s" % ( scanDir, lst[0], int( scanID), lst[1])
834
+
835
+ if not _os.path.exists( fileName):
836
+ argout = None
837
+ else:
838
+ argout = fileName
839
+
840
+ return fileName
841
+
842
+ #
843
+ # ===
844
+ #
845
+ def createScanInfo( title = None):
846
+ '''
847
+ Depending on whether createScanInfo() is called in an after-scan-scenario or
848
+ a pre-scan-scenario the title has to be supplied or not.
849
+
850
+ title == None (after-scan-scenario): the function takes the title from ScanHistory
851
+ returns None, if ScanID != serialno (history), probably because
852
+ the last scan has been aborted (ctrl-c)
853
+
854
+ title != None (pre-scan-scenario): if ScanHistory is not valid because createScanInfo()
855
+ is called from a hook, the title has to be supplied.
856
+
857
+ pre_scan_hook example:
858
+ scanInfo = HasyUtils.createScanInfo( self.getParentMacro().getCommand())
859
+
860
+ returns a data structure describing the scan, see below, used e.g. mvsa and CursorApp
861
+
862
+ {'motors': [{'name': 'exp_dmy01', 'start': 0.0, 'stop': 10.0}],
863
+ 'title': 'ascan exp_dmy01 0.0 10.0 10 1.0',
864
+ 'serialno': 1502,
865
+ 'intervals': 10,
866
+ 'nPts': 11,
867
+ 'sampleTime': 1.0}
868
+
869
+ {'motors': [{'name': 'exp_dmy01', 'start': 0.0, 'stop': 10.0},
870
+ {'name': 'exp_dmy02', 'start': 2.0, 'stop': 3.0}],
871
+ 'title': 'a2scan exp_dmy01 0.0 10.0 exp_dmy02 2.0 3.0 3 1.0',
872
+ 'serialno': 1503,
873
+ 'intervals': 3,
874
+ 'nPts': 4,
875
+ 'sampleTime': 1.0}
876
+
877
+ {'motors': [{'name': 'exp_dmy01', 'start': 0.0, 'stop': 1.0, 'intervals': 2},
878
+ {'name': 'exp_dmy02', 'start': 2.0, 'stop': 3.0, 'intervals': 3}],
879
+ 'title': 'mesh exp_dmy01 0.0 1.0 2 exp_dmy02 2.0 3.0 3 0.1 False None',
880
+ 'serialno': 1504,
881
+ 'nPts': 12,
882
+ 'sampleTime': 0.1}
883
+
884
+ serialno is taken from the environment.
885
+ nPts is normally (intervals + 1). For mesh scans it is the
886
+ total no. of points in the mesh
887
+ '''
888
+ #print( "MsUtils.createScanInfo: title %s" % repr(title))
889
+ env = TgUtils.getEnvDct()
890
+ scanInfo = {}
891
+ scanInfo[ 'motors'] = []
892
+ #
893
+ # 1. case: after a scan, ScanHistory can be used
894
+ #
895
+ if title is None:
896
+ if 'ScanHistory' not in list( env.keys()):
897
+ return None
898
+ lastScan = env['ScanHistory'][-1]
899
+
900
+ scanInfo[ 'serialno'] = lastScan['serialno']
901
+ #
902
+ # serialno is from ScanHistory which is created after the scan completed successfully
903
+ # ScanID is updated when a scan starts. ScanID != sericalno may be an indication
904
+ # that the last scan has been ctrl-c'ed
905
+ #
906
+ if TgUtils.getEnv( "ScanID") != scanInfo['serialno']:
907
+ return None
908
+ scanInfo[ 'title'] = lastScan['title']
909
+ #
910
+ # 2. case: from e.g. a hook
911
+ #
912
+ else:
913
+ if type( title) is str:
914
+ scanInfo[ 'title'] = title
915
+ scanInfo[ 'serialno'] = env['ScanID']
916
+ else:
917
+ return None
918
+
919
+ scanTitleToScanInfo( scanInfo[ 'title'], scanInfo)
920
+
921
+ #print( "MsUtils.createScanInfo %s " % repr( scanInfo))
922
+ return scanInfo
923
+ #
924
+ #
925
+ #
926
+ def scanTitleToScanInfo( title, scanInfo):
927
+
928
+ #print( "MsUtils.py: this is scanTitleToScanInfo, title %s" % title)
929
+
930
+ #
931
+ # if bad syntrax for fscan commands, indepvar contain spaces
932
+ #
933
+ if title is None:
934
+ return
935
+
936
+ lst = title.split()
937
+ #
938
+ # ascan exp_dmy01 0 1 10 0.1
939
+ #
940
+ if lst[0] == 'ascan':
941
+ _appendAbs( scanInfo, lst[1], lst[2], lst[3])
942
+ scanInfo[ 'intervals'] = int( lst[4])
943
+ scanInfo[ 'nPts'] = int( lst[4]) + 1
944
+ scanInfo[ 'sampleTime'] = float( lst[5])
945
+ #
946
+ # a2scan exp_dmy01 0 1 exp_dmy02 0 2 10 0.1
947
+ #
948
+ elif lst[0] == 'a2scan':
949
+ _appendAbs( scanInfo, lst[1], lst[2], lst[3])
950
+ _appendAbs( scanInfo, lst[4], lst[5], lst[6])
951
+ scanInfo[ 'intervals'] = int( lst[7])
952
+ scanInfo[ 'nPts'] = int( lst[7]) + 1
953
+ scanInfo[ 'sampleTime'] = float( lst[8])
954
+ #
955
+ # a3scan exp_dmy01 0 1 exp_dmy02 0 2 ... 10 0.1
956
+ #
957
+ elif lst[0] == 'a3scan':
958
+ _appendAbs( scanInfo, lst[1], lst[2], lst[3])
959
+ _appendAbs( scanInfo, lst[4], lst[5], lst[6])
960
+ _appendAbs( scanInfo, lst[7], lst[8], lst[9])
961
+ scanInfo[ 'intervals'] = int( lst[10])
962
+ scanInfo[ 'nPts'] = int( lst[10]) + 1
963
+ scanInfo[ 'sampleTime'] = float( lst[11])
964
+
965
+ #
966
+ # ascan_repeat exp_dmy01 0 1 10 0.1 2
967
+ #
968
+ elif lst[0] == 'ascan_repeat':
969
+ _appendAbs( scanInfo, lst[1], lst[2], lst[3])
970
+ scanInfo[ 'intervals'] = int( lst[4])
971
+ scanInfo[ 'nPts'] = int( lst[4]) + 1
972
+ scanInfo[ 'sampleTime'] = float( lst[5])
973
+ scanInfo[ 'repeats'] = int( lst[6])
974
+ #
975
+ # hscan 1.0 1.1 20 0.1
976
+ #
977
+ elif lst[0] == 'hscan':
978
+ if TgUtils.isDevice( 'e6cctrl_h'):
979
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
980
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
981
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
982
+ scanInfo[ 'intervals'] = int( lst[3])
983
+ scanInfo[ 'nPts'] = int( lst[3]) + 1
984
+ scanInfo[ 'sampleTime'] = float( lst[4])
985
+ elif lst[0] == 'kscan':
986
+ if TgUtils.isDevice( 'e6cctrl_k'):
987
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[1], lst[2])
988
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
989
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[1], lst[2])
990
+ scanInfo[ 'intervals'] = int( lst[3])
991
+ scanInfo[ 'nPts'] = int( lst[3]) + 1
992
+ scanInfo[ 'sampleTime'] = float( lst[4])
993
+ elif lst[0] == 'lscan':
994
+ if TgUtils.isDevice( 'e6cctrl_l'):
995
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[1], lst[2])
996
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
997
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[1], lst[2])
998
+ scanInfo[ 'intervals'] = int( lst[3])
999
+ scanInfo[ 'nPts'] = int( lst[3]) + 1
1000
+ scanInfo[ 'sampleTime'] = float( lst[4])
1001
+
1002
+ #
1003
+ # hklscan 1.0 1.1 2 2.2 3 3.3 20 0.1
1004
+ #
1005
+ elif lst[0] == 'hklscan':
1006
+ diffH = _math.fabs( float( lst[2]) - float( lst[1]))
1007
+ diffK = _math.fabs( float( lst[4]) - float( lst[3]))
1008
+ diffL = _math.fabs( float( lst[6]) - float( lst[5]))
1009
+ if diffH > diffK and diffH > diffL:
1010
+ if TgUtils.isDevice( 'e6cctrl_h'):
1011
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
1012
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
1013
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
1014
+ if TgUtils.isDevice( 'e6cctrl_k'):
1015
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[3], lst[4])
1016
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
1017
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[3], lst[4])
1018
+ if TgUtils.isDevice( 'e6cctrl_l'):
1019
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[5], lst[6])
1020
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
1021
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[5], lst[6])
1022
+ elif diffK > diffH and diffK > diffL:
1023
+ if TgUtils.isDevice( 'e6cctrl_k'):
1024
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[3], lst[4])
1025
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
1026
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[3], lst[4])
1027
+ if TgUtils.isDevice( 'e6cctrl_h'):
1028
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
1029
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
1030
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
1031
+ if TgUtils.isDevice( 'e6cctrl_l'):
1032
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[5], lst[6])
1033
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
1034
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[5], lst[6])
1035
+ elif diffL > diffH and diffL > diffK:
1036
+ if TgUtils.isDevice( 'e6cctrl_l'):
1037
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[5], lst[6])
1038
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
1039
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[5], lst[6])
1040
+ if TgUtils.isDevice( 'e6cctrl_h'):
1041
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
1042
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
1043
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
1044
+ if TgUtils.isDevice( 'e6cctrl_k'):
1045
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[3], lst[4])
1046
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
1047
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[3], lst[4])
1048
+ elif diffH > 0.:
1049
+ if TgUtils.isDevice( 'e6cctrl_h'):
1050
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
1051
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
1052
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
1053
+ if TgUtils.isDevice( 'e6cctrl_k'):
1054
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[3], lst[4])
1055
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
1056
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[3], lst[4])
1057
+ if TgUtils.isDevice( 'e6cctrl_l'):
1058
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[5], lst[6])
1059
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
1060
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[5], lst[6])
1061
+ elif diffK > 0.:
1062
+ if TgUtils.isDevice( 'e6cctrl_k'):
1063
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[3], lst[4])
1064
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
1065
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[3], lst[4])
1066
+ if TgUtils.isDevice( 'e6cctrl_h'):
1067
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
1068
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
1069
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
1070
+ if TgUtils.isDevice( 'e6cctrl_l'):
1071
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[5], lst[6])
1072
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
1073
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[5], lst[6])
1074
+ else:
1075
+ if TgUtils.isDevice( 'e6cctrl_l'):
1076
+ _appendAbs( scanInfo, 'e6cctrl_l', lst[5], lst[6])
1077
+ elif TgUtils.isDevice( 'kozhue6cctrl_l'):
1078
+ _appendAbs( scanInfo, 'kozhue6cctrl_l', lst[5], lst[6])
1079
+ if TgUtils.isDevice( 'e6cctrl_h'):
1080
+ _appendAbs( scanInfo, 'e6cctrl_h', lst[1], lst[2])
1081
+ elif TgUtils.isDevice( 'kozhue6cctrl_h'):
1082
+ _appendAbs( scanInfo, 'kozhue6cctrl_h', lst[1], lst[2])
1083
+ if TgUtils.isDevice( 'e6cctrl_k'):
1084
+ _appendAbs( scanInfo, 'e6cctrl_k', lst[3], lst[4])
1085
+ elif TgUtils.isDevice( 'kozhue6cctrl_k'):
1086
+ _appendAbs( scanInfo, 'kozhue6cctrl_k', lst[3], lst[4])
1087
+ scanInfo[ 'intervals'] = int( lst[7])
1088
+ scanInfo[ 'nPts'] = int( lst[7]) + 1
1089
+ scanInfo[ 'sampleTime'] = float( lst[8])
1090
+ #
1091
+ # dscan exp_dmy01 -1 1 10 0.1
1092
+ #
1093
+ elif lst[0] == 'dscan':
1094
+ _appendRel( scanInfo, lst[1], lst[2], lst[3])
1095
+ scanInfo[ 'intervals'] = int( lst[4])
1096
+ scanInfo[ 'nPts'] = int( lst[4]) + 1
1097
+ scanInfo[ 'sampleTime'] = float( lst[5])
1098
+ #
1099
+ # d2scan exp_dmy01 0 1 exp_dmy02 0 2 10 0.1
1100
+ #
1101
+ elif lst[0] == 'd2scan':
1102
+ _appendRel( scanInfo, lst[1], lst[2], lst[3])
1103
+ _appendRel( scanInfo, lst[4], lst[5], lst[6])
1104
+ scanInfo[ 'intervals'] = int( lst[7])
1105
+ scanInfo[ 'nPts'] = int( lst[7]) + 1
1106
+ scanInfo[ 'sampleTime'] = float( lst[8])
1107
+ #
1108
+ # d3scan exp_dmy01 0 1 exp_dmy02 0 2 ... 10 0.1
1109
+ #
1110
+ elif lst[0] == 'd3scan':
1111
+ _appendRel( scanInfo, lst[1], lst[2], lst[3])
1112
+ _appendRel( scanInfo, lst[4], lst[5], lst[6])
1113
+ _appendRel( scanInfo, lst[7], lst[8], lst[9])
1114
+ scanInfo[ 'intervals'] = int( lst[10])
1115
+ scanInfo[ 'nPts'] = int( lst[10]) + 1
1116
+ scanInfo[ 'sampleTime'] = float( lst[11])
1117
+
1118
+ #
1119
+ # dscan_repeat exp_dmy01 -1 1 10 0.1 2
1120
+ #
1121
+ elif lst[0] == 'dscan_repeat':
1122
+ _appendRel( scanInfo, lst[1], lst[2], lst[3])
1123
+ scanInfo[ 'intervals'] = int( lst[4])
1124
+ scanInfo[ 'nPts'] = int( lst[4]) + 1
1125
+ scanInfo[ 'sampleTime'] = float( lst[5])
1126
+ scanInfo[ 'repeats'] = int( lst[6])
1127
+ #
1128
+ # mesh exp_dmy01 0 1 10 exp_dmy02 1 2 12 0.1
1129
+ #
1130
+ elif lst[0] == 'mesh':
1131
+ _appendAbs( scanInfo, lst[1], lst[2], lst[3], lst[4])
1132
+ _appendAbs( scanInfo, lst[5], lst[6], lst[7], lst[8])
1133
+ scanInfo[ 'nPts'] = (int( lst[4]) + 1)*(int( lst[8]) + 1)
1134
+ scanInfo[ 'sampleTime'] = float( lst[9])
1135
+ #
1136
+ # dmesh exp_dmy01 1 1 10 exp_dmy02 -1 2 12 0.1
1137
+ #
1138
+ elif lst[0] == 'dmesh':
1139
+ _appendRel( scanInfo, lst[1], lst[2], lst[3], lst[4])
1140
+ _appendRel( scanInfo, lst[5], lst[6], lst[7], lst[8])
1141
+ scanInfo[ 'nPts'] = (int( lst[4]) + 1)*(int( lst[8]) + 1)
1142
+ scanInfo[ 'sampleTime'] = float( lst[9])
1143
+ #
1144
+ # timescan 10 0.1
1145
+ #
1146
+ elif lst[0] == 'timescan':
1147
+ scanInfo[ 'intervals'] = int( lst[1])
1148
+ scanInfo[ 'nPts'] = int( lst[1]) + 1
1149
+ scanInfo[ 'sampleTime'] = float( lst[2])
1150
+ #
1151
+ # fscan np=1500 0.1 exp_dmy01 exp_dmy02, this is a fake because I do not calculate start/stop for fscans
1152
+ # the real syntax: fscan "x=[1,3,5,7,9],y=arange(5)" 0.1 exp_dmy01 x**2 exp_dmy02 sqrt(y*x+3)
1153
+ #
1154
+ elif lst[0] == 'fscan':
1155
+ #np = int( lst[1].split( '=')[1])
1156
+ np = 1500
1157
+ nPts = 1
1158
+ for mot in lst[ 3:]:
1159
+ _appendAbs( scanInfo, mot, 0, 100, intervals = np)
1160
+ nPts = nPts*(np + 1)
1161
+ try:
1162
+ scanInfo[ 'sampleTime'] = float( lst[2])
1163
+ scanInfo[ 'nPts'] = nPts
1164
+ except:
1165
+ scanInfo[ 'sampleTime'] = -1
1166
+ scanInfo[ 'nPts'] = -1
1167
+ else:
1168
+ pass
1169
+ #raise ValueError( "MsUtils.scanTitleToScanInfo: failed to identify scan type %s" % lst[0])
1170
+
1171
+ return
1172
+ #
1173
+ # ===
1174
+ #
1175
+ def repairFscanTitle( title):
1176
+ #
1177
+ # u"fscan x=[0,1,2],y=[10,11,12] 0.1 \
1178
+ # [[Motor(tango://haso107tk.desy.de:10000/motor/dummy_mot_ctrl/1), 'x'], \
1179
+ # [Motor(tango://haso107tk.desy.de:10000/motor/dummy_mot_ctrl/2), 'y']]"
1180
+ # -> 'fscan' np=3 0.1 exp_dmy0 exp_dmy02'
1181
+
1182
+ # about fscan syntax, see remark in diary 17.3.2023
1183
+
1184
+ lines = title.split( ' ')
1185
+
1186
+ try:
1187
+ nameSpace = {}
1188
+ exec( "a = dict( %s)" % lines[1], nameSpace)
1189
+ lengths = []
1190
+ lenMin = 10000000000
1191
+ for elm in nameSpace[ 'a']:
1192
+ if len( nameSpace[ 'a'][ elm]) < lenMin:
1193
+ lenMin = len( nameSpace[ 'a'][ elm])
1194
+ except:
1195
+ lenMin = 1500
1196
+
1197
+ cmdLine = lines[0] + " "
1198
+ cmdLine += "np=%d " % lenMin
1199
+ cmdLine += lines[2] + " "
1200
+
1201
+ temp = ""
1202
+ for line in lines[3:]:
1203
+ temp += line
1204
+ temp = temp.replace( 'Motor(tango://', '\'')
1205
+ temp = temp.replace( ')', '\'')
1206
+
1207
+ try:
1208
+ nameSpace = {}
1209
+ exec( "a = %s" % temp, nameSpace)
1210
+ for elm in nameSpace[ 'a']:
1211
+ p = _PyTango.DeviceProxy( elm[0])
1212
+ cmdLine += " %s" % (p.alias())
1213
+ except Exception as e:
1214
+ cmdLine = None
1215
+ #raise Exception( "MsUtils.RepairFscanTitle", "failed to parse %s" % title)
1216
+
1217
+ return cmdLine
1218
+
1219
+
1220
+ def dataRecordToScanInfo( dataRecord):
1221
+ '''
1222
+ creates the scanInfo dictionary from the first dataRecord
1223
+
1224
+ scanInfo:
1225
+ {'title': u'ascan exp_dmy01 0.0 0.1 10 0.1',
1226
+ 'serialno': 1775,
1227
+ 'motors': [{'start': 0.0, 'stop': 0.1, 'name': u'exp_dmy01', 'proxy': Motor(motor/dummy_mot_ctrl/1)}],
1228
+ 'scanfile': [u'tst.fio', u'tst.nxs'],
1229
+ 'filename': [u'tst_01780.fio', u'tst_01780.nxs'],
1230
+ 'starttime': u'Thu Oct 13 15:35:48 2016',
1231
+ 'scandir': u'/home/kracht/Misc/IVP/temp'}
1232
+ '''
1233
+ scanInfo = {}
1234
+ scanInfo['scanfile'] = dataRecord[1]['data'][ 'scanfile']
1235
+ if scanInfo['scanfile'] is None:
1236
+ raise Exception( "MsUtils.dataRecordToScanInfo", "scanfile not defined")
1237
+ scanInfo['scandir'] = dataRecord[1]['data'][ 'scandir']
1238
+ if scanInfo['scandir'] is None:
1239
+ raise Exception( "MsUtils.dataRecordToScanInfo", "scandir not defined")
1240
+ scanInfo['serialno'] = dataRecord[1]['data'][ 'serialno']
1241
+
1242
+ scanInfo['filename'] = []
1243
+ if type(scanInfo['scanfile']) is list:
1244
+ for sf in scanInfo['scanfile']:
1245
+ tpl = sf.rpartition('.')
1246
+ scanInfo['filename'].append( "%s_%05d.%s" % (tpl[0], scanInfo['serialno'], tpl[2]))
1247
+ else:
1248
+ tpl = scanInfo['scanfile'].rpartition('.')
1249
+ scanInfo['filename'].append( "%s_%05d.%s" % (tpl[0], scanInfo['serialno'], tpl[2]))
1250
+
1251
+ scanInfo['starttime'] = dataRecord[1]['data']['starttime']
1252
+ if dataRecord[1]['data']['title'].find( 'fscan') == 0:
1253
+ scanInfo['title'] = repairFscanTitle( dataRecord[1]['data']['title'])
1254
+ else:
1255
+ scanInfo['title'] = dataRecord[1]['data']['title']
1256
+ #
1257
+ # scanInfo is None for an fscan command spaces in the indepvar definition
1258
+ #
1259
+ if scanInfo is not None:
1260
+ scanInfo[ 'motors'] = []
1261
+ scanTitleToScanInfo( scanInfo[ 'title'], scanInfo)
1262
+
1263
+ return scanInfo
1264
+
1265
+ def doorAbortMacro( doorName = None):
1266
+ '''
1267
+ executes abortMacro() on the specified Door
1268
+ or choses the first Door. This is more than
1269
+ executing abort()
1270
+ '''
1271
+ if doorName is None:
1272
+ try:
1273
+ doorName = TgUtils.getDoorNames()[0]
1274
+ except Exception as e:
1275
+ print( "MsUtils.abortMacro: failed to get doorName")
1276
+ print( repr( e))
1277
+ return False
1278
+
1279
+ p = _PyTango.DeviceProxy( doorName)
1280
+ p.abortMacro()
1281
+
1282
+ return True
1283
+