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

View File

@ -21,36 +21,53 @@ class Namespace:
self.top_levels = {}
if basic:
self.add_namespace({'x': (None, 'x values'), '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(
{'x': (None, 'x values'),
'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)'),
'tan': (np.tan, 'Tangens', 'tan(PIKA)'), 'ln': (np.log, 'Natural Logarithm', 'ln(PIKA)'),
'log': (np.log10, 'Logarithm (base 10)', 'log(PIKA)'),
'exp': (np.exp, 'Exponential', 'exp(PIKA)'), 'sqrt': (np.sqrt, 'Root', 'sqrt(PIKA)'),
'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)')},
parents=('Basic', 'Functions'))
self.add_namespace({'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'))
self.add_namespace(
{'sin': (np.sin, 'Sine', 'sin(PIKA)'),
'cos': (np.cos, 'Cosine', 'cos(PIKA)'),
'tan': (np.tan, 'Tangens', 'tan(PIKA)'),
'ln': (np.log, 'Natural Logarithm', 'ln(PIKA)'),
'log': (np.log10, 'Logarithm (base 10)', 'log(PIKA)'),
'exp': (np.exp, 'Exponential', 'exp(PIKA)'),
'sqrt': (np.sqrt, 'Root', 'sqrt(PIKA)'),
'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)'),
},
parents=('Basic', 'Functions'))
self.add_namespace(
{'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:
self.add_namespace({'e': (constants.e, 'e / As'), 'eps0': (constants.epsilon0, 'epsilon0 / As/Vm'),
'Eu': (constants.Eu,), 'h': (constants.h, 'h / eVs'),
'hbar': (constants.hbar, 'hbar / eVs'), 'kB': (constants.kB, 'kB / eV/K'),
'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(
{'e': (constants.e, 'e / As'),
'eps0': (constants.epsilon0, 'epsilon0 / As/Vm'),
'Eu': (constants.Eu,), 'h': (constants.h, 'h / eVs'),
'hbar': (constants.hbar, 'hbar / eVs'), 'kB': (constants.kB, 'kB / eV/K'),
'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()},
parents=('Constants', 'Magnetogyric ratios (in 1/(sT))'))
self.add_namespace(
{f'gamma["{k}"]': (v, k, f'gamma["{k}"]') for k, v in constants.gamma.items()},
parents=('Constants', 'Magnetogyric ratios (in 1/(sT))')
)
if fitfuncs:
self.make_dict_from_fitmodule(models)
@ -104,9 +121,18 @@ class Namespace:
graph = namedtuple('graphs', ['s'])
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)')
gamma_re = re.compile(r'gamma\["(\w+)"\]')
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)
if m:
if 'g' not in ret_dic:
@ -118,7 +144,7 @@ class Namespace:
gg = ret_dic['g'][int(g_num)]
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)]
if pos == 'fit':
@ -130,8 +156,11 @@ class Namespace:
else:
ret_dic['g'][int(g_num)].s[int(s_num)] = ss._replace(**{pos: v[0]})
else:
ret_dic[k] = v[0]
continue
ret_dic[k] = v[0]
ret_dic['gamma'] = gamma
return ret_dic

View File

@ -939,21 +939,26 @@ class UpperManagement(QtCore.QObject):
self.undostack.beginMacro('Evaluate expression')
failures = []
for sid in set_ids:
data_i = self.data[sid]
try:
# use a copy of original namespace
new_data = data_i.eval_expression(cmds, dict(ns))
if overwrite:
cmd = EvalCommand(self.data, sid, new_data, 'Evaluate expression')
self.undostack.push(cmd)
else:
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
for i, g in enumerate(self.graphs.values()):
for j, sid in enumerate(g.sets):
if sid not in set_ids:
continue
data_i = self.data[sid]
try:
# use a copy of original namespace
new_data = data_i.eval_expression(cmds, dict(ns), i=i, j=j)
if overwrite:
cmd = EvalCommand(self.data, sid, new_data, 'Evaluate expression')
self.undostack.push(cmd)
else:
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:
self.undostack.endMacro()