Coverage for larch/io/stepscan_file.py: 12%

101 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-10-16 21:04 +0000

1#!/usr/bin/env python 

2""" 

3Output data file from Epics Step Scan (slightly different from gse_escan) 

4""" 

5 

6import time 

7import numpy as np 

8from .. import Group 

9 

10COM1 = '#' 

11COM2 = '##' 

12SEP = '||' # separater between value, pvname in header 

13FILETOP = '##Epics StepScan File' 

14 

15class EpicsScanData(object): 

16 """ 

17 Holds data as read from a Scan Data File. 

18 """ 

19 def __init__(self, filename=None, **kws): 

20 self.filename = filename 

21 self.extra_pvs = [] 

22 self.comments = [] 

23 self.column_keys = [] 

24 self.column_names = [] 

25 self.column_units = [] 

26 self.column_pvnames = [] 

27 self.breakpoints = [] 

28 self.breakpoint_times = [] 

29 self.__arraymap = None 

30 self.start_time = None 

31 self.stop_time = None 

32 self.data = [] 

33 if filename is not None: 

34 self.read(filename) 

35 

36 def get_data(self, key, fold_breakpoints=False): 

37 """get positioner or detector array either by key, name, or index 

38 key can be any of (case-insensitive): 

39 column number, starting at 0 

40 column label, 'p1', 'd1', etc 

41 name of column 

42 pvname of column 

43 """ 

44 # cache lower-case version of all keys and names 

45 if self.__arraymap is None: 

46 self.__arraymap = {} 

47 for a in (self.column_keys, self.column_names, self.column_pvnames): 

48 for i, nam in enumerate(a): 

49 self.__arraymap[nam.lower()] = i 

50 # 

51 if isinstance(key, int) and key > -1 and key < len(self.column_keys): 

52 icol = key 

53 else: 

54 icol = self.__arraymap.get(key.lower(), None) 

55 

56 if icol is None: 

57 print( 'cannot find column %s' % repr(key)) 

58 return None 

59 return self.data[icol] 

60 

61 def read(self, filename=None): 

62 if filename is not None: 

63 self.filename = filename 

64 try: 

65 fh = open(self.filename, 'r') 

66 except IOError: 

67 print( 'cannot open file %s for read' % self.filename) 

68 return 

69 lines = fh.readlines() 

70 line0 = lines.pop(0) 

71 if not line0.startswith(FILETOP): 

72 print( '%s is not a valid Epics Scan file' % self.filename) 

73 return 

74 

75 def split_header(line): 

76 w = [k.strip() for k in line.replace('#', '').split(':', 1)] 

77 if len(w) == 1: 

78 w.append('') 

79 return w 

80 mode = None 

81 extras = {} 

82 modes = {'Time': 'comment', '----': 'data', 

83 'Legend Start': 'legend', 'Legend End': 'legend_end', 

84 'ExtraPVs Start': 'extras', 'ExtraPVs End': 'extras_end'} 

85 for line in lines: 

86 if line.startswith(COM1): 

87 key, val = split_header(line[:-1]) 

88 if key.startswith('----'): key = '----' 

89 if key in modes: 

90 mode = modes[key] 

91 if mode == 'comment': 

92 self.stop_time = val 

93 if self.start_time is None: 

94 self.start_time = val 

95 elif mode == 'extras': 

96 self.breakpoints.append(len(self.data)) 

97 self.breakpoint_times.append(self.stop_time) 

98 elif mode == 'extras_end': 

99 self.extra_pvs.append(extras) 

100 extras = {} 

101 continue 

102 if mode == 'comment': 

103 cmt = line[:-1].strip() 

104 if cmt.startswith('#'): cmt = line[1:].strip() 

105 self.comments.append(cmt) 

106 elif mode in ('legend', 'extras'): 

107 words = [w.strip() for w in val.split(SEP)] 

108 if len(words) == 1: words.append('') 

109 if mode == 'extras': 

110 extras[key] = (words[0], words[1]) 

111 else: 

112 if len(words) == 2: words.append('') 

113 self.column_keys.append(key) 

114 self.column_names.append(words[0]) 

115 self.column_units.append(words[1]) 

116 self.column_pvnames.append(words[2]) 

117 

118 else: # data! 

119 self.data.append([float(i) for i in line[:-1].split()]) 

120 # 

121 self.comments = '\n'.join(self.comments) 

122 self.data = np.array(self.data).transpose() 

123 

124def read_stepscan(fname, _larch=None, **kws): 

125 """read Epics Step Scan file to larch Group""" 

126 

127 scan = EpicsScanData(fname) 

128 group = Group() 

129 group.__name__ ='Epics Step Sscan Data file %s' % fname 

130 for key, val in scan.__dict__.items(): 

131 if not key.startswith('_'): 

132 setattr(group, key, val) 

133 

134 group.get_data = scan.get_data 

135 return group