forked from IPKM/nmreval
		
	bugfix eval expression; closes #83
This commit is contained in:
		@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user