first version of new bookeeping system

This commit is contained in:
Fabian Joswig 2021-11-01 17:14:30 +00:00
parent b86dda2394
commit e4d7d56180
4 changed files with 38 additions and 54 deletions

View file

@ -33,4 +33,4 @@ jobs:
pip install pytest-benchmark pip install pytest-benchmark
- name: Run tests - name: Run tests
run: pytest --cov=pyerrors -v run: pytest --cov=pyerrors -vv

View file

@ -24,9 +24,6 @@ class Obs:
Attributes Attributes
---------- ----------
e_tag_global : int
Integer which determines which part of the name belongs
to the ensemble and which to the replicum.
S_global : float S_global : float
Standard value for S (default 2.0) Standard value for S (default 2.0)
S_dict : dict S_dict : dict
@ -41,12 +38,11 @@ class Obs:
Standard value for N_sigma (default 1.0) Standard value for N_sigma (default 1.0)
""" """
__slots__ = ['names', 'shape', 'r_values', 'deltas', 'N', '_value', '_dvalue', __slots__ = ['names', 'shape', 'r_values', 'deltas', 'N', '_value', '_dvalue',
'ddvalue', 'reweighted', 'S', 'tau_exp', 'N_sigma', 'e_names', 'ddvalue', 'reweighted', 'S', 'tau_exp', 'N_sigma',
'e_content', 'e_dvalue', 'e_ddvalue', 'e_tauint', 'e_dtauint', 'e_dvalue', 'e_ddvalue', 'e_tauint', 'e_dtauint',
'e_windowsize', 'e_rho', 'e_drho', 'e_n_tauint', 'e_n_dtauint', 'e_windowsize', 'e_rho', 'e_drho', 'e_n_tauint', 'e_n_dtauint',
'idl', 'is_merged', 'tag', '__dict__'] 'idl', 'is_merged', 'tag', '__dict__']
e_tag_global = 0
S_global = 2.0 S_global = 2.0
S_dict = {} S_dict = {}
tau_exp_global = 0.0 tau_exp_global = 0.0
@ -141,6 +137,19 @@ class Obs:
def dvalue(self): def dvalue(self):
return self._dvalue return self._dvalue
@property
def e_names(self):
return sorted(set([o.split('|')[0] for o in self.names]))
@property
def e_content(self):
res = {}
for e, e_name in enumerate(self.e_names):
res[e_name] = sorted(filter(lambda x: x.startswith(e_name + '|'), self.names))
if e_name in self.names:
res[e_name].append(e_name)
return res
def expand_deltas(self, deltas, idx, shape): def expand_deltas(self, deltas, idx, shape):
"""Expand deltas defined on idx to a regular, contiguous range, where holes are filled by 0. """Expand deltas defined on idx to a regular, contiguous range, where holes are filled by 0.
If idx is of type range, the deltas are not changed If idx is of type range, the deltas are not changed
@ -202,23 +211,12 @@ class Obs:
N_sigma : float N_sigma : float
number of standard deviations from zero until the tail is number of standard deviations from zero until the tail is
attached to the autocorrelation function (default 1) attached to the autocorrelation function (default 1)
e_tag : int
number of characters which label the ensemble. The remaining
ones label replica (default 0)
fft : bool fft : bool
determines whether the fft algorithm is used for the computation determines whether the fft algorithm is used for the computation
of the autocorrelation function (default True) of the autocorrelation function (default True)
""" """
if 'e_tag' in kwargs: e_content = self.e_content
e_tag_local = kwargs.get('e_tag')
if not isinstance(e_tag_local, int):
raise TypeError('Error: e_tag is not integer')
else:
e_tag_local = Obs.e_tag_global
self.e_names = sorted(set([o[:e_tag_local] for o in self.names]))
self.e_content = {}
self.e_dvalue = {} self.e_dvalue = {}
self.e_ddvalue = {} self.e_ddvalue = {}
self.e_tauint = {} self.e_tauint = {}
@ -295,36 +293,26 @@ class Obs:
else: else:
self.N_sigma = Obs.N_sigma_global self.N_sigma = Obs.N_sigma_global
if max([len(x) for x in self.names]) <= e_tag_local:
for e, e_name in enumerate(self.e_names):
self.e_content[e_name] = [e_name]
else:
for e, e_name in enumerate(self.e_names):
if len(e_name) < e_tag_local:
self.e_content[e_name] = [e_name]
else:
self.e_content[e_name] = sorted(filter(lambda x: x.startswith(e_name), self.names))
for e, e_name in enumerate(self.e_names): for e, e_name in enumerate(self.e_names):
r_length = [] r_length = []
for r_name in self.e_content[e_name]: for r_name in e_content[e_name]:
if self.idl[r_name] is range: if self.idl[r_name] is range:
r_length.append(len(self.idl[r_name])) r_length.append(len(self.idl[r_name]))
else: else:
r_length.append((self.idl[r_name][-1] - self.idl[r_name][0] + 1)) r_length.append((self.idl[r_name][-1] - self.idl[r_name][0] + 1))
e_N = np.sum([self.shape[r_name] for r_name in self.e_content[e_name]]) e_N = np.sum([self.shape[r_name] for r_name in e_content[e_name]])
w_max = max(r_length) // 2 w_max = max(r_length) // 2
e_gamma[e_name] = np.zeros(w_max) e_gamma[e_name] = np.zeros(w_max)
self.e_rho[e_name] = np.zeros(w_max) self.e_rho[e_name] = np.zeros(w_max)
self.e_drho[e_name] = np.zeros(w_max) self.e_drho[e_name] = np.zeros(w_max)
for r_name in self.e_content[e_name]: for r_name in e_content[e_name]:
e_gamma[e_name] += self.calc_gamma(self.deltas[r_name], self.idl[r_name], self.shape[r_name], w_max, fft) e_gamma[e_name] += self.calc_gamma(self.deltas[r_name], self.idl[r_name], self.shape[r_name], w_max, fft)
gamma_div = np.zeros(w_max) gamma_div = np.zeros(w_max)
for r_name in self.e_content[e_name]: for r_name in e_content[e_name]:
gamma_div += self.calc_gamma(np.ones((self.shape[r_name])), self.idl[r_name], self.shape[r_name], w_max, fft) gamma_div += self.calc_gamma(np.ones((self.shape[r_name])), self.idl[r_name], self.shape[r_name], w_max, fft)
e_gamma[e_name] /= gamma_div[:w_max] e_gamma[e_name] /= gamma_div[:w_max]
@ -384,11 +372,11 @@ class Obs:
self.ddvalue += (self.e_dvalue[e_name] * self.e_ddvalue[e_name]) ** 2 self.ddvalue += (self.e_dvalue[e_name] * self.e_ddvalue[e_name]) ** 2
self._dvalue = np.sqrt(self.dvalue) self._dvalue = np.sqrt(self.dvalue)
if self.dvalue == 0.0: if self._dvalue == 0.0:
self.ddvalue = 0.0 self.ddvalue = 0.0
else: else:
self.ddvalue = np.sqrt(self.ddvalue) / self.dvalue self.ddvalue = np.sqrt(self.ddvalue) / self.dvalue
return 0 return
def print(self, level=1): def print(self, level=1):
"""Print basic properties of the Obs.""" """Print basic properties of the Obs."""
@ -400,7 +388,7 @@ class Obs:
else: else:
percentage = np.abs(self.dvalue / self.value) * 100 percentage = np.abs(self.dvalue / self.value) * 100
print('Result\t %3.8e +/- %3.8e +/- %3.8e (%3.3f%%)' % (self.value, self.dvalue, self.ddvalue, percentage)) print('Result\t %3.8e +/- %3.8e +/- %3.8e (%3.3f%%)' % (self.value, self.dvalue, self.ddvalue, percentage))
if hasattr(self, 'e_names'): if hasattr(self, 'e_dvalue'):
if len(self.e_names) > 1: if len(self.e_names) > 1:
print(' Ensemble errors:') print(' Ensemble errors:')
for e_name in self.e_names: for e_name in self.e_names:

View file

@ -30,9 +30,8 @@ def test_least_squares():
out = pe.least_squares(x, oy, func) out = pe.least_squares(x, oy, func)
beta = out.fit_parameters beta = out.fit_parameters
pe.Obs.e_tag_global = 5
for i in range(2): for i in range(2):
beta[i].gamma_method(e_tag=5, S=1.0) beta[i].gamma_method(S=1.0)
assert math.isclose(beta[i].value, popt[i], abs_tol=1e-5) assert math.isclose(beta[i].value, popt[i], abs_tol=1e-5)
assert math.isclose(pcov[i, i], beta[i].dvalue ** 2, abs_tol=1e-3) assert math.isclose(pcov[i, i], beta[i].dvalue ** 2, abs_tol=1e-3)
assert math.isclose(pe.covariance(beta[0], beta[1]), pcov[0, 1], abs_tol=1e-3) assert math.isclose(pe.covariance(beta[0], beta[1]), pcov[0, 1], abs_tol=1e-3)

View file

@ -135,7 +135,7 @@ def test_fft():
test_obs2 = copy.deepcopy(test_obs1) test_obs2 = copy.deepcopy(test_obs1)
test_obs1.gamma_method() test_obs1.gamma_method()
test_obs2.gamma_method(fft=False) test_obs2.gamma_method(fft=False)
assert max(np.abs(test_obs1.e_rho[''] - test_obs2.e_rho[''])) <= 10 * np.finfo(np.float64).eps assert max(np.abs(test_obs1.e_rho['t'] - test_obs2.e_rho['t'])) <= 10 * np.finfo(np.float64).eps
assert np.abs(test_obs1.dvalue - test_obs2.dvalue) <= 10 * max(test_obs1.dvalue, test_obs2.dvalue) * np.finfo(np.float64).eps assert np.abs(test_obs1.dvalue - test_obs2.dvalue) <= 10 * max(test_obs1.dvalue, test_obs2.dvalue) * np.finfo(np.float64).eps
@ -190,22 +190,19 @@ def test_derived_observables():
assert i_am_one.e_ddvalue['t'] <= 2 * np.finfo(np.float64).eps assert i_am_one.e_ddvalue['t'] <= 2 * np.finfo(np.float64).eps
def test_multi_ens_system(): def test_multi_ens():
names = [] names = ['A0', 'A1|r001', 'A1|r002']
for i in range(100 + int(np.random.rand() * 50)): test_obs = pe.Obs([np.random.rand(50), np.random.rand(50), np.random.rand(50)], names)
tmp_string = '' assert test_obs.e_names == ['A0', 'A1']
for _ in range(int(2 + np.random.rand() * 4)): assert test_obs.e_content['A0'] == ['A0']
tmp_string += random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) assert test_obs.e_content['A1'] == ['A1|r001', 'A1|r002']
names.append(tmp_string)
names = list(set(names))
samples = [np.random.rand(5)] * len(names)
new_obs = pe.Obs(samples, names)
for e_tag_length in range(1, 6): my_sum = 0
new_obs.gamma_method(e_tag=e_tag_length) ensembles = []
e_names = sorted(set([n[:e_tag_length] for n in names])) for i in range(100):
assert e_names == new_obs.e_names my_sum += pe.Obs([np.random.rand(50)], [str(i)])
assert sorted(x for y in sorted(new_obs.e_content.values()) for x in y) == sorted(new_obs.names) ensembles.append(str(i))
assert my_sum.e_names == sorted(ensembles)
def test_overloaded_functions(): def test_overloaded_functions():