bugfix eval expression; closes #83

This commit is contained in:
Dominik Demuth 2023-07-09 19:44:33 +02:00
parent 91afe8224f
commit fbf4246c7e
3 changed files with 103 additions and 52 deletions

View File

@ -438,7 +438,7 @@ class ExperimentContainer(QtCore.QObject):
if (i is None) and (j is None): if (i is None) and (j is None):
prefix = '' prefix = ''
else: else:
prefix = 'g[%i].s[%i].' % (i, j) prefix = f'g[{i}].s[{j}].'
namespace = {prefix + 'x': (self.x, 'x values'), namespace = {prefix + 'x': (self.x, 'x values'),
prefix + 'y': [self.y, 'y values'], prefix + 'y': [self.y, 'y values'],
@ -459,16 +459,33 @@ class ExperimentContainer(QtCore.QObject):
return namespace return namespace
def eval_expression(self, cmds, namespace): def eval_expression(self, cmds, namespace, i=None, j=None):
namespace.update({'x': self._data.x, 'y': self._data.y, 'y_err': self._data.y_err, 'value': self.value}) if i is not None:
namespace['i'] = i
if len(self._fits) == 1: if j is not None:
namespace.update({"fit['%s']" % (convert(pname, old='tex', new='str')): pvalue.value namespace['j'] = j
for (pname, pvalue) in self._manager[self._fits[0]].parameter.items()})
namespace.update({'x': self._data.x, 'y': self._data.y, 'y_err': self._data.y_err, 'value': self.value})
namespace['fit'] = {}
if isinstance(self, FitContainer):
namespace['fit'].update({
'%s' % convert(pname, old='latex', new='plain'): pvalue.value
for (pname, pvalue) in self._data.parameter.items()
})
elif len(self._fits) == 1:
namespace['fit'].update({
'%s' % convert(pname, old='tex', new='str'): pvalue.value
for (pname, pvalue) in self._manager[self._fits[0]].parameter.items()
})
else: else:
for k, f in enumerate(self._fits): for k, f in enumerate(self._fits):
namespace.update({"fit['%s_%i']" % (convert(pname, old='tex', new='str'), k): pvalue.value namespace['fit'].update({
for (pname, pvalue) in self._manager[f].parameter.items()}) "%s_%i" % (convert(pname, old='tex', new='str'), k): pvalue.value
for (pname, pvalue) in self._manager[f].parameter.items()
})
new_data = self.copy() new_data = self.copy()
for c in cmds: for c in cmds:

View File

@ -21,36 +21,53 @@ class Namespace:
self.top_levels = {} self.top_levels = {}
if basic: if basic:
self.add_namespace({'x': (None, 'x values'), 'y': (None, 'x values'), 'y_err': (None, 'y error values'), self.add_namespace(
'fit': (None, 'dictionary of fit parameter', 'fit["PIKA"]'), 'np': (np, 'numpy module')}, {'x': (None, 'x values'),
parents=('Basic', 'General')) 'y': (None, 'x values'),
'y_err': (None, 'y error values'),
'fit': (None, 'dictionary of fit parameter', 'fit["PIKA"]'),
'np': (np, 'numpy module'),
},
parents=('Basic', 'General'),
)
self.add_namespace({'sin': (np.sin, 'Sine', 'sin(PIKA)'), 'cos': (np.cos, 'Cosine', 'cos(PIKA)'), self.add_namespace(
'tan': (np.tan, 'Tangens', 'tan(PIKA)'), 'ln': (np.log, 'Natural Logarithm', 'ln(PIKA)'), {'sin': (np.sin, 'Sine', 'sin(PIKA)'),
'log': (np.log10, 'Logarithm (base 10)', 'log(PIKA)'), 'cos': (np.cos, 'Cosine', 'cos(PIKA)'),
'exp': (np.exp, 'Exponential', 'exp(PIKA)'), 'sqrt': (np.sqrt, 'Root', 'sqrt(PIKA)'), 'tan': (np.tan, 'Tangens', 'tan(PIKA)'),
'lin_range': (np.linspace, 'N evenly spaced over interval [start, stop]', 'ln': (np.log, 'Natural Logarithm', 'ln(PIKA)'),
'lin_range(start, stop, N)'), 'log': (np.log10, 'Logarithm (base 10)', 'log(PIKA)'),
'log_range': (np.geomspace, 'N evenly spaced (log-scale) over interval [start, stop]', 'exp': (np.exp, 'Exponential', 'exp(PIKA)'),
'lin_range(start, stop, N)')}, 'sqrt': (np.sqrt, 'Root', 'sqrt(PIKA)'),
parents=('Basic', 'Functions')) 'lin_range': (np.linspace, 'N evenly spaced over interval [start, stop]', 'lin_range(start, stop, N)'),
'log_range': (np.geomspace, 'N evenly spaced (log-scale) over interval [start, stop]', 'lin_range(start, stop, N)'),
self.add_namespace({'max': (np.max, 'Maximum value', 'max(PIKA)'), },
'min': (np.min, 'Minimum value', 'min(PIKA)'), parents=('Basic', 'Functions'))
'argmax': (np.argmax, 'Index of maximum value', 'argmax(PIKA)'),
'argmin': (np.argmax, 'Index of minimum value', 'argmin(PIKA)')}, self.add_namespace(
parents=('Basic', 'Values')) {'max': (np.max, 'Maximum value', 'max(PIKA)'),
'min': (np.min, 'Minimum value', 'min(PIKA)'),
'argmax': (np.argmax, 'Index of maximum value', 'argmax(PIKA)'),
'argmin': (np.argmax, 'Index of minimum value', 'argmin(PIKA)'),
},
parents=('Basic', 'Values')),
if const: if const:
self.add_namespace({'e': (constants.e, 'e / As'), 'eps0': (constants.epsilon0, 'epsilon0 / As/Vm'), self.add_namespace(
'Eu': (constants.Eu,), 'h': (constants.h, 'h / eVs'), {'e': (constants.e, 'e / As'),
'hbar': (constants.hbar, 'hbar / eVs'), 'kB': (constants.kB, 'kB / eV/K'), 'eps0': (constants.epsilon0, 'epsilon0 / As/Vm'),
'mu0': (constants.mu0, 'mu0 / Vs/Am'), 'NA': (constants.NA, 'NA / 1/mol'), 'Eu': (constants.Eu,), 'h': (constants.h, 'h / eVs'),
'pi': (constants.pi,), 'R': (constants.R, 'R / eV')}, 'hbar': (constants.hbar, 'hbar / eVs'), 'kB': (constants.kB, 'kB / eV/K'),
parents=('Constants', 'Maybe useful')) 'mu0': (constants.mu0, 'mu0 / Vs/Am'), 'NA': (constants.NA, 'NA / 1/mol'),
'pi': (constants.pi,), 'R': (constants.R, 'R / eV'),
},
parents=('Constants', 'Maybe useful'),
)
self.add_namespace({f'gamma["{k}"]': (v, k, f'gamma["{k}"]') for k, v in constants.gamma.items()}, self.add_namespace(
parents=('Constants', 'Magnetogyric ratios (in 1/(sT))')) {f'gamma["{k}"]': (v, k, f'gamma["{k}"]') for k, v in constants.gamma.items()},
parents=('Constants', 'Magnetogyric ratios (in 1/(sT))')
)
if fitfuncs: if fitfuncs:
self.make_dict_from_fitmodule(models) self.make_dict_from_fitmodule(models)
@ -104,9 +121,18 @@ class Namespace:
graph = namedtuple('graphs', ['s']) graph = namedtuple('graphs', ['s'])
sets = namedtuple('sets', ['x', 'y', 'y_err', 'value', 'fit'], defaults=(None,)) sets = namedtuple('sets', ['x', 'y', 'y_err', 'value', 'fit'], defaults=(None,))
gamma = {}
gs = re.compile(r'g\[(\d+)].s\[(\d+)].(x|y(?:_err)*|value|fit)') gs = re.compile(r'g\[(\d+)].s\[(\d+)].(x|y(?:_err)*|value|fit)')
gamma_re = re.compile(r'gamma\["(\w+)"\]')
for k, v in self.namespace.items(): for k, v in self.namespace.items():
m = gamma_re.match(k)
if m:
gamma[m.group(1)] = v[0]
continue
m = gs.match(k) m = gs.match(k)
if m: if m:
if 'g' not in ret_dic: if 'g' not in ret_dic:
@ -118,7 +144,7 @@ class Namespace:
gg = ret_dic['g'][int(g_num)] gg = ret_dic['g'][int(g_num)]
if int(s_num) not in gg.s: if int(s_num) not in gg.s:
gg.s[int(s_num)] = sets('', '', '', '') gg.s[int(s_num)] = sets('', '', '', '', {})
ss = gg.s[int(s_num)] ss = gg.s[int(s_num)]
if pos == 'fit': if pos == 'fit':
@ -130,8 +156,11 @@ class Namespace:
else: else:
ret_dic['g'][int(g_num)].s[int(s_num)] = ss._replace(**{pos: v[0]}) ret_dic['g'][int(g_num)].s[int(s_num)] = ss._replace(**{pos: v[0]})
else: continue
ret_dic[k] = v[0]
ret_dic[k] = v[0]
ret_dic['gamma'] = gamma
return ret_dic return ret_dic

View File

@ -939,21 +939,26 @@ class UpperManagement(QtCore.QObject):
self.undostack.beginMacro('Evaluate expression') self.undostack.beginMacro('Evaluate expression')
failures = [] failures = []
for sid in set_ids: for i, g in enumerate(self.graphs.values()):
data_i = self.data[sid] for j, sid in enumerate(g.sets):
try:
# use a copy of original namespace if sid not in set_ids:
new_data = data_i.eval_expression(cmds, dict(ns)) continue
if overwrite:
cmd = EvalCommand(self.data, sid, new_data, 'Evaluate expression') data_i = self.data[sid]
self.undostack.push(cmd) try:
else: # use a copy of original namespace
new_id = self.copy_sets(sets=[sid]) new_data = data_i.eval_expression(cmds, dict(ns), i=i, j=j)
self.data[new_id[0]].data = new_data if overwrite:
except Exception as e: cmd = EvalCommand(self.data, sid, new_data, 'Evaluate expression')
failures.append((data_i, e)) self.undostack.push(cmd)
logger.warning(str(data_i) + ' failed with Exception: ' + ''.join(e.args)) else:
continue new_id = self.copy_sets(sets=[sid])
self.data[new_id[0]].data = new_data
except Exception as e:
failures.append((data_i, e))
logger.warning(str(data_i) + ' failed with Exception: ' + ''.join(e.args))
continue
if overwrite: if overwrite:
self.undostack.endMacro() self.undostack.endMacro()