Refactor limr class for enhanced functionality

Refactored the limr class to streamline initialization and improve parameter management by directly fetching default parameters from the `limedriver` binary with a `--dump` flag, eliminating manual parsing, leading to more robust and maintainable code. These changes improve the maintainability and extend the functionality of the parameter handling in the limr class, making it easier to scale and adapt for future requirements.
This commit is contained in:
Kumi 2024-02-05 11:38:49 +01:00
parent 72e809ccec
commit a4d109dffd
Signed by: kumi
GPG key ID: ECBCC9082395383F

View file

@ -15,437 +15,475 @@ Note for release: The communication between the python and the Cpp routine is ve
Update Feb 2020: Slight changes to make it compatible with Python 3 Update Feb 2020: Slight changes to make it compatible with Python 3
""" """
import subprocess # to call the program import subprocess # to call the program
import datetime # to generate timestamps for parsweeps import datetime # to generate timestamps for parsweeps
import h5py # to have organized data storage..... import h5py # to have organized data storage.....
import numpy as np # ... import numpy as np # ...
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import json
class limr(): class limr:
def __init__(self, filename = './pulseN_USB.cpp'): def __init__(self, filename="./limedriver"):
# check first for the filename provided
if filename[-3:] == 'cpp':
self.Csrc = filename
else:
self.Csrc = './pulseN_USB.cpp'
# the program to call # the program to call
self.Cprog = self.Csrc[:-4] self.Cprog = filename
fp = open(self.Csrc, 'r')
in_arg = {} # fetch the default parameters from the limedriver binary
startpattern = 'struct Config2HDFattr_t HDFattr[]' str2call = self.Cprog + " --dump"
stoppattern = '};'
parsing = False p = subprocess.Popen(
ii_oupargs = 0 str2call.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT
for line in fp.readlines(): )
if (stoppattern in line) & parsing:
break # read the output
if parsing: in_arg = json.loads(p.stdout.read().decode("utf-8"))
stripped = line.replace('\t','').replace('"','').strip('\n').strip(',').strip('{').strip('}')
splitted = stripped.split(',') # initialize the parameters
# remove irrrelevant stuff
rmvidx = range(4,len(splitted)-1)
for ii in range(len(rmvidx)):
splitted.pop(4)
if splitted[0] == '///':
splitted[0] = '//' + str(ii_oupargs)
ii_oupargs+=1
in_arg[splitted[0]] = splitted
in_arg[splitted[0]][0] = []
if startpattern in line:
parsing = True
fp.close()
self.parsinp = in_arg
for key in in_arg: for key in in_arg:
setattr(self, key, in_arg[key][0]) setattr(self, key, in_arg[key][0])
# initialize other variables # initialize other variables
self.parvar = {} self.parvar = {}
self.parvar_cpl = {} self.parvar_cpl = {}
self.HDFfile = [] self.HDFfile = []
self.HDF = HDF() self.HDF = HDF()
self.segcount = 0 self.segcount = 0
# print the arguments that have been set # print the arguments that have been set
def print_params(self, allel = False): def print_params(self, allel=False):
for key in sorted(self.parsinp): for key in sorted(self.parsinp):
val = getattr(self,key) val = getattr(self, key)
if (val != []) | (allel): if (val != []) | (allel):
print('{:<5}: {:>50} {:<25}'.format(key, val, self.parsinp[key][1])) print("{:<5}: {:>50} {:<25}".format(key, val, self.parsinp[key][1]))
# add parameter variation:
# add parameter variation:
# key is the argument to vary # key is the argument to vary
# idx the indices of values # idx the indices of values
# strt the starting point # strt the starting point
# end the endpoint # end the endpoint
# npts the dimension of the sweep # npts the dimension of the sweep
def parsweep(self, key, strt, end, npts, idx = 0): def parsweep(self, key, strt, end, npts, idx=0):
if ~isinstance(idx, list):
idx = [idx] # idx as list eases iteration
if ~isinstance(idx,list): idx = [idx] # idx as list eases iteration
# check the key # check the key
try: try:
vals = getattr(self,key) vals = getattr(self, key)
except: except:
print('Problem with sweep: Key ' + key + ' is not valid! See below for valid keys') print(
"Problem with sweep: Key "
+ key
+ " is not valid! See below for valid keys"
)
self.print_params(allel=True) self.print_params(allel=True)
return return
# check for existing val and for proper dimension. Dimension is a priori not known due to number of pulses that can be flexible # check for existing val and for proper dimension. Dimension is a priori not known due to number of pulses that can be flexible
if (vals == []): if vals == []:
print('Problem with sweep: Initialize first a value to argument ' + key +'. I will try with assuming zero') print(
vals = 0; "Problem with sweep: Initialize first a value to argument "
+ key
+ ". I will try with assuming zero"
)
vals = 0
if isinstance(vals, (list, np.ndarray)): if isinstance(vals, (list, np.ndarray)):
if len(vals) < max(idx): if len(vals) < max(idx):
print('Problem with sweep: ' + key + ' has only ' + str(len(vals)) + ' objects, while an index of ' + str(max(idx)) + ' was requested!') print(
"Problem with sweep: "
+ key
+ " has only "
+ str(len(vals))
+ " objects, while an index of "
+ str(max(idx))
+ " was requested!"
)
return return
startlist = [[vals[jj] for jj in range(len(vals))] for ii in range(npts)] startlist = [[vals[jj] for jj in range(len(vals))] for ii in range(npts)]
elif max(idx) > 0: elif max(idx) > 0:
print('Problem with sweep: ' + key + ' is scalar, while an index of ' + str(max(idx)) + ' was requested!') print(
"Problem with sweep: "
+ key
+ " is scalar, while an index of "
+ str(max(idx))
+ " was requested!"
)
return return
else: else:
startlist = [[vals] for ii in range(npts)] startlist = [[vals] for ii in range(npts)]
# check if a parvar already exists for this key # check if a parvar already exists for this key
if len(self.parvar) == 0: if len(self.parvar) == 0:
self.parvar['sweeplist'] = startlist self.parvar["sweeplist"] = startlist
elif not((key == self.parvar['key']) & (npts == self.parvar['dim'])): elif not ((key == self.parvar["key"]) & (npts == self.parvar["dim"])):
self.parvar['sweeplist'] = startlist self.parvar["sweeplist"] = startlist
self.parvar['key'] = key self.parvar["key"] = key
self.parvar['dim'] = npts self.parvar["dim"] = npts
if npts > 1: if npts > 1:
incr = (end - strt)/(npts-1) incr = (end - strt) / (npts - 1)
else: else:
incr = 0; incr = 0
for ii_swp in range(npts): for ii_swp in range(npts):
for swp_idx in idx: for swp_idx in idx:
self.parvar['sweeplist'][ii_swp][swp_idx] = strt + ii_swp*incr self.parvar["sweeplist"][ii_swp][swp_idx] = strt + ii_swp * incr
# add coupled parameter variation of another variable: (one variable is not enough... two neither, but better than one. A list of dicts would more general....) # add coupled parameter variation of another variable: (one variable is not enough... two neither, but better than one. A list of dicts would more general....)
# key is the argument to vary # key is the argument to vary
# idx the indices of values # idx the indices of values
# strt the starting point # strt the starting point
# end the endpoint # end the endpoint
# npts the dimension of the sweep # npts the dimension of the sweep
def parsweep_cpl(self, key, strt, end, npts, idx = 0): def parsweep_cpl(self, key, strt, end, npts, idx=0):
if ~isinstance(idx, list):
idx = [idx] # idx as list eases iteration
if ~isinstance(idx,list): idx = [idx] # idx as list eases iteration
# check the key # check the key
try: try:
vals = getattr(self,key) vals = getattr(self, key)
except: except:
print('Problem with sweep: Key ' + key + ' is not valid! See below for valid keys') print(
"Problem with sweep: Key "
+ key
+ " is not valid! See below for valid keys"
)
self.print_params(allel=True) self.print_params(allel=True)
return return
# check for existing val and for proper dimension. Dimension is a priori not known due to number of pulses that can be flexible # check for existing val and for proper dimension. Dimension is a priori not known due to number of pulses that can be flexible
if (vals == []): if vals == []:
print('Problem with sweep: Initialize first a value to argument ' + key +'. I will try with assuming zero') print(
vals = 0; "Problem with sweep: Initialize first a value to argument "
+ key
+ ". I will try with assuming zero"
)
vals = 0
if isinstance(vals, (list, np.ndarray)): if isinstance(vals, (list, np.ndarray)):
if len(vals) < max(idx): if len(vals) < max(idx):
print('Problem with sweep: ' + key + ' has only ' + str(len(vals)) + ' objects, while an index of ' + str(max(idx)) + ' was requested!') print(
"Problem with sweep: "
+ key
+ " has only "
+ str(len(vals))
+ " objects, while an index of "
+ str(max(idx))
+ " was requested!"
)
return return
startlist = [[vals[jj] for jj in range(len(vals))] for ii in range(npts)] startlist = [[vals[jj] for jj in range(len(vals))] for ii in range(npts)]
elif max(idx) > 0: elif max(idx) > 0:
print('Problem with sweep: ' + key + ' is scalar, while an index of ' + str(max(idx)) + ' was requested!') print(
"Problem with sweep: "
+ key
+ " is scalar, while an index of "
+ str(max(idx))
+ " was requested!"
)
return return
else: else:
startlist = [[vals] for ii in range(npts)] startlist = [[vals] for ii in range(npts)]
# check if a parvar already exists for this key # check if a parvar already exists for this key
if len(self.parvar_cpl) == 0: if len(self.parvar_cpl) == 0:
self.parvar_cpl['sweeplist'] = startlist self.parvar_cpl["sweeplist"] = startlist
elif not((key == self.parvar_cpl['key']) & (npts == self.parvar_cpl['dim'])): elif not ((key == self.parvar_cpl["key"]) & (npts == self.parvar_cpl["dim"])):
self.parvar_cpl['sweeplist'] = startlist self.parvar_cpl["sweeplist"] = startlist
self.parvar_cpl['key'] = key self.parvar_cpl["key"] = key
self.parvar_cpl['dim'] = npts self.parvar_cpl["dim"] = npts
incr = (end - strt)/(npts-1) incr = (end - strt) / (npts - 1)
for ii_swp in range(npts): for ii_swp in range(npts):
for swp_idx in idx: for swp_idx in idx:
self.parvar_cpl['sweeplist'][ii_swp][swp_idx] = strt + ii_swp*incr self.parvar_cpl["sweeplist"][ii_swp][swp_idx] = strt + ii_swp * incr
def run(self, oup=True):
def run(self, oup = True):
# check if there is a parvar or only a single # check if there is a parvar or only a single
if len(self.parvar) == 0: if len(self.parvar) == 0:
self.__run_single(oup) self.__run_single(oup)
else: else:
# store the value currently in the swept parameter # store the value currently in the swept parameter
stdval = getattr(self, self.parvar['key']) stdval = getattr(self, self.parvar["key"])
if len(self.parvar_cpl) != 0: if len(self.parvar_cpl) != 0:
stdval2 = getattr(self, self.parvar_cpl['key']) stdval2 = getattr(self, self.parvar_cpl["key"])
# handle the timestamp # handle the timestamp
stddatestr = getattr(self,'fst') stddatestr = getattr(self, "fst")
if (stddatestr == []): if stddatestr == []:
setattr(self, 'fst', datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) setattr(self, "fst", datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
# give it a useful name
stdfilepat = getattr(self, "fpa")
if stdfilepat == []:
setattr(self, "fpa", self.parvar["key"] + "_swp")
# give it a useful name
stdfilepat = getattr(self,'fpa')
if (stdfilepat == []):
setattr(self, 'fpa', self.parvar['key'] + '_swp')
# actual iteration over the sweeplist # actual iteration over the sweeplist
for ii in range(self.parvar['dim']): for ii in range(self.parvar["dim"]):
setattr(self, self.parvar['key'], self.parvar['sweeplist'][ii]) setattr(self, self.parvar["key"], self.parvar["sweeplist"][ii])
if len(self.parvar_cpl) != 0: # as well as the coupled variable if len(self.parvar_cpl) != 0: # as well as the coupled variable
setattr(self, self.parvar_cpl['key'], self.parvar_cpl['sweeplist'][ii]) setattr(
self, self.parvar_cpl["key"], self.parvar_cpl["sweeplist"][ii]
)
self.__run_single(oup) self.__run_single(oup)
# save parvar info as attribute, which means that we need to detect the file # save parvar info as attribute, which means that we need to detect the file
if getattr(self,'nos') != 0: # this one is suspicious... if getattr(self, "nos") != 0: # this one is suspicious...
if self.HDFfile == []: if self.HDFfile == []:
self.HDFfile = self.__guess_savepath() self.HDFfile = self.__guess_savepath()
try: try:
# this is probably erroneous and was never recognized...! self.parvar is not a key/value pair # this is probably erroneous and was never recognized...! self.parvar is not a key/value pair
f = h5py.File(self.HDFfile, 'r+') f = h5py.File(self.HDFfile, "r+")
for key in self.parvar: for key in self.parvar:
f.attrs.create(key, self.parvar[key]) f.attrs.create(key, self.parvar[key])
f.close() f.close()
except: except:
print('Problem opening file ' + self.HDFfile) print("Problem opening file " + self.HDFfile)
setattr(self, self.parvar['key'], stdval) # set back to non-swept value
setattr(self, 'fst', stddatestr) # set back to non-swept value
setattr(self, 'fpa', stdfilepat) # set back to non-swept value
if len(self.parvar_cpl) != 0:
setattr(self, self.parvar_cpl['key'], stdval2) # set back to non-swept value
setattr(self, self.parvar["key"], stdval) # set back to non-swept value
def readHDF(self, filename = ''): setattr(self, "fst", stddatestr) # set back to non-swept value
if filename != '': setattr(self, "fpa", stdfilepat) # set back to non-swept value
if len(self.parvar_cpl) != 0:
setattr(
self, self.parvar_cpl["key"], stdval2
) # set back to non-swept value
def readHDF(self, filename=""):
if filename != "":
self.HDFfile = filename self.HDFfile = filename
self.HDF.load(self.HDFfile) self.HDF.load(self.HDFfile)
# helper functoin to guess the savepath from the file. This should not be called, since it should be obtained from the output of the program call
# helper functoin to guess the savepath from the file. This should not be called, since it should be obtained from the output of the program call
def __guess_savepath(self): def __guess_savepath(self):
savepath = getattr(self,'spt') savepath = getattr(self, "spt")
if savepath == []: savepath = './asdf/' # not recommended here: knowledge about the standard directory in the cpp file.... could be parsed, but user will usually provide a folder to limr.spt if savepath == []:
if savepath[-1] != '/': savepath += '/' # and that little fix since users seldomly put the '/' for the directory... savepath = "./asdf/" # not recommended here: knowledge about the standard directory in the cpp file.... could be parsed, but user will usually provide a folder to limr.spt
savepath = savepath + getattr(self,'fst') + '_' + getattr(self,'fpa') + '.h5' if savepath[-1] != "/":
savepath += "/" # and that little fix since users seldomly put the '/' for the directory...
savepath = savepath + getattr(self, "fst") + "_" + getattr(self, "fpa") + ".h5"
return savepath return savepath
# run for one single constellation # run for one single constellation
def __run_single(self, oup = True): def __run_single(self, oup=True):
terminated = False terminated = False
while (terminated == False): while terminated == False:
str2call= self.Cprog str2call = self.Cprog
for key in self.parsinp: for key in self.parsinp:
vals = getattr(self,key) vals = getattr(self, key)
if (vals == []): continue # ignore arguments that are not set if vals == []:
str2call += ' -' + key # set the key and then the value/s continue # ignore arguments that are not set
str2call += " -" + key # set the key and then the value/s
if isinstance(vals, (list, np.ndarray)): if isinstance(vals, (list, np.ndarray)):
for val in vals: for val in vals:
str2call += ' ' + str(val) str2call += " " + str(val)
else: else:
str2call += ' ' + str(vals) str2call += " " + str(vals)
if oup:
if oup: print(str2call) print(str2call)
p = subprocess.Popen(str2call.split(), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT); p = subprocess.Popen(
str2call.split(),
if getattr(self,'nos') != 0: shell=False,
terminated = True stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
if getattr(self, "nos") != 0:
terminated = True
for line_b in p.stdout.readlines(): for line_b in p.stdout.readlines():
line = line_b.decode('utf-8').rstrip() line = line_b.decode("utf-8").rstrip()
if oup: print(line), if oup:
if '.h5' in line: print(line),
if ".h5" in line:
self.HDFfile = line self.HDFfile = line
terminated = True terminated = True
if 'Unable to open device' in line: if "Unable to open device" in line:
terminated = True terminated = True
if 'Muted output, exiting immediate' in line: if "Muted output, exiting immediate" in line:
terminated = True terminated = True
if self.Cprog + ': not found' in line: if self.Cprog + ": not found" in line:
terminated = True terminated = True
if 'Devices found: 0' in line: if "Devices found: 0" in line:
terminated = True terminated = True
if 'Segmentation' in line: if "Segmentation" in line:
self.segcount += 1 self.segcount += 1
terminated = False terminated = False
self.retval = p.wait() self.retval = p.wait()
if terminated == False: if terminated == False:
print('RE-RUNNING DUE TO PROBLEM WITH SAVING!!!') print("RE-RUNNING DUE TO PROBLEM WITH SAVING!!!")
# class for accessing data of stored HDF5 file # class for accessing data of stored HDF5 file
class HDF(): class HDF:
def __init__(self, filename = ''): def __init__(self, filename=""):
# check first for the filename provided # check first for the filename provided
if filename != '': if filename != "":
self.HDFsrc = filename self.HDFsrc = filename
else: else:
self.HDFsrc = '' self.HDFsrc = ""
# get data # get data
self.__get_data() self.__get_data()
# just an alias for __init__ that does load a specific file # just an alias for __init__ that does load a specific file
def load(self, filename = ''): def load(self, filename=""):
self.__init__(filename) self.__init__(filename)
# gets the data of the file # gets the data of the file
def __get_data(self): def __get_data(self):
if (self.HDFsrc == '') | (self.HDFsrc == []): if (self.HDFsrc == "") | (self.HDFsrc == []):
# initialize all as empty # initialize all as empty
self.tdy = [] self.tdy = []
self.tdx = [] self.tdx = []
self.attrs = [] self.attrs = []
self.parsoutp = {} self.parsoutp = {}
self.parvar = {} self.parvar = {}
else: else:
f = h5py.File(self.HDFsrc, 'r') f = h5py.File(self.HDFsrc, "r")
HDFkeys = list(f.keys()) HDFkeys = list(f.keys())
for ii, HDFkey in enumerate(HDFkeys): for ii, HDFkey in enumerate(HDFkeys):
if ii == 0: if ii == 0:
# initialize data array # initialize data array
dsize = f[HDFkey].shape dsize = f[HDFkey].shape
inddim = dsize[0] inddim = dsize[0]
self.tdy = np.zeros((int(dsize[1]/2), int(dsize[0] * len(HDFkeys))),dtype=np.complex_) self.tdy = np.zeros(
(int(dsize[1] / 2), int(dsize[0] * len(HDFkeys))),
dtype=np.complex_,
)
# initialize the output objects # initialize the output objects
self.attrs = [dynclass() for jj in range(len(HDFkeys))] self.attrs = [dynclass() for jj in range(len(HDFkeys))]
# get the attribute keys # get the attribute keys
self.parsoutp = {} self.parsoutp = {}
ii_oupargs = 0 ii_oupargs = 0
for item in f[HDFkey].attrs.items(): for item in f[HDFkey].attrs.items():
itemname = item[0][5:] itemname = item[0][5:]
itemarg = item[0][1:4] itemarg = item[0][1:4]
if not ('///' in itemarg): if not ("///" in itemarg):
self.parsoutp[itemarg] = [ item[1], itemname] self.parsoutp[itemarg] = [item[1], itemname]
else: else:
self.parsoutp['//'+str(ii_oupargs)] = [ item[1], itemname] self.parsoutp["//" + str(ii_oupargs)] = [item[1], itemname]
ii_oupargs+=1 ii_oupargs += 1
# look for eventual parvar lists # look for eventual parvar lists
self.parvar = {} self.parvar = {}
for item in f.attrs.items(): for item in f.attrs.items():
self.parvar[item[0]] = item[1] self.parvar[item[0]] = item[1]
# Get the data # Get the data
data_raw = np.array(f[HDFkey]) data_raw = np.array(f[HDFkey])
try: try:
self.tdy[:,ii*inddim:(ii+1)*inddim] = np.transpose(np.float_(data_raw[:,::2])) + 1j*np.transpose(np.float_(data_raw[:,1::2])) self.tdy[:, ii * inddim : (ii + 1) * inddim] = np.transpose(
np.float_(data_raw[:, ::2])
) + 1j * np.transpose(np.float_(data_raw[:, 1::2]))
except: except:
pass pass
# Get the arguments # Get the arguments
ii_oupargs = 0 ii_oupargs = 0
for item in f[HDFkey].attrs.items(): for item in f[HDFkey].attrs.items():
itemname = item[0][5:] itemname = item[0][5:]
itemarg = item[0][1:4] itemarg = item[0][1:4]
if not ('///' in itemarg): if not ("///" in itemarg):
setattr(self.attrs[ii], itemarg, item[1]) setattr(self.attrs[ii], itemarg, item[1])
else: else:
setattr(self.attrs[ii], '//'+str(ii_oupargs), item[1]) setattr(self.attrs[ii], "//" + str(ii_oupargs), item[1])
ii_oupargs+=1 ii_oupargs += 1
f.close() f.close()
srate_MHz = getattr(self.attrs[0], 'sra')*1e-6 srate_MHz = getattr(self.attrs[0], "sra") * 1e-6
self.tdx = 1/srate_MHz*np.arange(self.tdy.shape[0]) self.tdx = 1 / srate_MHz * np.arange(self.tdy.shape[0])
# get an argument by matching the text description # get an argument by matching the text description
def attr_by_txt(self, pattern): def attr_by_txt(self, pattern):
for key in sorted(self.parsoutp): for key in sorted(self.parsoutp):
if pattern in self.parsoutp[key][1]: # pattern match if pattern in self.parsoutp[key][1]: # pattern match
attr = getattr(self.attrs[0], key) attr = getattr(self.attrs[0], key)
try: try:
ouparr = np.zeros( ( len(attr), len(self.attrs)), attr.dtype) ouparr = np.zeros((len(attr), len(self.attrs)), attr.dtype)
except: except:
ouparr = np.zeros( ( 1, len(self.attrs)), attr.dtype) ouparr = np.zeros((1, len(self.attrs)), attr.dtype)
for ii in np.arange(len(self.attrs)): for ii in np.arange(len(self.attrs)):
ouparr[:,ii] = getattr(self.attrs[ii], key) ouparr[:, ii] = getattr(self.attrs[ii], key)
return np.transpose(ouparr) return np.transpose(ouparr)
print('Problem obtaining the attribute from the description using the pattern ' + pattern + '!') print(
print('Valid descriptions are: ') "Problem obtaining the attribute from the description using the pattern "
+ pattern
+ "!"
)
print("Valid descriptions are: ")
self.print_params() self.print_params()
# get an argument by key # get an argument by key
def attr_by_key(self, key): def attr_by_key(self, key):
if key in dir(self.attrs[0]): if key in dir(self.attrs[0]):
attr = getattr(self.attrs[0], key) attr = getattr(self.attrs[0], key)
try: try:
ouparr = np.zeros( ( len(attr), len(self.attrs)), attr.dtype) ouparr = np.zeros((len(attr), len(self.attrs)), attr.dtype)
except: except:
ouparr = np.zeros( ( 1, len(self.attrs)), attr.dtype) ouparr = np.zeros((1, len(self.attrs)), attr.dtype)
for ii in np.arange(len(self.attrs)): for ii in np.arange(len(self.attrs)):
ouparr[:,ii] = getattr(self.attrs[ii], key) ouparr[:, ii] = getattr(self.attrs[ii], key)
return np.transpose(ouparr) return np.transpose(ouparr)
print('Problem obtaining the attribute from key ' + key + '!') print("Problem obtaining the attribute from key " + key + "!")
print('Valid keys are: ') print("Valid keys are: ")
self.print_params() self.print_params()
# print the arguments # print the arguments
def print_params(self, ouponly = False): def print_params(self, ouponly=False):
for key in sorted(self.parsoutp): for key in sorted(self.parsoutp):
val = getattr(self.attrs[0], key) val = getattr(self.attrs[0], key)
if not('//' in key): # input argument? if not ("//" in key): # input argument?
if ouponly: continue; if ouponly:
continue
print('{:<5}: {:>50} {:<25}'.format(key, val, self.parsoutp[key][1]))
print("{:<5}: {:>50} {:<25}".format(key, val, self.parsoutp[key][1]))
def plot_dta(self, fignum = 1, stack = False, dtamax = 0.0):
if (fignum == 1) & stack: fignum = 2; def plot_dta(self, fignum=1, stack=False, dtamax=0.0):
if (fignum == 1) & stack:
fignum = 2
if self.tdy != []: if self.tdy != []:
if dtamax == 0: if dtamax == 0:
dtamax = np.max(np.max(abs(self.tdy),axis=0)) dtamax = np.max(np.max(abs(self.tdy), axis=0))
offset = 1.5*dtamax offset = 1.5 * dtamax
plt.figure(fignum) plt.figure(fignum)
plt.clf() plt.clf()
if stack: if stack:
for ii in np.arange(self.tdy.shape[1]): for ii in np.arange(self.tdy.shape[1]):
plt.plot(self.tdx, self.tdy[:,ii].real + ii* offset) plt.plot(self.tdx, self.tdy[:, ii].real + ii * offset)
else: else:
plt.plot(self.tdx, self.tdy.real) plt.plot(self.tdx, self.tdy.real)
plt.xlabel('$t$ [$\mu$s]') plt.xlabel("$t$ [$\mu$s]")
plt.ylabel('$y$ [Counts]') plt.ylabel("$y$ [Counts]")
# empty class to store dynamic attributes, basically for the attributes in HDF keys # empty class to store dynamic attributes, basically for the attributes in HDF keys
class dynclass: class dynclass:
pass pass
@ -457,19 +495,20 @@ import serial
import time import time
from os import listdir from os import listdir
class PSU():
class PSU:
def __init__(self): def __init__(self):
self.GperV = 14.309 self.GperV = 14.309
self.sleeptime = 0.4 self.sleeptime = 0.4
devdir = '/dev/' devdir = "/dev/"
ttydevs = [f for f in listdir(devdir) if 'ttyUSB' in f] ttydevs = [f for f in listdir(devdir) if "ttyUSB" in f]
# ttydev = devdir + [f for f in ttydevs if int(f[-1]) > 4][0] # ttydev = devdir + [f for f in ttydevs if int(f[-1]) > 4][0]
ttydev = devdir + [f for f in ttydevs][0] ttydev = devdir + [f for f in ttydevs][0]
self.psu=serial.Serial(ttydev, stopbits=2, dsrdtr=True) self.psu = serial.Serial(ttydev, stopbits=2, dsrdtr=True)
# read at the beginning to remove eventual junk # read at the beginning to remove eventual junk
response = self.psu.read_all() response = self.psu.read_all()
@ -477,21 +516,20 @@ class PSU():
self.psu.write("*IDN?\r\n") self.psu.write("*IDN?\r\n")
time.sleep(self.sleeptime) time.sleep(self.sleeptime)
response = self.psu.read_all() response = self.psu.read_all()
if response == 'HEWLETT-PACKARD,E3631A,0,2.1-5.0-1.0\r\n': if response == "HEWLETT-PACKARD,E3631A,0,2.1-5.0-1.0\r\n":
print('Success in opening the HP PSU!') print("Success in opening the HP PSU!")
else: else:
print('Fail!!!') print("Fail!!!")
self.psu.write("INST:SEL P6V\r\n") self.psu.write("INST:SEL P6V\r\n")
time.sleep(self.sleeptime) time.sleep(self.sleeptime)
self.psu.write("OUTP:STAT ON\r\n") self.psu.write("OUTP:STAT ON\r\n")
time.sleep(self.sleeptime) time.sleep(self.sleeptime)
self.psu.close() self.psu.close()
def getVoltage(self): def getVoltage(self):
if not self.psu.isOpen(): if not self.psu.isOpen():
self.psu.open() self.psu.open()
# read at the beginning to remove eventual junk # read at the beginning to remove eventual junk
@ -502,32 +540,31 @@ class PSU():
actval = float(self.psu.read_all()) actval = float(self.psu.read_all())
self.psu.close() self.psu.close()
return actval return actval
def setVoltage(self, setval, dV=0.02, ramptime=0.1):
def setVoltage(self, setval, dV = 0.02, ramptime = 0.1):
actval = self.getVoltage() actval = self.getVoltage()
diff = setval - actval diff = setval - actval
dVsigned = dV * (-1 if diff < 0 else 1) dVsigned = dV * (-1 if diff < 0 else 1)
if not self.psu.isOpen(): if not self.psu.isOpen():
self.psu.open() self.psu.open()
while (abs(diff) > dV): while abs(diff) > dV:
actval += dVsigned actval += dVsigned
diff -= dVsigned diff -= dVsigned
self.psu.write("VOLT " + str(actval) + "\r\n") self.psu.write("VOLT " + str(actval) + "\r\n")
time.sleep(ramptime) time.sleep(ramptime)
self.psu.write("VOLT " + str(setval) + "\r\n") self.psu.write("VOLT " + str(setval) + "\r\n")
time.sleep(ramptime) time.sleep(ramptime)
self.psu.close() self.psu.close()
def getField(self): def getField(self):
return self.getVoltage() * self.GperV return self.getVoltage() * self.GperV
def setField(self, field): def setField(self, field):
return self.setVoltage(field / self.GperV) return self.setVoltage(field / self.GperV)