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
« 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"""
6import time
7import numpy as np
8from .. import Group
10COM1 = '#'
11COM2 = '##'
12SEP = '||' # separater between value, pvname in header
13FILETOP = '##Epics StepScan File'
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)
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)
56 if icol is None:
57 print( 'cannot find column %s' % repr(key))
58 return None
59 return self.data[icol]
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
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])
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()
124def read_stepscan(fname, _larch=None, **kws):
125 """read Epics Step Scan file to larch Group"""
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)
134 group.get_data = scan.get_data
135 return group